1
1
#include " DNSServer.h"
2
2
#include < lwip/def.h>
3
3
#include < Arduino.h>
4
+ #include < WiFi.h>
5
+
4
6
5
7
// #define DEBUG_ESP_DNS
6
8
#ifdef DEBUG_ESP_PORT
9
11
#define DEBUG_OUTPUT Serial
10
12
#endif
11
13
12
- DNSServer::DNSServer () : _port(0 ), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain){}
14
+ #define DNS_MIN_REQ_LEN 17 // minimal size for DNS request asking ROOT = DNS_HEADER_SIZE + 1 null byte for Name + 4 bytes type/class
15
+
16
+ DNSServer::DNSServer () : _port(DNS_DEFAULT_PORT), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain){}
17
+
18
+ DNSServer::DNSServer (const String &domainName) : _port(DNS_DEFAULT_PORT), _ttl(htonl(DNS_DEFAULT_TTL)), _errorReplyCode(DNSReplyCode::NonExistentDomain), _domainName(domainName){};
19
+
20
+
21
+ bool DNSServer::start (){
22
+ if (WiFi.getMode () & WIFI_AP){
23
+ _resolvedIP = WiFi.softAPIP ();
24
+ } else return false ; // won't run if WiFi is not in AP mode
13
25
14
- DNSServer::~DNSServer (){}
26
+ _udp.close ();
27
+ _udp.onPacket ([this ](AsyncUDPPacket& pkt){ this ->_handleUDP (pkt); });
28
+ return _udp.listen (_port);
29
+ }
15
30
16
31
bool DNSServer::start (const uint16_t &port, const String &domainName,
17
32
const IPAddress &resolvedIP)
18
33
{
19
34
_port = port;
20
- _domainName = domainName;
21
- _resolvedIP[0 ] = resolvedIP[0 ];
22
- _resolvedIP[1 ] = resolvedIP[1 ];
23
- _resolvedIP[2 ] = resolvedIP[2 ];
24
- _resolvedIP[3 ] = resolvedIP[3 ];
25
- downcaseAndRemoveWwwPrefix (_domainName);
35
+ if (domainName != " *" ){
36
+ _domainName = domainName;
37
+ downcaseAndRemoveWwwPrefix (_domainName);
38
+ } else
39
+ _domainName.clear ();
40
+
41
+ _resolvedIP = resolvedIP;
26
42
_udp.close ();
27
43
_udp.onPacket ([this ](AsyncUDPPacket& pkt){ this ->_handleUDP (pkt); });
28
44
return _udp.listen (_port);
@@ -51,8 +67,7 @@ void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
51
67
52
68
void DNSServer::_handleUDP (AsyncUDPPacket& pkt)
53
69
{
54
- size_t currentPacketSize = pkt.length ();
55
- if (currentPacketSize < DNS_HEADER_SIZE) return ;
70
+ if (pkt.length () < DNS_MIN_REQ_LEN) return ; // truncated packet or not a DNS req
56
71
57
72
// get DNS header (beginning of message)
58
73
DNSHeader dnsHeader;
@@ -67,15 +82,15 @@ void DNSServer::_handleUDP(AsyncUDPPacket& pkt)
67
82
// Each label contains a byte to describe its length and the label itself. The list of
68
83
// labels terminates with a zero-valued byte. In "github.com", we have two labels "github" & "com"
69
84
*/
70
- const char * enoflbls = strchr (( const char *) pkt.data () + DNS_HEADER_SIZE, 0 ); // find end_of_label marker
85
+ const char * enoflbls = strchr (reinterpret_cast < const char *>( pkt.data () ) + DNS_HEADER_SIZE, 0 ); // find end_of_label marker
71
86
++enoflbls; // advance after null terminator
72
87
dnsQuestion.QName = pkt.data () + DNS_HEADER_SIZE; // we can reference labels from the request
73
88
dnsQuestion.QNameLength = enoflbls - (char *)pkt.data () - DNS_HEADER_SIZE;
74
89
/*
75
90
check if we aint going out of pkt bounds
76
91
proper dns req should have label terminator at least 4 bytes before end of packet
77
92
*/
78
- if (dnsQuestion.QNameLength < 3 || dnsQuestion. QNameLength > currentPacketSize - DNS_HEADER_SIZE - sizeof (dnsQuestion.QType ) - sizeof (dnsQuestion.QClass )) return ; // malformed packet
93
+ if (dnsQuestion.QNameLength > pkt. length () - DNS_HEADER_SIZE - sizeof (dnsQuestion.QType ) - sizeof (dnsQuestion.QClass )) return ; // malformed packet
79
94
80
95
// Copy the QType and QClass
81
96
memcpy ( &dnsQuestion.QType , enoflbls, sizeof (dnsQuestion.QType ) );
@@ -85,8 +100,8 @@ void DNSServer::_handleUDP(AsyncUDPPacket& pkt)
85
100
// will reply with IP only to "*" or if doman matches without www. subdomain
86
101
if (dnsHeader.OPCode == DNS_OPCODE_QUERY &&
87
102
requestIncludesOnlyOneQuestion (dnsHeader) &&
88
- (_domainName == " * " ||
89
- getDomainNameWithoutWwwPrefix (( const char *)pkt. data () + DNS_HEADER_SIZE , dnsQuestion.QNameLength ) == _domainName)
103
+ (_domainName. isEmpty () ||
104
+ getDomainNameWithoutWwwPrefix (static_cast < const unsigned char *>(dnsQuestion. QName ) , dnsQuestion.QNameLength ) == _domainName)
90
105
)
91
106
{
92
107
replyWithIP (pkt, dnsHeader, dnsQuestion);
@@ -106,14 +121,14 @@ bool DNSServer::requestIncludesOnlyOneQuestion(DNSHeader& dnsHeader)
106
121
}
107
122
108
123
109
- String DNSServer::getDomainNameWithoutWwwPrefix (const char * start, size_t len)
124
+ String DNSServer::getDomainNameWithoutWwwPrefix (const unsigned char * start, size_t len)
110
125
{
111
126
String parsedDomainName (start, --len); // exclude trailing null byte from labels length, String constructor will add it anyway
112
127
113
128
int pos = 0 ;
114
129
while (pos<len)
115
130
{
116
- parsedDomainName.setCharAt (pos, 0x2e ); // replace len byte with dot char "."
131
+ parsedDomainName.setCharAt (pos, 0x2e ); // replace label len byte with dot char "."
117
132
pos += *(start + pos);
118
133
++pos;
119
134
}
@@ -151,23 +166,24 @@ void DNSServer::replyWithIP(AsyncUDPPacket& req, DNSHeader& dnsHeader, DNSQuesti
151
166
rpl.write ((unsigned char *) &answerClass, 2 );
152
167
rpl.write ((unsigned char *) &_ttl, 4 ); // DNS Time To Live
153
168
rpl.write ((unsigned char *) &answerIPv4, 2 );
154
- rpl.write (_resolvedIP, sizeof (_resolvedIP)); // The IP address to return
169
+ uint32_t ip = _resolvedIP;
170
+ rpl.write (reinterpret_cast <uint8_t *>(&ip), sizeof (uint32_t )); // The IPv4 address to return
155
171
156
172
_udp.sendTo (rpl, req.remoteIP (), req.remotePort ());
157
173
158
174
#ifdef DEBUG_ESP_DNS
159
175
DEBUG_OUTPUT.printf (" DNS responds: %s for %s\n " ,
160
- IPAddress ( _resolvedIP) .toString ().c_str (), getDomainNameWithoutWwwPrefix (( const char *)rpl. data () + DNS_HEADER_SIZE , dnsQuestion.QNameLength ).c_str () );
176
+ _resolvedIP.toString ().c_str (), getDomainNameWithoutWwwPrefix (static_cast < const unsigned char *>(dnsQuestion. QName ) , dnsQuestion.QNameLength ).c_str () );
161
177
#endif
162
178
}
163
179
164
180
void DNSServer::replyWithCustomCode (AsyncUDPPacket& req, DNSHeader& dnsHeader)
165
181
{
166
182
dnsHeader.QR = DNS_QR_RESPONSE;
167
- dnsHeader.RCode = ( uint16_t ) _errorReplyCode;
183
+ dnsHeader.RCode = static_cast < uint16_t >( _errorReplyCode) ;
168
184
dnsHeader.QDCount = 0 ;
169
185
170
186
AsyncUDPMessage rpl (sizeof (DNSHeader));
171
- rpl.write (( unsigned char *) &dnsHeader, sizeof (DNSHeader));
187
+ rpl.write (reinterpret_cast < const uint8_t *>( &dnsHeader) , sizeof (DNSHeader));
172
188
_udp.sendTo (rpl, req.remoteIP (), req.remotePort ());
173
189
}
0 commit comments