-
Notifications
You must be signed in to change notification settings - Fork 3
/
dns.cpp
124 lines (108 loc) · 3.68 KB
/
dns.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// DNS look-up functions based on the udp client
// Author: Guido Socher
// Copyright: GPL V2
//
// 2010-05-20 <jc@wippler.nl>
#include "EtherCard.h"
#include "net.h"
#include "timer.h"
#include <string.h>
#define gPB ether.buffer
static uint8_t dnstid_l; // a counter for transaction ID
#define DNSCLIENT_SRC_PORT_H 0xE0
#define DNS_TYPE_A 1
#define DNS_CLASS_IN 1
static void dnsRequest (const char *hostname, bool fromRam) {
++dnstid_l; // increment for next request, finally wrap
if (ether.dnsip[0] == 0)
memset(ether.dnsip, 8, IP_LEN); // use 8.8.8.8 Google DNS as default
ether.udpPrepare((DNSCLIENT_SRC_PORT_H << 8) | dnstid_l, ether.dnsip, DNS_PORT);
memset(gPB + UDP_DATA_P, 0, 12);
uint8_t *p = gPB + UDP_DATA_P + 12;
char c;
do {
uint8_t n = 0;
for(;;) {
c = fromRam ? *hostname : pgm_read_byte(hostname);
++hostname;
if (c == '.' || c == 0)
break;
p[++n] = c;
}
*p++ = n;
p += n;
} while (c != 0);
*p++ = 0; // terminate with zero, means root domain.
*p++ = 0;
*p++ = DNS_TYPE_A;
*p++ = 0;
*p++ = DNS_CLASS_IN;
uint8_t i = p - gPB - UDP_DATA_P;
gPB[UDP_DATA_P] = i;
gPB[UDP_DATA_P+1] = dnstid_l;
gPB[UDP_DATA_P+2] = 1; // flags, standard recursive query
gPB[UDP_DATA_P+5] = 1; // 1 question
ether.udpTransmit(i);
}
/** @brief Check if packet is DNS response.
@param plen Size of packet
@return <i>bool</i> True if DNS response has error. False if not DNS response or DNS response OK.
@note hisip contains IP address of requested host or 0.0.0.0 on failure
*/
static bool checkForDnsAnswer (uint16_t plen) {
uint8_t *p = gPB + UDP_DATA_P; //start of UDP payload
if (plen < 70 || gPB[UDP_SRC_PORT_L_P] != DNS_PORT || //from DNS source port
gPB[UDP_DST_PORT_H_P] != DNSCLIENT_SRC_PORT_H || //response to same port as we sent from (MSB)
gPB[UDP_DST_PORT_L_P] != dnstid_l || //response to same port as we sent from (LSB)
p[1] != dnstid_l) //message id same as we sent
return false; //not our DNS response
if((p[3] & 0x0F) != 0)
return true; //DNS response received with error
p += *p; // we encoded the query len into tid
for (;;) {
if (*p & 0xC0)
p += 2;
else
while (++p < gPB + plen) {
if (*p == 0) {
++p;
break;
}
}
if (p + 14 > gPB + plen)
break;
if (p[1] == DNS_TYPE_A && p[9] == 4) { // type "A" and IPv4
ether.copyIp(ether.hisip, p + 10);
break;
}
p += p[9] + 10;
}
return false; //No error
}
// use during setup, as this discards all incoming requests until it returns
bool EtherCard::dnsLookup (const char* name, bool fromRam) {
uint16_t start = millis();
while(!isLinkUp())
{
if (uint16_t(millis()) - start >= 30000)
return false; //timeout waiting for link
}
while(clientWaitingDns())
{
packetLoop(packetReceive());
if (uint16_t(millis()) - start >= 30000)
return false; //timeout waiting for gateway ARP
}
memset(hisip, 0, IP_LEN);
dnsRequest(name, fromRam);
start = millis();
while (hisip[0] == 0) {
if (uint16_t(millis()) - start >= 30000)
return false; //timout waiting for dns response
uint16_t len = packetReceive();
if (len > 0 && packetLoop(len) == 0) //packet not handled by tcp/ip packet loop
if(checkForDnsAnswer(len))
return false; //DNS response recieved with error
}
return true;
}