mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-12 09:33:23 +00:00
The gateway's DNS forwarder accepted whatever datagram arrived on its upstream socket as the answer. It reused the client's own transaction ID in the upstream query, bound that socket to a wildcard address, received with a call that discards the sender, never compared the response ID or the question section against what it asked, and never checked that the returned address was inside the mesh prefix. The address it extracted is installed as a DNAT rule that carries no interface constraint, so a forged answer redirected traffic rather than merely poisoning a lookup. Four changes close it. The upstream query now carries a freshly drawn random transaction ID rather than the client's. The upstream socket is connected to the resolver before use, so the kernel drops datagrams from anyone else. A parsed response must be a response, carry the same ID, carry exactly one question matching the qname and qclass that were sent, and be for AAAA; anything else is discarded and the receive continues against the original deadline instead of accepting the first datagram to arrive. The extracted address goes through the validating address parser rather than a comment asserting the prefix byte, and a non-mesh answer is refused before any pool allocation, so no mapping event is emitted and no rule is installed. The validation sits before the rcode check, which changes one behaviour worth naming: an upstream that answers FORMERR or REFUSED with an empty question section no longer has that rcode relayed to the client and gets SERVFAIL instead. Checking after the rcode would let a forged NXDOMAIN through, so the placement is deliberate. Connecting the socket also fixes the dead-upstream half of the availability problem in the same loop, since a connected socket surfaces ECONNREFUSED immediately instead of stalling to the five second timeout. The serve loop still handles one query at a time; that half is untouched here. The tests drive real queries through a fake upstream: a foreign source injecting a well-formed answer, a wrong transaction ID, a wrong question, a non-mesh address, and the healthy path as an over-rejection guard. Each was checked by reverting the corresponding fix and confirming the intended test reds alone.