ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/irc_res.c
Revision: 1247
Committed: Sat Oct 1 07:54:24 2011 UTC (13 years, 10 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/irc_res.c
File size: 22737 byte(s)
Log Message:
- Rewrite and cleanup half-broken logging subsystem.
  Logfile rotating is not working yet

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

Properties

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