ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/trunk/src/firedns.c
Revision: 8185
Committed: Thu Apr 13 20:19:02 2017 UTC (8 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 18961 byte(s)
Log Message:
- Avoid list_t initialization via list_create(); scan.c: remove unused MASKS list

File Contents

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

Properties

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