9
9
#define DEBUG_OUTPUT Serial
10
10
#endif
11
11
12
- DNSServer::DNSServer ()
12
+ DNSServer::DNSServer () : _port( 0 ), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain)
13
13
{
14
- _ttl = htonl (DNS_DEFAULT_TTL);
15
- _errorReplyCode = DNSReplyCode::NonExistentDomain;
16
- _dnsHeader = (DNSHeader*) malloc ( sizeof (DNSHeader) ) ;
17
- _dnsQuestion = (DNSQuestion*) malloc ( sizeof (DNSQuestion) ) ;
18
- _buffer = NULL ;
19
- _currentPacketSize = 0 ;
20
- _port = 0 ;
14
+ _dnsHeader = new DNSHeader ();
15
+ _dnsQuestion = new DNSQuestion ();
21
16
}
22
17
23
18
DNSServer::~DNSServer ()
24
19
{
25
20
if (_dnsHeader) {
26
- free ( _dnsHeader) ;
27
- _dnsHeader = NULL ;
21
+ delete _dnsHeader;
22
+ _dnsHeader = nullptr ;
28
23
}
29
24
if (_dnsQuestion) {
30
- free (_dnsQuestion);
31
- _dnsQuestion = NULL ;
32
- }
33
- if (_buffer) {
34
- free (_buffer);
35
- _buffer = NULL ;
25
+ delete _dnsQuestion;
26
+ _dnsQuestion = nullptr ;
36
27
}
37
28
}
38
29
39
30
bool DNSServer::start (const uint16_t &port, const String &domainName,
40
31
const IPAddress &resolvedIP)
41
32
{
42
33
_port = port;
43
- _buffer = NULL ;
44
34
_domainName = domainName;
45
35
_resolvedIP[0 ] = resolvedIP[0 ];
46
36
_resolvedIP[1 ] = resolvedIP[1 ];
@@ -64,8 +54,6 @@ void DNSServer::setTTL(const uint32_t &ttl)
64
54
void DNSServer::stop ()
65
55
{
66
56
_udp.close ();
67
- free (_buffer);
68
- _buffer = NULL ;
69
57
}
70
58
71
59
void DNSServer::downcaseAndRemoveWwwPrefix (String &domainName)
@@ -76,22 +64,30 @@ void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
76
64
77
65
void DNSServer::_handleUDP (AsyncUDPPacket& pkt)
78
66
{
79
- _currentPacketSize = pkt.length ();
80
- if (!_currentPacketSize) return ;
81
-
82
- // Allocate buffer for the DNS query
83
- if (_buffer != NULL )
84
- free (_buffer);
85
- _buffer = (unsigned char *)malloc (_currentPacketSize * sizeof (char ));
86
- if (_buffer == NULL )
87
- return ;
67
+ size_t _currentPacketSize = pkt.length ();
68
+ if (_currentPacketSize < DNS_HEADER_SIZE) return ;
69
+
70
+ // get DNS header (beginning of message)
71
+ memcpy ( _dnsHeader, pkt.data (), DNS_HEADER_SIZE );
72
+ if (_dnsHeader->QR != DNS_QR_QUERY) return ; // ignore non-query mesages
88
73
89
- // Put the packet received in the buffer and get DNS header (beginning of message)
90
- // and the question
91
- pkt.read (_buffer, _currentPacketSize);
92
- memcpy ( _dnsHeader, _buffer, DNS_HEADER_SIZE ) ;
93
74
if ( requestIncludesOnlyOneQuestion () )
94
75
{
76
+ char * enoflbls = strchr ((const char *)pkt.data () + DNS_HEADER_SIZE, 0 ); // find end_of_label marker
77
+ ++enoflbls; // include null terminator
78
+ _dnsQuestion->QName = pkt.data () + DNS_HEADER_SIZE; // we can reference labels from the request
79
+ _dnsQuestion->QNameLength = enoflbls - (char *)pkt.data () - DNS_HEADER_SIZE;
80
+ /*
81
+ check if we aint going out of pkt bounds
82
+ proper dns req should have label terminator at least 4 bytes before end of packet
83
+ */
84
+ if (_dnsQuestion->QNameLength > _currentPacketSize - sizeof (_dnsQuestion->QType ) - sizeof (_dnsQuestion->QClass )) return ; // malformed packet
85
+
86
+ // Copy the QType and QClass
87
+ memcpy ( &_dnsQuestion->QType , enoflbls, sizeof (_dnsQuestion->QType ) );
88
+ memcpy ( &_dnsQuestion->QClass , enoflbls + sizeof (_dnsQuestion->QType ), sizeof (_dnsQuestion->QClass ) );
89
+
90
+ /*
95
91
// The QName has a variable length, maximum 255 bytes and is comprised of multiple labels.
96
92
// Each label contains a byte to describe its length and the label itself. The list of
97
93
// labels terminates with a zero-valued byte. In "github.com", we have two labels "github" & "com"
@@ -108,25 +104,22 @@ void DNSServer::_handleUDP(AsyncUDPPacket& pkt)
108
104
// Copy the QType and QClass
109
105
memcpy( &_dnsQuestion->QType, (void*) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength], sizeof(_dnsQuestion->QType) ) ;
110
106
memcpy( &_dnsQuestion->QClass, (void*) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength + sizeof(_dnsQuestion->QType)], sizeof(_dnsQuestion->QClass) ) ;
107
+ */
111
108
}
112
109
113
-
114
- if (_dnsHeader->QR == DNS_QR_QUERY &&
115
- _dnsHeader->OPCode == DNS_OPCODE_QUERY &&
110
+ // will reply with IP only to "*" or if doman matches without www. subdomain
111
+ if (_dnsHeader->OPCode == DNS_OPCODE_QUERY &&
116
112
requestIncludesOnlyOneQuestion () &&
117
- (_domainName == " *" || getDomainNameWithoutWwwPrefix () == _domainName)
113
+ (_domainName == " *" ||
114
+ getDomainNameWithoutWwwPrefix ((const char *)pkt.data () + DNS_HEADER_SIZE, _dnsQuestion->QNameLength ) == _domainName)
118
115
)
119
116
{
120
117
replyWithIP (pkt);
118
+ return ;
121
119
}
122
- else if (_dnsHeader->QR == DNS_QR_QUERY)
123
- {
124
- replyWithCustomCode (pkt);
125
- }
126
-
127
- free (_buffer);
128
- _buffer = NULL ;
129
120
121
+ // otherwise reply with custom code
122
+ replyWithCustomCode (pkt);
130
123
}
131
124
132
125
bool DNSServer::requestIncludesOnlyOneQuestion ()
@@ -138,25 +131,22 @@ bool DNSServer::requestIncludesOnlyOneQuestion()
138
131
}
139
132
140
133
141
- String DNSServer::getDomainNameWithoutWwwPrefix ()
134
+ String DNSServer::getDomainNameWithoutWwwPrefix (const char * start, size_t len )
142
135
{
143
- // Error checking : if the buffer containing the DNS request is a null pointer, return an empty domain
144
136
String parsedDomainName (" " );
145
- if (_buffer == NULL )
146
- return parsedDomainName;
147
137
148
- // Set the start of the domain just after the header (12 bytes). If equal to null character, return an empty domain
149
- unsigned char *start = _buffer + DNS_OFFSET_DOMAIN_NAME;
150
138
if (*start == 0 )
151
139
{
152
140
return parsedDomainName;
153
141
}
154
142
143
+ parsedDomainName.reserve (len);
155
144
int pos = 0 ;
156
145
while (true )
157
146
{
158
- unsigned char labelLength = *(start + pos);
159
- for (int i = 0 ; i < labelLength; i++)
147
+ uint8_t labelLength = *(start + pos);
148
+
149
+ for (uint8_t i = 0 ; i < labelLength; i++)
160
150
{
161
151
pos++;
162
152
parsedDomainName += (char )*(start + pos);
@@ -186,8 +176,8 @@ void DNSServer::replyWithIP(AsyncUDPPacket& req)
186
176
187
177
// Write the question
188
178
rpl.write (_dnsQuestion->QName , _dnsQuestion->QNameLength ) ;
189
- rpl.write ( (unsigned char *) &_dnsQuestion->QType , 2 ) ;
190
- rpl.write ( (unsigned char *) &_dnsQuestion->QClass , 2 ) ;
179
+ rpl.write ( (uint8_t *) &_dnsQuestion->QType , 2 ) ;
180
+ rpl.write ( (uint8_t *) &_dnsQuestion->QClass , 2 ) ;
191
181
192
182
// Write the answer
193
183
// Use DNS name compression : instead of repeating the name in this RNAME occurence,
@@ -209,14 +199,14 @@ void DNSServer::replyWithIP(AsyncUDPPacket& req)
209
199
210
200
#ifdef DEBUG_ESP_DNS
211
201
DEBUG_OUTPUT.printf (" DNS responds: %s for %s\n " ,
212
- IPAddress (_resolvedIP).toString ().c_str (), getDomainNameWithoutWwwPrefix ().c_str () );
202
+ IPAddress (_resolvedIP).toString ().c_str (), getDomainNameWithoutWwwPrefix (( const char *)rpl. data () + DNS_HEADER_SIZE, _dnsQuestion-> QNameLength ).c_str () );
213
203
#endif
214
204
}
215
205
216
206
void DNSServer::replyWithCustomCode (AsyncUDPPacket& req)
217
207
{
218
208
_dnsHeader->QR = DNS_QR_RESPONSE;
219
- _dnsHeader->RCode = (unsigned char )_errorReplyCode;
209
+ _dnsHeader->RCode = (uint16_t )_errorReplyCode;
220
210
_dnsHeader->QDCount = 0 ;
221
211
222
212
AsyncUDPMessage rpl (sizeof (DNSHeader));
0 commit comments