ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/res.c
Revision: 3505
Committed: Sat May 10 19:51:42 2014 UTC (9 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 23352 byte(s)
Log Message:
- Renamed MyMalloc() to MyCalloc()

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 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 "misc.h"
60 #include "send.h"
61 #include "memory.h"
62 #include "mempool.h"
63 #include "res.h"
64 #include "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 unsigned int 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;
119 static mp_pool_t *dns_pool;
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, unsigned 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
156 for (unsigned int i = 0; i < irc_nscount; ++i)
157 {
158 const struct irc_ssaddr *srv = &irc_nsaddr_list[i];
159 #ifdef IPV6
160 v6 = (const struct sockaddr_in6 *)srv;
161 #endif
162 v4 = (const struct sockaddr_in *)srv;
163
164 /* could probably just memcmp(srv, inp, srv.ss_len) here
165 * but we'll air on the side of caution - stu
166 *
167 */
168 switch (srv->ss.ss_family)
169 {
170 #ifdef IPV6
171 case AF_INET6:
172 if (srv->ss.ss_family == inp->ss.ss_family)
173 if (v6->sin6_port == v6in->sin6_port)
174 if (!memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
175 sizeof(struct in6_addr)))
176 return 1;
177 break;
178 #endif
179 case AF_INET:
180 if (srv->ss.ss_family == inp->ss.ss_family)
181 if (v4->sin_port == v4in->sin_port)
182 if (v4->sin_addr.s_addr == v4in->sin_addr.s_addr)
183 return 1;
184 break;
185 default:
186 break;
187 }
188 }
189
190 return 0;
191 }
192
193 /*
194 * timeout_query_list - Remove queries from the list which have been
195 * there too long without being resolved.
196 */
197 static time_t
198 timeout_query_list(time_t now)
199 {
200 dlink_node *ptr = NULL, *ptr_next = NULL;
201 struct reslist *request;
202 time_t next_time = 0;
203 time_t timeout = 0;
204
205 DLINK_FOREACH_SAFE(ptr, ptr_next, request_list.head)
206 {
207 request = ptr->data;
208 timeout = request->sentat + request->timeout;
209
210 if (now >= timeout)
211 {
212 if (--request->retries <= 0)
213 {
214 (*request->callback)(request->callback_ctx, NULL, NULL);
215 rem_request(request);
216 continue;
217 }
218 else
219 {
220 request->sentat = now;
221 request->timeout += request->timeout;
222 resend_query(request);
223 }
224 }
225
226 if ((next_time == 0) || timeout < next_time)
227 next_time = timeout;
228 }
229
230 return (next_time > now) ? next_time : (now + AR_TTL);
231 }
232
233 /*
234 * timeout_resolver - check request list
235 */
236 static void
237 timeout_resolver(void *notused)
238 {
239 timeout_query_list(CurrentTime);
240 }
241
242 /*
243 * start_resolver - do everything we need to read the resolv.conf file
244 * and initialize the resolver file descriptor if needed
245 */
246 static void
247 start_resolver(void)
248 {
249 irc_res_init();
250
251 if (!ResolverFileDescriptor.flags.open)
252 {
253 if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
254 SOCK_DGRAM, 0, "Resolver socket") == -1)
255 return;
256
257 /* At the moment, the resolver FD data is global .. */
258 comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ, res_readreply, NULL, 0);
259 eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
260 }
261 }
262
263 /*
264 * init_resolver - initialize resolver and resolver library
265 */
266 void
267 init_resolver(void)
268 {
269 dns_pool = mp_pool_new(sizeof(struct reslist), MP_CHUNK_SIZE_DNS);
270 memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
271 start_resolver();
272 }
273
274 /*
275 * restart_resolver - reread resolv.conf, reopen socket
276 */
277 void
278 restart_resolver(void)
279 {
280 fd_close(&ResolverFileDescriptor);
281 eventDelete(timeout_resolver, NULL);
282 start_resolver();
283 }
284
285 /*
286 * rem_request - remove a request from the list.
287 * This must also free any memory that has been allocated for
288 * temporary storage of DNS results.
289 */
290 static void
291 rem_request(struct reslist *request)
292 {
293 dlinkDelete(&request->node, &request_list);
294
295 MyFree(request->name);
296 mp_pool_release(request);
297 }
298
299 /*
300 * make_request - Create a DNS request record for the server.
301 */
302 static struct reslist *
303 make_request(dns_callback_fnc callback, void *ctx)
304 {
305 struct reslist *request = mp_pool_get(dns_pool);
306
307 memset(request, 0, sizeof(*request));
308 request->sentat = CurrentTime;
309 request->retries = 2;
310 request->resend = 1;
311 request->timeout = 4; /* Start at 4 and exponential inc. */
312 request->state = REQ_IDLE;
313 request->callback = callback;
314 request->callback_ctx = ctx;
315
316 dlinkAdd(request, &request->node, &request_list);
317 return request;
318 }
319
320 /*
321 * delete_resolver_queries - cleanup outstanding queries
322 * for which there no longer exist clients or conf lines.
323 */
324 void
325 delete_resolver_queries(const void *vptr)
326 {
327 dlink_node *ptr = NULL, *ptr_next = NULL;
328
329 DLINK_FOREACH_SAFE(ptr, ptr_next, request_list.head)
330 {
331 struct reslist *request = ptr->data;
332
333 if (request->callback_ctx == vptr)
334 rem_request(request);
335 }
336 }
337
338 /*
339 * send_res_msg - sends msg to all nameservers found in the "_res" structure.
340 * This should reflect /etc/resolv.conf. We will get responses
341 * which arent needed but is easier than checking to see if nameserver
342 * isnt present. Returns number of messages successfully sent to
343 * nameservers or -1 if no successful sends.
344 */
345 static int
346 send_res_msg(const char *msg, int len, unsigned int rcount)
347 {
348 int sent = 0;
349 unsigned int max_queries = IRCD_MIN(irc_nscount, rcount);
350
351 /* RES_PRIMARY option is not implemented
352 * if (res.options & RES_PRIMARY || 0 == max_queries)
353 */
354 if (max_queries == 0)
355 max_queries = 1;
356
357 for (unsigned int i = 0; i < max_queries; ++i)
358 {
359 if (sendto(ResolverFileDescriptor.fd, msg, len, 0,
360 (struct sockaddr*)&(irc_nsaddr_list[i]),
361 irc_nsaddr_list[i].ss_len) == len)
362 ++sent;
363 }
364
365 return sent;
366 }
367
368 /*
369 * find_id - find a dns request id (id is determined by dn_mkquery)
370 */
371 static struct reslist *
372 find_id(int id)
373 {
374 dlink_node *ptr = NULL;
375
376 DLINK_FOREACH(ptr, request_list.head)
377 {
378 struct reslist *request = ptr->data;
379
380 if (request->id == id)
381 return request;
382 }
383
384 return NULL;
385 }
386
387 /*
388 * gethost_byname_type - get host address from name
389 *
390 */
391 void
392 gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
393 {
394 assert(name);
395 do_query_name(callback, ctx, name, NULL, type);
396 }
397
398 /*
399 * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
400 */
401 void
402 gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
403 {
404 #ifdef IPV6
405 gethost_byname_type(callback, ctx, name, T_AAAA);
406 #else
407 gethost_byname_type(callback, ctx, name, T_A);
408 #endif
409 }
410
411 /*
412 * gethost_byaddr - get host name from address
413 */
414 void
415 gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
416 {
417 do_query_number(callback, ctx, addr, NULL);
418 }
419
420 /*
421 * do_query_name - nameserver lookup name
422 */
423 static void
424 do_query_name(dns_callback_fnc callback, void *ctx, const char *name,
425 struct reslist *request, int type)
426 {
427 char host_name[HOSTLEN + 1];
428
429 strlcpy(host_name, name, sizeof(host_name));
430
431 if (request == NULL)
432 {
433 request = make_request(callback, ctx);
434 request->name = MyCalloc(strlen(host_name) + 1);
435 request->type = type;
436 strcpy(request->name, host_name);
437 #ifdef IPV6
438 if (type != T_A)
439 request->state = REQ_AAAA;
440 else
441 #endif
442 request->state = REQ_A;
443 }
444
445 request->type = type;
446 query_name(host_name, C_IN, type, request);
447 }
448
449 /*
450 * do_query_number - Use this to do reverse IP# lookups.
451 */
452 static void
453 do_query_number(dns_callback_fnc callback, void *ctx,
454 const struct irc_ssaddr *addr,
455 struct reslist *request)
456 {
457 char ipbuf[128] = "";
458
459 if (addr->ss.ss_family == AF_INET)
460 {
461 const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
462 const unsigned char *cp = (const unsigned char *)&v4->sin_addr.s_addr;
463
464 snprintf(ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
465 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
466 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
467 }
468 #ifdef IPV6
469 else if (addr->ss.ss_family == AF_INET6)
470 {
471 const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
472 const unsigned char *cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
473
474 snprintf(ipbuf, sizeof(ipbuf),
475 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
476 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.",
477 (unsigned int)(cp[15] & 0xf), (unsigned int)(cp[15] >> 4),
478 (unsigned int)(cp[14] & 0xf), (unsigned int)(cp[14] >> 4),
479 (unsigned int)(cp[13] & 0xf), (unsigned int)(cp[13] >> 4),
480 (unsigned int)(cp[12] & 0xf), (unsigned int)(cp[12] >> 4),
481 (unsigned int)(cp[11] & 0xf), (unsigned int)(cp[11] >> 4),
482 (unsigned int)(cp[10] & 0xf), (unsigned int)(cp[10] >> 4),
483 (unsigned int)(cp[9] & 0xf), (unsigned int)(cp[9] >> 4),
484 (unsigned int)(cp[8] & 0xf), (unsigned int)(cp[8] >> 4),
485 (unsigned int)(cp[7] & 0xf), (unsigned int)(cp[7] >> 4),
486 (unsigned int)(cp[6] & 0xf), (unsigned int)(cp[6] >> 4),
487 (unsigned int)(cp[5] & 0xf), (unsigned int)(cp[5] >> 4),
488 (unsigned int)(cp[4] & 0xf), (unsigned int)(cp[4] >> 4),
489 (unsigned int)(cp[3] & 0xf), (unsigned int)(cp[3] >> 4),
490 (unsigned int)(cp[2] & 0xf), (unsigned int)(cp[2] >> 4),
491 (unsigned int)(cp[1] & 0xf), (unsigned int)(cp[1] >> 4),
492 (unsigned int)(cp[0] & 0xf), (unsigned int)(cp[0] >> 4));
493 }
494 #endif
495 if (request == NULL)
496 {
497 request = make_request(callback, ctx);
498 request->type = T_PTR;
499 memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
500 request->name = MyCalloc(HOSTLEN + 1);
501 }
502
503 query_name(ipbuf, C_IN, T_PTR, request);
504 }
505
506 /*
507 * query_name - generate a query based on class, type and name.
508 */
509 static void
510 query_name(const char *name, int query_class, int type,
511 struct reslist *request)
512 {
513 char buf[MAXPACKET];
514 int request_len = 0;
515
516 memset(buf, 0, sizeof(buf));
517
518 if ((request_len = irc_res_mkquery(name, query_class, type,
519 (unsigned char *)buf, sizeof(buf))) > 0)
520 {
521 HEADER *header = (HEADER *)buf;
522
523 /*
524 * generate an unique id
525 * NOTE: we don't have to worry about converting this to and from
526 * network byte order, the nameserver does not interpret this value
527 * and returns it unchanged
528 */
529 do
530 header->id = (header->id + genrand_int32()) & 0xffff;
531 while (find_id(header->id));
532
533 request->id = header->id;
534 ++request->sends;
535
536 request->sent += send_res_msg(buf, request_len, request->sends);
537 }
538 }
539
540 static void
541 resend_query(struct reslist *request)
542 {
543 if (request->resend == 0)
544 return;
545
546 switch (request->type)
547 {
548 case T_PTR:
549 do_query_number(NULL, NULL, &request->addr, request);
550 break;
551 case T_A:
552 do_query_name(NULL, NULL, request->name, request, request->type);
553 break;
554 #ifdef IPV6
555 case T_AAAA:
556 /* didnt work, try A */
557 if (request->state == REQ_AAAA)
558 do_query_name(NULL, NULL, request->name, request, T_A);
559 #endif
560 default:
561 break;
562 }
563 }
564
565 /*
566 * proc_answer - process name server reply
567 */
568 static int
569 proc_answer(struct reslist *request, HEADER *header, char *buf, char *eob)
570 {
571 char hostbuf[HOSTLEN + 100]; /* working buffer */
572 unsigned char *current; /* current position in buf */
573 int query_class; /* answer class */
574 int type; /* answer type */
575 int n; /* temp count */
576 int rd_length;
577 struct sockaddr_in *v4; /* conversion */
578 #ifdef IPV6
579 struct sockaddr_in6 *v6;
580 #endif
581 current = (unsigned char *)buf + sizeof(HEADER);
582
583 for (; header->qdcount > 0; --header->qdcount)
584 {
585 if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
586 break;
587
588 current += (size_t)n + QFIXEDSZ;
589 }
590
591 /*
592 * process each answer sent to us blech.
593 */
594 while (header->ancount > 0 && (char *)current < eob)
595 {
596 header->ancount--;
597
598 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
599 hostbuf, sizeof(hostbuf));
600
601 if (n < 0 /* Broken message */ || n == 0 /* No more answers left */)
602 return 0;
603
604 hostbuf[HOSTLEN] = '\0';
605
606 /* With Address arithmetic you have to be very anal
607 * this code was not working on alpha due to that
608 * (spotted by rodder/jailbird/dianora)
609 */
610 current += (size_t)n;
611
612 if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
613 break;
614
615 type = irc_ns_get16(current);
616 current += TYPE_SIZE;
617
618 query_class = irc_ns_get16(current);
619 current += CLASS_SIZE;
620
621 request->ttl = irc_ns_get32(current);
622 current += TTL_SIZE;
623
624 rd_length = irc_ns_get16(current);
625 current += RDLENGTH_SIZE;
626
627 /*
628 * Wait to set request->type until we verify this structure
629 */
630 switch (type)
631 {
632 case T_A:
633 if (request->type != T_A)
634 return 0;
635
636 /*
637 * Check for invalid rd_length or too many addresses
638 */
639 if (rd_length != sizeof(struct in_addr))
640 return 0;
641
642 v4 = (struct sockaddr_in *)&request->addr;
643 request->addr.ss_len = sizeof(struct sockaddr_in);
644 v4->sin_family = AF_INET;
645 memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
646 return 1;
647 break;
648 #ifdef IPV6
649 case T_AAAA:
650 if (request->type != T_AAAA)
651 return 0;
652
653 if (rd_length != sizeof(struct in6_addr))
654 return 0;
655
656 request->addr.ss_len = sizeof(struct sockaddr_in6);
657 v6 = (struct sockaddr_in6 *)&request->addr;
658 v6->sin6_family = AF_INET6;
659 memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
660 return 1;
661 break;
662 #endif
663 case T_PTR:
664 if (request->type != T_PTR)
665 return 0;
666
667 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
668 current, hostbuf, sizeof(hostbuf));
669 if (n < 0 /* Broken message */ || n == 0 /* No more answers left */)
670 return 0;
671
672 strlcpy(request->name, hostbuf, HOSTLEN + 1);
673 return 1;
674 break;
675 case T_CNAME: /* first check we already havent started looking
676 into a cname */
677 if (request->type != T_PTR)
678 return 0;
679
680 if (request->state == REQ_CNAME)
681 {
682 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
683 current, hostbuf, sizeof(hostbuf));
684
685 if (n < 0)
686 return 0;
687 return 1;
688 }
689
690 request->state = REQ_CNAME;
691 current += rd_length;
692 break;
693
694 default:
695 /* XXX I'd rather just throw away the entire bogus thing
696 * but its possible its just a broken nameserver with still
697 * valid answers. But lets do some rudimentary logging for now...
698 */
699 ilog(LOG_TYPE_IRCD, "irc_res.c bogus type %d", type);
700 break;
701 }
702 }
703
704 return 1;
705 }
706
707 /*
708 * res_readreply - read a dns reply from the nameserver and process it.
709 */
710 static void
711 res_readreply(fde_t *fd, void *data)
712 {
713 char buf[sizeof(HEADER) + MAXPACKET]
714 /* Sparc and alpha need 16bit-alignment for accessing header->id
715 * (which is uint16_t). Because of the header = (HEADER*) buf;
716 * lateron, this is neeeded. --FaUl
717 */
718 #if defined(__sparc__) || defined(__alpha__)
719 __attribute__((aligned (16)))
720 #endif
721 ;
722 HEADER *header;
723 struct reslist *request = NULL;
724 int rc;
725 socklen_t len = sizeof(struct irc_ssaddr);
726 struct irc_ssaddr lsin;
727
728 rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
729
730 /* Re-schedule a read *after* recvfrom, or we'll be registering
731 * interest where it'll instantly be ready for read :-) -- adrian
732 */
733 comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
734
735 /* Better to cast the sizeof instead of rc */
736 if (rc <= (int)(sizeof(HEADER)))
737 return;
738
739 /*
740 * Convert DNS reply reader from Network byte order to CPU byte order.
741 */
742 header = (HEADER *)buf;
743 header->ancount = ntohs(header->ancount);
744 header->qdcount = ntohs(header->qdcount);
745 header->nscount = ntohs(header->nscount);
746 header->arcount = ntohs(header->arcount);
747
748 /*
749 * Check against possibly fake replies
750 */
751 if (!res_ourserver(&lsin))
752 return;
753
754 /*
755 * Response for an id which we have already received an answer for
756 * just ignore this response.
757 */
758 if (!(request = find_id(header->id)))
759 return;
760
761 if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
762 {
763 if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
764 {
765 /*
766 * If a bad error was returned, stop here and don't
767 * send any more (no retries granted).
768 */
769 (*request->callback)(request->callback_ctx, NULL, NULL);
770 rem_request(request);
771 }
772 #ifdef IPV6
773 else
774 {
775 /*
776 * If we havent already tried this, and we're looking up AAAA, try A
777 * now
778 */
779 if (request->state == REQ_AAAA && request->type == T_AAAA)
780 {
781 request->timeout += 4;
782 resend_query(request);
783 }
784 }
785 #endif
786
787 return;
788 }
789
790 /*
791 * If this fails there was an error decoding the received packet,
792 * try it again and hope it works the next time.
793 */
794 if (proc_answer(request, header, buf, buf + rc))
795 {
796 if (request->type == T_PTR)
797 {
798 if (request->name == NULL)
799 {
800 /*
801 * Got a PTR response with no name, something bogus is happening
802 * don't bother trying again, the client address doesn't resolve
803 */
804 (*request->callback)(request->callback_ctx, NULL, NULL);
805 rem_request(request);
806 return;
807 }
808
809 /*
810 * Lookup the 'authoritative' name that we were given for the ip#.
811 */
812 #ifdef IPV6
813 if (request->addr.ss.ss_family == AF_INET6)
814 gethost_byname_type(request->callback, request->callback_ctx, request->name, T_AAAA);
815 else
816 #endif
817 gethost_byname_type(request->callback, request->callback_ctx, request->name, T_A);
818 rem_request(request);
819 }
820 else
821 {
822 /*
823 * Got a name and address response, client resolved
824 */
825 (*request->callback)(request->callback_ctx, &request->addr, request->name);
826 rem_request(request);
827 }
828 }
829 else if (!request->sent)
830 {
831 /* XXX - we got a response for a query we didn't send with a valid id?
832 * this should never happen, bail here and leave the client unresolved
833 */
834 assert(0);
835
836 /* XXX don't leak it */
837 rem_request(request);
838 }
839 }
840
841 void
842 report_dns_servers(struct Client *source_p)
843 {
844 char ipaddr[HOSTIPLEN + 1] = "";
845
846 for (unsigned int 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_numeric(source_p, &me, RPL_STATSALINE, ipaddr);
852 }
853 }

Properties

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