ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/libio/net/res.c
Revision: 152
Committed: Mon Oct 17 01:48:08 2005 UTC (20 years, 9 months ago) by db
Content type: text/x-csrc
File size: 23571 byte(s)
Log Message:
- res.c would send out hundreds? of retry requests on clients that
  did not resolve, i.e. SERVFAIL. The code was essentailly ignoring
  SERVFAIL hence generating request after request after request.
  This appears to fix this major bug. It would be a good idea to add
  some logging here however.


File Contents

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

Properties

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