5
5
6
6
DNSServer::DNSServer ()
7
7
{
8
- _ttl = htonl (60 );
8
+ _ttl = htonl (DNS_DEFAULT_TTL );
9
9
_errorReplyCode = DNSReplyCode::NonExistentDomain;
10
- _dnsHeader = NULL ;
11
- _buffer = NULL ;
10
+ _dnsHeader = (DNSHeader*) malloc ( sizeof (DNSHeader) ) ;
11
+ _dnsQuestion = (DNSQuestion*) malloc ( sizeof (DNSQuestion) ) ;
12
+ _buffer = NULL ;
12
13
_currentPacketSize = 0 ;
13
14
_port = 0 ;
14
15
}
@@ -55,11 +56,37 @@ void DNSServer::processNextRequest()
55
56
_currentPacketSize = _udp.parsePacket ();
56
57
if (_currentPacketSize)
57
58
{
58
- if (_buffer != NULL ) free (_buffer);
59
+ // Allocate buffer for the DNS query
60
+ if (_buffer != NULL )
61
+ free (_buffer);
59
62
_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
61
68
_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
+
63
90
64
91
if (_dnsHeader->QR == DNS_QR_QUERY &&
65
92
_dnsHeader->OPCode == DNS_OPCODE_QUERY &&
@@ -87,15 +114,21 @@ bool DNSServer::requestIncludesOnlyOneQuestion()
87
114
_dnsHeader->ARCount == 0 ;
88
115
}
89
116
117
+
90
118
String DNSServer::getDomainNameWithoutWwwPrefix ()
91
119
{
120
+ // Error checking : if the buffer containing the DNS request is a null pointer, return an empty domain
92
121
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;
95
127
if (*start == 0 )
96
128
{
97
129
return parsedDomainName;
98
130
}
131
+
99
132
int pos = 0 ;
100
133
while (true )
101
134
{
@@ -121,16 +154,35 @@ String DNSServer::getDomainNameWithoutWwwPrefix()
121
154
void DNSServer::replyWithIP ()
122
155
{
123
156
if (_buffer == NULL ) return ;
124
- _dnsHeader->QR = DNS_QR_RESPONSE;
125
- _dnsHeader->ANCount = _dnsHeader->QDCount ;
126
- _dnsHeader->QDCount = 0 ;
127
-
157
+
128
158
_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
134
186
_udp.endPacket ();
135
187
}
136
188
0 commit comments