1515DNSServer::DNSServer () : _port(DNS_DEFAULT_PORT), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain) {}
1616
1717DNSServer::DNSServer (const String &domainName)
18- : _port(DNS_DEFAULT_PORT), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain), _domainName(domainName){};
18+ : _port(DNS_DEFAULT_PORT), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain), _domainName(domainName) {};
1919
2020bool DNSServer::start () {
2121 if (_resolvedIP.operator uint32_t () == 0 ) { // no address is set, try to obtain AP interface's IP
@@ -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 ; // && dnsHeader.ARCount == 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,77 @@ 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.QDCount = 1;
200+ dnsHeader.ANCount = 0 ;
201+ dnsHeader.NSCount = htons (1 );
202+
203+ AsyncUDPMessage rpl;
204+ rpl.write (reinterpret_cast <const uint8_t *>(&dnsHeader), sizeof (DNSHeader));
205+
206+ // Write the question
207+ rpl.write (dnsQuestion.QName , dnsQuestion.QNameLength );
208+ rpl.write ((uint8_t *)&dnsQuestion.QType , 2 );
209+ rpl.write ((uint8_t *)&dnsQuestion.QClass , 2 );
210+
211+ // An empty answer contains an authority section with a SOA,
212+ // We take the name of the query as the root of the zone for which the SOA is generated
213+ // and use a value of DNS_MINIMAL_TTL seconds in order to minimize negative caching
214+ // Write the authority section:
215+ // The SOA RR's ownername is set equal to the query name, and we use made up names for
216+ // the MNAME and RNAME - it doesn't really matter from a protocol perspective - as for
217+ // a no such QTYPE answer only the timing fields are used.
218+ // a protocol perspective - it
219+ // Use DNS name compression : instead of repeating the name in this RNAME occurrence,
220+ // set the two MSB of the byte corresponding normally to the length to 1. The following
221+ // 14 bits must be used to specify the offset of the domain name in the message
222+ // (<255 here so the first byte has the 6 LSB at 0)
223+ rpl.write ((uint8_t )0xC0 );
224+ rpl.write ((uint8_t )DNS_OFFSET_DOMAIN_NAME);
225+
226+ // DNS type A : host address, DNS class IN for INternet, returning an IPv4 address
227+ uint16_t answerType = htons (DNS_TYPE_SOA), answerClass = htons (DNS_CLASS_IN);
228+ uint32_t Serial = htonl (DNS_SOA_SERIAL); // Date type serial based on the date this piece of code was written
229+ uint32_t Refresh = htonl (DNS_SOA_REFRESH); // These timers don't matter, we don't serve zone transfers
230+ uint32_t Retry = htonl (DNS_SOA_RETRY);
231+ uint32_t Expire = htonl (DNS_SOA_EXPIRE);
232+ uint32_t MinTTL = htonl (DNS_MINIMAL_TTL); // See RFC2308 section 5
233+ char MLabel[] = DNS_SOA_MNAME_LABEL;
234+ char RLabel[] = DNS_SOA_RNAME_LABEL;
235+ char PostFixLabel[] = DNS_SOA_POSTFIX_LABEL;
236+
237+ // 4 accounts for len fields and for both rname
238+ // and lname and their postfix labels and there are 5 32 bit fields
239+
240+ uint16_t RdataLength = htons ((uint16_t )(strlen (MLabel) + strlen (RLabel) + 2 * strlen (PostFixLabel) + 4 + 5 * sizeof (Serial)));
241+
242+ rpl.write ((unsigned char *)&answerType, 2 );
243+ rpl.write ((unsigned char *)&answerClass, 2 );
244+ rpl.write ((unsigned char *)&MinTTL, 4 ); // DNS Time To Live
245+
246+ rpl.write ((unsigned char *)&RdataLength, 2 );
247+
248+ rpl.write ((uint8_t )strlen (MLabel));
249+ rpl.write ((unsigned char *)&MLabel, strlen (MLabel));
250+
251+ rpl.write ((unsigned char *)&PostFixLabel, strlen (PostFixLabel));
252+ rpl.write ((uint8_t )0 );
253+ // rpl.write((uint8_t)0xC0);
254+ // rpl.write((uint8_t)DNS_OFFSET_DOMAIN_NAME);
255+
256+ rpl.write ((uint8_t )strlen (RLabel));
257+ rpl.write ((unsigned char *)&RLabel, strlen (RLabel));
258+ rpl.write ((unsigned char *)&PostFixLabel, strlen (PostFixLabel));
259+ rpl.write ((uint8_t )0 );
260+
261+ rpl.write ((unsigned char *)&Serial, 4 );
262+ rpl.write ((unsigned char *)&Refresh, 4 );
263+ rpl.write ((unsigned char *)&Retry, 4 );
264+ rpl.write ((unsigned char *)&Expire, 4 );
265+ rpl.write ((unsigned char *)&MinTTL, 4 );
266+
267+ _udp.sendTo (rpl, req.remoteIP (), req.remotePort ());
268+ }
0 commit comments