Search code examples
dnsresponsenameservers

Proper response for a nameserver when no relevant query has been sent?


I have a very rudimentary nameserver written in Python which only makes use of socket and dnslib, mainly intended for Let's Encrypt DNS-01 challenge responses, and also a couple of A records of experimental purposes.

My question is what should the nameserver respond when a query reaches the server but it contains no relevant data which the server wants to respond to?

Should it just ignore it?

I'm asking because I've been receiving queries for ANY leth.cc which apparently are used for DNS amplification attacks. Before noticing this I was responding to queries with an empty answer section, now I'm not sending anything back to the address provided.

I changed from

data, addr = sock_dns.recvfrom(1024)
q = dnslib.DNSRecord.parse(data)
a = q.reply()
# add an answer if query is relevant
# a.add_answer(*dnslib.RR.fromZone(qname + " 30 IN TXT " + verification_code))
sock_dns.sendto(a.pack(), addr)

to

data, addr = sock_dns.recvfrom(1024)
q = dnslib.DNSRecord.parse(data)
a = q.reply()
# add an answer if query is relevant
# a.add_answer(*dnslib.RR.fromZone(qname + " 30 IN TXT " + verification_code))
if len(a.rr) > 0:
 sock_dns.sendto(a.pack(), addr)

Is this acceptable behavior?


Taking Patrick Mevzek's answer into consideration, I have now modified it to

data, addr = sock_dns.recvfrom(1024)
q = dnslib.DNSRecord.parse(data)
a = q.reply()
# add an answer if query is relevant
# a.add_answer(*dnslib.RR.fromZone(qname + " 30 IN TXT " + verification_code))
if not a.rr:
  a.header.rcode = dnslib.RCODE.REFUSED
sock_dns.sendto(a.pack(), addr)

While this may be the proper response for valid clients, under normal operation no query for leth.cc should ever be reaching the server, as there is nothing pointing to my nameserver other than the NS records which I configured in the registrars DNS online configuration interface. It's their nameservers indicating that the client should go and ask my nameserver for an answer for more specific queries which they can't answer.

But in the case of a query for leth.cc reaching my server, this query must be very likely originating from a very unusual source. Is it still OK to answer to those requests with a RCODE.REFUSED, or could the request have been spoofed in such a way, that the addr contains an address which should not be contacted, in order to avoid a DDOS attack of that address? After all, it's an amplification attack; is that something like a reflected DDOS attack? I don't mind MY nameserver being unter DDOS attack (that's then my business to resolve), I just don't want it to be participating in one, in case that's possible.

Also, this is not a resolving nameserver, it does not go out and query other nameservers if information can't be found. I don't see anything bad in not answering to requests to qnames which don't belong to this nameservers domain.


Solution

  • Ignoring a query is definitively not what you want to do (in normal operation), as the client will then try again, and switch to another nameserver at some point, so at the very least you inflict them delays, if not bad results.

    Possible return codes are defined in https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 and mostly defined in RFC 1035.

    For your case I think you have exactly what you need: REFUSED

    It is defined as such:

    The name server refuses to perform the specified operation for policy reasons. For example, a name server may not wish to provide the information to the particular requester, or a name server may not wish to perform a particular operation (e.g., zone transfer) for particular data.

    Now, your nameserver is authoritative on some domain names. If it receives query for other ones, it should say it is not authoritative for them, which is NXDOMAIN or precisely RCODE 3 defined as such in RFC 1035:

    Name Error - Meaningful only for responses from an authoritative name server, this code signifies that the domain name referenced in the query does not exist.

    This is a very small answer, hence you are not amplifying anything. Your server could still be hit by many such queries, and you may decide to implement rate limiting (see below). It is true that traffic being UDP your server may answer to a victim not being the true source of the query, but without amplification, and like any other nameserver in the world will do also as this is the sad fate of all UDP-based protocols.

    A DDOS would be if you reply to the query with an answer being even larger (like if you tried to replied to ANY, even for the names you are authoritative on), as here a victim could receive a lot of traffic while the attacker would have need very little to send to you.

    Also, ANY is more a (bad) troubleshooting tool intended for recursive nameservers (as in "give me the current state of your cache for a specific label") instead of authoritative ones. There are works currently to just deprecate it completely: https://blog.cloudflare.com/what-happened-next-the-deprecation-of-any/

    Now you seem more to speak about operational problems, and DDOS attack. This is another case where even replying may be costly. Current nameservers implement a RRL mechanism, for "Response Rate Limiting", basically by reducing the rate of replies. Have a look at this article for Bind that present the feature: https://kb.isc.org/article/AA-01000/0/A-Quick-Introduction-to-Response-Rate-Limiting.html

    You may wish to implement something like that for your own nameserver if you fear it could be attacked.