ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/res.c
Revision: 1793
Committed: Sun Mar 31 14:06:08 2013 UTC (12 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/src/irc_res.c
File size: 22494 byte(s)
Log Message:
- Replaced all occurrences of ircsprintf with sprintf/snprintf
  and killed sprintf_irc.(c|h)

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 "ircd.h"
28     #include "numeric.h"
29 michael 982 #include "rng_mt.h"
30 adx 30 #include "fdlist.h"
31     #include "s_bsd.h"
32 michael 1309 #include "log.h"
33 michael 1243 #include "s_misc.h"
34 adx 30 #include "send.h"
35     #include "memory.h"
36 michael 1654 #include "mempool.h"
37 adx 30 #include "irc_res.h"
38     #include "irc_reslib.h"
39    
40     #if (CHAR_BIT != 8)
41     #error this code needs to be able to address individual octets
42     #endif
43    
44     static PF res_readreply;
45    
46     #define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */
47     #define RES_MAXALIASES 35 /* maximum aliases allowed */
48     #define RES_MAXADDRS 35 /* maximum addresses allowed */
49     #define AR_TTL 600 /* TTL in seconds for dns cache entries */
50    
51     /* RFC 1104/1105 wasn't very helpful about what these fields
52     * should be named, so for now, we'll just name them this way.
53     * we probably should look at what named calls them or something.
54     */
55     #define TYPE_SIZE (size_t)2
56     #define CLASS_SIZE (size_t)2
57     #define TTL_SIZE (size_t)4
58     #define RDLENGTH_SIZE (size_t)2
59     #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
60    
61     typedef enum
62     {
63     REQ_IDLE, /* We're doing not much at all */
64     REQ_PTR, /* Looking up a PTR */
65     REQ_A, /* Looking up an A, possibly because AAAA failed */
66     #ifdef IPV6
67     REQ_AAAA, /* Looking up an AAAA */
68     #endif
69 michael 985 REQ_CNAME /* We got a CNAME in response, we better get a real answer next */
70 adx 30 } request_state;
71    
72     struct reslist
73     {
74     dlink_node node;
75     int id;
76     int sent; /* number of requests sent */
77     request_state state; /* State the resolver machine is in */
78     time_t ttl;
79     char type;
80     char retries; /* retry counter */
81     char sends; /* number of sends (>1 means resent) */
82     char resend; /* send flag. 0 == dont resend */
83     time_t sentat;
84     time_t timeout;
85     struct irc_ssaddr addr;
86     char *name;
87 michael 992 dns_callback_fnc callback;
88     void *callback_ctx;
89 adx 30 };
90    
91     static fde_t ResolverFileDescriptor;
92 michael 986 static dlink_list request_list = { NULL, NULL, 0 };
93 michael 1654 static mp_pool_t *dns_pool = NULL;
94 adx 30
95 michael 1124 static void rem_request(struct reslist *);
96     static struct reslist *make_request(dns_callback_fnc, void *);
97     static void do_query_name(dns_callback_fnc, void *,
98 michael 992 const char *, struct reslist *, int);
99 michael 1124 static void do_query_number(dns_callback_fnc, void *,
100 adx 30 const struct irc_ssaddr *,
101 michael 1124 struct reslist *);
102     static void query_name(const char *, int, int, struct reslist *);
103     static int send_res_msg(const char *, int, int);
104     static void resend_query(struct reslist *);
105     static int proc_answer(struct reslist *, HEADER *, char *, char *);
106     static struct reslist *find_id(int);
107 adx 30
108    
109     /*
110     * int
111     * res_ourserver(inp)
112     * looks up "inp" in irc_nsaddr_list[]
113     * returns:
114     * 0 : not found
115     * >0 : found
116     * author:
117     * paul vixie, 29may94
118     * revised for ircd, cryogen(stu) may03
119     */
120     static int
121     res_ourserver(const struct irc_ssaddr *inp)
122     {
123     #ifdef IPV6
124 michael 992 const struct sockaddr_in6 *v6;
125     const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
126 adx 30 #endif
127 michael 992 const struct sockaddr_in *v4;
128     const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
129 adx 30 int ns;
130    
131 michael 1346 for (ns = 0; ns < irc_nscount; ++ns)
132 adx 30 {
133     const struct irc_ssaddr *srv = &irc_nsaddr_list[ns];
134     #ifdef IPV6
135 michael 992 v6 = (const struct sockaddr_in6 *)srv;
136 adx 30 #endif
137 michael 992 v4 = (const struct sockaddr_in *)srv;
138 adx 30
139     /* could probably just memcmp(srv, inp, srv.ss_len) here
140     * but we'll air on the side of caution - stu
141     *
142     */
143     switch (srv->ss.ss_family)
144     {
145     #ifdef IPV6
146     case AF_INET6:
147     if (srv->ss.ss_family == inp->ss.ss_family)
148     if (v6->sin6_port == v6in->sin6_port)
149 michael 1346 if (!memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
150     sizeof(struct in6_addr)))
151 michael 1124 return 1;
152 adx 30 break;
153     #endif
154     case AF_INET:
155     if (srv->ss.ss_family == inp->ss.ss_family)
156     if (v4->sin_port == v4in->sin_port)
157 michael 1346 if (v4->sin_addr.s_addr == v4in->sin_addr.s_addr)
158 michael 1124 return 1;
159 adx 30 break;
160     default:
161     break;
162     }
163     }
164    
165 michael 1124 return 0;
166 adx 30 }
167    
168     /*
169     * timeout_query_list - Remove queries from the list which have been
170     * there too long without being resolved.
171     */
172     static time_t
173     timeout_query_list(time_t now)
174     {
175     dlink_node *ptr;
176     dlink_node *next_ptr;
177     struct reslist *request;
178     time_t next_time = 0;
179     time_t timeout = 0;
180    
181     DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
182     {
183     request = ptr->data;
184     timeout = request->sentat + request->timeout;
185    
186     if (now >= timeout)
187     {
188     if (--request->retries <= 0)
189     {
190 michael 992 (*request->callback)(request->callback_ctx, NULL, NULL);
191 adx 30 rem_request(request);
192     continue;
193     }
194     else
195     {
196     request->sentat = now;
197     request->timeout += request->timeout;
198     resend_query(request);
199     }
200     }
201    
202     if ((next_time == 0) || timeout < next_time)
203     next_time = timeout;
204     }
205    
206 michael 1124 return (next_time > now) ? next_time : (now + AR_TTL);
207 adx 30 }
208    
209     /*
210     * timeout_resolver - check request list
211     */
212     static void
213     timeout_resolver(void *notused)
214     {
215     timeout_query_list(CurrentTime);
216     }
217    
218     /*
219     * start_resolver - do everything we need to read the resolv.conf file
220     * and initialize the resolver file descriptor if needed
221     */
222     static void
223     start_resolver(void)
224     {
225     irc_res_init();
226    
227     if (!ResolverFileDescriptor.flags.open)
228     {
229     if (comm_open(&ResolverFileDescriptor, irc_nsaddr_list[0].ss.ss_family,
230     SOCK_DGRAM, 0, "Resolver socket") == -1)
231     return;
232    
233     /* At the moment, the resolver FD data is global .. */
234     comm_setselect(&ResolverFileDescriptor, COMM_SELECT_READ,
235     res_readreply, NULL, 0);
236     eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
237     }
238     }
239    
240     /*
241     * init_resolver - initialize resolver and resolver library
242     */
243     void
244     init_resolver(void)
245     {
246 michael 1654 dns_pool = mp_pool_new(sizeof(struct reslist), MP_CHUNK_SIZE_DNS);
247 adx 30 memset(&ResolverFileDescriptor, 0, sizeof(fde_t));
248     start_resolver();
249     }
250    
251     /*
252     * restart_resolver - reread resolv.conf, reopen socket
253     */
254     void
255     restart_resolver(void)
256     {
257     fd_close(&ResolverFileDescriptor);
258     eventDelete(timeout_resolver, NULL); /* -ddosen */
259     start_resolver();
260     }
261    
262     /*
263     * rem_request - remove a request from the list.
264     * This must also free any memory that has been allocated for
265     * temporary storage of DNS results.
266     */
267     static void
268     rem_request(struct reslist *request)
269     {
270     dlinkDelete(&request->node, &request_list);
271 michael 998
272 adx 30 MyFree(request->name);
273 michael 1654 mp_pool_release(request);
274 adx 30 }
275    
276     /*
277     * make_request - Create a DNS request record for the server.
278     */
279     static struct reslist *
280 michael 992 make_request(dns_callback_fnc callback, void *ctx)
281 adx 30 {
282 michael 1654 struct reslist *request = mp_pool_get(dns_pool);
283 adx 30
284 michael 1654 memset(request, 0, sizeof(*request));
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