ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
Revision: 447
Committed: Sun Feb 12 02:59:16 2006 UTC (19 years, 6 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

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
11 adx 30 *
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 adx 411 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 adx 30 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 db 447 if ((SERVFAIL == header->rcode) || (NXDOMAIN == header->rcode))
817 db 155 {
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 adx 30 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