ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/irc_res.c
Revision: 3109
Committed: Thu Mar 6 19:25:12 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 23370 byte(s)
Log Message:
- Applied Adam's sendto_one_numeric() changes

File Contents

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

Properties

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