ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
Revision: 32
Committed: Sun Oct 2 20:41:23 2005 UTC (18 years, 5 months ago) by knight
Content type: text/x-csrc
Original Path: ircd-hybrid/src/irc_res.c
File size: 24420 byte(s)
Log Message:
- svn:keywords

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     memset(request, 0, sizeof(struct reslist));
324    
325     request->sentat = CurrentTime;
326     request->retries = 3;
327     request->resend = 1;
328     request->timeout = 4; /* start at 4 and exponential inc. */
329     memset(&request->addr, 0, sizeof(request->addr));
330     request->query = query;
331     request->state = REQ_IDLE;
332    
333     dlinkAdd(request, &request->node, &request_list);
334     return(request);
335     }
336    
337     /*
338     * delete_resolver_queries - cleanup outstanding queries
339     * for which there no longer exist clients or conf lines.
340     */
341     void
342     delete_resolver_queries(const struct DNSQuery *query)
343     {
344     dlink_node *ptr;
345     dlink_node *next_ptr;
346     struct reslist *request;
347    
348     DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
349     {
350     if ((request = ptr->data) != NULL)
351     {
352     if (query == request->query)
353     rem_request(request);
354     }
355     }
356     }
357    
358     /*
359     * send_res_msg - sends msg to all nameservers found in the "_res" structure.
360     * This should reflect /etc/resolv.conf. We will get responses
361     * which arent needed but is easier than checking to see if nameserver
362     * isnt present. Returns number of messages successfully sent to
363     * nameservers or -1 if no successful sends.
364     */
365     static int
366     send_res_msg(const char *msg, int len, int rcount)
367     {
368     int i;
369     int sent = 0;
370     int max_queries = IRCD_MIN(irc_nscount, rcount);
371    
372     /* RES_PRIMARY option is not implemented
373     * if (res.options & RES_PRIMARY || 0 == max_queries)
374     */
375     if (max_queries == 0)
376     max_queries = 1;
377    
378     for (i = 0; i < max_queries; i++)
379     {
380     if (sendto(ResolverFileDescriptor.fd, msg, len, 0,
381     (struct sockaddr*)&(irc_nsaddr_list[i]),
382     irc_nsaddr_list[i].ss_len) == len)
383     ++sent;
384     }
385    
386     return(sent);
387     }
388    
389     /*
390     * find_id - find a dns request id (id is determined by dn_mkquery)
391     */
392     static struct reslist *
393     find_id(int id)
394     {
395     dlink_node *ptr;
396     struct reslist *request;
397    
398     DLINK_FOREACH(ptr, request_list.head)
399     {
400     request = ptr->data;
401    
402     if (request->id == id)
403     return(request);
404     }
405    
406     return(NULL);
407     }
408    
409     /*
410     * gethost_byname_type - get host address from name
411     *
412     */
413     void
414     gethost_byname_type(const char *name, struct DNSQuery *query, int type)
415     {
416     assert(name != 0);
417     do_query_name(query, name, NULL, type);
418     }
419    
420     /*
421     * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
422     */
423     void
424     gethost_byname(const char *name, struct DNSQuery *query)
425     {
426     #ifdef IPV6
427     gethost_byname_type(name, query, T_AAAA);
428     #else
429     gethost_byname_type(name, query, T_A);
430     #endif
431     }
432    
433     /*
434     * gethost_byaddr - get host name from address
435     */
436     void
437     gethost_byaddr(const struct irc_ssaddr *addr, struct DNSQuery *query)
438     {
439     do_query_number(query, addr, NULL);
440     }
441    
442     /*
443     * do_query_name - nameserver lookup name
444     */
445     static void
446     do_query_name(struct DNSQuery *query, const char *name,
447     struct reslist *request, int type)
448     {
449     char host_name[HOSTLEN + 1];
450    
451     strlcpy(host_name, name, HOSTLEN);
452     add_local_domain(host_name, HOSTLEN);
453    
454     if (request == NULL)
455     {
456     request = make_request(query);
457     request->name = (char *)MyMalloc(strlen(host_name) + 1);
458     request->type = type;
459     strcpy(request->name, host_name);
460     #ifdef IPV6
461     if (type == T_A)
462     request->state = REQ_A;
463     else
464     request->state = REQ_AAAA;
465     #else
466     request->state = REQ_A;
467     #endif
468     }
469    
470     request->type = type;
471     query_name(host_name, C_IN, type, request);
472     }
473    
474     /*
475     * do_query_number - Use this to do reverse IP# lookups.
476     */
477     static void
478     do_query_number(struct DNSQuery *query, const struct irc_ssaddr *addr,
479     struct reslist *request)
480     {
481     char ipbuf[128];
482     const unsigned char *cp;
483     #ifdef IPV6
484     const char *intarpa;
485     #endif
486     if (addr->ss.ss_family == AF_INET)
487     {
488     struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
489     cp = (const unsigned char*)&v4->sin_addr.s_addr;
490    
491     ircsprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
492     (unsigned int)(cp[3]), (unsigned int)(cp[2]),
493     (unsigned int)(cp[1]), (unsigned int)(cp[0]));
494     }
495     #ifdef IPV6
496     else if (addr->ss.ss_family == AF_INET6)
497     {
498     struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
499     cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
500    
501     if (request != NULL && request->state == REQ_INT)
502     intarpa = "int";
503     else
504     intarpa = "arpa";
505    
506     (void)sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
507     "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
508     (unsigned int)(cp[15]&0xf), (unsigned int)(cp[15]>>4),
509     (unsigned int)(cp[14]&0xf), (unsigned int)(cp[14]>>4),
510     (unsigned int)(cp[13]&0xf), (unsigned int)(cp[13]>>4),
511     (unsigned int)(cp[12]&0xf), (unsigned int)(cp[12]>>4),
512     (unsigned int)(cp[11]&0xf), (unsigned int)(cp[11]>>4),
513     (unsigned int)(cp[10]&0xf), (unsigned int)(cp[10]>>4),
514     (unsigned int)(cp[9]&0xf), (unsigned int)(cp[9]>>4),
515     (unsigned int)(cp[8]&0xf), (unsigned int)(cp[8]>>4),
516     (unsigned int)(cp[7]&0xf), (unsigned int)(cp[7]>>4),
517     (unsigned int)(cp[6]&0xf), (unsigned int)(cp[6]>>4),
518     (unsigned int)(cp[5]&0xf), (unsigned int)(cp[5]>>4),
519     (unsigned int)(cp[4]&0xf), (unsigned int)(cp[4]>>4),
520     (unsigned int)(cp[3]&0xf), (unsigned int)(cp[3]>>4),
521     (unsigned int)(cp[2]&0xf), (unsigned int)(cp[2]>>4),
522     (unsigned int)(cp[1]&0xf), (unsigned int)(cp[1]>>4),
523     (unsigned int)(cp[0]&0xf), (unsigned int)(cp[0]>>4), intarpa);
524     }
525     #endif
526     if (request == NULL)
527     {
528     request = make_request(query);
529     request->type = T_PTR;
530     memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
531     request->name = (char *)MyMalloc(HOSTLEN + 1);
532     }
533    
534     query_name(ipbuf, C_IN, T_PTR, request);
535     }
536    
537     /*
538     * query_name - generate a query based on class, type and name.
539     */
540     static void
541     query_name(const char *name, int query_class, int type,
542     struct reslist *request)
543     {
544     char buf[MAXPACKET];
545     int request_len = 0;
546    
547     memset(buf, 0, sizeof(buf));
548    
549     if ((request_len = irc_res_mkquery(name, query_class, type,
550     (unsigned char *)buf, sizeof(buf))) > 0)
551     {
552     HEADER *header = (HEADER *)buf;
553     #ifndef HAVE_LRAND48
554     int k = 0;
555     struct timeval tv;
556     #endif
557     /*
558     * generate an unique id
559     * NOTE: we don't have to worry about converting this to and from
560     * network byte order, the nameserver does not interpret this value
561     * and returns it unchanged
562     */
563     #ifdef HAVE_LRAND48
564     do
565     {
566     header->id = (header->id + lrand48()) & 0xffff;
567     } while (find_id(header->id));
568     #else
569     gettimeofday(&tv, NULL);
570     do
571     {
572     header->id = (header->id + k + tv.tv_usec) & 0xffff;
573     k++;
574     } while (find_id(header->id));
575     #endif /* HAVE_LRAND48 */
576     request->id = header->id;
577     ++request->sends;
578    
579     request->sent += send_res_msg(buf, request_len, request->sends);
580     }
581     }
582    
583     static void
584     resend_query(struct reslist *request)
585     {
586     if (request->resend == 0)
587     return;
588    
589     switch(request->type)
590     {
591     case T_PTR:
592     do_query_number(NULL, &request->addr, request);
593     break;
594     case T_A:
595     do_query_name(NULL, request->name, request, request->type);
596     break;
597     #ifdef IPV6
598     case T_AAAA:
599     /* didnt work, try A */
600     if (request->state == REQ_AAAA)
601     do_query_name(NULL, request->name, request, T_A);
602     #endif
603     default:
604     break;
605     }
606     }
607    
608     /*
609     * proc_answer - process name server reply
610     */
611     static int
612     proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob)
613     {
614     char hostbuf[HOSTLEN + 100]; /* working buffer */
615     unsigned char *current; /* current position in buf */
616     int query_class; /* answer class */
617     int type; /* answer type */
618     int n; /* temp count */
619     int rd_length;
620     struct sockaddr_in *v4; /* conversion */
621     #ifdef IPV6
622     struct sockaddr_in6 *v6;
623     #endif
624     current = (unsigned char *)buf + sizeof(HEADER);
625    
626     for (; header->qdcount > 0; --header->qdcount)
627     {
628     if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
629     break;
630    
631     current += (size_t) n + QFIXEDSZ;
632     }
633    
634     /*
635     * process each answer sent to us blech.
636     */
637     while (header->ancount > 0 && (char *)current < eob)
638     {
639     header->ancount--;
640    
641     n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
642     hostbuf, sizeof(hostbuf));
643    
644     if (n < 0)
645     {
646     /*
647     * broken message
648     */
649     return(0);
650     }
651     else if (n == 0)
652     {
653     /*
654     * no more answers left
655     */
656     return(0);
657     }
658    
659     hostbuf[HOSTLEN] = '\0';
660    
661     /* With Address arithmetic you have to be very anal
662     * this code was not working on alpha due to that
663     * (spotted by rodder/jailbird/dianora)
664     */
665     current += (size_t) n;
666    
667     if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
668     break;
669    
670     type = irc_ns_get16(current);
671     current += TYPE_SIZE;
672    
673     query_class = irc_ns_get16(current);
674     current += CLASS_SIZE;
675    
676     request->ttl = irc_ns_get32(current);
677     current += TTL_SIZE;
678    
679     rd_length = irc_ns_get16(current);
680     current += RDLENGTH_SIZE;
681    
682     /*
683     * Wait to set request->type until we verify this structure
684     */
685     switch (type)
686     {
687     case T_A:
688     if (request->type != T_A)
689     return(0);
690    
691     /*
692     * check for invalid rd_length or too many addresses
693     */
694     if (rd_length != sizeof(struct in_addr))
695     return(0);
696     v4 = (struct sockaddr_in *)&request->addr;
697     request->addr.ss_len = sizeof(struct sockaddr_in);
698     v4->sin_family = AF_INET;
699     memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
700     return(1);
701     break;
702     #ifdef IPV6
703     case T_AAAA:
704     if (request->type != T_AAAA)
705     return(0);
706     if (rd_length != sizeof(struct in6_addr))
707     return(0);
708     request->addr.ss_len = sizeof(struct sockaddr_in6);
709     v6 = (struct sockaddr_in6 *)&request->addr;
710     v6->sin6_family = AF_INET6;
711     memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
712     return(1);
713     break;
714     #endif
715     case T_PTR:
716     if (request->type != T_PTR)
717     return(0);
718     n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
719     current, hostbuf, sizeof(hostbuf));
720     if (n < 0)
721     return(0); /* broken message */
722     else if (n == 0)
723     return(0); /* no more answers left */
724    
725     strlcpy(request->name, hostbuf, HOSTLEN);
726    
727     return(1);
728     break;
729     case T_CNAME: /* first check we already havent started looking
730     into a cname */
731     if (request->type != T_PTR)
732     return(0);
733    
734     if (request->state == REQ_CNAME)
735     {
736     n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
737     current, hostbuf, sizeof(hostbuf));
738    
739     if (n < 0)
740     return(0);
741     return(1);
742     }
743    
744     request->state = REQ_CNAME;
745     current += rd_length;
746     break;
747    
748     default:
749     /* XXX I'd rather just throw away the entire bogus thing
750     * but its possible its just a broken nameserver with still
751     * valid answers. But lets do some rudimentary logging for now...
752     */
753     ilog(L_ERROR, "irc_res.c bogus type %d", type);
754     break;
755     }
756     }
757    
758     return(1);
759     }
760    
761     /*
762     * res_readreply - read a dns reply from the nameserver and process it.
763     */
764     static void
765     res_readreply(fde_t *fd, void *data)
766     {
767     char buf[sizeof(HEADER) + MAXPACKET];
768     HEADER *header;
769     struct reslist *request = NULL;
770     struct DNSReply *reply = NULL;
771     int rc;
772     int answer_count;
773     socklen_t len = sizeof(struct irc_ssaddr);
774     struct irc_ssaddr lsin;
775    
776     rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
777    
778     /* Re-schedule a read *after* recvfrom, or we'll be registering
779     * interest where it'll instantly be ready for read :-) -- adrian
780     */
781     comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
782     /* Better to cast the sizeof instead of rc */
783     if (rc <= (int)(sizeof(HEADER)))
784     return;
785    
786     /*
787     * convert DNS reply reader from Network byte order to CPU byte order.
788     */
789     header = (HEADER *)buf;
790     header->ancount = ntohs(header->ancount);
791     header->qdcount = ntohs(header->qdcount);
792     header->nscount = ntohs(header->nscount);
793     header->arcount = ntohs(header->arcount);
794    
795     /*
796     * response for an id which we have already received an answer for
797     * just ignore this response.
798     */
799     if (0 == (request = find_id(header->id)))
800     return;
801    
802     /*
803     * check against possibly fake replies
804     */
805     if (!res_ourserver(&lsin))
806     return;
807    
808     if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
809     {
810     if (SERVFAIL == header->rcode)
811     resend_query(request);
812     else
813     {
814     /*
815     * If we havent already tried this, and we're looking up AAAA, try A
816     * now
817     */
818    
819     #ifdef IPV6
820     if (request->state == REQ_AAAA && request->type == T_AAAA)
821     {
822     request->timeout += 4;
823     resend_query(request);
824     }
825     else if (request->type == T_PTR && request->state != REQ_INT &&
826     request->addr.ss.ss_family == AF_INET6)
827     {
828     request->state = REQ_INT;
829     request->timeout += 4;
830     request->retries--;
831     resend_query(request);
832     }
833     else
834     #endif
835     {
836     /*
837     * If a bad error was returned, we stop here and dont send
838     * send any more (no retries granted).
839     */
840     (*request->query->callback)(request->query->ptr, NULL);
841     rem_request(request);
842     }
843     }
844    
845     return;
846     }
847     /*
848     * If this fails there was an error decoding the received packet,
849     * try it again and hope it works the next time.
850     */
851     answer_count = proc_answer(request, header, buf, buf + rc);
852    
853     if (answer_count)
854     {
855     if (request->type == T_PTR)
856     {
857     if (request->name == NULL)
858     {
859     /*
860     * got a PTR response with no name, something bogus is happening
861     * don't bother trying again, the client address doesn't resolve
862     */
863     (*request->query->callback)(request->query->ptr, reply);
864     rem_request(request);
865     return;
866     }
867    
868     /*
869     * Lookup the 'authoritative' name that we were given for the
870     * ip#.
871     *
872     */
873     #ifdef IPV6
874     if (request->addr.ss.ss_family == AF_INET6)
875     gethost_byname_type(request->name, request->query, T_AAAA);
876     else
877     #endif
878     gethost_byname_type(request->name, request->query, T_A);
879     rem_request(request);
880     }
881     else
882     {
883     /*
884     * got a name and address response, client resolved
885     */
886     reply = make_dnsreply(request);
887     (*request->query->callback)(request->query->ptr, reply);
888     MyFree(reply);
889     rem_request(request);
890     }
891     }
892     else if (!request->sent)
893     {
894     /* XXX - we got a response for a query we didn't send with a valid id?
895     * this should never happen, bail here and leave the client unresolved
896     */
897     assert(0);
898    
899     /* XXX don't leak it */
900     rem_request(request);
901     }
902     }
903    
904     static struct DNSReply *
905     make_dnsreply(struct reslist *request)
906     {
907     struct DNSReply *cp;
908     assert(request != 0);
909    
910     cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
911    
912     cp->h_name = request->name;
913     memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
914     return(cp);
915     }
916    
917     void
918     report_dns_servers(struct Client *source_p)
919     {
920     int i;
921     char ipaddr[HOSTIPLEN];
922    
923     for (i = 0; i < irc_nscount; i++)
924     {
925     irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
926     irc_nsaddr_list[i].ss_len, ipaddr, HOSTIPLEN, NULL, 0,
927     NI_NUMERICHOST);
928     sendto_one(source_p, form_str(RPL_STATSALINE),
929     me.name, source_p->name, ipaddr);
930     }
931     }

Properties

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