ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/res.c
Revision: 986
Committed: Sat Aug 15 21:12:34 2009 UTC (14 years, 8 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/irc_res.c
File size: 23739 byte(s)
Log Message:
- irc_res.c: fixed wide-spread off-by-one when copying hostnames

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

Properties

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