@@ -111,16 +111,22 @@ void DNSServer::_handleUDP(AsyncUDPPacket &pkt) {
111111 // will reply with IP only to "*" or if domain matches without www. subdomain
112112 if (dnsHeader.OPCode == DNS_OPCODE_QUERY && requestIncludesOnlyOneQuestion (dnsHeader)
113113 && (_domainName.isEmpty () || getDomainNameWithoutWwwPrefix (static_cast <const unsigned char *>(dnsQuestion.QName ), dnsQuestion.QNameLength ) == _domainName)) {
114- replyWithIP (pkt, dnsHeader, dnsQuestion);
114+
115+ // Qtype = A (1) or ANY (255): send an A record otherwise an empty response
116+ if (ntohs (dnsQuestion.QType ) == 1 || ntohs (dnsQuestion.QType ) == 255 ) {
117+ replyWithIP (pkt, dnsHeader, dnsQuestion);
118+ } else {
119+ replyWithNoAnsw (pkt, dnsHeader, dnsQuestion);
120+ }
115121 return ;
116122 }
117-
118123 // otherwise reply with custom code
119124 replyWithCustomCode (pkt, dnsHeader);
120125}
121126
122127bool DNSServer::requestIncludesOnlyOneQuestion (DNSHeader &dnsHeader) {
123- return ntohs (dnsHeader.QDCount ) == 1 && dnsHeader.ANCount == 0 && dnsHeader.NSCount == 0 && dnsHeader.ARCount == 0 ;
128+ dnsHeader.ARCount = 0 ; // We assume that if ARCount !=0 there is a EDNS OPT packet, just ignore
129+ return ntohs (dnsHeader.QDCount ) == 1 && dnsHeader.ANCount == 0 && dnsHeader.NSCount == 0 ;
124130}
125131
126132String DNSServer::getDomainNameWithoutWwwPrefix (const unsigned char *start, size_t len) {
@@ -139,7 +145,6 @@ String DNSServer::getDomainNameWithoutWwwPrefix(const unsigned char *start, size
139145
140146void DNSServer::replyWithIP (AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion) {
141147 AsyncUDPMessage rpl;
142-
143148 // Change the type of message to a response and set the number of answers equal to
144149 // the number of questions in the header
145150 dnsHeader.QR = DNS_QR_RESPONSE;
@@ -187,3 +192,76 @@ void DNSServer::replyWithCustomCode(AsyncUDPPacket &req, DNSHeader &dnsHeader) {
187192 rpl.write (reinterpret_cast <const uint8_t *>(&dnsHeader), sizeof (DNSHeader));
188193 _udp.sendTo (rpl, req.remoteIP (), req.remotePort ());
189194}
195+
196+ void DNSServer::replyWithNoAnsw (AsyncUDPPacket &req, DNSHeader &dnsHeader, DNSQuestion &dnsQuestion) {
197+
198+ dnsHeader.QR = DNS_QR_RESPONSE;
199+ dnsHeader.ANCount = 0 ;
200+ dnsHeader.NSCount = htons (1 );
201+
202+ AsyncUDPMessage rpl;
203+ rpl.write (reinterpret_cast <const uint8_t *>(&dnsHeader), sizeof (DNSHeader));
204+
205+ // Write the question
206+ rpl.write (dnsQuestion.QName , dnsQuestion.QNameLength );
207+ rpl.write ((uint8_t *)&dnsQuestion.QType , 2 );
208+ rpl.write ((uint8_t *)&dnsQuestion.QClass , 2 );
209+
210+ // An empty answer contains an authority section with a SOA,
211+ // We take the name of the query as the root of the zone for which the SOA is generated
212+ // and use a value of DNS_MINIMAL_TTL seconds in order to minimize negative caching
213+ // Write the authority section:
214+ // The SOA RR's ownername is set equal to the query name, and we use made up names for
215+ // the MNAME and RNAME - it doesn't really matter from a protocol perspective - as for
216+ // a no such QTYPE answer only the timing fields are used.
217+ // a protocol perspective - it
218+ // Use DNS name compression : instead of repeating the name in this RNAME occurrence,
219+ // set the two MSB of the byte corresponding normally to the length to 1. The following
220+ // 14 bits must be used to specify the offset of the domain name in the message
221+ // (<255 here so the first byte has the 6 LSB at 0)
222+ rpl.write ((uint8_t )0xC0 );
223+ rpl.write ((uint8_t )DNS_OFFSET_DOMAIN_NAME);
224+
225+ // DNS type A : host address, DNS class IN for INternet, returning an IPv4 address
226+ uint16_t answerType = htons (DNS_TYPE_SOA), answerClass = htons (DNS_CLASS_IN);
227+ uint32_t Serial = htonl (DNS_SOA_SERIAL); // Date type serial based on the date this piece of code was written
228+ uint32_t Refresh = htonl (DNS_SOA_REFRESH); // These timers don't matter, we don't serve zone transfers
229+ uint32_t Retry = htonl (DNS_SOA_RETRY);
230+ uint32_t Expire = htonl (DNS_SOA_EXPIRE);
231+ uint32_t MinTTL = htonl (DNS_MINIMAL_TTL); // See RFC2308 section 5
232+ char MLabel[] = DNS_SOA_MNAME_LABEL;
233+ char RLabel[] = DNS_SOA_RNAME_LABEL;
234+ char PostFixLabel[] = DNS_SOA_POSTFIX_LABEL;
235+
236+ // 4 accounts for len fields and for both rname
237+ // and lname and their postfix labels and there are 5 32 bit fields
238+
239+ uint16_t RdataLength = htons ((uint16_t )(strlen (MLabel) + strlen (RLabel) + 2 * strlen (PostFixLabel) + 4 + 5 * sizeof (Serial)));
240+
241+ rpl.write ((unsigned char *)&answerType, 2 );
242+ rpl.write ((unsigned char *)&answerClass, 2 );
243+ rpl.write ((unsigned char *)&MinTTL, 4 ); // DNS Time To Live
244+
245+ rpl.write ((unsigned char *)&RdataLength, 2 );
246+
247+ rpl.write ((uint8_t )strlen (MLabel));
248+ rpl.write ((unsigned char *)&MLabel, strlen (MLabel));
249+
250+ rpl.write ((unsigned char *)&PostFixLabel, strlen (PostFixLabel));
251+ rpl.write ((uint8_t )0 );
252+ // rpl.write((uint8_t)0xC0);
253+ // rpl.write((uint8_t)DNS_OFFSET_DOMAIN_NAME);
254+
255+ rpl.write ((uint8_t )strlen (RLabel));
256+ rpl.write ((unsigned char *)&RLabel, strlen (RLabel));
257+ rpl.write ((unsigned char *)&PostFixLabel, strlen (PostFixLabel));
258+ rpl.write ((uint8_t )0 );
259+
260+ rpl.write ((unsigned char *)&Serial, 4 );
261+ rpl.write ((unsigned char *)&Refresh, 4 );
262+ rpl.write ((unsigned char *)&Retry, 4 );
263+ rpl.write ((unsigned char *)&Expire, 4 );
264+ rpl.write ((unsigned char *)&MinTTL, 4 );
265+
266+ _udp.sendTo (rpl, req.remoteIP (), req.remotePort ());
267+ }
0 commit comments