fehQlibs 26
Qlibs
Loading...
Searching...
No Matches
dns_transmit.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <unistd.h>
4#include "socket_if.h"
5#include "alloc.h"
6#include "error.h"
7#include "byte.h"
8#include "uint_t.h"
9#include "ip.h"
10#include "dnsresolv.h"
11
20#define DNSPORT 53
21
23
24static const int timeouts[5] = { 1, 2, 4, 8, 16 }; /* quadratic, not exponentially */
25
26int getscopeid(const struct dns_transmit *d,const char *ip)
27{
28 int i;
29
30 if (byte_diff(ip,2,V6linklocal)) return 0;
31 for (i = 0; i < QUERY_MAXNS; ++i)
32 if (byte_equal(d->servers + 16 * i,16,ip))
33 return scope_ids[i];
34
35 return 0;
36}
37
38int serverwantstcp(const char *buf,unsigned int len)
39{
40 char out[12];
41
42 if (!dns_packet_copy(buf,len,0,out,12)) return 1;
43 if (out[2] & 2) return 1;
44
45 return 0;
46}
47
48int serverfailed(const char *buf,unsigned int len)
49{
50 char out[12];
51 unsigned int rcode;
52
53 if (!dns_packet_copy(buf,len,0,out,12)) return 1;
54 rcode = out[3];
55 rcode &= 15;
56 if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; }
57
58 return 0;
59}
60
61static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
62{
63 char out[12];
64 char *dn;
65 unsigned int pos;
66
67 pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1;
68 if (byte_diff(out,2,d->query + 2)) return 1;
69 if (out[4] != 0) return 1;
70 if (out[5] != 1) return 1;
71
72 dn = 0;
73 pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
74 if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; }
75 alloc_free(dn);
76
77 pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
78 if (byte_diff(out,2,d->qtype)) return 1;
79 if (byte_diff(out + 2,2,DNS_C_IN)) return 1;
80
81 return 0;
82}
83
84void packetfree(struct dns_transmit *d)
85{
86 if (!d->packet) return;
88 d->packet = 0;
89}
90
91void queryfree(struct dns_transmit *d)
92{
93 if (!d->query) return;
94 alloc_free(d->query);
95 d->query = 0;
96}
97
98void socketfree(struct dns_transmit *d)
99{
100 if (!d->s1) return;
101 close(d->s1 - 1);
102 d->s1 = 0;
103}
104
106{
107 queryfree(d);
108 socketfree(d);
109 packetfree(d);
110}
111
113{
114 int j;
115
116 for (j = 0; j < 10; ++j) {
117 if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
118 return 0;
119 }
120 if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
121 return 0;
122
123 return DNS_COM;
124}
125
127{
128 int j;
129
130 for (j = 0; j < 10; ++j) {
131 if (socket_bind4(d->s1 - 1,d->localip + 12,1025 + dns_random(64510)) == 0)
132 return 0;
133 }
134 if (socket_bind4(d->s1 - 1,d->localip + 12,0) == 0)
135 return 0;
136
137 return DNS_COM;
138}
139
140static int thisudp(struct dns_transmit *d)
141{
142 const char *ip;
143
144 socketfree(d);
145
146 while (d->udploop < 5) {
147 for (; d->curserver < QUERY_MAXNS; ++d->curserver) {
148 ip = d->servers + 16 * d->curserver;
149 if (byte_diff(ip,16,V6localnet)) {
150 d->query[2] = dns_random(256);
151 d->query[3] = dns_random(256);
152
153 if (ip6_isv4mapped(ip)) {
154 d->s1 = 1 + socket_udp4();
155 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
156 if (randombind4(d) < 0) { dns_transmit_free(d); return DNS_COM; }
157 } else {
158 d->s1 = 1 + socket_udp6();
159 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
160 if (randombind6(d) < 0) { dns_transmit_free(d); return DNS_COM; }
161 }
162
163 if (byte_equal(ip,2,V6linklocal) && !d->scope_id)
164 d->scope_id = getscopeid(d,ip);
165 if (socket_connect(d->s1 - 1,ip,DNSPORT,d->scope_id) == 0)
166 if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
167 struct taia now;
168 taia_now(&now);
169 taia_uint(&d->deadline,timeouts[d->udploop]);
170 taia_add(&d->deadline,&d->deadline,&now);
171 d->tcpstate = 0;
172 return 0;
173 }
174 socketfree(d);
175 }
176 }
177 ++d->udploop;
178 d->curserver = 0;
179 }
180
181 dns_transmit_free(d); return DNS_COM;
182}
183
184int firstudp(struct dns_transmit *d)
185{
186 d->curserver = 0;
187 return thisudp(d);
188}
189
190int nextudp(struct dns_transmit *d)
191{
192 ++d->curserver;
193 return thisudp(d);
194}
195
196static int thistcp(struct dns_transmit *d)
197{
198 struct taia now;
199 const char *ip;
200
201 socketfree(d);
202 packetfree(d);
203
204 for (; d->curserver < QUERY_MAXNS; ++d->curserver) {
205 ip = d->servers + 16 * d->curserver;
206 if (byte_diff(ip,16,V6localnet)) {
207 d->query[2] = dns_random(256);
208 d->query[3] = dns_random(256);
209
210 if (ip6_isv4mapped(ip)) {
211 d->s1 = 1 + socket_tcp4();
212 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
213 if (randombind4(d) < 0) { dns_transmit_free(d); return DNS_COM; }
214 } else {
215 d->s1 = 1 + socket_tcp6();
216 if (!d->s1) { dns_transmit_free(d); return DNS_COM; }
217 if (randombind6(d) < 0) { dns_transmit_free(d); return DNS_COM; }
218 }
219
220 taia_now(&now);
221 taia_uint(&d->deadline,10);
222 taia_add(&d->deadline,&d->deadline,&now);
223
224 if (byte_equal(ip,2,V6linklocal) && !d->scope_id)
225 d->scope_id = getscopeid(d,ip);
226 if (socket_connect(d->s1 - 1,ip,DNSPORT,d->scope_id) == 0) {
227 d->tcpstate = 2;
228 return 0;
229 }
230 if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
231 d->tcpstate = 1;
232 return 0;
233 }
234
235 socketfree(d);
236 }
237 }
238
240 return DNS_COM;
241}
242
243int firsttcp(struct dns_transmit *d)
244{
245 d->curserver = 0;
246 return thistcp(d);
247}
248
249int nexttcp(struct dns_transmit *d)
250{
251 ++d->curserver;
252 return thistcp(d);
253}
254
255int dns_transmit_start(struct dns_transmit *d,const char servers[QUERY_MAXIPLEN], \
256 int flagrecursive,const char *q,const char qtype[2],const char localip[16])
257{
258 unsigned int len;
259
261 errno = EIO;
262
263 len = dns_domain_length(q);
264 d->querylen = len + 18;
265 d->query = alloc(d->querylen);
266 if (!d->query) return DNS_COM;
267
268 uint16_pack_big(d->query,len + 16);
269 byte_copy(d->query + 2,12,flagrecursive ? "\0\0\1\0\0\1\0\0\0\0\0\0" : \
270 "\0\0\0\0\0\1\0\0\0\0\0\0gcc-bug-workaround");
271 byte_copy(d->query + 14,len,q);
272 byte_copy(d->query + 14 + len,2,qtype);
273 byte_copy(d->query + 16 + len,2,DNS_C_IN);
274
275 byte_copy(d->qtype,2,(char *) qtype);
276 d->servers = servers;
277 byte_copy(d->localip,16,(char *) localip);
278
279 d->udploop = flagrecursive ? 1 : 0;
280
281 if (len + 16 > MSGSIZE) return firsttcp(d);
282 return firstudp(d);
283}
284
285int dns_transmit_start6(struct dns_transmit *d,const char servers[QUERY_MAXIPLEN], \
286 int flagrecursive,const char *q,const char qtype[2], \
287 const char localip[16],const uint32 scopes[QUERY_MAXNS])
288{
289 byte_copy(scope_ids,128,(char *) scopes);
290
291 return dns_transmit_start(d,servers,flagrecursive,q,qtype,localip);
292}
293
294void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
295{
296 x->fd = d->s1 - 1;
297
298 switch (d->tcpstate) {
299 case 0: case 3: case 4: case 5:
300 x->events = IOPAUSE_READ;
301 break;
302 case 1: case 2:
304 break;
305 }
306
307 if (taia_less(&d->deadline,deadline))
308 *deadline = d->deadline;
309}
310
311int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
312{
313 char udpbuf[MSGSIZE + 1];
314 unsigned char ch;
315 int r;
316 int fd;
317
318 errno = EIO;
319 fd = d->s1 - 1;
320
321 if (!x->revents) {
322 if (taia_less((struct taia *)when,&d->deadline)) return 0;
323 errno = ETIMEDOUT;
324 if (d->tcpstate == 0) return nextudp(d);
325 return nexttcp(d);
326 }
327
328/*
329have attempted to send UDP query to each server udploop times
330have sent query to curserver on UDP socket s
331*/
332 if (d->tcpstate == 0) {
333 r = recv(fd,udpbuf,sizeof(udpbuf),0);
334 if (r <= 0) {
335 if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
336 return nextudp(d);
337 }
338 if (r + 1 > sizeof(udpbuf)) return 0;
339
340 if (irrelevant(d,udpbuf,r)) return 0;
341 if (serverwantstcp(udpbuf,r)) return firsttcp(d);
342 if (serverfailed(udpbuf,r)) {
343 if (d->udploop == 2) return 0;
344 return nextudp(d);
345 }
346 socketfree(d);
347
348 d->packetlen = r;
349 d->packet = alloc(d->packetlen);
350 if (!d->packet) { dns_transmit_free(d); return DNS_COM; }
351 byte_copy(d->packet,d->packetlen,udpbuf);
352 queryfree(d);
353 return 1;
354 }
355
356/*
357have sent connection attempt to curserver on TCP socket s
358pos not defined
359*/
360 if (d->tcpstate == 1) {
361 if (!socket_connected(fd)) return nexttcp(d);
362 d->pos = 0;
363 d->tcpstate = 2;
364 return 0;
365 }
366
367/*
368have connection to curserver on TCP socket s
369have sent pos bytes of query
370*/
371 if (d->tcpstate == 2) {
372 r = write(fd,d->query + d->pos,d->querylen - d->pos);
373 if (r <= 0) return nexttcp(d);
374 d->pos += r;
375 if (d->pos == d->querylen) {
376 struct taia now;
377 taia_now(&now);
378 taia_uint(&d->deadline,10);
379 taia_add(&d->deadline,&d->deadline,&now);
380 d->tcpstate = 3;
381 }
382 return 0;
383 }
384
385/*
386have sent entire query to curserver on TCP socket s
387pos not defined
388*/
389 if (d->tcpstate == 3) {
390 r = read(fd,&ch,1);
391 if (r <= 0) return nexttcp(d);
392 d->packetlen = ch;
393 d->tcpstate = 4;
394 return 0;
395 }
396
397/*
398have sent entire query to curserver on TCP socket s
399pos not defined
400have received one byte of packet length into packetlen
401*/
402 if (d->tcpstate == 4) {
403 r = read(fd,&ch,1);
404 if (r <= 0) return nexttcp(d);
405 d->packetlen <<= 8;
406 d->packetlen += ch;
407 d->tcpstate = 5;
408 d->pos = 0;
409 d->packet = alloc(d->packetlen);
410 if (!d->packet) { dns_transmit_free(d); return DNS_COM; }
411 return 0;
412 }
413
414/*
415have sent entire query to curserver on TCP socket s
416have received entire packet length into packetlen
417packet is allocated
418have received pos bytes of packet
419*/
420 if (d->tcpstate == 5) {
421 r = read(fd,d->packet + d->pos,d->packetlen - d->pos);
422 if (r <= 0) return nexttcp(d);
423 d->pos += r;
424 if (d->pos < d->packetlen) return 0;
425
426 socketfree(d);
427 if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d);
428 if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d);
429 if (serverfailed(d->packet,d->packetlen)) return nexttcp(d);
430
431 queryfree(d);
432 return 1;
433 }
434
435 return 0;
436}
int read(int _str, void *_buf, int _b)
void dns_transmit_io(struct dns_transmit *d, iopause_fd *x, struct taia *deadline)
Definition: dns_transmit.c:294
void socketfree(struct dns_transmit *d)
Definition: dns_transmit.c:98
void packetfree(struct dns_transmit *d)
Definition: dns_transmit.c:84
void dns_transmit_free(struct dns_transmit *d)
Definition: dns_transmit.c:105
int randombind6(struct dns_transmit *d)
Definition: dns_transmit.c:112
int getscopeid(const struct dns_transmit *d, const char *ip)
Definition: dns_transmit.c:26
int randombind4(struct dns_transmit *d)
Definition: dns_transmit.c:126
int firstudp(struct dns_transmit *d)
Definition: dns_transmit.c:184
int dns_transmit_start6(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], int flagrecursive, const char *q, const char qtype[2], const char localip[16], const uint32 scopes[QUERY_MAXNS])
Definition: dns_transmit.c:285
int nexttcp(struct dns_transmit *d)
Definition: dns_transmit.c:249
int serverfailed(const char *buf, unsigned int len)
Definition: dns_transmit.c:48
int serverwantstcp(const char *buf, unsigned int len)
Definition: dns_transmit.c:38
uint32 scope_ids[QUERY_MAXNS]
Definition: dns_transmit.c:22
void queryfree(struct dns_transmit *d)
Definition: dns_transmit.c:91
int dns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], int flagrecursive, const char *q, const char qtype[2], const char localip[16])
Definition: dns_transmit.c:255
#define DNSPORT
Definition: dns_transmit.c:20
int dns_transmit_get(struct dns_transmit *d, const iopause_fd *x, const struct taia *when)
Definition: dns_transmit.c:311
int nextudp(struct dns_transmit *d)
Definition: dns_transmit.c:190
int firsttcp(struct dns_transmit *d)
Definition: dns_transmit.c:243
#define IOPAUSE_READ
Definition: iopause.h:19
#define IOPAUSE_WRITE
Definition: iopause.h:20
void alloc_free(void *)
Definition: alloc.c:45
void * alloc(unsigned int)
Definition: alloc.c:27
additional types and pack routines
void uint16_pack_big(char[16], uint16)
uint32_t uint32
Definition: uint_t.h:40
#define ip6_isv4mapped(ip)
Definition: ip.h:105
int socket_bind4(int, const char[4], uint16)
Definition: socket_bind.c:16
int socket_connected(int)
int socket_udp4(void)
Definition: socket_udp.c:33
int socket_bind6(int, const char[16], uint16, uint32)
Definition: socket_bind.c:44
int socket_udp6(void)
Definition: socket_udp.c:22
int socket_tcp6(void)
Definition: socket_tcp.c:33
int socket_connect(int, const char[16], uint16, uint32)
int socket_tcp4(void)
Definition: socket_tcp.c:22
int taia_less(struct taia *, struct taia *)
Definition: taia.c:39
void taia_add(struct taia *, struct taia *, struct taia *)
Definition: taia.c:14
void taia_uint(struct taia *, unsigned int)
Definition: taia.c:99
int taia_now(struct taia *)
Definition: taia.c:48
int close(int __fd)
int byte_diff(const void *, unsigned int, const void *)
Definition: byte.c:40
void byte_copy(void *, unsigned int, const void *)
Definition: byte.c:20
#define byte_equal(s, n, t)
Definition: byte.h:18
unsigned int dns_packet_copy(const char *, unsigned int, unsigned int, char *, unsigned int)
Definition: dns_packet.c:12
#define QUERY_MAXIPLEN
Definition: dnsresolv.h:56
int dns_domain_equal(const char *, const char *)
Definition: dns_domain.c:46
unsigned int dns_random(unsigned int)
Definition: dns_random.c:59
#define DNS_C_IN
Definition: dnsresolv.h:60
#define MSGSIZE
Definition: dnsresolv.h:50
unsigned int dns_domain_length(const char *)
Definition: dns_domain.c:13
#define QUERY_MAXNS
Definition: dnsresolv.h:55
unsigned int dns_packet_getname(const char *, unsigned int, unsigned int, char **)
Definition: dns_packet.c:39
#define DNS_COM
Definition: dnsresolv.h:45
uint32 scope_id
Definition: dnsresolv.h:111
unsigned int curserver
Definition: dnsresolv.h:107
char qtype[2]
Definition: dnsresolv.h:113
unsigned int udploop
Definition: dnsresolv.h:106
char localip[16]
Definition: dnsresolv.h:112
struct taia deadline
Definition: dnsresolv.h:108
const char * servers
Definition: dnsresolv.h:110
unsigned int packetlen
Definition: dnsresolv.h:103
unsigned int querylen
Definition: dnsresolv.h:101
char * packet
Definition: dnsresolv.h:102
unsigned int pos
Definition: dnsresolv.h:109
char * query
Definition: dnsresolv.h:100
int fd
Definition: iopause.h:15
short events
Definition: iopause.h:16
short revents
Definition: iopause.h:17
Definition: taia.h:13