ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.3/src/irc_res.c
Revision: 447
Committed: Sun Feb 12 02:59:16 2006 UTC (20 years, 5 months ago) by db
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/irc_res.c
File size: 24572 byte(s)
Log Message:
- reported by Jon, resolver was not checking for NXDOMAIN as well as SERVFAIL
this caused odd DNS reports and took longer to connect.

Tested by Jon (ThaPrince).

(backported from head)


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

Properties

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