ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/firedns.c
Revision: 8579
Committed: Sun Oct 14 15:12:50 2018 UTC (6 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 18908 byte(s)
Log Message:
- Allocate most list_t and node_t items from within their corresponding structure to save extra calloc/free calls

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

Properties

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