ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/firedns.c
Revision: 5952
Committed: Fri May 8 20:47:10 2015 UTC (11 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 17411 byte(s)
Log Message:
- firedns.c: replace PF_INET(6) with AF_INET(6)

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

Properties

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