ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/irc_res.c
Revision: 1123
Committed: Sun Feb 6 21:57:50 2011 UTC (14 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.3/src/irc_res.c
File size: 23016 byte(s)
Log Message:
- Got rid of irc_addrinfo.c and irc_getnameinfo.c
- Fixed broken ipv6 detection due to incorrect use of AC_CHECK_TYPES

File Contents

# Content
1 /*
2 * A rewrite of Darren Reeds original res.c As there is nothing
3 * left of Darrens original code, this is now licensed by the hybrid group.
4 * (Well, some of the function names are the same, and bits of the structs..)
5 * You can use it where it is useful, free even. Buy us a beer and stuff.
6 *
7 * The authors takes no responsibility for any damage or loss
8 * of property which results from the use of this software.
9 *
10 * $Id$
11 *
12 * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
13 * added callbacks and reference counting of returned hostents.
14 * --Bleep (Thomas Helvey <tomh@inxpress.net>)
15 *
16 * This was all needlessly complicated for irc. Simplified. No more hostent
17 * All we really care about is the IP -> hostname mappings. Thats all.
18 *
19 * Apr 28, 2003 --cryogen and Dianora
20 */
21
22 #include "stdinc.h"
23 #include "list.h"
24 #include "balloc.h"
25 #include "client.h"
26 #include "event.h"
27 #include "irc_string.h"
28 #include "sprintf_irc.h"
29 #include "ircd.h"
30 #include "numeric.h"
31 #include "rng_mt.h"
32 #include "fdlist.h"
33 #include "fileio.h" /* for fbopen / fbclose / fbputs */
34 #include "s_bsd.h"
35 #include "s_log.h"
36 #include "send.h"
37 #include "memory.h"
38 #include "irc_res.h"
39 #include "irc_reslib.h"
40 #include "common.h"
41
42 #if (CHAR_BIT != 8)
43 #error this code needs to be able to address individual octets
44 #endif
45
46 static PF res_readreply;
47
48 #define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */
49 #define RES_MAXALIASES 35 /* maximum aliases allowed */
50 #define RES_MAXADDRS 35 /* maximum addresses allowed */
51 #define AR_TTL 600 /* TTL in seconds for dns cache entries */
52
53 /* RFC 1104/1105 wasn't very helpful about what these fields
54 * should be named, so for now, we'll just name them this way.
55 * we probably should look at what named calls them or something.
56 */
57 #define TYPE_SIZE (size_t)2
58 #define CLASS_SIZE (size_t)2
59 #define TTL_SIZE (size_t)4
60 #define RDLENGTH_SIZE (size_t)2
61 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
62
63 typedef enum
64 {
65 REQ_IDLE, /* We're doing not much at all */
66 REQ_PTR, /* Looking up a PTR */
67 REQ_A, /* Looking up an A, possibly because AAAA failed */
68 #ifdef IPV6
69 REQ_AAAA, /* Looking up an AAAA */
70 #endif
71 REQ_CNAME /* We got a CNAME in response, we better get a real answer next */
72 } request_state;
73
74 struct reslist
75 {
76 dlink_node node;
77 int id;
78 int sent; /* number of requests sent */
79 request_state state; /* State the resolver machine is in */
80 time_t ttl;
81 char type;
82 char retries; /* retry counter */
83 char sends; /* number of sends (>1 means resent) */
84 char resend; /* send flag. 0 == dont resend */
85 time_t sentat;
86 time_t timeout;
87 struct irc_ssaddr addr;
88 char *name;
89 dns_callback_fnc callback;
90 void *callback_ctx;
91 };
92
93 static fde_t ResolverFileDescriptor;
94 static dlink_list request_list = { NULL, NULL, 0 };
95 static BlockHeap *dns_heap = NULL;
96
97 static void rem_request(struct reslist *request);
98 static struct reslist *make_request(dns_callback_fnc callback, void *);
99 static void do_query_name(dns_callback_fnc callback, void *,
100 const char *, struct reslist *, int);
101 static void do_query_number(dns_callback_fnc callback, void *ctx,
102 const struct irc_ssaddr *,
103 struct reslist *request);
104 static void query_name(const char *name, int query_class, int query_type,
105 struct reslist *request);
106 static int send_res_msg(const char *buf, int len, int count);
107 static void resend_query(struct reslist *request);
108 static int proc_answer(struct reslist *request, HEADER *header, char *, char *);
109 static struct reslist *find_id(int id);
110
111
112 /*
113 * int
114 * res_ourserver(inp)
115 * looks up "inp" in irc_nsaddr_list[]
116 * returns:
117 * 0 : not found
118 * >0 : found
119 * author:
120 * paul vixie, 29may94
121 * revised for ircd, cryogen(stu) may03
122 */
123 static int
124 res_ourserver(const struct irc_ssaddr *inp)
125 {
126 #ifdef IPV6
127 const struct sockaddr_in6 *v6;
128 const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
129 #endif
130 const struct sockaddr_in *v4;
131 const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
132 int ns;
133
134 for (ns = 0; ns < irc_nscount; ns++)
135 {
136 const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
137 #ifdef IPV6
138 v6 = (const struct sockaddr_in6 *)srv;
139 #endif
140 v4 = (const struct sockaddr_in *)srv;
141
142 /* could probably just memcmp(srv, inp, srv.ss_len) here
143 * but we'll air on the side of caution - stu
144 *
145 */
146 switch (srv->ss.ss_family)
147 {
148 #ifdef IPV6
149 case AF_INET6:
150 if (srv->ss.ss_family == inp->ss.ss_family)
151 if (v6->sin6_port == v6in->sin6_port)
152 if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
153 sizeof(struct in6_addr)) == 0) ||
154 (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
155 sizeof(struct in6_addr)) == 0))
156 return(1);
157 break;
158 #endif
159 case AF_INET:
160 if (srv->ss.ss_family == inp->ss.ss_family)
161 if (v4->sin_port == v4in->sin_port)
162 if ((v4->sin_addr.s_addr == INADDR_ANY) ||
163 (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
164 return(1);
165 break;
166 default:
167 break;
168 }
169 }
170
171 return(0);
172 }
173
174 /*
175 * timeout_query_list - Remove queries from the list which have been
176 * there too long without being resolved.
177 */
178 static time_t
179 timeout_query_list(time_t now)
180 {
181 dlink_node *ptr;
182 dlink_node *next_ptr;
183 struct reslist *request;
184 time_t next_time = 0;
185 time_t timeout = 0;
186
187 DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
188 {
189 request = ptr->data;
190 timeout = request->sentat + request->timeout;
191
192 if (now >= timeout)
193 {
194 if (--request->retries <= 0)
195 {
196 (*request->callback)(request->callback_ctx, NULL, NULL);
197 rem_request(request);
198 continue;
199 }
200 else
201 {
202 request->sentat = now;
203 request->timeout += request->timeout;
204 resend_query(request);
205 }
206 }
207
208 if ((next_time == 0) || timeout < next_time)
209 {
210 next_time = timeout;
211 }
212 }
213
214 return((next_time > now) ? next_time : (now + AR_TTL));
215 }
216
217 /*
218 * timeout_resolver - check request list
219 */
220 static void
221 timeout_resolver(void *notused)
222 {
223 timeout_query_list(CurrentTime);
224 }
225
226 /*
227 * start_resolver - do everything we need to read the resolv.conf file
228 * and initialize the resolver file descriptor if needed
229 */
230 static void
231 start_resolver(void)
232 {
233 irc_res_init();
234
235 if (!ResolverFileDescriptor.flags.open)
236 {
237 if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
238 SOCK_DGRAM, 0, "Resolver socket") == -1)
239 return;
240
241 /* At the moment, the resolver FD data is global .. */
242 comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ,
243 res_readreply, NULL, 0);
244 eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
245 }
246 }
247
248 /*
249 * init_resolver - initialize resolver and resolver library
250 */
251 void
252 init_resolver(void)
253 {
254 dns_heap = BlockHeapCreate("dns", sizeof(struct reslist), DNS_HEAP_SIZE);
255 memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
256 start_resolver();
257 }
258
259 /*
260 * restart_resolver - reread resolv.conf, reopen socket
261 */
262 void
263 restart_resolver(void)
264 {
265 fd_close(&ResolverFileDescriptor);
266 eventDelete(timeout_resolver, NULL); /* -ddosen */
267 start_resolver();
268 }
269
270 /*
271 * rem_request - remove a request from the list.
272 * This must also free any memory that has been allocated for
273 * temporary storage of DNS results.
274 */
275 static void
276 rem_request(struct reslist *request)
277 {
278 dlinkDelete(&request->node, &request_list);
279
280 MyFree(request->name);
281 BlockHeapFree(dns_heap, request);
282 }
283
284 /*
285 * make_request - Create a DNS request record for the server.
286 */
287 static struct reslist *
288 make_request(dns_callback_fnc callback, void *ctx)
289 {
290 struct reslist *request = BlockHeapAlloc(dns_heap);
291
292 request->sentat = CurrentTime;
293 request->retries = 3;
294 request->resend = 1;
295 request->timeout = 4; /* start at 4 and exponential inc. */
296 request->state = REQ_IDLE;
297 request->callback = callback;
298 request->callback_ctx = ctx;
299
300 dlinkAdd(request, &request->node, &request_list);
301 return request;
302 }
303
304 /*
305 * delete_resolver_queries - cleanup outstanding queries
306 * for which there no longer exist clients or conf lines.
307 */
308 void
309 delete_resolver_queries(const void *vptr)
310 {
311 dlink_node *ptr = NULL, *next_ptr = NULL;
312
313 DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
314 {
315 struct reslist *request = ptr->data;
316
317 if (request->callback_ctx == vptr)
318 rem_request(request);
319 }
320 }
321
322 /*
323 * send_res_msg - sends msg to all nameservers found in the "_res" structure.
324 * This should reflect /etc/resolv.conf. We will get responses
325 * which arent needed but is easier than checking to see if nameserver
326 * isnt present. Returns number of messages successfully sent to
327 * nameservers or -1 if no successful sends.
328 */
329 static int
330 send_res_msg(const char *msg, int len, int rcount)
331 {
332 int i;
333 int sent = 0;
334 int max_queries = IRCD_MIN(irc_nscount, rcount);
335
336 /* RES_PRIMARY option is not implemented
337 * if (res.options & RES_PRIMARY || 0 == max_queries)
338 */
339 if (max_queries == 0)
340 max_queries = 1;
341
342 for (i = 0; i < max_queries; i++)
343 {
344 if (sendto(ResolverFileDescriptor.fd, msg, len, 0,
345 (struct sockaddr*)&(irc_nsaddr_list[i]),
346 irc_nsaddr_list[i].ss_len) == len)
347 ++sent;
348 }
349
350 return(sent);
351 }
352
353 /*
354 * find_id - find a dns request id (id is determined by dn_mkquery)
355 */
356 static struct reslist *
357 find_id(int id)
358 {
359 dlink_node *ptr;
360 struct reslist *request;
361
362 DLINK_FOREACH(ptr, request_list.head)
363 {
364 request = ptr->data;
365
366 if (request->id == id)
367 return(request);
368 }
369
370 return(NULL);
371 }
372
373 /*
374 * gethost_byname_type - get host address from name
375 *
376 */
377 void
378 gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
379 {
380 assert(name != 0);
381 do_query_name(callback, ctx, name, NULL, type);
382 }
383
384 /*
385 * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
386 */
387 void
388 gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
389 {
390 #ifdef IPV6
391 gethost_byname_type(callback, ctx, name, T_AAAA);
392 #else
393 gethost_byname_type(callback, ctx, name, T_A);
394 #endif
395 }
396
397 /*
398 * gethost_byaddr - get host name from address
399 */
400 void
401 gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
402 {
403 do_query_number(callback, ctx, addr, NULL);
404 }
405
406 /*
407 * do_query_name - nameserver lookup name
408 */
409 static void
410 do_query_name(dns_callback_fnc callback, void *ctx, const char *name,
411 struct reslist *request, int type)
412 {
413 char host_name[HOSTLEN + 1];
414
415 strlcpy(host_name, name, sizeof(host_name));
416
417 if (request == NULL)
418 {
419 request = make_request(callback, ctx);
420 request->name = MyMalloc(strlen(host_name) + 1);
421 request->type = type;
422 strcpy(request->name, host_name);
423 #ifdef IPV6
424 if (type != T_A)
425 request->state = REQ_AAAA;
426 else
427 #endif
428 request->state = REQ_A;
429 }
430
431 request->type = type;
432 query_name(host_name, C_IN, type, request);
433 }
434
435 /*
436 * do_query_number - Use this to do reverse IP# lookups.
437 */
438 static void
439 do_query_number(dns_callback_fnc callback, void *ctx,
440 const struct irc_ssaddr *addr,
441 struct reslist *request)
442 {
443 char ipbuf[128];
444 const unsigned char *cp;
445
446 if (addr->ss.ss_family == AF_INET)
447 {
448 const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
449 cp = (const unsigned char*)&v4->sin_addr.s_addr;
450
451 ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
452 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
453 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
454 }
455 #ifdef IPV6
456 else if (addr->ss.ss_family == AF_INET6)
457 {
458 const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
459 cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
460
461 sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
462 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.",
463 (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
464 (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
465 (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
466 (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4),
467 (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4),
468 (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4),
469 (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4),
470 (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4),
471 (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4),
472 (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4),
473 (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4),
474 (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4),
475 (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
476 (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
477 (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
478 (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4));
479 }
480 #endif
481 if (request == NULL)
482 {
483 request = make_request(callback, ctx);
484 request->type = T_PTR;
485 memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
486 request->name = MyMalloc(HOSTLEN + 1);
487 }
488
489 query_name(ipbuf, C_IN, T_PTR, request);
490 }
491
492 /*
493 * query_name - generate a query based on class, type and name.
494 */
495 static void
496 query_name(const char *name, int query_class, int type,
497 struct reslist *request)
498 {
499 char buf[MAXPACKET];
500 int request_len = 0;
501
502 memset(buf, 0, sizeof(buf));
503
504 if ((request_len = irc_res_mkquery(name, query_class, type,
505 (unsigned char *)buf, sizeof(buf))) > 0)
506 {
507 HEADER *header = (HEADER *)buf;
508
509 /*
510 * generate an unique id
511 * NOTE: we don't have to worry about converting this to and from
512 * network byte order, the nameserver does not interpret this value
513 * and returns it unchanged
514 */
515 do
516 header->id = (header->id + genrand_int32()) & 0xffff;
517 while (find_id(header->id));
518
519 request->id = header->id;
520 ++request->sends;
521
522 request->sent += send_res_msg(buf, request_len, request->sends);
523 }
524 }
525
526 static void
527 resend_query(struct reslist *request)
528 {
529 if (request->resend == 0)
530 return;
531
532 switch (request->type)
533 {
534 case T_PTR:
535 do_query_number(NULL, NULL, &request->addr, request);
536 break;
537 case T_A:
538 do_query_name(NULL, NULL, request->name, request, request->type);
539 break;
540 #ifdef IPV6
541 case T_AAAA:
542 /* didnt work, try A */
543 if (request->state == REQ_AAAA)
544 do_query_name(NULL, NULL, request->name, request, T_A);
545 #endif
546 default:
547 break;
548 }
549 }
550
551 /*
552 * proc_answer - process name server reply
553 */
554 static int
555 proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob)
556 {
557 char hostbuf[HOSTLEN + 100]; /* working buffer */
558 unsigned char *current; /* current position in buf */
559 int query_class; /* answer class */
560 int type; /* answer type */
561 int n; /* temp count */
562 int rd_length;
563 struct sockaddr_in *v4; /* conversion */
564 #ifdef IPV6
565 struct sockaddr_in6 *v6;
566 #endif
567 current = (unsigned char *)buf + sizeof(HEADER);
568
569 for (; header->qdcount > 0; --header->qdcount)
570 {
571 if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
572 break;
573
574 current += (size_t) n + QFIXEDSZ;
575 }
576
577 /*
578 * process each answer sent to us blech.
579 */
580 while (header->ancount > 0 && (char *)current < eob)
581 {
582 header->ancount--;
583
584 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
585 hostbuf, sizeof(hostbuf));
586
587 if (n < 0)
588 {
589 /*
590 * broken message
591 */
592 return(0);
593 }
594 else if (n == 0)
595 {
596 /*
597 * no more answers left
598 */
599 return(0);
600 }
601
602 hostbuf[HOSTLEN] = '\0';
603
604 /* With Address arithmetic you have to be very anal
605 * this code was not working on alpha due to that
606 * (spotted by rodder/jailbird/dianora)
607 */
608 current += (size_t) n;
609
610 if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
611 break;
612
613 type = irc_ns_get16(current);
614 current += TYPE_SIZE;
615
616 query_class = irc_ns_get16(current);
617 current += CLASS_SIZE;
618
619 request->ttl = irc_ns_get32(current);
620 current += TTL_SIZE;
621
622 rd_length = irc_ns_get16(current);
623 current += RDLENGTH_SIZE;
624
625 /*
626 * Wait to set request->type until we verify this structure
627 */
628 switch (type)
629 {
630 case T_A:
631 if (request->type != T_A)
632 return(0);
633
634 /*
635 * check for invalid rd_length or too many addresses
636 */
637 if (rd_length != sizeof(struct in_addr))
638 return(0);
639 v4 = (struct sockaddr_in *)&request->addr;
640 request->addr.ss_len = sizeof(struct sockaddr_in);
641 v4->sin_family = AF_INET;
642 memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
643 return(1);
644 break;
645 #ifdef IPV6
646 case T_AAAA:
647 if (request->type != T_AAAA)
648 return(0);
649 if (rd_length != sizeof(struct in6_addr))
650 return(0);
651 request->addr.ss_len = sizeof(struct sockaddr_in6);
652 v6 = (struct sockaddr_in6 *)&request->addr;
653 v6->sin6_family = AF_INET6;
654 memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
655 return(1);
656 break;
657 #endif
658 case T_PTR:
659 if (request->type != T_PTR)
660 return(0);
661 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
662 current, hostbuf, sizeof(hostbuf));
663 if (n < 0)
664 return(0); /* broken message */
665 else if (n == 0)
666 return(0); /* no more answers left */
667
668 strlcpy(request->name, hostbuf, HOSTLEN + 1);
669
670 return(1);
671 break;
672 case T_CNAME: /* first check we already havent started looking
673 into a cname */
674 if (request->type != T_PTR)
675 return(0);
676
677 if (request->state == REQ_CNAME)
678 {
679 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
680 current, hostbuf, sizeof(hostbuf));
681
682 if (n < 0)
683 return(0);
684 return(1);
685 }
686
687 request->state = REQ_CNAME;
688 current += rd_length;
689 break;
690
691 default:
692 /* XXX I'd rather just throw away the entire bogus thing
693 * but its possible its just a broken nameserver with still
694 * valid answers. But lets do some rudimentary logging for now...
695 */
696 ilog(L_ERROR, "irc_res.c bogus type %d", type);
697 break;
698 }
699 }
700
701 return(1);
702 }
703
704 /*
705 * res_readreply - read a dns reply from the nameserver and process it.
706 */
707 static void
708 res_readreply(fde_t *fd, void *data)
709 {
710 char buf[sizeof(HEADER) + MAXPACKET]
711 /* Sparc and alpha need 16bit-alignment for accessing header->id
712 * (which is uint16_t). Because of the header = (HEADER*) buf;
713 * lateron, this is neeeded. --FaUl
714 */
715 #if defined(__sparc__) || defined(__alpha__)
716 __attribute__((aligned (16)))
717 #endif
718 ;
719 HEADER *header;
720 struct reslist *request = NULL;
721 int rc;
722 socklen_t len = sizeof(struct irc_ssaddr);
723 struct irc_ssaddr lsin;
724
725 rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
726
727 /* Re-schedule a read *after* recvfrom, or we'll be registering
728 * interest where it'll instantly be ready for read :-) -- adrian
729 */
730 comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
731
732 /* Better to cast the sizeof instead of rc */
733 if (rc <= (int)(sizeof(HEADER)))
734 return;
735
736 /*
737 * convert DNS reply reader from Network byte order to CPU byte order.
738 */
739 header = (HEADER *)buf;
740 header->ancount = ntohs(header->ancount);
741 header->qdcount = ntohs(header->qdcount);
742 header->nscount = ntohs(header->nscount);
743 header->arcount = ntohs(header->arcount);
744
745 /*
746 * check against possibly fake replies
747 */
748 if (!res_ourserver(&lsin))
749 return;
750
751 /*
752 * response for an id which we have already received an answer for
753 * just ignore this response.
754 */
755 if (!(request = find_id(header->id)))
756 return;
757
758 if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
759 {
760 if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
761 {
762 /*
763 * If a bad error was returned, stop here and don't
764 * send any more (no retries granted).
765 */
766 (*request->callback)(request->callback_ctx, NULL, NULL);
767 rem_request(request);
768 }
769 #ifdef IPV6
770 else
771 {
772 /*
773 * If we havent already tried this, and we're looking up AAAA, try A
774 * now
775 */
776 if (request->state == REQ_AAAA && request->type == T_AAAA)
777 {
778 request->timeout += 4;
779 resend_query(request);
780 }
781 }
782 #endif
783
784 return;
785 }
786
787 /*
788 * If this fails there was an error decoding the received packet,
789 * try it again and hope it works the next time.
790 */
791 if (proc_answer(request, header, buf, buf + rc))
792 {
793 if (request->type == T_PTR)
794 {
795 if (request->name == NULL)
796 {
797 /*
798 * got a PTR response with no name, something bogus is happening
799 * don't bother trying again, the client address doesn't resolve
800 */
801 (*request->callback)(request->callback_ctx, NULL, NULL);
802 rem_request(request);
803 return;
804 }
805
806 /*
807 * Lookup the 'authoritative' name that we were given for the
808 * ip#.
809 *
810 */
811 #ifdef IPV6
812 if (request->addr.ss.ss_family == AF_INET6)
813 gethost_byname_type(request->callback, request->callback_ctx, request->name, T_AAAA);
814 else
815 #endif
816 gethost_byname_type(request->callback, request->callback_ctx, request->name, T_A);
817 rem_request(request);
818 }
819 else
820 {
821 /*
822 * got a name and address response, client resolved
823 */
824 (*request->callback)(request->callback_ctx, &request->addr, request->name);
825 rem_request(request);
826 }
827 }
828 else if (!request->sent)
829 {
830 /* XXX - we got a response for a query we didn't send with a valid id?
831 * this should never happen, bail here and leave the client unresolved
832 */
833 assert(0);
834
835 /* XXX don't leak it */
836 rem_request(request);
837 }
838 }
839
840 void
841 report_dns_servers(struct Client *source_p)
842 {
843 int i;
844 char ipaddr[HOSTIPLEN + 1];
845
846 for (i = 0; i < irc_nscount; i++)
847 {
848 getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
849 irc_nsaddr_list[i].ss_len, ipaddr,
850 sizeof(ipaddr), NULL, 0, NI_NUMERICHOST);
851 sendto_one(source_p, form_str(RPL_STATSALINE),
852 me.name, source_p->name, ipaddr);
853 }
854 }

Properties

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