ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
Revision: 1654
Committed: Fri Nov 16 19:39:37 2012 UTC (12 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/irc_res.c
File size: 22519 byte(s)
Log Message:
- Implemented memory pool allocator which basically is taken from Tor's
  mempool allocator for Tor cells
- Fixed compile warnings in conf_class.c
- ./configure --enable-assert works again

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 adx 30 #include "client.h"
25     #include "event.h"
26     #include "irc_string.h"
27     #include "sprintf_irc.h"
28     #include "ircd.h"
29     #include "numeric.h"
30 michael 982 #include "rng_mt.h"
31 adx 30 #include "fdlist.h"
32     #include "s_bsd.h"
33 michael 1309 #include "log.h"
34 michael 1243 #include "s_misc.h"
35 adx 30 #include "send.h"
36     #include "memory.h"
37 michael 1654 #include "mempool.h"
38 adx 30 #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 1654 static mp_pool_t *dns_pool = 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 1654 dns_pool = mp_pool_new(sizeof(struct reslist), MP_CHUNK_SIZE_DNS);
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 1654 mp_pool_release(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 1654 struct reslist *request = mp_pool_get(dns_pool);
284 adx 30
285 michael 1654 memset(request, 0, sizeof(*request));
286 michael 992 request->sentat = CurrentTime;
287     request->retries = 3;
288     request->resend = 1;
289     request->timeout = 4; /* start at 4 and exponential inc. */
290     request->state = REQ_IDLE;
291     request->callback = callback;
292     request->callback_ctx = ctx;
293 adx 30
294     dlinkAdd(request, &request->node, &request_list);
295 michael 998 return request;
296 adx 30 }
297    
298     /*
299     * delete_resolver_queries - cleanup outstanding queries
300     * for which there no longer exist clients or conf lines.
301     */
302     void
303 michael 992 delete_resolver_queries(const void *vptr)
304 adx 30 {
305 michael 997 dlink_node *ptr = NULL, *next_ptr = NULL;
306 adx 30
307     DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
308     {
309 michael 997 struct reslist *request = ptr->data;
310    
311     if (request->callback_ctx == vptr)
312     rem_request(request);
313 adx 30 }
314     }
315    
316     /*
317     * send_res_msg - sends msg to all nameservers found in the "_res" structure.
318     * This should reflect /etc/resolv.conf. We will get responses
319     * which arent needed but is easier than checking to see if nameserver
320     * isnt present. Returns number of messages successfully sent to
321     * nameservers or -1 if no successful sends.
322     */
323     static int
324     send_res_msg(const char *msg, int len, int rcount)
325     {
326     int i;
327     int sent = 0;
328     int max_queries = IRCD_MIN(irc_nscount, rcount);
329    
330     /* RES_PRIMARY option is not implemented
331     * if (res.options & RES_PRIMARY || 0 == max_queries)
332     */
333     if (max_queries == 0)
334     max_queries = 1;
335    
336     for (i = 0; i < max_queries; i++)
337     {
338     if (sendto(ResolverFileDescriptor.fd, msg, len, 0,
339     (struct sockaddr*)&(irc_nsaddr_list[i]),
340     irc_nsaddr_list[i].ss_len) == len)
341     ++sent;
342     }
343    
344 michael 1124 return sent;
345 adx 30 }
346    
347     /*
348     * find_id - find a dns request id (id is determined by dn_mkquery)
349     */
350     static struct reslist *
351     find_id(int id)
352     {
353 michael 1124 dlink_node *ptr = NULL;
354 adx 30
355     DLINK_FOREACH(ptr, request_list.head)
356     {
357 michael 1124 struct reslist *request = ptr->data;
358 adx 30
359     if (request->id == id)
360 michael 1124 return request;
361 adx 30 }
362    
363 michael 1124 return NULL;
364 adx 30 }
365    
366     /*
367     * gethost_byname_type - get host address from name
368     *
369     */
370     void
371 michael 992 gethost_byname_type(dns_callback_fnc callback, void *ctx, const char *name, int type)
372 adx 30 {
373 michael 1124 assert(name != NULL);
374 michael 992 do_query_name(callback, ctx, name, NULL, type);
375 adx 30 }
376    
377     /*
378     * gethost_byname - wrapper for _type - send T_AAAA first if IPV6 supported
379     */
380     void
381 michael 992 gethost_byname(dns_callback_fnc callback, void *ctx, const char *name)
382 adx 30 {
383     #ifdef IPV6
384 michael 992 gethost_byname_type(callback, ctx, name, T_AAAA);
385 adx 30 #else
386 michael 992 gethost_byname_type(callback, ctx, name, T_A);
387 adx 30 #endif
388     }
389    
390     /*
391     * gethost_byaddr - get host name from address
392     */
393     void
394 michael 992 gethost_byaddr(dns_callback_fnc callback, void *ctx, const struct irc_ssaddr *addr)
395 adx 30 {
396 michael 992 do_query_number(callback, ctx, addr, NULL);
397 adx 30 }
398    
399     /*
400     * do_query_name - nameserver lookup name
401     */
402     static void
403 michael 992 do_query_name(dns_callback_fnc callback, void *ctx, const char *name,
404 adx 30 struct reslist *request, int type)
405     {
406     char host_name[HOSTLEN + 1];
407    
408 michael 998 strlcpy(host_name, name, sizeof(host_name));
409 adx 30
410     if (request == NULL)
411     {
412 michael 992 request = make_request(callback, ctx);
413 michael 986 request->name = MyMalloc(strlen(host_name) + 1);
414 adx 30 request->type = type;
415     strcpy(request->name, host_name);
416     #ifdef IPV6
417 michael 984 if (type != T_A)
418     request->state = REQ_AAAA;
419 adx 30 else
420 michael 984 #endif
421 adx 30 request->state = REQ_A;
422     }
423    
424     request->type = type;
425     query_name(host_name, C_IN, type, request);
426     }
427    
428     /*
429     * do_query_number - Use this to do reverse IP# lookups.
430     */
431     static void
432 michael 992 do_query_number(dns_callback_fnc callback, void *ctx,
433     const struct irc_ssaddr *addr,
434 adx 30 struct reslist *request)
435     {
436     char ipbuf[128];
437     const unsigned char *cp;
438 michael 985
439 adx 30 if (addr->ss.ss_family == AF_INET)
440     {
441 michael 992 const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
442 michael 1124 cp = (const unsigned char *)&v4->sin_addr.s_addr;
443 adx 30
444 michael 1124 snprintf(ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
445     (unsigned int)(cp[3]), (unsigned int)(cp[2]),
446     (unsigned int)(cp[1]), (unsigned int)(cp[0]));
447 adx 30 }
448     #ifdef IPV6
449     else if (addr->ss.ss_family == AF_INET6)
450     {
451 michael 992 const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
452 adx 30 cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
453    
454 michael 1124 snprintf(ipbuf, sizeof(ipbuf),
455     "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
456     "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa.",
457     (unsigned int)(cp[15] & 0xf), (unsigned int)(cp[15] >> 4),
458     (unsigned int)(cp[14] & 0xf), (unsigned int)(cp[14] >> 4),
459     (unsigned int)(cp[13] & 0xf), (unsigned int)(cp[13] >> 4),
460     (unsigned int)(cp[12] & 0xf), (unsigned int)(cp[12] >> 4),
461     (unsigned int)(cp[11] & 0xf), (unsigned int)(cp[11] >> 4),
462     (unsigned int)(cp[10] & 0xf), (unsigned int)(cp[10] >> 4),
463     (unsigned int)(cp[9] & 0xf), (unsigned int)(cp[9] >> 4),
464     (unsigned int)(cp[8] & 0xf), (unsigned int)(cp[8] >> 4),
465     (unsigned int)(cp[7] & 0xf), (unsigned int)(cp[7] >> 4),
466     (unsigned int)(cp[6] & 0xf), (unsigned int)(cp[6] >> 4),
467     (unsigned int)(cp[5] & 0xf), (unsigned int)(cp[5] >> 4),
468     (unsigned int)(cp[4] & 0xf), (unsigned int)(cp[4] >> 4),
469     (unsigned int)(cp[3] & 0xf), (unsigned int)(cp[3] >> 4),
470     (unsigned int)(cp[2] & 0xf), (unsigned int)(cp[2] >> 4),
471     (unsigned int)(cp[1] & 0xf), (unsigned int)(cp[1] >> 4),
472     (unsigned int)(cp[0] & 0xf), (unsigned int)(cp[0] >> 4));
473 adx 30 }
474     #endif
475     if (request == NULL)
476     {
477 michael 992 request = make_request(callback, ctx);
478 adx 30 request->type = T_PTR;
479     memcpy(&request->addr, addr, sizeof(struct irc_ssaddr));
480 michael 986 request->name = MyMalloc(HOSTLEN + 1);
481 adx 30 }
482    
483     query_name(ipbuf, C_IN, T_PTR, request);
484     }
485    
486     /*
487     * query_name - generate a query based on class, type and name.
488     */
489     static void
490     query_name(const char *name, int query_class, int type,
491     struct reslist *request)
492     {
493     char buf[MAXPACKET];
494     int request_len = 0;
495    
496     memset(buf, 0, sizeof(buf));
497    
498     if ((request_len = irc_res_mkquery(name, query_class, type,
499     (unsigned char *)buf, sizeof(buf))) > 0)
500     {
501     HEADER *header = (HEADER *)buf;
502 michael 982
503 adx 30 /*
504     * generate an unique id
505     * NOTE: we don't have to worry about converting this to and from
506     * network byte order, the nameserver does not interpret this value
507     * and returns it unchanged
508     */
509     do
510 michael 982 header->id = (header->id + genrand_int32()) & 0xffff;
511     while (find_id(header->id));
512    
513 adx 30 request->id = header->id;
514     ++request->sends;
515    
516     request->sent += send_res_msg(buf, request_len, request->sends);
517     }
518     }
519    
520     static void
521     resend_query(struct reslist *request)
522     {
523     if (request->resend == 0)
524     return;
525    
526 michael 982 switch (request->type)
527 adx 30 {
528     case T_PTR:
529 michael 992 do_query_number(NULL, NULL, &request->addr, request);
530 adx 30 break;
531     case T_A:
532 michael 992 do_query_name(NULL, NULL, request->name, request, request->type);
533 adx 30 break;
534     #ifdef IPV6
535     case T_AAAA:
536     /* didnt work, try A */
537     if (request->state == REQ_AAAA)
538 michael 992 do_query_name(NULL, NULL, request->name, request, T_A);
539 adx 30 #endif
540     default:
541     break;
542     }
543     }
544    
545     /*
546     * proc_answer - process name server reply
547     */
548     static int
549 michael 1124 proc_answer(struct reslist *request, HEADER *header, char *buf, char *eob)
550 adx 30 {
551     char hostbuf[HOSTLEN + 100]; /* working buffer */
552     unsigned char *current; /* current position in buf */
553     int query_class; /* answer class */
554     int type; /* answer type */
555     int n; /* temp count */
556     int rd_length;
557     struct sockaddr_in *v4; /* conversion */
558     #ifdef IPV6
559     struct sockaddr_in6 *v6;
560     #endif
561     current = (unsigned char *)buf + sizeof(HEADER);
562    
563     for (; header->qdcount > 0; --header->qdcount)
564     {
565     if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
566     break;
567    
568 michael 1124 current += (size_t)n + QFIXEDSZ;
569 adx 30 }
570    
571     /*
572     * process each answer sent to us blech.
573     */
574     while (header->ancount > 0 && (char *)current < eob)
575     {
576     header->ancount--;
577    
578     n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
579     hostbuf, sizeof(hostbuf));
580    
581 michael 1124 if (n < 0 /* broken message */ || n == 0 /* no more answers left */)
582     return 0;
583 adx 30
584     hostbuf[HOSTLEN] = '\0';
585    
586     /* With Address arithmetic you have to be very anal
587     * this code was not working on alpha due to that
588     * (spotted by rodder/jailbird/dianora)
589     */
590     current += (size_t) n;
591    
592     if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
593     break;
594    
595     type = irc_ns_get16(current);
596     current += TYPE_SIZE;
597    
598     query_class = irc_ns_get16(current);
599     current += CLASS_SIZE;
600    
601     request->ttl = irc_ns_get32(current);
602     current += TTL_SIZE;
603    
604     rd_length = irc_ns_get16(current);
605     current += RDLENGTH_SIZE;
606    
607     /*
608     * Wait to set request->type until we verify this structure
609     */
610     switch (type)
611     {
612     case T_A:
613     if (request->type != T_A)
614 michael 1124 return 0;
615 adx 30
616     /*
617     * check for invalid rd_length or too many addresses
618     */
619     if (rd_length != sizeof(struct in_addr))
620 michael 1124 return 0;
621    
622 adx 30 v4 = (struct sockaddr_in *)&request->addr;
623     request->addr.ss_len = sizeof(struct sockaddr_in);
624     v4->sin_family = AF_INET;
625     memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
626 michael 1124 return 1;
627 adx 30 break;
628     #ifdef IPV6
629     case T_AAAA:
630     if (request->type != T_AAAA)
631 michael 1124 return 0;
632    
633 adx 30 if (rd_length != sizeof(struct in6_addr))
634 michael 1124 return 0;
635    
636 adx 30 request->addr.ss_len = sizeof(struct sockaddr_in6);
637     v6 = (struct sockaddr_in6 *)&request->addr;
638     v6->sin6_family = AF_INET6;
639     memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
640 michael 1124 return 1;
641 adx 30 break;
642     #endif
643     case T_PTR:
644     if (request->type != T_PTR)
645 michael 1124 return 0;
646    
647 adx 30 n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
648     current, hostbuf, sizeof(hostbuf));
649 michael 1124 if (n < 0 /* broken message */ || n == 0 /* no more answers left */)
650     return 0;
651 adx 30
652 michael 986 strlcpy(request->name, hostbuf, HOSTLEN + 1);
653 michael 1124 return 1;
654 adx 30 break;
655     case T_CNAME: /* first check we already havent started looking
656     into a cname */
657     if (request->type != T_PTR)
658 michael 1124 return 0;
659 adx 30
660     if (request->state == REQ_CNAME)
661     {
662     n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob,
663     current, hostbuf, sizeof(hostbuf));
664    
665     if (n < 0)
666 michael 1124 return 0;
667     return 1;
668 adx 30 }
669    
670     request->state = REQ_CNAME;
671     current += rd_length;
672     break;
673    
674     default:
675     /* XXX I'd rather just throw away the entire bogus thing
676     * but its possible its just a broken nameserver with still
677     * valid answers. But lets do some rudimentary logging for now...
678     */
679 michael 1247 ilog(LOG_TYPE_IRCD, "irc_res.c bogus type %d", type);
680 adx 30 break;
681     }
682     }
683    
684 michael 1124 return 1;
685 adx 30 }
686    
687     /*
688     * res_readreply - read a dns reply from the nameserver and process it.
689     */
690     static void
691     res_readreply(fde_t *fd, void *data)
692     {
693 adx 411 char buf[sizeof(HEADER) + MAXPACKET]
694     /* Sparc and alpha need 16bit-alignment for accessing header->id
695     * (which is uint16_t). Because of the header = (HEADER*) buf;
696     * lateron, this is neeeded. --FaUl
697     */
698     #if defined(__sparc__) || defined(__alpha__)
699     __attribute__((aligned (16)))
700     #endif
701     ;
702 adx 30 HEADER *header;
703     struct reslist *request = NULL;
704     int rc;
705     socklen_t len = sizeof(struct irc_ssaddr);
706     struct irc_ssaddr lsin;
707    
708     rc = recvfrom(fd->fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
709    
710     /* Re-schedule a read *after* recvfrom, or we'll be registering
711     * interest where it'll instantly be ready for read :-) -- adrian
712     */
713     comm_setselect(fd, COMM_SELECT_READ, res_readreply, NULL, 0);
714 michael 984
715 adx 30 /* Better to cast the sizeof instead of rc */
716     if (rc <= (int)(sizeof(HEADER)))
717     return;
718    
719     /*
720     * convert DNS reply reader from Network byte order to CPU byte order.
721     */
722     header = (HEADER *)buf;
723     header->ancount = ntohs(header->ancount);
724     header->qdcount = ntohs(header->qdcount);
725     header->nscount = ntohs(header->nscount);
726     header->arcount = ntohs(header->arcount);
727    
728     /*
729 michael 994 * check against possibly fake replies
730 adx 30 */
731 michael 994 if (!res_ourserver(&lsin))
732 adx 30 return;
733    
734     /*
735 michael 994 * response for an id which we have already received an answer for
736     * just ignore this response.
737 adx 30 */
738 michael 994 if (!(request = find_id(header->id)))
739 adx 30 return;
740    
741     if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
742     {
743 michael 984 if (header->rcode == SERVFAIL || header->rcode == NXDOMAIN)
744 db 155 {
745 michael 984 /*
746     * If a bad error was returned, stop here and don't
747     * send any more (no retries granted).
748     */
749 michael 992 (*request->callback)(request->callback_ctx, NULL, NULL);
750 michael 984 rem_request(request);
751     }
752     #ifdef IPV6
753     else
754     {
755 adx 30 /*
756     * If we havent already tried this, and we're looking up AAAA, try A
757     * now
758     */
759     if (request->state == REQ_AAAA && request->type == T_AAAA)
760     {
761     request->timeout += 4;
762     resend_query(request);
763     }
764 michael 984 }
765 adx 30 #endif
766 michael 984
767 db 468 return;
768 adx 30 }
769 michael 984
770 adx 30 /*
771     * If this fails there was an error decoding the received packet,
772     * try it again and hope it works the next time.
773     */
774 michael 994 if (proc_answer(request, header, buf, buf + rc))
775 adx 30 {
776     if (request->type == T_PTR)
777     {
778     if (request->name == NULL)
779     {
780     /*
781     * got a PTR response with no name, something bogus is happening
782     * don't bother trying again, the client address doesn't resolve
783     */
784 michael 992 (*request->callback)(request->callback_ctx, NULL, NULL);
785 adx 30 rem_request(request);
786     return;
787     }
788    
789     /*
790     * Lookup the 'authoritative' name that we were given for the
791     * ip#.
792     *
793     */
794     #ifdef IPV6
795     if (request->addr.ss.ss_family == AF_INET6)
796 michael 992 gethost_byname_type(request->callback, request->callback_ctx, request->name, T_AAAA);
797 adx 30 else
798     #endif
799 michael 992 gethost_byname_type(request->callback, request->callback_ctx, request->name, T_A);
800 adx 30 rem_request(request);
801     }
802     else
803     {
804     /*
805     * got a name and address response, client resolved
806     */
807 michael 992 (*request->callback)(request->callback_ctx, &request->addr, request->name);
808 adx 30 rem_request(request);
809     }
810     }
811     else if (!request->sent)
812     {
813     /* XXX - we got a response for a query we didn't send with a valid id?
814     * this should never happen, bail here and leave the client unresolved
815     */
816     assert(0);
817    
818     /* XXX don't leak it */
819     rem_request(request);
820     }
821     }
822    
823     void
824     report_dns_servers(struct Client *source_p)
825     {
826     int i;
827 michael 992 char ipaddr[HOSTIPLEN + 1];
828 adx 30
829     for (i = 0; i < irc_nscount; i++)
830     {
831 michael 1123 getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
832     irc_nsaddr_list[i].ss_len, ipaddr,
833     sizeof(ipaddr), NULL, 0, NI_NUMERICHOST);
834 adx 30 sendto_one(source_p, form_str(RPL_STATSALINE),
835     me.name, source_p->name, ipaddr);
836     }
837     }

Properties

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