Release v1.20260501.0 fixes a failure mode in dnstt-server

This release fixes a bug in dnstt-server that could cause it to stop processing traffic while still running, likely more often under conditions of heavy load. The symptom was that the server would continue receiving incoming DNS queries, but would no longer send DNS responses.

Here is a description of the cause of the bug. The server started up two goroutines, recvLoop for receiving queries and sendLoop for sending responses. Under normal conditions, both of these goroutines are expected to run forever. If recvLoop ever terminated unexpectedly due to an error, then the whole process would terminate, making the failure obvious. But if sendLoop terminated with an error, recvLoop and the process would keep running. The fix was to make the process terminate if either of recvLoop or sendLoop returns, and to make sendLoop consider fewer errors fatal.

It was unusual for sendLoop to terminate with an error, which is why this problem arose inconsistently. I was able to reproduce it on a server with many users, so many that the Linux Netfilter conntrack table overflowed and stopped being able to track the state of UDP associations:

nf_conntrack: nf_conntrack: table full, dropping packet

When this happened, an outbound packet sent by dnstt-server would be blocked by the local firewall, because the packet was no longer known to be in a RELATED state. That would result in a “operation not permitted” error inside sendLoop:

sendLoop: write udp [::]:5300->X.X.X.X:YYYYY: sendto: operation not permitted

Now, such an error in sendLoop will only be logged, but will not cause sendLoop to return. And if sendLoop does return for any reason, the process will exit, making the failure obvious, and letting you recover by restarting it.