ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/libio/net/res.c
Revision: 71
Committed: Tue Oct 4 18:05:45 2005 UTC (20 years, 10 months ago) by knight
Content type: text/x-csrc
File size: 23620 byte(s)
Log Message:
- svn:keywords *smacks adx*

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     resend_query(request);
795     else
796     {
797     /*
798     * If we havent already tried this, and we're looking up AAAA, try A
799     * now
800     */
801    
802     #ifdef IPV6
803     if (request->state == REQ_AAAA && request->type == T_AAAA)
804     {
805     request->timeout += 4;
806     resend_query(request);
807     }
808     else if (request->type == T_PTR && request->state != REQ_INT &&
809     request->addr.ss.ss_family == AF_INET6)
810     {
811     request->state = REQ_INT;
812     request->timeout += 4;
813     request->retries--;
814     resend_query(request);
815     }
816     else
817     #endif
818     {
819     /*
820     * If a bad error was returned, we stop here and dont send
821     * send any more (no retries granted).
822     */
823     (*request->query->callback)(request->query->ptr, NULL);
824     rem_request(request);
825     }
826     }
827    
828     return;
829     }
830     /*
831     * If this fails there was an error decoding the received packet,
832     * try it again and hope it works the next time.
833     */
834     answer_count = proc_answer(request, header, buf, buf + rc);
835    
836     if (answer_count)
837     {
838     if (request->type == T_PTR)
839     {
840     if (request->name == NULL)
841     {
842     /*
843     * got a PTR response with no name, something bogus is happening
844     * don't bother trying again, the client address doesn't resolve
845     */
846     (*request->query->callback)(request->query->ptr, reply);
847     rem_request(request);
848     return;
849     }
850    
851     /*
852     * Lookup the 'authoritative' name that we were given for the
853     * ip#.
854     *
855     */
856     #ifdef IPV6
857     if (request->addr.ss.ss_family == AF_INET6)
858     gethost_byname_type(request->name, request->query, T_AAAA);
859     else
860     #endif
861     gethost_byname_type(request->name, request->query, T_A);
862     rem_request(request);
863     }
864     else
865     {
866     /*
867     * got a name and address response, client resolved
868     */
869     reply = make_dnsreply(request);
870     (*request->query->callback)(request->query->ptr, reply);
871     MyFree(reply);
872     rem_request(request);
873     }
874     }
875     else if (!request->sent)
876     {
877     /* XXX - we got a response for a query we didn't send with a valid id?
878     * this should never happen, bail here and leave the client unresolved
879     */
880     assert(0);
881    
882     /* XXX don't leak it */
883     rem_request(request);
884     }
885     }
886    
887     static struct DNSReply *
888     make_dnsreply(struct reslist *request)
889     {
890     struct DNSReply *cp;
891     assert(request != 0);
892    
893     cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
894    
895     cp->h_name = request->name;
896     memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
897     return(cp);
898     }

Properties

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