55
66DNSServer::DNSServer ()
77{
8- _ttl = htonl (60 );
8+ _ttl = htonl (DNS_DEFAULT_TTL );
99 _errorReplyCode = DNSReplyCode::NonExistentDomain;
10- _dnsHeader = NULL ;
11- _buffer = NULL ;
10+ _dnsHeader = (DNSHeader*) malloc ( sizeof (DNSHeader) ) ;
11+ _dnsQuestion = (DNSQuestion*) malloc ( sizeof (DNSQuestion) ) ;
12+ _buffer = NULL ;
1213 _currentPacketSize = 0 ;
1314 _port = 0 ;
1415}
@@ -55,11 +56,37 @@ void DNSServer::processNextRequest()
5556 _currentPacketSize = _udp.parsePacket ();
5657 if (_currentPacketSize)
5758 {
58- if (_buffer != NULL ) free (_buffer);
59+ // Allocate buffer for the DNS query
60+ if (_buffer != NULL )
61+ free (_buffer);
5962 _buffer = (unsigned char *)malloc (_currentPacketSize * sizeof (char ));
60- if (_buffer == NULL ) return ;
63+ if (_buffer == NULL )
64+ return ;
65+
66+ // Put the packet received in the buffer and get DNS header (beginning of message)
67+ // and the question
6168 _udp.read (_buffer, _currentPacketSize);
62- _dnsHeader = (DNSHeader*) _buffer;
69+ memcpy ( _dnsHeader, _buffer, DNS_HEADER_SIZE ) ;
70+ if ( requestIncludesOnlyOneQuestion () )
71+ {
72+ // The QName has a variable length, maximum 255 bytes and is comprised of multiple labels.
73+ // Each label contains a byte to describe its length and the label itself. The list of
74+ // labels terminates with a zero-valued byte. In "github.com", we have two labels "github" & "com"
75+ // Iterate through the labels and copy them as they come into a single buffer (for simplicity's sake)
76+ _dnsQuestion->QNameLength = 0 ;
77+ while ( _buffer[ DNS_HEADER_SIZE + _dnsQuestion->QNameLength ] != 0 )
78+ {
79+ memcpy ( (void *) &_dnsQuestion->QName [_dnsQuestion->QNameLength ], (void *) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength ], _buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength ] + 1 ) ;
80+ _dnsQuestion->QNameLength += _buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength ] + 1 ;
81+ }
82+ _dnsQuestion->QName [_dnsQuestion->QNameLength ] = 0 ;
83+ _dnsQuestion->QNameLength ++ ;
84+
85+ // Copy the QType and QClass
86+ memcpy ( &_dnsQuestion->QType , (void *) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength ], sizeof (_dnsQuestion->QType ) ) ;
87+ memcpy ( &_dnsQuestion->QClass , (void *) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength + sizeof (_dnsQuestion->QType )], sizeof (_dnsQuestion->QClass ) ) ;
88+ }
89+
6390
6491 if (_dnsHeader->QR == DNS_QR_QUERY &&
6592 _dnsHeader->OPCode == DNS_OPCODE_QUERY &&
@@ -87,15 +114,21 @@ bool DNSServer::requestIncludesOnlyOneQuestion()
87114 _dnsHeader->ARCount == 0 ;
88115}
89116
117+
90118String DNSServer::getDomainNameWithoutWwwPrefix ()
91119{
120+ // Error checking : if the buffer containing the DNS request is a null pointer, return an empty domain
92121 String parsedDomainName = " " ;
93- if (_buffer == NULL ) return parsedDomainName;
94- unsigned char *start = _buffer + 12 ;
122+ if (_buffer == NULL )
123+ return parsedDomainName;
124+
125+ // Set the start of the domain just after the header (12 bytes). If equal to null character, return an empty domain
126+ unsigned char *start = _buffer + DNS_OFFSET_DOMAIN_NAME;
95127 if (*start == 0 )
96128 {
97129 return parsedDomainName;
98130 }
131+
99132 int pos = 0 ;
100133 while (true )
101134 {
@@ -121,16 +154,35 @@ String DNSServer::getDomainNameWithoutWwwPrefix()
121154void DNSServer::replyWithIP ()
122155{
123156 if (_buffer == NULL ) return ;
124- _dnsHeader->QR = DNS_QR_RESPONSE;
125- _dnsHeader->ANCount = _dnsHeader->QDCount ;
126- _dnsHeader->QDCount = 0 ;
127-
157+
128158 _udp.beginPacket (_udp.remoteIP (), _udp.remotePort ());
129- _udp.write (_buffer, _currentPacketSize);
130- _udp.write ((unsigned char *)&_ttl, 4 );
131- _udp.write ((uint8_t )0 );
132- _udp.write ((uint8_t )4 );
133- _udp.write (_resolvedIP, 4 );
159+
160+ // Change the type of message to a response and set the number of answers equal to
161+ // the number of questions in the header
162+ _dnsHeader->QR = DNS_QR_RESPONSE;
163+ _dnsHeader->ANCount = _dnsHeader->QDCount ;
164+ _udp.write ( (unsigned char *) _dnsHeader, DNS_HEADER_SIZE ) ;
165+
166+ // Write the question
167+ _udp.write (_dnsQuestion->QName , _dnsQuestion->QNameLength ) ;
168+ _udp.write ( (unsigned char *) &_dnsQuestion->QType , 2 ) ;
169+ _udp.write ( (unsigned char *) &_dnsQuestion->QClass , 2 ) ;
170+
171+ // Write the answer
172+ // Use DNS name compression : instead of repeating the name in this RNAME occurence,
173+ // set the two MSB of the byte corresponding normally to the length to 1. The following
174+ // 14 bits must be used to specify the offset of the domain name in the message
175+ // (<255 here so the first byte has the 6 LSB at 0)
176+ _udp.write ((uint8_t ) 0xC0 );
177+ _udp.write ((uint8_t ) DNS_OFFSET_DOMAIN_NAME);
178+
179+ // DNS type A : host address, DNS class IN for INternet, returning an IPv4 address
180+ uint16_t answerType = htons (DNS_TYPE_A), answerClass = htons (DNS_CLASS_IN), answerIPv4 = htons (DNS_RDLENGTH_IPV4) ;
181+ _udp.write ((unsigned char *) &answerType, 2 );
182+ _udp.write ((unsigned char *) &answerClass, 2 );
183+ _udp.write ((unsigned char *) &_ttl, 4 ); // DNS Time To Live
184+ _udp.write ((unsigned char *) &answerIPv4, 2 );
185+ _udp.write (_resolvedIP, sizeof (_resolvedIP)); // The IP address to return
134186 _udp.endPacket ();
135187}
136188
0 commit comments