ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
Revision: 468
Committed: Fri Feb 17 02:42:23 2006 UTC (18 years, 1 month ago) by db
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/irc_res.c
File size: 24863 byte(s)
Log Message:
- Cleaned up the resolver some more, added some comments


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 463 if (NXDOMAIN == header->rcode)
817 db 155 {
818 adx 30 /*
819     * If we havent already tried this, and we're looking up AAAA, try A
820     * now
821     */
822     #ifdef IPV6
823     if (request->state == REQ_AAAA && request->type == T_AAAA)
824     {
825     request->timeout += 4;
826     resend_query(request);
827     }
828     else if (request->type == T_PTR && request->state != REQ_INT &&
829     request->addr.ss.ss_family == AF_INET6)
830     {
831     request->state = REQ_INT;
832     request->timeout += 4;
833 db 463 request->retries--;
834 adx 30 resend_query(request);
835     }
836 db 468 else /* It's NXDOMAIN but not IPV6 */
837 adx 30 #endif
838 db 463 {
839     /*
840     * If a bad error was returned, stop here and don't
841     * send any more (no retries granted).
842     */
843     (*request->query->callback)(request->query->ptr, NULL);
844     rem_request(request);
845     }
846 adx 30 }
847 db 468 else /* Some other error other than NXDOMAIN */
848     {
849     /*
850     * If a bad error was returned, stop here and don't
851     * send any more (no retries granted).
852     */
853     (*request->query->callback)(request->query->ptr, NULL);
854     rem_request(request);
855     }
856     return;
857 adx 30 }
858     /*
859     * If this fails there was an error decoding the received packet,
860     * try it again and hope it works the next time.
861     */
862     answer_count = proc_answer(request, header, buf, buf + rc);
863    
864     if (answer_count)
865     {
866     if (request->type == T_PTR)
867     {
868     if (request->name == NULL)
869     {
870     /*
871     * got a PTR response with no name, something bogus is happening
872     * don't bother trying again, the client address doesn't resolve
873     */
874     (*request->query->callback)(request->query->ptr, reply);
875     rem_request(request);
876     return;
877     }
878    
879     /*
880     * Lookup the 'authoritative' name that we were given for the
881     * ip#.
882     *
883     */
884     #ifdef IPV6
885     if (request->addr.ss.ss_family == AF_INET6)
886     gethost_byname_type(request->name, request->query, T_AAAA);
887     else
888     #endif
889     gethost_byname_type(request->name, request->query, T_A);
890     rem_request(request);
891     }
892     else
893     {
894     /*
895     * got a name and address response, client resolved
896     */
897     reply = make_dnsreply(request);
898     (*request->query->callback)(request->query->ptr, reply);
899     MyFree(reply);
900     rem_request(request);
901     }
902     }
903     else if (!request->sent)
904     {
905     /* XXX - we got a response for a query we didn't send with a valid id?
906     * this should never happen, bail here and leave the client unresolved
907     */
908     assert(0);
909    
910     /* XXX don't leak it */
911     rem_request(request);
912     }
913     }
914    
915     static struct DNSReply *
916     make_dnsreply(struct reslist *request)
917     {
918     struct DNSReply *cp;
919     assert(request != 0);
920    
921     cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
922    
923     cp->h_name = request->name;
924     memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
925     return(cp);
926     }
927    
928     void
929     report_dns_servers(struct Client *source_p)
930     {
931     int i;
932     char ipaddr[HOSTIPLEN];
933    
934     for (i = 0; i < irc_nscount; i++)
935     {
936     irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
937     irc_nsaddr_list[i].ss_len, ipaddr, HOSTIPLEN, NULL, 0,
938     NI_NUMERICHOST);
939     sendto_one(source_p, form_str(RPL_STATSALINE),
940     me.name, source_p->name, ipaddr);
941     }
942     }

Properties

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