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.
7 * The authors takes no responsibility for any damage or loss
8 * of property which results from the use of this software.
10 * $Id: res.c 26 2006-09-20 18:02:06Z spb $
11 * from Hybrid Id: res.c 459 2006-02-12 22:21:37Z db $
13 * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
14 * added callbacks and reference counting of returned hostents.
15 * --Bleep (Thomas Helvey <tomh@inxpress.net>)
17 * This was all needlessly complicated for irc. Simplified. No more hostent
18 * All we really care about is the IP -> hostname mappings. Thats all.
20 * Apr 28, 2003 --cryogen and Dianora
22 * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support
23 * removed, various robustness fixes
25 * 2006 --jilles and nenolod
29 #include "ircd_defs.h"
37 #include "irc_string.h"
38 #include "sprintf_irc.h"
40 #include "client.h" /* SNO_* */
43 #error this code needs to be able to address individual octets
46 static PF res_readreply
;
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 */
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.
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)
65 REQ_IDLE
, /* We're doing not much at all */
66 REQ_PTR
, /* Looking up a PTR */
67 REQ_A
, /* Looking up an A or AAAA */
68 REQ_CNAME
/* We got a CNAME in response, we better get a real answer next */
75 int sent
; /* number of requests sent */
76 request_state state
; /* State the resolver machine is in */
79 char queryname
[128]; /* name currently being queried */
80 char retries
; /* retry counter */
81 char sends
; /* number of sends (>1 means resent) */
82 char resend
; /* send flag. 0 == dont resend */
85 struct irc_sockaddr_storage addr
;
87 struct DNSQuery
*query
; /* query callback for this request */
91 static dlink_list request_list
= { NULL
, NULL
, 0 };
93 static void rem_request(struct reslist
*request
);
94 static struct reslist
*make_request(struct DNSQuery
*query
);
95 static void do_query_name(struct DNSQuery
*query
, const char *name
, struct reslist
*request
, int);
96 static void do_query_number(struct DNSQuery
*query
, const struct irc_sockaddr_storage
*,
97 struct reslist
*request
);
98 static void query_name(struct reslist
*request
);
99 static int send_res_msg(const char *buf
, int len
, int count
);
100 static void resend_query(struct reslist
*request
);
101 static int check_question(struct reslist
*request
, HEADER
* header
, char *buf
, char *eob
);
102 static int proc_answer(struct reslist
*request
, HEADER
* header
, char *, char *);
103 static struct reslist
*find_id(int id
);
104 static struct DNSReply
*make_dnsreply(struct reslist
*request
);
106 extern struct irc_sockaddr_storage irc_nsaddr_list
[IRCD_MAXNS
];
107 extern int irc_nscount
;
108 extern char irc_domain
[HOSTLEN
+ 1];
114 * looks up "inp" in irc_nsaddr_list[]
119 * paul vixie, 29may94
120 * revised for ircd, cryogen(stu) may03
122 static int res_ourserver(const struct irc_sockaddr_storage
*inp
)
125 struct sockaddr_in6
*v6
;
126 struct sockaddr_in6
*v6in
= (struct sockaddr_in6
*)inp
;
128 struct sockaddr_in
*v4
;
129 struct sockaddr_in
*v4in
= (struct sockaddr_in
*)inp
;
132 for (ns
= 0; ns
< irc_nscount
; ns
++)
134 const struct irc_sockaddr_storage
*srv
= &irc_nsaddr_list
[ns
];
136 v6
= (struct sockaddr_in6
*)srv
;
138 v4
= (struct sockaddr_in
*)srv
;
140 /* could probably just memcmp(srv, inp, srv.ss_len) here
141 * but we'll air on the side of caution - stu
143 switch (srv
->ss_family
)
147 if (srv
->ss_family
== inp
->ss_family
)
148 if (v6
->sin6_port
== v6in
->sin6_port
)
149 if ((memcmp(&v6
->sin6_addr
.s6_addr
, &v6in
->sin6_addr
.s6_addr
,
150 sizeof(struct in6_addr
)) == 0) ||
151 (memcmp(&v6
->sin6_addr
.s6_addr
, &in6addr_any
,
152 sizeof(struct in6_addr
)) == 0))
157 if (srv
->ss_family
== inp
->ss_family
)
158 if (v4
->sin_port
== v4in
->sin_port
)
159 if ((v4
->sin_addr
.s_addr
== INADDR_ANY
)
160 || (v4
->sin_addr
.s_addr
== v4in
->sin_addr
.s_addr
))
172 * timeout_query_list - Remove queries from the list which have been
173 * there too long without being resolved.
175 static time_t timeout_query_list(time_t now
)
178 dlink_node
*next_ptr
;
179 struct reslist
*request
;
180 time_t next_time
= 0;
183 DLINK_FOREACH_SAFE(ptr
, next_ptr
, request_list
.head
)
186 timeout
= request
->sentat
+ request
->timeout
;
190 if (--request
->retries
<= 0)
192 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
193 rem_request(request
);
198 request
->sentat
= now
;
199 request
->timeout
+= request
->timeout
;
200 resend_query(request
);
204 if ((next_time
== 0) || timeout
< next_time
)
210 return (next_time
> now
) ? next_time
: (now
+ AR_TTL
);
214 * timeout_resolver - check request list
216 static void timeout_resolver(void *notused
)
218 timeout_query_list(CurrentTime
);
222 * start_resolver - do everything we need to read the resolv.conf file
223 * and initialize the resolver file descriptor if needed
225 static void start_resolver(void)
229 if (res_fd
<= 0) /* there isn't any such thing as fd 0, that's just a myth. */
231 if ((res_fd
= comm_socket(irc_nsaddr_list
[0].ss_family
, SOCK_DGRAM
, 0,
232 "UDP resolver socket")) == -1)
235 /* At the moment, the resolver FD data is global .. */
236 comm_setselect(res_fd
, FDLIST_NONE
, COMM_SELECT_READ
, res_readreply
, NULL
, 0);
237 eventAdd("timeout_resolver", timeout_resolver
, NULL
, 1);
242 * init_resolver - initialize resolver and resolver library
244 void init_resolver(void)
247 srand48(CurrentTime
);
253 * restart_resolver - reread resolv.conf, reopen socket
255 void restart_resolver(void)
259 eventDelete(timeout_resolver
, NULL
); /* -ddosen */
264 * add_local_domain - Add the domain to hostname, if it is missing
265 * (as suggested by eps@TOASTER.SFSU.EDU)
267 void add_local_domain(char *hname
, size_t size
)
269 /* try to fix up unqualified names */
270 if (strchr(hname
, '.') == NULL
)
274 size_t len
= strlen(hname
);
276 if ((strlen(irc_domain
) + len
+ 2) < size
)
279 strcpy(hname
+ len
, irc_domain
);
286 * rem_request - remove a request from the list.
287 * This must also free any memory that has been allocated for
288 * temporary storage of DNS results.
290 static void rem_request(struct reslist
*request
)
292 dlinkDelete(&request
->node
, &request_list
);
293 MyFree(request
->name
);
298 * make_request - Create a DNS request record for the server.
300 static struct reslist
*make_request(struct DNSQuery
*query
)
302 struct reslist
*request
= MyMalloc(sizeof(struct reslist
));
304 request
->sentat
= CurrentTime
;
305 request
->retries
= 3;
307 request
->timeout
= 4; /* start at 4 and exponential inc. */
308 request
->query
= query
;
309 request
->state
= REQ_IDLE
;
311 dlinkAdd(request
, &request
->node
, &request_list
);
317 * delete_resolver_queries - cleanup outstanding queries
318 * for which there no longer exist clients or conf lines.
320 void delete_resolver_queries(const struct DNSQuery
*query
)
323 dlink_node
*next_ptr
;
324 struct reslist
*request
;
326 DLINK_FOREACH_SAFE(ptr
, next_ptr
, request_list
.head
)
328 if ((request
= ptr
->data
) != NULL
)
330 if (query
== request
->query
)
331 rem_request(request
);
337 * send_res_msg - sends msg to all nameservers found in the "_res" structure.
338 * This should reflect /etc/resolv.conf. We will get responses
339 * which arent needed but is easier than checking to see if nameserver
340 * isnt present. Returns number of messages successfully sent to
341 * nameservers or -1 if no successful sends.
343 static int send_res_msg(const char *msg
, int len
, int rcount
)
347 int max_queries
= IRCD_MIN(irc_nscount
, rcount
);
349 /* RES_PRIMARY option is not implemented
350 * if (res.options & RES_PRIMARY || 0 == max_queries)
352 if (max_queries
== 0)
355 for (i
= 0; i
< max_queries
; i
++)
357 if (sendto(res_fd
, msg
, len
, 0,
358 (struct sockaddr
*)&(irc_nsaddr_list
[i
]),
359 GET_SS_LEN(irc_nsaddr_list
[i
])) == len
)
367 * find_id - find a dns request id (id is determined by dn_mkquery)
369 static struct reslist
*find_id(int id
)
372 struct reslist
*request
;
374 DLINK_FOREACH(ptr
, request_list
.head
)
378 if (request
->id
== id
)
386 * gethost_byname_type - get host address from name
389 void gethost_byname_type(const char *name
, struct DNSQuery
*query
, int type
)
392 do_query_name(query
, name
, NULL
, type
);
396 * gethost_byaddr - get host name from address
398 void gethost_byaddr(const struct irc_sockaddr_storage
*addr
, struct DNSQuery
*query
)
400 do_query_number(query
, addr
, NULL
);
404 * do_query_name - nameserver lookup name
406 static void do_query_name(struct DNSQuery
*query
, const char *name
, struct reslist
*request
,
409 char host_name
[HOSTLEN
+ 1];
411 strlcpy(host_name
, name
, HOSTLEN
);
412 add_local_domain(host_name
, HOSTLEN
);
416 request
= make_request(query
);
417 request
->name
= (char *)MyMalloc(strlen(host_name
) + 1);
418 strcpy(request
->name
, host_name
);
419 request
->state
= REQ_A
;
422 strlcpy(request
->queryname
, host_name
, sizeof(request
->queryname
));
423 request
->type
= type
;
428 * do_query_number - Use this to do reverse IP# lookups.
430 static void do_query_number(struct DNSQuery
*query
, const struct irc_sockaddr_storage
*addr
,
431 struct reslist
*request
)
433 const unsigned char *cp
;
437 request
= make_request(query
);
438 memcpy(&request
->addr
, addr
, sizeof(struct irc_sockaddr_storage
));
439 request
->name
= (char *)MyMalloc(HOSTLEN
+ 1);
442 if (addr
->ss_family
== AF_INET
)
444 struct sockaddr_in
*v4
= (struct sockaddr_in
*)addr
;
445 cp
= (const unsigned char *)&v4
->sin_addr
.s_addr
;
447 ircsprintf(request
->queryname
, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp
[3]),
448 (unsigned int)(cp
[2]), (unsigned int)(cp
[1]), (unsigned int)(cp
[0]));
451 else if (addr
->ss_family
== AF_INET6
)
453 struct sockaddr_in6
*v6
= (struct sockaddr_in6
*)addr
;
454 cp
= (const unsigned char *)&v6
->sin6_addr
.s6_addr
;
456 (void)sprintf(request
->queryname
, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
457 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
458 (unsigned int)(cp
[15] & 0xf), (unsigned int)(cp
[15] >> 4),
459 (unsigned int)(cp
[14] & 0xf), (unsigned int)(cp
[14] >> 4),
460 (unsigned int)(cp
[13] & 0xf), (unsigned int)(cp
[13] >> 4),
461 (unsigned int)(cp
[12] & 0xf), (unsigned int)(cp
[12] >> 4),
462 (unsigned int)(cp
[11] & 0xf), (unsigned int)(cp
[11] >> 4),
463 (unsigned int)(cp
[10] & 0xf), (unsigned int)(cp
[10] >> 4),
464 (unsigned int)(cp
[9] & 0xf), (unsigned int)(cp
[9] >> 4),
465 (unsigned int)(cp
[8] & 0xf), (unsigned int)(cp
[8] >> 4),
466 (unsigned int)(cp
[7] & 0xf), (unsigned int)(cp
[7] >> 4),
467 (unsigned int)(cp
[6] & 0xf), (unsigned int)(cp
[6] >> 4),
468 (unsigned int)(cp
[5] & 0xf), (unsigned int)(cp
[5] >> 4),
469 (unsigned int)(cp
[4] & 0xf), (unsigned int)(cp
[4] >> 4),
470 (unsigned int)(cp
[3] & 0xf), (unsigned int)(cp
[3] >> 4),
471 (unsigned int)(cp
[2] & 0xf), (unsigned int)(cp
[2] >> 4),
472 (unsigned int)(cp
[1] & 0xf), (unsigned int)(cp
[1] >> 4),
473 (unsigned int)(cp
[0] & 0xf), (unsigned int)(cp
[0] >> 4));
477 request
->type
= T_PTR
;
482 * query_name - generate a query based on class, type and name.
484 static void query_name(struct reslist
*request
)
489 memset(buf
, 0, sizeof(buf
));
492 irc_res_mkquery(request
->queryname
, C_IN
, request
->type
, (unsigned char *)buf
, sizeof(buf
))) > 0)
494 HEADER
*header
= (HEADER
*) buf
;
500 * generate an unique id
501 * NOTE: we don't have to worry about converting this to and from
502 * network byte order, the nameserver does not interpret this value
503 * and returns it unchanged
508 header
->id
= (header
->id
+ lrand48()) & 0xffff;
509 } while (find_id(header
->id
));
511 gettimeofday(&tv
, NULL
);
514 header
->id
= (header
->id
+ k
+ tv
.tv_usec
) & 0xffff;
516 } while (find_id(header
->id
));
517 #endif /* HAVE_LRAND48 */
518 request
->id
= header
->id
;
521 request
->sent
+= send_res_msg(buf
, request_len
, request
->sends
);
525 static void resend_query(struct reslist
*request
)
527 if (request
->resend
== 0)
530 switch (request
->type
)
533 do_query_number(NULL
, &request
->addr
, request
);
539 do_query_name(NULL
, request
->name
, request
, request
->type
);
547 * check_question - check if the reply really belongs to the
548 * name we queried (to guard against late replies from previous
549 * queries with the same id).
551 static int check_question(struct reslist
*request
, HEADER
* header
, char *buf
, char *eob
)
553 char hostbuf
[128]; /* working buffer */
554 unsigned char *current
; /* current position in buf */
555 int n
; /* temp count */
557 current
= (unsigned char *)buf
+ sizeof(HEADER
);
558 if (header
->qdcount
!= 1)
560 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
, hostbuf
,
564 if (strcasecmp(hostbuf
, request
->queryname
))
570 * proc_answer - process name server reply
572 static int proc_answer(struct reslist
*request
, HEADER
* header
, char *buf
, char *eob
)
574 char hostbuf
[HOSTLEN
+ 100]; /* working buffer */
575 unsigned char *current
; /* current position in buf */
576 int query_class
; /* answer class */
577 int type
; /* answer type */
578 int n
; /* temp count */
580 struct sockaddr_in
*v4
; /* conversion */
582 struct sockaddr_in6
*v6
;
584 current
= (unsigned char *)buf
+ sizeof(HEADER
);
586 for (; header
->qdcount
> 0; --header
->qdcount
)
588 if ((n
= irc_dn_skipname(current
, (unsigned char *)eob
)) < 0)
591 current
+= (size_t) n
+ QFIXEDSZ
;
595 * process each answer sent to us blech.
597 while (header
->ancount
> 0 && (char *)current
< eob
)
601 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
, hostbuf
,
614 * no more answers left
619 hostbuf
[HOSTLEN
] = '\0';
621 /* With Address arithmetic you have to be very anal
622 * this code was not working on alpha due to that
623 * (spotted by rodder/jailbird/dianora)
625 current
+= (size_t) n
;
627 if (!(((char *)current
+ ANSWER_FIXED_SIZE
) < eob
))
630 type
= irc_ns_get16(current
);
631 current
+= TYPE_SIZE
;
633 query_class
= irc_ns_get16(current
);
634 current
+= CLASS_SIZE
;
636 request
->ttl
= irc_ns_get32(current
);
639 rd_length
= irc_ns_get16(current
);
640 current
+= RDLENGTH_SIZE
;
643 * Wait to set request->type until we verify this structure
648 if (request
->type
!= T_A
)
652 * check for invalid rd_length or too many addresses
654 if (rd_length
!= sizeof(struct in_addr
))
656 v4
= (struct sockaddr_in
*)&request
->addr
;
657 SET_SS_LEN(request
->addr
, sizeof(struct sockaddr_in
));
658 v4
->sin_family
= AF_INET
;
659 memcpy(&v4
->sin_addr
, current
, sizeof(struct in_addr
));
664 if (request
->type
!= T_AAAA
)
666 if (rd_length
!= sizeof(struct in6_addr
))
668 SET_SS_LEN(request
->addr
, sizeof(struct sockaddr_in6
));
669 v6
= (struct sockaddr_in6
*)&request
->addr
;
670 v6
->sin6_family
= AF_INET6
;
671 memcpy(&v6
->sin6_addr
, current
, sizeof(struct in6_addr
));
676 if (request
->type
!= T_PTR
)
678 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
,
679 hostbuf
, sizeof(hostbuf
));
681 return (0); /* broken message */
683 return (0); /* no more answers left */
685 strlcpy(request
->name
, hostbuf
, HOSTLEN
);
689 case T_CNAME
: /* first check we already havent started looking
691 if (request
->type
!= T_PTR
)
694 if (request
->state
== REQ_CNAME
)
696 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
,
697 current
, hostbuf
, sizeof(hostbuf
));
704 request
->state
= REQ_CNAME
;
705 current
+= rd_length
;
709 /* XXX I'd rather just throw away the entire bogus thing
710 * but its possible its just a broken nameserver with still
711 * valid answers. But lets do some rudimentary logging for now...
713 ilog(L_MAIN
, "irc_res.c bogus type %d", type
);
722 * res_readreply - read a dns reply from the nameserver and process it.
724 static void res_readreply(int fd
, void *data
)
726 char buf
[sizeof(HEADER
) + MAXPACKET
]
727 /* Sparc and alpha need 16bit-alignment for accessing header->id
728 * (which is uint16_t). Because of the header = (HEADER*) buf;
729 * lateron, this is neeeded. --FaUl
731 #if defined(__sparc__) || defined(__alpha__)
732 __attribute__ ((aligned(16)))
736 struct reslist
*request
= NULL
;
737 struct DNSReply
*reply
= NULL
;
740 socklen_t len
= sizeof(struct irc_sockaddr_storage
);
741 struct irc_sockaddr_storage lsin
;
743 rc
= recvfrom(fd
, buf
, sizeof(buf
), 0, (struct sockaddr
*)&lsin
, &len
);
745 /* Re-schedule a read *after* recvfrom, or we'll be registering
746 * interest where it'll instantly be ready for read :-) -- adrian
748 comm_setselect(fd
, FDLIST_NONE
, COMM_SELECT_READ
, res_readreply
, NULL
, 0);
749 /* Better to cast the sizeof instead of rc */
750 if (rc
<= (int)(sizeof(HEADER
)))
754 * convert DNS reply reader from Network byte order to CPU byte order.
756 header
= (HEADER
*) buf
;
757 header
->ancount
= ntohs(header
->ancount
);
758 header
->qdcount
= ntohs(header
->qdcount
);
759 header
->nscount
= ntohs(header
->nscount
);
760 header
->arcount
= ntohs(header
->arcount
);
763 * response for an id which we have already received an answer for
764 * just ignore this response.
766 if (0 == (request
= find_id(header
->id
)))
770 * check against possibly fake replies
772 if (!res_ourserver(&lsin
))
775 if (!check_question(request
, header
, buf
, buf
+ rc
))
778 if ((header
->rcode
!= NO_ERRORS
) || (header
->ancount
== 0))
780 if (NXDOMAIN
== header
->rcode
)
782 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
783 rem_request(request
);
788 * If a bad error was returned, we stop here and dont send
789 * send any more (no retries granted).
791 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
792 rem_request(request
);
797 * If this fails there was an error decoding the received packet,
800 answer_count
= proc_answer(request
, header
, buf
, buf
+ rc
);
804 if (request
->type
== T_PTR
)
806 if (request
->name
== NULL
)
809 * got a PTR response with no name, something bogus is happening
810 * don't bother trying again, the client address doesn't resolve
812 (*request
->query
->callback
) (request
->query
->ptr
, reply
);
813 rem_request(request
);
818 * Lookup the 'authoritative' name that we were given for the
823 if (request
->addr
.ss_family
== AF_INET6
)
824 gethost_byname_type(request
->name
, request
->query
, T_AAAA
);
827 gethost_byname_type(request
->name
, request
->query
, T_A
);
828 rem_request(request
);
833 * got a name and address response, client resolved
835 reply
= make_dnsreply(request
);
836 (*request
->query
->callback
) (request
->query
->ptr
, reply
);
838 rem_request(request
);
843 /* couldn't decode, give up -- jilles */
844 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
845 rem_request(request
);
849 static struct DNSReply
*make_dnsreply(struct reslist
*request
)
852 s_assert(request
!= 0);
854 cp
= (struct DNSReply
*)MyMalloc(sizeof(struct DNSReply
));
856 cp
->h_name
= request
->name
;
857 memcpy(&cp
->addr
, &request
->addr
, sizeof(cp
->addr
));
861 void report_dns_servers(struct Client
*source_p
)
866 for (i
= 0; i
< irc_nscount
; i
++)
868 if (!inetntop_sock((struct sockaddr
*)&(irc_nsaddr_list
[i
]),
869 ipaddr
, sizeof ipaddr
))
870 strlcpy(ipaddr
, "?", sizeof ipaddr
);
871 sendto_one_numeric(source_p
, RPL_STATSDEBUG
,