ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/hopm/branches/1.0.x/src/firedns.c
Revision: 5165
Committed: Fri Dec 26 18:53:10 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 19622 byte(s)
Log Message:
- Replaced all occurrences of inet_pton() with getaddrinfo()

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

Properties

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