Fix flawed response logic for COOKIE-less queries

The "yield" keyword does not cause a function to return.  By design,
get_responses() may yield multiple DNS responses in a single call.  As
currently implemented, CookieHandler.get_responses() sends two responses
to each client query that does not contain a COOKIE option.  Make the
logic in that method consistent with code comments by only sending one
response to every query - either SERVFAIL or BADCOOKIE, never both.
This commit is contained in:
Michał Kępień 2026-05-21 11:52:56 +02:00
parent c61539279d
commit de42425bbd
No known key found for this signature in database

View file

@ -73,21 +73,17 @@ class CookieHandler(DomainHandler):
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[DnsResponseSend, None]:
# Check for client cookie
cookie = _get_cookie(qctx)
# If missing cookie entirely, just return SERVFAIL
if cookie is None:
if cookie := _get_cookie(qctx):
# If there is a client cookie, mock BADCOOKIE to trigger
# the resend loop logic.
qctx.response.use_edns(options=[cookie])
qctx.response.set_rcode(dns.rcode.BADCOOKIE)
yield DnsResponseSend(qctx.response)
else:
# If missing cookie entirely, just return SERVFAIL
qctx.response.set_rcode(dns.rcode.SERVFAIL)
yield DnsResponseSend(qctx.response)
# If there is a client cookie, mock BADCOOKIE to trigger
# the resend loop logic.
qctx.response.use_edns(options=[cookie])
qctx.response.set_rcode(dns.rcode.BADCOOKIE)
yield DnsResponseSend(qctx.response)
def resend_server() -> AsyncDnsServer:
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)