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.
11 * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
12 * added callbacks and reference counting of returned hostents.
13 * --Bleep (Thomas Helvey <tomh@inxpress.net>)
15 * This was all needlessly complicated for irc. Simplified. No more hostent
16 * All we really care about is the IP -> hostname mappings. Thats all.
18 * Apr 28, 2003 --cryogen and Dianora
20 * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support
21 * removed, various robustness fixes
23 * 2006 --jilles and nenolod
27 #include "ircd_defs.h"
34 #include "client.h" /* SNO_* */
37 #error this code needs to be able to address individual octets
40 static PF res_readreply
;
42 #define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */
43 #define RES_MAXALIASES 35 /* maximum aliases allowed */
44 #define RES_MAXADDRS 35 /* maximum addresses allowed */
45 #define AR_TTL 600 /* TTL in seconds for dns cache entries */
47 /* RFC 1104/1105 wasn't very helpful about what these fields
48 * should be named, so for now, we'll just name them this way.
49 * we probably should look at what named calls them or something.
51 #define TYPE_SIZE (size_t)2
52 #define CLASS_SIZE (size_t)2
53 #define TTL_SIZE (size_t)4
54 #define RDLENGTH_SIZE (size_t)2
55 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
63 char queryname
[IRCD_RES_HOSTLEN
+ 1]; /* name currently being queried */
64 char retries
; /* retry counter */
65 char sends
; /* number of sends (>1 means resent) */
68 unsigned int lastns
; /* index of last server sent to */
69 struct rb_sockaddr_storage addr
;
71 struct DNSQuery
*query
; /* query callback for this request */
74 static rb_fde_t
*res_fd
;
75 static rb_dlink_list request_list
= { NULL
, NULL
, 0 };
76 static int ns_timeout_count
[IRCD_MAXNS
];
78 static void rem_request(struct reslist
*request
);
79 static struct reslist
*make_request(struct DNSQuery
*query
);
80 static void do_query_name(struct DNSQuery
*query
, const char *name
, struct reslist
*request
, int);
81 static void do_query_number(struct DNSQuery
*query
, const struct rb_sockaddr_storage
*,
82 struct reslist
*request
);
83 static void query_name(struct reslist
*request
);
84 static int send_res_msg(const char *buf
, int len
, int count
);
85 static void resend_query(struct reslist
*request
);
86 static int check_question(struct reslist
*request
, HEADER
* header
, char *buf
, char *eob
);
87 static int proc_answer(struct reslist
*request
, HEADER
* header
, char *, char *);
88 static struct reslist
*find_id(int id
);
89 static struct DNSReply
*make_dnsreply(struct reslist
*request
);
94 * looks up "inp" in irc_nsaddr_list[]
100 * revised for ircd, cryogen(stu) may03
102 static int res_ourserver(const struct rb_sockaddr_storage
*inp
)
105 const struct sockaddr_in6
*v6
;
106 const struct sockaddr_in6
*v6in
= (const struct sockaddr_in6
*)inp
;
108 const struct sockaddr_in
*v4
;
109 const struct sockaddr_in
*v4in
= (const struct sockaddr_in
*)inp
;
112 for (ns
= 0; ns
< irc_nscount
; ns
++)
114 const struct rb_sockaddr_storage
*srv
= &irc_nsaddr_list
[ns
];
116 v6
= (const struct sockaddr_in6
*)srv
;
118 v4
= (const struct sockaddr_in
*)srv
;
120 /* could probably just memcmp(srv, inp, srv.ss_len) here
121 * but we'll air on the side of caution - stu
123 switch (srv
->ss_family
)
127 if (srv
->ss_family
== inp
->ss_family
)
128 if (v6
->sin6_port
== v6in
->sin6_port
)
129 if ((memcmp(&v6
->sin6_addr
.s6_addr
, &v6in
->sin6_addr
.s6_addr
,
130 sizeof(struct in6_addr
)) == 0) ||
131 (memcmp(&v6
->sin6_addr
.s6_addr
, &in6addr_any
,
132 sizeof(struct in6_addr
)) == 0))
134 ns_timeout_count
[ns
] = 0;
140 if (srv
->ss_family
== inp
->ss_family
)
141 if (v4
->sin_port
== v4in
->sin_port
)
142 if ((v4
->sin_addr
.s_addr
== INADDR_ANY
)
143 || (v4
->sin_addr
.s_addr
== v4in
->sin_addr
.s_addr
))
145 ns_timeout_count
[ns
] = 0;
158 * timeout_query_list - Remove queries from the list which have been
159 * there too long without being resolved.
161 static time_t timeout_query_list(time_t now
)
164 rb_dlink_node
*next_ptr
;
165 struct reslist
*request
;
166 time_t next_time
= 0;
169 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, request_list
.head
)
172 timeout
= request
->sentat
+ request
->timeout
;
176 if (--request
->retries
<= 0)
178 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
179 rem_request(request
);
184 ns_timeout_count
[request
->lastns
]++;
185 request
->sentat
= now
;
186 request
->timeout
+= request
->timeout
;
187 resend_query(request
);
191 if ((next_time
== 0) || timeout
< next_time
)
197 return (next_time
> now
) ? next_time
: (now
+ AR_TTL
);
201 * timeout_resolver - check request list
203 static void timeout_resolver(void *notused
)
205 timeout_query_list(rb_current_time());
208 static struct ev_entry
*timeout_resolver_ev
= NULL
;
211 * start_resolver - do everything we need to read the resolv.conf file
212 * and initialize the resolver file descriptor if needed
214 static void start_resolver(void)
219 for (i
= 0; i
< irc_nscount
; i
++)
220 ns_timeout_count
[i
] = 0;
224 if ((res_fd
= rb_socket(irc_nsaddr_list
[0].ss_family
, SOCK_DGRAM
, 0,
225 "UDP resolver socket")) == NULL
)
228 /* At the moment, the resolver FD data is global .. */
229 rb_setselect(res_fd
, RB_SELECT_READ
, res_readreply
, NULL
);
230 timeout_resolver_ev
= rb_event_add("timeout_resolver", timeout_resolver
, NULL
, 1);
235 * init_resolver - initialize resolver and resolver library
237 void init_resolver(void)
240 srand48(rb_current_time());
246 * restart_resolver - reread resolv.conf, reopen socket
248 void restart_resolver(void)
252 rb_event_delete(timeout_resolver_ev
); /* -ddosen */
257 * add_local_domain - Add the domain to hostname, if it is missing
258 * (as suggested by eps@TOASTER.SFSU.EDU)
260 void add_local_domain(char *hname
, size_t size
)
262 /* try to fix up unqualified names */
263 if (strchr(hname
, '.') == NULL
)
267 size_t len
= strlen(hname
);
269 if ((strlen(irc_domain
) + len
+ 2) < size
)
272 strcpy(hname
+ len
, irc_domain
);
279 * rem_request - remove a request from the list.
280 * This must also free any memory that has been allocated for
281 * temporary storage of DNS results.
283 static void rem_request(struct reslist
*request
)
285 rb_dlinkDelete(&request
->node
, &request_list
);
286 rb_free(request
->name
);
291 * make_request - Create a DNS request record for the server.
293 static struct reslist
*make_request(struct DNSQuery
*query
)
295 struct reslist
*request
= rb_malloc(sizeof(struct reslist
));
297 request
->sentat
= rb_current_time();
298 request
->retries
= 3;
299 request
->timeout
= 4; /* start at 4 and exponential inc. */
300 request
->query
= query
;
302 rb_dlinkAdd(request
, &request
->node
, &request_list
);
308 * delete_resolver_queries - cleanup outstanding queries
309 * for which there no longer exist clients or conf lines.
311 void delete_resolver_queries(const struct DNSQuery
*query
)
314 rb_dlink_node
*next_ptr
;
315 struct reslist
*request
;
317 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, request_list
.head
)
319 if ((request
= ptr
->data
) != NULL
)
321 if (query
== request
->query
)
322 rem_request(request
);
328 * retryfreq - determine how many queries to wait before resending
329 * if there have been that many consecutive timeouts
331 static int retryfreq(int timeouts
)
349 * send_res_msg - sends msg to a nameserver.
350 * This should reflect /etc/resolv.conf.
351 * Returns number of nameserver successfully sent to
352 * or -1 if no successful sends.
354 static int send_res_msg(const char *msg
, int len
, int rcount
)
361 /* First try a nameserver that seems to work.
362 * Every once in a while, try a possibly broken one to check
363 * if it is working again.
365 for (i
= 0; i
< irc_nscount
; i
++)
367 ns
= (i
+ rcount
- 1) % irc_nscount
;
368 if (ns_timeout_count
[ns
] && retrycnt
% retryfreq(ns_timeout_count
[ns
]))
370 if (sendto(rb_get_fd(res_fd
), msg
, len
, 0,
371 (struct sockaddr
*)&(irc_nsaddr_list
[ns
]),
372 GET_SS_LEN(&irc_nsaddr_list
[ns
])) == len
)
376 /* No known working nameservers, try some broken one. */
377 for (i
= 0; i
< irc_nscount
; i
++)
379 ns
= (i
+ rcount
- 1) % irc_nscount
;
380 if (!ns_timeout_count
[ns
])
382 if (sendto(rb_get_fd(res_fd
), msg
, len
, 0,
383 (struct sockaddr
*)&(irc_nsaddr_list
[ns
]),
384 GET_SS_LEN(&irc_nsaddr_list
[ns
])) == len
)
392 * find_id - find a dns request id (id is determined by dn_mkquery)
394 static struct reslist
*find_id(int id
)
397 struct reslist
*request
;
399 RB_DLINK_FOREACH(ptr
, request_list
.head
)
403 if (request
->id
== id
)
411 * gethost_byname_type - get host address from name
414 void gethost_byname_type(const char *name
, struct DNSQuery
*query
, int type
)
417 do_query_name(query
, name
, NULL
, type
);
421 * gethost_byaddr - get host name from address
423 void gethost_byaddr(const struct rb_sockaddr_storage
*addr
, struct DNSQuery
*query
)
425 do_query_number(query
, addr
, NULL
);
429 * do_query_name - nameserver lookup name
431 static void do_query_name(struct DNSQuery
*query
, const char *name
, struct reslist
*request
,
434 char host_name
[IRCD_RES_HOSTLEN
+ 1];
436 rb_strlcpy(host_name
, name
, IRCD_RES_HOSTLEN
+ 1);
437 add_local_domain(host_name
, IRCD_RES_HOSTLEN
);
441 request
= make_request(query
);
442 request
->name
= (char *)rb_malloc(strlen(host_name
) + 1);
443 strcpy(request
->name
, host_name
);
446 rb_strlcpy(request
->queryname
, host_name
, sizeof(request
->queryname
));
447 request
->type
= type
;
452 * do_query_number - Use this to do reverse IP# lookups.
454 static void do_query_number(struct DNSQuery
*query
, const struct rb_sockaddr_storage
*addr
,
455 struct reslist
*request
)
457 const unsigned char *cp
;
461 request
= make_request(query
);
462 memcpy(&request
->addr
, addr
, sizeof(struct rb_sockaddr_storage
));
463 request
->name
= (char *)rb_malloc(IRCD_RES_HOSTLEN
+ 1);
466 if (addr
->ss_family
== AF_INET
)
468 const struct sockaddr_in
*v4
= (const struct sockaddr_in
*)addr
;
469 cp
= (const unsigned char *)&v4
->sin_addr
.s_addr
;
471 rb_sprintf(request
->queryname
, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp
[3]),
472 (unsigned int)(cp
[2]), (unsigned int)(cp
[1]), (unsigned int)(cp
[0]));
475 else if (addr
->ss_family
== AF_INET6
)
477 const struct sockaddr_in6
*v6
= (const struct sockaddr_in6
*)addr
;
478 cp
= (const unsigned char *)&v6
->sin6_addr
.s6_addr
;
480 (void)sprintf(request
->queryname
, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
481 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
482 (unsigned int)(cp
[15] & 0xf), (unsigned int)(cp
[15] >> 4),
483 (unsigned int)(cp
[14] & 0xf), (unsigned int)(cp
[14] >> 4),
484 (unsigned int)(cp
[13] & 0xf), (unsigned int)(cp
[13] >> 4),
485 (unsigned int)(cp
[12] & 0xf), (unsigned int)(cp
[12] >> 4),
486 (unsigned int)(cp
[11] & 0xf), (unsigned int)(cp
[11] >> 4),
487 (unsigned int)(cp
[10] & 0xf), (unsigned int)(cp
[10] >> 4),
488 (unsigned int)(cp
[9] & 0xf), (unsigned int)(cp
[9] >> 4),
489 (unsigned int)(cp
[8] & 0xf), (unsigned int)(cp
[8] >> 4),
490 (unsigned int)(cp
[7] & 0xf), (unsigned int)(cp
[7] >> 4),
491 (unsigned int)(cp
[6] & 0xf), (unsigned int)(cp
[6] >> 4),
492 (unsigned int)(cp
[5] & 0xf), (unsigned int)(cp
[5] >> 4),
493 (unsigned int)(cp
[4] & 0xf), (unsigned int)(cp
[4] >> 4),
494 (unsigned int)(cp
[3] & 0xf), (unsigned int)(cp
[3] >> 4),
495 (unsigned int)(cp
[2] & 0xf), (unsigned int)(cp
[2] >> 4),
496 (unsigned int)(cp
[1] & 0xf), (unsigned int)(cp
[1] >> 4),
497 (unsigned int)(cp
[0] & 0xf), (unsigned int)(cp
[0] >> 4));
501 request
->type
= T_PTR
;
506 * query_name - generate a query based on class, type and name.
508 static void query_name(struct reslist
*request
)
514 memset(buf
, 0, sizeof(buf
));
517 irc_res_mkquery(request
->queryname
, C_IN
, request
->type
, (unsigned char *)buf
, sizeof(buf
))) > 0)
519 HEADER
*header
= (HEADER
*) buf
;
525 * generate an unique id
526 * NOTE: we don't have to worry about converting this to and from
527 * network byte order, the nameserver does not interpret this value
528 * and returns it unchanged
533 header
->id
= (header
->id
+ lrand48()) & 0xffff;
534 } while (find_id(header
->id
));
536 gettimeofday(&tv
, NULL
);
539 header
->id
= (header
->id
+ k
+ tv
.tv_usec
) & 0xffff;
541 } while (find_id(header
->id
));
542 #endif /* HAVE_LRAND48 */
543 request
->id
= header
->id
;
546 ns
= send_res_msg(buf
, request_len
, request
->sends
);
548 request
->lastns
= ns
;
552 static void resend_query(struct reslist
*request
)
554 switch (request
->type
)
557 do_query_number(NULL
, &request
->addr
, request
);
563 do_query_name(NULL
, request
->name
, request
, request
->type
);
571 * check_question - check if the reply really belongs to the
572 * name we queried (to guard against late replies from previous
573 * queries with the same id).
575 static int check_question(struct reslist
*request
, HEADER
* header
, char *buf
, char *eob
)
577 char hostbuf
[IRCD_RES_HOSTLEN
+ 1]; /* working buffer */
578 unsigned char *current
; /* current position in buf */
579 int n
; /* temp count */
581 current
= (unsigned char *)buf
+ sizeof(HEADER
);
582 if (header
->qdcount
!= 1)
584 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
, hostbuf
,
588 if (strcasecmp(hostbuf
, request
->queryname
))
594 * proc_answer - process name server reply
596 static int proc_answer(struct reslist
*request
, HEADER
* header
, char *buf
, char *eob
)
598 char hostbuf
[IRCD_RES_HOSTLEN
+ 100]; /* working buffer */
599 unsigned char *current
; /* current position in buf */
600 int query_class
; /* answer class */
601 int type
; /* answer type */
602 int n
; /* temp count */
604 struct sockaddr_in
*v4
; /* conversion */
606 struct sockaddr_in6
*v6
;
608 current
= (unsigned char *)buf
+ sizeof(HEADER
);
610 for (; header
->qdcount
> 0; --header
->qdcount
)
612 if ((n
= irc_dn_skipname(current
, (unsigned char *)eob
)) < 0)
615 current
+= (size_t) n
+ QFIXEDSZ
;
619 * process each answer sent to us blech.
621 while (header
->ancount
> 0 && (char *)current
< eob
)
625 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
, hostbuf
,
638 * no more answers left
643 hostbuf
[IRCD_RES_HOSTLEN
] = '\0';
645 /* With Address arithmetic you have to be very anal
646 * this code was not working on alpha due to that
647 * (spotted by rodder/jailbird/dianora)
649 current
+= (size_t) n
;
651 if (!(((char *)current
+ ANSWER_FIXED_SIZE
) < eob
))
654 type
= irc_ns_get16(current
);
655 current
+= TYPE_SIZE
;
657 query_class
= irc_ns_get16(current
);
658 current
+= CLASS_SIZE
;
660 request
->ttl
= irc_ns_get32(current
);
663 rd_length
= irc_ns_get16(current
);
664 current
+= RDLENGTH_SIZE
;
667 * Wait to set request->type until we verify this structure
672 if (request
->type
!= T_A
)
676 * check for invalid rd_length or too many addresses
678 if (rd_length
!= sizeof(struct in_addr
))
680 v4
= (struct sockaddr_in
*)&request
->addr
;
681 SET_SS_LEN(&request
->addr
, sizeof(struct sockaddr_in
));
682 v4
->sin_family
= AF_INET
;
683 memcpy(&v4
->sin_addr
, current
, sizeof(struct in_addr
));
688 if (request
->type
!= T_AAAA
)
690 if (rd_length
!= sizeof(struct in6_addr
))
692 SET_SS_LEN(&request
->addr
, sizeof(struct sockaddr_in6
));
693 v6
= (struct sockaddr_in6
*)&request
->addr
;
694 v6
->sin6_family
= AF_INET6
;
695 memcpy(&v6
->sin6_addr
, current
, sizeof(struct in6_addr
));
700 if (request
->type
!= T_PTR
)
702 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
,
703 hostbuf
, sizeof(hostbuf
));
705 return (0); /* broken message */
707 return (0); /* no more answers left */
709 rb_strlcpy(request
->name
, hostbuf
, IRCD_RES_HOSTLEN
+ 1);
714 /* real answer will follow */
715 current
+= rd_length
;
719 /* XXX I'd rather just throw away the entire bogus thing
720 * but its possible its just a broken nameserver with still
721 * valid answers. But lets do some rudimentary logging for now...
723 ilog(L_MAIN
, "irc_res.c bogus type %d", type
);
732 * res_read_single_reply - read a dns reply from the nameserver and process it.
733 * Return value: 1 if a packet was read, 0 otherwise
735 static int res_read_single_reply(rb_fde_t
*F
, void *data
)
737 char buf
[sizeof(HEADER
) + MAXPACKET
]
738 /* Sparc and alpha need 16bit-alignment for accessing header->id
739 * (which is uint16_t). Because of the header = (HEADER*) buf;
740 * lateron, this is neeeded. --FaUl
742 #if defined(__sparc__) || defined(__alpha__)
743 __attribute__ ((aligned(16)))
747 struct reslist
*request
= NULL
;
748 struct DNSReply
*reply
= NULL
;
751 socklen_t len
= sizeof(struct rb_sockaddr_storage
);
752 struct rb_sockaddr_storage lsin
;
754 rc
= recvfrom(rb_get_fd(F
), buf
, sizeof(buf
), 0, (struct sockaddr
*)&lsin
, &len
);
757 if (rc
== 0 || rc
== -1)
761 if (rc
<= (int)(sizeof(HEADER
)))
765 * convert DNS reply reader from Network byte order to CPU byte order.
767 header
= (HEADER
*) buf
;
768 header
->ancount
= ntohs(header
->ancount
);
769 header
->qdcount
= ntohs(header
->qdcount
);
770 header
->nscount
= ntohs(header
->nscount
);
771 header
->arcount
= ntohs(header
->arcount
);
774 * response for an id which we have already received an answer for
775 * just ignore this response.
777 if (0 == (request
= find_id(header
->id
)))
781 * check against possibly fake replies
783 if (!res_ourserver(&lsin
))
786 if (!check_question(request
, header
, buf
, buf
+ rc
))
789 if ((header
->rcode
!= NO_ERRORS
) || (header
->ancount
== 0))
791 if (NXDOMAIN
== header
->rcode
)
793 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
794 rem_request(request
);
799 * If a bad error was returned, we stop here and dont send
800 * send any more (no retries granted).
802 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
803 rem_request(request
);
808 * If this fails there was an error decoding the received packet,
811 answer_count
= proc_answer(request
, header
, buf
, buf
+ rc
);
815 if (request
->type
== T_PTR
)
817 if (request
->name
== NULL
)
820 * got a PTR response with no name, something bogus is happening
821 * don't bother trying again, the client address doesn't resolve
823 (*request
->query
->callback
) (request
->query
->ptr
, reply
);
824 rem_request(request
);
829 * Lookup the 'authoritative' name that we were given for the
834 if (request
->addr
.ss_family
== AF_INET6
)
835 gethost_byname_type(request
->name
, request
->query
, T_AAAA
);
838 gethost_byname_type(request
->name
, request
->query
, T_A
);
839 rem_request(request
);
844 * got a name and address response, client resolved
846 reply
= make_dnsreply(request
);
847 (*request
->query
->callback
) (request
->query
->ptr
, reply
);
849 rem_request(request
);
854 /* couldn't decode, give up -- jilles */
855 (*request
->query
->callback
) (request
->query
->ptr
, NULL
);
856 rem_request(request
);
861 static void res_readreply(rb_fde_t
*F
, void *data
)
863 while (res_read_single_reply(F
, data
))
865 rb_setselect(F
, RB_SELECT_READ
, res_readreply
, NULL
);
868 static struct DNSReply
*make_dnsreply(struct reslist
*request
)
871 s_assert(request
!= 0);
873 cp
= (struct DNSReply
*)rb_malloc(sizeof(struct DNSReply
));
875 cp
->h_name
= request
->name
;
876 memcpy(&cp
->addr
, &request
->addr
, sizeof(cp
->addr
));
880 void report_dns_servers(struct Client
*source_p
)
885 for (i
= 0; i
< irc_nscount
; i
++)
887 if (!rb_inet_ntop_sock((struct sockaddr
*)&(irc_nsaddr_list
[i
]),
888 ipaddr
, sizeof ipaddr
))
889 rb_strlcpy(ipaddr
, "?", sizeof ipaddr
);
890 sendto_one_numeric(source_p
, RPL_STATSDEBUG
,
891 "A %s %d", ipaddr
, ns_timeout_count
[i
]);