ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/irc_res.c
Revision: 994
Committed: Fri Aug 21 09:15:31 2009 UTC (14 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 23701 byte(s)
Log Message:
- res_readreply(): check for fake replies before doing anything else

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

Properties

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