ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
Revision: 1592
Committed: Sat Oct 27 21:02:32 2012 UTC (12 years, 10 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/irc_res.c
File size: 22496 byte(s)
Log Message:
- Second time's the charm? Moving svnroot/ircd-hybrid-8 to
  svnroot/ircd-hybrid/trunk

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

Properties

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