forked from njh/EtherCard
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dns.cpp
executable file
·142 lines (122 loc) · 3.24 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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// DNS look-up functions based on the udp client
// Author: Guido Socher
// Copyright: GPL V2
//
// 2010-05-20 <[email protected]>
#include "EtherCard.h"
#include "net.h"
#define gPB ether.buffer
static byte dnstid_l; // a counter for transaction ID
#define DNSCLIENT_SRC_PORT_H 0xE0
static void dnsRequest (const prog_char *progmem_hostname, bool fromRam) {
++dnstid_l; // increment for next request, finally wrap
if (ether.dnsip[0] == 0)
memset(ether.dnsip, 8, 4); // use 8.8.8.8 Google DNS as default
ether.udpPrepare((DNSCLIENT_SRC_PORT_H << 8) | dnstid_l,
ether.dnsip, 53);
memset(gPB + UDP_DATA_P, 0, 12);
byte *p = gPB + UDP_DATA_P + 12;
char c;
do {
byte n = 0;
for(;;) {
c = fromRam ? *progmem_hostname : pgm_read_byte(progmem_hostname);
++progmem_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++ = 1; // type A
*p++ = 0;
*p++ = 1; // class IN
byte 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);
}
static void checkForDnsAnswer (uint16_t plen) {
byte *p = gPB + UDP_DATA_P;
if (plen < 70 || gPB[UDP_SRC_PORT_L_P] != 53 ||
gPB[UDP_DST_PORT_H_P] != DNSCLIENT_SRC_PORT_H ||
gPB[UDP_DST_PORT_L_P] != dnstid_l ||
p[1] != dnstid_l ||
(p[3] & 0x0F) != 0)
return;
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] == 1 && p[9] == 4) { // type "A" and IPv4
ether.copyIp(ether.hisip, p + 10);
break;
}
p += p[9] + 10;
}
}
static const prog_char *dns_name;
static bool from_ram;
// use during setup, as this discards all incoming requests until it returns
void EtherCard::dnsLookupAsync (const prog_char* name, bool fromRam) {
memset(hisip, 0, 4);
dns_name = name;
from_ram = fromRam;
}
bool EtherCard::dnsLookupPoll()
{
if (!isLinkUp())
return false;
if (clientWaitingGw())
{
packetLoop(packetReceive());
return false;
}
if (dns_name)
{
dnsRequest(dns_name, from_ram);
dns_name = NULL;
return false;
}
if (hisip[0] == 0)
{
word len = packetReceive();
if (len > 0 && packetLoop(len) == 0)
checkForDnsAnswer(len);
}
return hisip[0] != 0;
}
// use during setup, as this discards all incoming requests until it returns
bool EtherCard::dnsLookup (prog_char* name, bool fromRam) {
word start = millis();
while (!isLinkUp() || clientWaitingGw()) {
packetLoop(packetReceive());
if ((word) (millis() - start) >= 30000)
return false;
}
memset(hisip, 0, 4);
dnsRequest(name, fromRam);
start = millis();
while (hisip[0] == 0) {
if ((word) (millis() - start) >= 30000)
return false;
word len = packetReceive();
if (len > 0 && packetLoop(len) == 0)
checkForDnsAnswer(len);
}
return true;
}