ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/firedns.c
Revision: 8153
Committed: Fri Apr 7 18:09:43 2017 UTC (8 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 19028 byte(s)
Log Message:
- firedns.c, firedns.h: minor cleanups

File Contents

# User Rev Content
1 michael 5052 /*
2     firedns.c - firedns library
3     Copyright (C) 2002 Ian Gulliver
4 michael 5876
5 michael 5052 This file has been gutted and mucked with for use in BOPM - see the
6     real library at http://ares.penguinhosting.net/~ian/ before you judge
7     firedns based on this..
8 michael 5876
9 michael 5052 This program is free software; you can redistribute it and/or modify
10     it under the terms of version 2 of the GNU General Public License as
11     published by the Free Software Foundation.
12 michael 5876
13 michael 5052 This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17 michael 5876
18 michael 5052 You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21     */
22    
23     #include "setup.h"
24    
25     #include <stdlib.h>
26     #include <time.h>
27     #include <sys/types.h>
28     #include <sys/socket.h>
29 michael 5227 #include <poll.h>
30 michael 5052 #include <sys/time.h>
31     #include <netinet/in.h>
32 michael 5175 #include <arpa/inet.h>
33 michael 5052 #include <string.h>
34     #include <unistd.h>
35     #include <stdio.h>
36     #include <errno.h>
37     #include <fcntl.h>
38    
39     #include "compat.h"
40 michael 5333 #include "memory.h"
41 michael 5052 #include "firedns.h"
42     #include "config.h"
43     #include "list.h"
44     #include "log.h"
45     #include "dnsbl.h"
46    
47     #define FIREDNS_TRIES 3
48    
49 michael 5390 int firedns_errno = FDNS_ERR_NONE;
50 michael 5052
51     /* Variables local to this file */
52 michael 5390 static unsigned int firedns_fdinuse;
53 michael 5052
54     /* up to FDNS_MAX nameservers; populated by firedns_init() */
55     static struct in_addr servers4[FDNS_MAX];
56 michael 5380 static struct in6_addr servers6[FDNS_MAX];
57 michael 8153
58 michael 5052 /* actual count of nameservers; set by firedns_init() */
59 michael 8153 static unsigned int i4;
60     static unsigned int i6;
61 michael 5052
62     /*
63 michael 5181 * Linked list of open DNS queries; populated by firedns_add_query(),
64 michael 5052 * decimated by firedns_getresult()
65     */
66 michael 5181 static list_t *CONNECTIONS;
67 michael 5052
68     /*
69     * List of errors, in order of values used in FDNS_ERR_*, returned by
70     * firedns_strerror
71     */
72 michael 8153 static const char *const errors[] =
73 michael 5181 {
74 michael 6019 [FDNS_ERR_NONE] = "Success",
75     [FDNS_ERR_FORMAT] = "Format error",
76     [FDNS_ERR_SERVFAIL] = "Server failure",
77     [FDNS_ERR_NXDOMAIN] = "Name error",
78     [FDNS_ERR_NOIMPT] = "Not implemented",
79     [FDNS_ERR_REFUSED] = "Refused",
80     [FDNS_ERR_TIMEOUT] = "Timeout",
81     [FDNS_ERR_NETWORK] = "Network error",
82     [FDNS_ERR_FDLIMIT] = "FD Limit reached",
83     [FDNS_ERR_OTHER] = "Unknown error"
84 michael 5052 };
85    
86     /* Structures */
87    
88     /* open DNS query */
89     struct s_connection
90     {
91 michael 5181 /*
92     * unique ID (random number), matches header ID; both set by
93     * firedns_add_query()
94     */
95     unsigned char id[2];
96     uint16_t class;
97     uint16_t type;
98    
99     /* file descriptor returned from sockets */
100     int fd;
101     void *info;
102     time_t start;
103     char lookup[256];
104     int v6;
105 michael 5052 };
106    
107     struct s_rr_middle
108     {
109 michael 5181 uint16_t type;
110     uint16_t class;
111    
112     /* XXX - firedns depends on this being 4 bytes */
113     uint32_t ttl;
114     uint16_t rdlength;
115 michael 5052 };
116    
117     /* DNS query header */
118     struct s_header
119     {
120 michael 5181 unsigned char id[2];
121     unsigned char flags1;
122 michael 5052 #define FLAGS1_MASK_QR 0x80
123     /* bitshift right 3 */
124     #define FLAGS1_MASK_OPCODE 0x78
125     #define FLAGS1_MASK_AA 0x04
126     #define FLAGS1_MASK_TC 0x02
127     #define FLAGS1_MASK_RD 0x01
128    
129 michael 5181 unsigned char flags2;
130 michael 5052 #define FLAGS2_MASK_RA 0x80
131     #define FLAGS2_MASK_Z 0x70
132     #define FLAGS2_MASK_RCODE 0x0f
133    
134 michael 5181 uint16_t qdcount;
135     uint16_t ancount;
136     uint16_t nscount;
137     uint16_t arcount;
138    
139     /* DNS question, populated by firedns_build_query_payload() */
140     unsigned char payload[512];
141 michael 5052 };
142    
143     /* Function prototypes */
144     static struct s_connection *firedns_add_query(void);
145 michael 5181 static int firedns_doquery(struct s_connection *);
146     static int firedns_build_query_payload(const char *const, uint16_t, uint16_t, unsigned char *);
147     static int firedns_send_requests(struct s_header *, struct s_connection *, int);
148 michael 5052
149    
150 michael 5181 void
151     firedns_init(void)
152 michael 5052 {
153 michael 5181 /*
154     * populates servers4 (or -6) struct with up to FDNS_MAX nameserver IP
155     * addresses from /etc/firedns.conf (or /etc/resolv.conf)
156     */
157     FILE *f;
158     struct in_addr addr4;
159     struct in6_addr addr6;
160     char buf[1024];
161 michael 5185 char *p = NULL;
162 michael 5052
163 michael 5181 i6 = 0;
164     i4 = 0;
165 michael 5052
166 michael 5181 /* Initialize connections list */
167     CONNECTIONS = list_create();
168 michael 5052
169 michael 5181 srand((unsigned int)time(NULL));
170 michael 5920 memset(servers4, 0, sizeof(servers4));
171     memset(servers6, 0, sizeof(servers6));
172 michael 5052
173 michael 5181 /* read etc/firedns.conf if we've got it, otherwise parse /etc/resolv.conf */
174     f = fopen(FDNS_CONFIG_PREF, "r");
175    
176     if (f == NULL)
177     {
178     f = fopen(FDNS_CONFIG_FBCK, "r");
179    
180     if (f == NULL)
181     {
182     log_printf("Unable to open %s", FDNS_CONFIG_FBCK);
183     return;
184     }
185    
186 michael 5187 while (fgets(buf, sizeof(buf), f))
187 michael 5181 {
188 michael 5185 if ((p = strchr(buf, '\n')))
189     *p = '\0';
190    
191 michael 5181 if (strncmp(buf, "nameserver", 10) == 0)
192 michael 5052 {
193 michael 8153 unsigned int i = 10;
194 michael 5181
195     while (buf[i] == ' ' || buf[i] == '\t')
196     ++i;
197    
198     if (i6 < FDNS_MAX)
199     {
200     if (inet_pton(AF_INET6, &buf[i], &addr6) > 0)
201     {
202     memcpy(&servers6[i6++], &addr6, sizeof(struct in6_addr));
203     continue;
204     }
205     }
206    
207     if (i4 < FDNS_MAX)
208     {
209     if (inet_pton(AF_INET, &buf[i], &addr4) > 0)
210     memcpy(&servers4[i4++], &addr4, sizeof(struct in_addr));
211     }
212 michael 5052 }
213 michael 5181 }
214     }
215     else
216     {
217 michael 5187 while (fgets(buf, sizeof(buf), f))
218 michael 5181 {
219 michael 5185 if ((p = strchr(buf, '\n')))
220     *p = '\0';
221    
222 michael 5181 if (i6 < FDNS_MAX)
223     {
224     if (inet_pton(AF_INET6, buf, &addr6) > 0)
225     {
226     memcpy(&servers6[i6++], &addr6, sizeof(struct in6_addr));
227     continue;
228     }
229 michael 5052 }
230 michael 5181
231     if (i4 < FDNS_MAX)
232 michael 5052 {
233 michael 5181 if (inet_pton(AF_INET, buf, &addr4) > 0)
234     memcpy(&servers4[i4++], &addr4, sizeof(struct in_addr));
235     }
236     }
237     }
238 michael 5179
239 michael 5181 fclose(f);
240 michael 5052 }
241    
242 michael 8151 /*
243     * These little hacks are here to avoid alignment and type sizing issues completely by doing manual copies
244     */
245     static inline void
246     firedns_fill_rr(struct s_rr_middle *restrict const rr, const unsigned char *const restrict input)
247     {
248     rr->type = input[0] * 256 + input[1];
249     rr->class = input[2] * 256 + input[3];
250     rr->ttl = input[4] * 16777216 + input[5] * 65536 + input[6] * 256 + input[7];
251     rr->rdlength = input[8] * 256 + input[9];
252     }
253    
254     static inline void
255     firedns_fill_header(struct s_header *const restrict header, const unsigned char *const restrict input, const int l)
256     {
257     header->id[0] = input[0];
258     header->id[1] = input[1];
259     header->flags1 = input[2];
260     header->flags2 = input[3];
261     header->qdcount = input[4] * 256 + input[5];
262     header->ancount = input[6] * 256 + input[7];
263     header->nscount = input[8] * 256 + input[9];
264     header->arcount = input[10] * 256 + input[11];
265     memcpy(header->payload, &input[12], l);
266     }
267    
268     static inline void
269     firedns_empty_header(unsigned char *const restrict output, const struct s_header *const restrict header, const int l)
270     {
271     output[0] = header->id[0];
272     output[1] = header->id[1];
273     output[2] = header->flags1;
274     output[3] = header->flags2;
275     output[4] = header->qdcount / 256;
276     output[5] = header->qdcount % 256;
277     output[6] = header->ancount / 256;
278     output[7] = header->ancount % 256;
279     output[8] = header->nscount / 256;
280     output[9] = header->nscount % 256;
281     output[10] = header->arcount / 256;
282     output[11] = header->arcount % 256;
283     memcpy(&output[12], header->payload, l);
284     }
285    
286 michael 5181 /* immediate A query */
287     struct in_addr *
288     firedns_resolveip4(const char *const name)
289     {
290     static struct in_addr addr;
291 michael 5052
292 michael 5181 if (inet_pton(AF_INET, name, &addr) > 0)
293     return &addr;
294    
295 michael 8153 return firedns_resolveip(FDNS_QRY_A, name);
296 michael 5052 }
297    
298 michael 5181 /* immediate AAAA query */
299     struct in6_addr *
300 michael 8110 firedns_resolveip6(const char *const name)
301 michael 5181 {
302 michael 5183 static struct in6_addr addr;
303    
304     if (inet_pton(AF_INET6, name, &addr) > 0)
305     return &addr;
306    
307 michael 8153 return firedns_resolveip(FDNS_QRY_AAAA, name);
308 michael 5052 }
309    
310 michael 5181 /* resolve a query of a given type */
311 michael 8153 void *
312 michael 5181 firedns_resolveip(int type, const char *const name)
313     {
314     struct firedns_result *result;
315     struct timeval tv;
316     fd_set s;
317 michael 5052
318 michael 8153 for (unsigned int t = 0; t < FIREDNS_TRIES; ++t)
319 michael 5181 {
320     int fd = firedns_getip(type, name, NULL);
321     if (fd == -1)
322     return NULL;
323 michael 5052
324 michael 5181 tv.tv_sec = 5;
325     tv.tv_usec = 0;
326     FD_ZERO(&s);
327     FD_SET(fd, &s);
328     select(fd + 1, &s, NULL, NULL, &tv);
329    
330     result = firedns_getresult(fd);
331    
332 michael 5390 if (firedns_errno == FDNS_ERR_NONE)
333 michael 5181 /*
334     * Return is from static memory in getresult, so there is no need to
335     * copy it until the next call to firedns.
336     */
337     return result->text;
338 michael 5390 else if (firedns_errno == FDNS_ERR_NXDOMAIN)
339 michael 5181 return NULL;
340     }
341    
342 michael 5390 if (firedns_errno == FDNS_ERR_NONE)
343     firedns_errno = FDNS_ERR_TIMEOUT;
344 michael 5181
345     return NULL;
346 michael 5052 }
347    
348     /*
349     * build, add and send specified query; retrieve result with
350     * firedns_getresult()
351     */
352 michael 5181 int
353 michael 8110 firedns_getip(int type, const char *const name, void *info)
354 michael 5052 {
355 michael 5181 struct s_connection *s;
356     node_t *node;
357 michael 5052
358 michael 5181 s = firedns_add_query();
359     s->class = 1;
360     s->type = type;
361     s->info = info;
362     strlcpy(s->lookup, name, sizeof(s->lookup));
363 michael 5052
364 michael 5390 if (firedns_fdinuse >= OptionsItem->dns_fdlimit)
365 michael 5181 {
366 michael 5390 firedns_errno = FDNS_ERR_FDLIMIT;
367 michael 5052
368 michael 5181 /* Don't add to queue if there is no info */
369     if (info == NULL)
370 michael 5426 xfree(s);
371 michael 5181 else
372     {
373     node = node_create(s);
374     list_add(CONNECTIONS, node);
375     }
376 michael 5052
377 michael 5181 return -1;
378     }
379    
380 michael 8153 int fd = firedns_doquery(s);
381 michael 5181 if (fd == -1)
382     {
383 michael 5426 xfree(s);
384 michael 5181 return -1;
385     }
386    
387     node = node_create(s);
388     list_add(CONNECTIONS, node);
389    
390     return fd;
391 michael 5052 }
392    
393 michael 5181 /* build DNS query, add to list */
394     static struct s_connection *
395     firedns_add_query(void)
396     {
397     struct s_connection *s;
398 michael 5052
399 michael 5181 /* create new connection object */
400 michael 6149 s = xcalloc(sizeof(*s));
401 michael 5052
402 michael 5181 /* verified by firedns_getresult() */
403     s->id[0] = rand() % 255;
404     s->id[1] = rand() % 255;
405     s->fd = -1;
406 michael 5052
407 michael 5181 return s;
408 michael 5052 }
409    
410 michael 5181 static int
411     firedns_doquery(struct s_connection *s)
412 michael 5052 {
413 michael 5181 struct s_header h;
414 michael 5052
415 michael 8153 int len = firedns_build_query_payload(s->lookup, s->type, 1, (unsigned char *)&h.payload);
416 michael 5181 if (len == -1)
417     {
418 michael 5390 firedns_errno = FDNS_ERR_FORMAT;
419 michael 5181 return -1;
420     }
421 michael 5052
422 michael 5181 return firedns_send_requests(&h, s, len);
423 michael 5052 }
424    
425     /*
426     * populate payload with query: name= question, rr= record type
427     */
428 michael 5181 static int
429     firedns_build_query_payload(const char *const name, uint16_t rr, uint16_t class,
430     unsigned char *payload)
431 michael 5052 {
432 michael 5181 int16_t payloadpos = 0;
433     const char *tempchr, *tempchr2;
434     uint16_t l;
435 michael 5052
436 michael 5181 tempchr2 = name;
437 michael 5052
438 michael 5181 /* split name up into labels, create query */
439     while ((tempchr = strchr(tempchr2, '.')))
440     {
441     l = tempchr - tempchr2;
442    
443     if (payloadpos + l + 1 > 507)
444 michael 5052 return -1;
445 michael 5181
446     payload[payloadpos++] = l;
447     memcpy(&payload[payloadpos], tempchr2, l);
448     payloadpos += l;
449     tempchr2 = &tempchr[1];
450     }
451    
452     l = strlen(tempchr2);
453    
454     if (l)
455     {
456     if (payloadpos + l + 2 > 507)
457     return -1;
458    
459     payload[payloadpos++] = l;
460     memcpy(&payload[payloadpos], tempchr2, l);
461     payloadpos += l;
462     payload[payloadpos++] = '\0';
463     }
464    
465     if (payloadpos > 508)
466     return -1;
467    
468     l = htons(rr);
469     memcpy(&payload[payloadpos], &l, 2);
470    
471     l = htons(class);
472     memcpy(&payload[payloadpos + 2], &l, 2);
473    
474     return payloadpos + 4;
475 michael 5052 }
476    
477     /* send DNS query */
478 michael 5181 static int
479     firedns_send_requests(struct s_header *h, struct s_connection *s, int l)
480 michael 5052 {
481 michael 8153 int sent_ok = 0;
482 michael 5181 struct sockaddr_in addr4;
483     struct sockaddr_in6 addr6;
484 michael 8151 unsigned char payload[sizeof(struct s_header)];
485 michael 5052
486 michael 5181 /* set header flags */
487 michael 8151 h->id[0] = s->id[0];
488     h->id[1] = s->id[1];
489 michael 5181 h->flags1 = 0 | FLAGS1_MASK_RD;
490     h->flags2 = 0;
491 michael 8151 h->qdcount = 1;
492     h->ancount = 0;
493     h->nscount = 0;
494     h->arcount = 0;
495 michael 5181
496     /* try to create ipv6 or ipv4 socket */
497     s->v6 = 0;
498    
499     if (i6 > 0)
500     {
501 michael 5952 s->fd = socket(AF_INET6, SOCK_DGRAM, 0);
502 michael 5181
503     if (s->fd != -1)
504     {
505     if (fcntl(s->fd, F_SETFL, O_NONBLOCK))
506 michael 5052 {
507 michael 5181 close(s->fd);
508     s->fd = -1;
509 michael 5052 }
510 michael 5181 }
511 michael 5052
512 michael 5181 if (s->fd != -1)
513     {
514     memset(&addr6, 0, sizeof(addr6));
515     addr6.sin6_family = AF_INET6;
516    
517     if (bind(s->fd, (struct sockaddr *)&addr6, sizeof(addr6)) == 0)
518     s->v6 = 1;
519     else
520     close(s->fd);
521     }
522     }
523    
524     if (s->v6 == 0)
525     {
526 michael 5952 s->fd = socket(AF_INET, SOCK_DGRAM, 0);
527 michael 5181
528     if (s->fd != -1)
529     {
530     if (fcntl(s->fd, F_SETFL, O_NONBLOCK))
531 michael 5052 {
532 michael 5181 close(s->fd);
533     s->fd = -1;
534 michael 5052 }
535 michael 5181 }
536 michael 5052
537 michael 5181 if (s->fd != -1)
538     {
539 michael 5951 memset(&addr4, 0, sizeof(addr4));
540     addr4.sin_family = AF_INET;
541     addr4.sin_port = 0;
542     addr4.sin_addr.s_addr = INADDR_ANY;
543 michael 5181
544 michael 5951 if (bind(s->fd, (struct sockaddr *)&addr4, sizeof(addr4)) != 0)
545 michael 5052 {
546 michael 5181 close(s->fd);
547     s->fd = -1;
548 michael 5052 }
549 michael 5181 }
550 michael 5179
551 michael 5181 if (s->fd == -1)
552     {
553 michael 5390 firedns_errno = FDNS_ERR_NETWORK;
554 michael 5052 return -1;
555 michael 5181 }
556     }
557    
558 michael 8153 firedns_empty_header(payload, h, l);
559 michael 8151
560 michael 5181 /* if we've got ipv6 support, an ip v6 socket, and ipv6 servers, send to them */
561     if (i6 > 0 && s->v6 == 1)
562     {
563 michael 8153 for (unsigned int i = 0; i < i6; ++i)
564 michael 5181 {
565     memset(&addr6, 0, sizeof(addr6));
566     memcpy(&addr6.sin6_addr, &servers6[i], sizeof(addr6.sin6_addr));
567    
568     addr6.sin6_family = AF_INET6;
569     addr6.sin6_port = htons(FDNS_PORT);
570    
571 michael 8151 if (sendto(s->fd, payload, l + 12, 0, (struct sockaddr *)&addr6, sizeof(addr6)) > 0)
572 michael 5181 sent_ok = 1;
573     }
574     }
575    
576 michael 8153 for (unsigned int i = 0; i < i4; ++i)
577 michael 5181 {
578     /* send via ipv4-over-ipv6 if we've got an ipv6 socket */
579     if (s->v6 == 1)
580     {
581     memset(&addr6, 0, sizeof(addr6));
582     memcpy(addr6.sin6_addr.s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
583     memcpy(&addr6.sin6_addr.s6_addr[12], &servers4[i].s_addr, 4);
584     addr6.sin6_family = AF_INET6;
585     addr6.sin6_port = htons(FDNS_PORT);
586    
587 michael 8151 if (sendto(s->fd, payload, l + 12, 0, (struct sockaddr *)&addr6, sizeof(addr6)) > 0)
588 michael 5181 sent_ok = 1;
589    
590     continue;
591     }
592    
593     /* otherwise send via standard ipv4 boringness */
594     memset(&addr4, 0, sizeof(addr4));
595     memcpy(&addr4.sin_addr, &servers4[i], sizeof(addr4.sin_addr));
596     addr4.sin_family = AF_INET;
597     addr4.sin_port = htons(FDNS_PORT);
598    
599 michael 8151 if (sendto(s->fd, payload, l + 12, 0, (struct sockaddr *)&addr4, sizeof(addr4)) > 0)
600 michael 5181 sent_ok = 1;
601     }
602    
603     if (!sent_ok)
604     {
605     close(s->fd);
606     s->fd = -1;
607 michael 5390 firedns_errno = FDNS_ERR_NETWORK;
608 michael 5181 return -1;
609     }
610    
611     time(&s->start);
612 michael 5390 firedns_fdinuse++;
613     firedns_errno = FDNS_ERR_NONE;
614 michael 5181
615     return s->fd;
616 michael 5052 }
617    
618 michael 5181 /* retrieve result of DNS query */
619     struct firedns_result *
620     firedns_getresult(const int fd)
621     {
622     static struct firedns_result result;
623     struct s_header h;
624     struct s_connection *c;
625     node_t *node;
626     int l, i, q, curanswer;
627 michael 8151 struct s_rr_middle rr = { .rdlength = 0 };
628     unsigned char buffer[sizeof(struct s_header)];
629 michael 5052
630 michael 5390 firedns_errno = FDNS_ERR_OTHER;
631 michael 5181 result.info = NULL;
632 michael 5052
633 michael 5181 memset(result.text, 0, sizeof(result.text));
634 michael 5052
635 michael 5181 /* Find query in list of dns lookups */
636     LIST_FOREACH(node, CONNECTIONS->head)
637     {
638     c = node->data;
639 michael 5052
640 michael 5181 if (c->fd == fd)
641     break;
642     else
643     c = NULL;
644     }
645 michael 5052
646 michael 5181 /* query not found */
647     if (c == NULL)
648     return &result;
649 michael 5052
650 michael 5181 /* query found -- we remove in cleanup */
651 michael 8151 l = recv(c->fd, buffer, sizeof(struct s_header), 0);
652    
653 michael 5181 result.info = c->info;
654     strlcpy(result.lookup, c->lookup, sizeof(result.lookup));
655 michael 5052
656 michael 5181 if (l == -1)
657     {
658 michael 5390 firedns_errno = FDNS_ERR_NETWORK;
659 michael 5181 goto cleanup;
660     }
661    
662     if (l < 12)
663     goto cleanup;
664    
665 michael 8151 firedns_fill_header(&h, buffer, l - 12);
666    
667 michael 5181 if (c->id[0] != h.id[0] || c->id[1] != h.id[1])
668     /*
669     * ID mismatch: we keep the connection, as this could be an answer to
670     * a previous lookup..
671     */
672     return NULL;
673    
674     if ((h.flags1 & FLAGS1_MASK_QR) == 0)
675     goto cleanup;
676    
677     if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0)
678     goto cleanup;
679    
680     if ((h.flags2 & FLAGS2_MASK_RCODE) != 0)
681     {
682 michael 5390 firedns_errno = (h.flags2 & FLAGS2_MASK_RCODE);
683 michael 5181 goto cleanup;
684     }
685    
686     if (h.ancount < 1)
687     {
688 michael 5390 firedns_errno = FDNS_ERR_NXDOMAIN;
689 michael 5181 /* no sense going on if we don't have any answers */
690     goto cleanup;
691     }
692    
693     /* skip queries */
694     i = 0;
695     q = 0;
696     l -= 12;
697    
698     while (q < h.qdcount && i < l)
699     {
700     if (h.payload[i] > 63)
701     {
702     /* pointer */
703     i += 6; /* skip pointer, class and type */
704     q++;
705     }
706     else
707     {
708     /* label */
709     if (h.payload[i] == 0)
710     {
711     q++;
712     i += 5; /* skip nil, class and type */
713 michael 5052 }
714     else
715 michael 5181 i += h.payload[i] + 1; /* skip length and label */
716     }
717     }
718    
719     /* &h.payload[i] should now be the start of the first response */
720     curanswer = 0;
721    
722     while (curanswer < h.ancount)
723     {
724     q = 0;
725    
726     while (q == 0 && i < l)
727     {
728     if (h.payload[i] > 63)
729 michael 5052 {
730 michael 5181 /* pointer */
731     i += 2; /* skip pointer */
732     q = 1;
733 michael 5052 }
734 michael 5181 else
735 michael 5052 {
736 michael 5181 /* label */
737     if (h.payload[i] == 0)
738     {
739     i++;
740     q = 1;
741     }
742     else
743     i += h.payload[i] + 1; /* skip length and label */
744 michael 5052 }
745 michael 5181 }
746 michael 5052
747 michael 5181 if (l - i < 10)
748 michael 5052 goto cleanup;
749    
750 michael 8151 firedns_fill_rr(&rr, &h.payload[i]);
751 michael 5181 i += 10;
752    
753 michael 8151 if (rr.type != c->type)
754 michael 5181 {
755     curanswer++;
756 michael 8151 i += rr.rdlength;
757 michael 5181 continue;
758     }
759    
760 michael 8151 if (rr.class != c->class)
761 michael 5181 {
762     curanswer++;
763 michael 8151 i += rr.rdlength;
764 michael 5181 continue;
765     }
766    
767     break;
768     }
769    
770     if (curanswer == h.ancount)
771     goto cleanup;
772 michael 8151 if (i + rr.rdlength > l)
773 michael 5181 goto cleanup;
774 michael 8151 if (rr.rdlength > 1023)
775 michael 5181 goto cleanup;
776    
777 michael 5390 firedns_errno = FDNS_ERR_NONE;
778 michael 8151 memcpy(result.text, &h.payload[i], rr.rdlength);
779     result.text[rr.rdlength] = '\0';
780 michael 5181
781     /* Clean-up */
782 michael 5052 cleanup:
783 michael 5181 list_remove(CONNECTIONS, node);
784     node_free(node);
785 michael 8153
786 michael 5181 close(c->fd);
787 michael 8153 xfree(c);
788 michael 5390 firedns_fdinuse--;
789 michael 5052
790 michael 5181 return &result;
791 michael 5052 }
792    
793 michael 5181 void
794     firedns_cycle(void)
795 michael 5052 {
796 michael 5695 node_t *node, *node_next;
797 michael 5181 struct s_connection *p;
798     struct firedns_result *res, new_result;
799     static struct pollfd *ufds = NULL;
800 michael 8153 unsigned int size = 0;
801 michael 5181 time_t timenow;
802 michael 5052
803 michael 5181 if (LIST_SIZE(CONNECTIONS) == 0)
804     return;
805 michael 5052
806 michael 5181 if (ufds == NULL)
807 michael 6149 ufds = xcalloc(sizeof(*ufds) * OptionsItem->dns_fdlimit);
808 michael 5052
809 michael 5181 time(&timenow);
810 michael 5052
811 michael 5695 LIST_FOREACH_SAFE(node, node_next, CONNECTIONS->head)
812 michael 5181 {
813     if (size >= OptionsItem->dns_fdlimit)
814     break;
815 michael 5052
816 michael 5181 p = node->data;
817 michael 5052
818 michael 5181 if (p->fd < 0)
819     continue;
820 michael 5052
821 michael 6200 if (p->fd > 0 && (p->start + OptionsItem->dns_timeout) < timenow)
822 michael 5181 {
823     /* Timed out - remove from list */
824     list_remove(CONNECTIONS, node);
825     node_free(node);
826 michael 5052
827 michael 5181 memset(new_result.text, 0, sizeof(new_result.text));
828     new_result.info = p->info;
829     strlcpy(new_result.lookup, p->lookup, sizeof(new_result.lookup));
830 michael 5052
831 michael 5181 close(p->fd);
832 michael 8153 xfree(p);
833 michael 5390 firedns_fdinuse--;
834 michael 5052
835 michael 5390 firedns_errno = FDNS_ERR_TIMEOUT;
836 michael 5052
837 michael 5181 if (new_result.info)
838     dnsbl_result(&new_result);
839 michael 5052
840 michael 5181 continue;
841     }
842 michael 5052
843 michael 5181 ufds[size].events = 0;
844     ufds[size].revents = 0;
845     ufds[size].fd = p->fd;
846     ufds[size].events = POLLIN;
847 michael 5052
848 michael 5699 ++size;
849 michael 5181 }
850 michael 5052
851 michael 5181 switch (poll(ufds, size, 0))
852     {
853     case -1:
854     case 0:
855     return;
856     }
857 michael 5052
858 michael 5699 LIST_FOREACH_SAFE(node, node_next, CONNECTIONS->head)
859 michael 5181 {
860     p = node->data;
861 michael 5052
862 michael 5181 if (p->fd > 0)
863     {
864 michael 8153 for (unsigned int i = 0; i < size; ++i)
865 michael 5052 {
866 michael 5181 if ((ufds[i].revents & POLLIN) && ufds[i].fd == p->fd)
867     {
868 michael 8153 res = firedns_getresult(p->fd);
869 michael 5052
870 michael 5181 if (res && res->info)
871     dnsbl_result(res);
872    
873     break;
874     }
875 michael 5052 }
876 michael 5181 }
877 michael 5390 else if (firedns_fdinuse < OptionsItem->dns_fdlimit)
878 michael 5181 firedns_doquery(p);
879     }
880 michael 5052 }
881    
882 michael 5181 const char *
883     firedns_strerror(int error)
884 michael 5052 {
885 michael 5181 if (error == FDNS_ERR_NETWORK)
886     return strerror(errno);
887    
888     return errors[error];
889 michael 5052 }

Properties

Name Value
svn:eol-style native
svn:keywords Id