2 * A rewrite of Darren Reed's original res.c As there is nothing
3 * left of Darren's 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 * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
11 * added callbacks and reference counting of returned hostents.
12 * --Bleep (Thomas Helvey <tomh@inxpress.net>)
14 * This was all needlessly complicated for irc. Simplified. No more hostent
15 * All we really care about is the IP -> hostname mappings. Thats all.
17 * Apr 28, 2003 --cryogen and Dianora
20 * @brief IRC resolver functions.
21 * @version $Id: ircd_res.c,v 1.23 2005/06/27 13:25:51 entrope Exp $
25 #include "ircd_alloc.h"
27 #include "ircd_osdep.h"
28 #include "ircd_reply.h"
29 #include "ircd_string.h"
30 #include "ircd_snprintf.h"
33 #include "fileio.h" /* for fbopen / fbclose / fbputs */
41 #include "ircd_reslib.h"
43 /* #include <assert.h> -- Now using assert in ircd_log.h */
46 #include <sys/socket.h>
50 #error this code needs to be able to address individual octets
53 /** IPv4 resolver UDP socket. */
54 static struct Socket res_socket_v4
;
55 /** IPv6 resolver UDP socket. */
56 static struct Socket res_socket_v6
;
57 /** Next DNS lookup timeout. */
58 static struct Timer res_timeout
;
59 /** Check for whether the resolver has been initialized yet. */
60 #define resolver_started() (request_list.next != NULL)
62 /** Maximum DNS packet length.
63 * RFC says 512, but we add extra for expanded names.
65 #define MAXPACKET 1024
66 #define AR_TTL 600 /**< TTL in seconds for dns cache entries */
68 /* RFC 1104/1105 wasn't very helpful about what these fields
69 * should be named, so for now, we'll just name them this way.
70 * we probably should look at what named calls them or something.
72 /** Size of TYPE field of a DNS RR header. */
73 #define TYPE_SIZE (size_t)2
74 /** Size of CLASS field of a DNS RR header. */
75 #define CLASS_SIZE (size_t)2
76 /** Size of TTL field of a DNS RR header. */
77 #define TTL_SIZE (size_t)4
78 /** Size of RDLENGTH field of a DNS RR header. */
79 #define RDLENGTH_SIZE (size_t)2
80 /** Size of fixed-format part of a DNS RR header. */
81 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
83 /** Current request state. */
86 REQ_IDLE
, /**< We're doing not much at all. */
87 REQ_PTR
, /**< Looking up a PTR. */
88 REQ_A
, /**< Looking up an A, possibly because AAAA failed. */
89 REQ_AAAA
, /**< Looking up an AAAA. */
90 REQ_CNAME
, /**< We got a CNAME in response, we better get a real answer next. */
91 REQ_INT
/**< ip6.arpa failed, falling back to ip6.int. */
94 /** Doubly linked list node. */
97 struct dlink
*prev
; /**< Previous element in list. */
98 struct dlink
*next
; /**< Next element in list. */
101 /** A single resolver request.
102 * (Do not be fooled by the "list" in the name.)
106 struct dlink node
; /**< Doubly linked list node. */
107 int id
; /**< Request ID (from request header). */
108 int sent
; /**< Number of requests sent. */
109 request_state state
; /**< State the resolver machine is in. */
110 char type
; /**< Current request type. */
111 char retries
; /**< Retry counter. */
112 char sends
; /**< Number of sends (>1 means resent). */
113 char resend
; /**< Send flag; 0 == don't resend. */
114 time_t sentat
; /**< Timestamp we last sent this request. */
115 time_t timeout
; /**< When this request times out. */
116 struct irc_in_addr addr
; /**< Address for this request. */
117 char *name
; /**< Hostname for this request. */
118 dns_callback_f callback
; /**< Callback function on completion. */
119 void *callback_ctx
; /**< Context pointer for callback. */
122 /** Base of request list. */
123 static struct dlink request_list
;
125 static void rem_request(struct reslist
*request
);
126 static struct reslist
*make_request(dns_callback_f callback
, void *ctx
);
127 static void do_query_name(dns_callback_f callback
, void *ctx
,
128 const char* name
, struct reslist
*request
, int);
129 static void do_query_number(dns_callback_f callback
, void *ctx
,
130 const struct irc_in_addr
*,
131 struct reslist
*request
);
132 static void query_name(const char *name
, int query_class
, int query_type
,
133 struct reslist
*request
);
134 static int send_res_msg(const char *buf
, int len
, int count
);
135 static void resend_query(struct reslist
*request
);
136 static int proc_answer(struct reslist
*request
, HEADER
*header
, char *, char *);
137 static struct reslist
*find_id(int id
);
138 static void res_readreply(struct Event
*ev
);
139 static void timeout_resolver(struct Event
*notused
);
141 extern struct irc_sockaddr irc_nsaddr_list
[IRCD_MAXNS
];
142 extern int irc_nscount
;
143 extern char irc_domain
[HOSTLEN
];
145 /** Check whether \a inp is a nameserver we use.
146 * @param[in] inp Nameserver address.
147 * @return Non-zero if we trust \a inp; zero if not.
150 res_ourserver(const struct irc_sockaddr
*inp
)
154 for (ns
= 0; ns
< irc_nscount
; ns
++)
155 if (!irc_in_addr_cmp(&inp
->addr
, &irc_nsaddr_list
[ns
].addr
)
156 && inp
->port
== irc_nsaddr_list
[ns
].port
)
162 /** Start (or re-start) resolver.
163 * This means read resolv.conf, initialize the list of pending
164 * requests, open the resolver socket and initialize its timeout.
167 restart_resolver(void)
171 if (!request_list
.next
)
172 request_list
.next
= request_list
.prev
= &request_list
;
174 if (!s_active(&res_socket_v4
))
176 int fd
= os_socket(&VirtualHost_v4
, SOCK_DGRAM
, "Resolver UDPv4 socket");
178 socket_add(&res_socket_v4
, res_readreply
, NULL
,
179 SS_DATAGRAM
, SOCK_EVENT_READABLE
, fd
);
182 if (!s_active(&res_socket_v6
))
184 int fd
= os_socket(&VirtualHost_v6
, SOCK_DGRAM
, "Resolver UDPv6 socket");
186 socket_add(&res_socket_v6
, res_readreply
, NULL
,
187 SS_DATAGRAM
, SOCK_EVENT_READABLE
, fd
);
190 if (s_active(&res_socket_v4
) || s_active(&res_socket_v6
))
191 timer_init(&res_timeout
);
194 /** Append local domain to hostname if needed.
195 * If \a hname does not contain any '.'s, append #irc_domain to it.
196 * @param[in,out] hname Hostname to check.
197 * @param[in] size Length of \a hname buffer.
200 add_local_domain(char* hname
, size_t size
)
202 /* try to fix up unqualified names
204 if (strchr(hname
, '.') == NULL
)
208 size_t len
= strlen(hname
);
210 if ((strlen(irc_domain
) + len
+ 2) < size
)
213 strcpy(hname
+ len
, irc_domain
);
219 /** Add a node to a doubly linked list.
220 * @param[in,out] node Node to add to list.
221 * @param[in,out] next Add \a node before this one.
224 add_dlink(struct dlink
*node
, struct dlink
*next
)
226 node
->prev
= next
->prev
;
228 node
->prev
->next
= node
;
229 node
->next
->prev
= node
;
232 /** Remove a request from the list and free it.
233 * @param[in] request Node to free.
236 rem_request(struct reslist
*request
)
238 /* remove from dlist */
239 request
->node
.prev
->next
= request
->node
.next
;
240 request
->node
.next
->prev
= request
->node
.prev
;
242 MyFree(request
->name
);
246 /** Create a DNS request record for the server.
247 * @param[in] query Callback information for caller.
248 * @return Newly allocated and linked-in reslist.
250 static struct reslist
*
251 make_request(dns_callback_f callback
, void *ctx
)
253 struct reslist
*request
;
255 if (!resolver_started())
258 request
= (struct reslist
*)MyMalloc(sizeof(struct reslist
));
259 memset(request
, 0, sizeof(struct reslist
));
261 request
->state
= REQ_IDLE
;
262 request
->sentat
= CurrentTime
;
263 request
->retries
= feature_int(FEAT_IRCD_RES_RETRIES
);
265 request
->timeout
= feature_int(FEAT_IRCD_RES_TIMEOUT
);
266 memset(&request
->addr
, 0, sizeof(request
->addr
));
267 request
->callback
= callback
;
268 request
->callback_ctx
= ctx
;
270 add_dlink(&request
->node
, &request_list
);
274 /** Make sure that a timeout event will happen by the given time.
275 * @param[in] when Latest time for timeout to run.
278 check_resolver_timeout(time_t when
)
280 if (when
> CurrentTime
+ AR_TTL
)
281 when
= CurrentTime
+ AR_TTL
;
282 /* TODO after 2.10.12: Rewrite the timer API because there should be
283 * no need for clients to know this kind of implementation detail. */
284 if (when
> t_expire(&res_timeout
))
286 else if (t_onqueue(&res_timeout
) && !(res_timeout
.t_header
.gh_flags
& GEN_MARKED
))
287 timer_chg(&res_timeout
, TT_ABSOLUTE
, when
);
289 timer_add(&res_timeout
, timeout_resolver
, NULL
, TT_ABSOLUTE
, when
);
292 /** Drop pending DNS lookups which have timed out.
293 * @param[in] ev Timer event data (ignored).
296 timeout_resolver(struct Event
*ev
)
298 struct dlink
*ptr
, *next_ptr
;
299 struct reslist
*request
;
300 time_t next_time
= 0;
303 if (ev_type(ev
) != ET_EXPIRE
)
306 for (ptr
= request_list
.next
; ptr
!= &request_list
; ptr
= next_ptr
)
308 next_ptr
= ptr
->next
;
309 request
= (struct reslist
*)ptr
;
310 timeout
= request
->sentat
+ request
->timeout
;
312 if (CurrentTime
>= timeout
)
314 if (--request
->retries
<= 0)
316 Debug((DEBUG_DNS
, "Request %p out of retries; destroying", request
));
317 (*request
->callback
)(request
->callback_ctx
, NULL
, NULL
);
318 rem_request(request
);
323 request
->sentat
= CurrentTime
;
324 request
->timeout
+= request
->timeout
;
325 resend_query(request
);
329 if ((next_time
== 0) || timeout
< next_time
)
335 if (next_time
<= CurrentTime
)
336 next_time
= CurrentTime
+ AR_TTL
;
337 check_resolver_timeout(next_time
);
340 /** Drop queries that are associated with a particular pointer.
341 * This is used to clean up lookups for clients or conf blocks
343 * @param[in] vptr User callback pointer to search for.
346 delete_resolver_queries(const void *vptr
)
348 struct dlink
*ptr
, *next_ptr
;
349 struct reslist
*request
;
351 if (request_list
.next
) {
352 for (ptr
= request_list
.next
; ptr
!= &request_list
; ptr
= next_ptr
)
354 next_ptr
= ptr
->next
;
355 request
= (struct reslist
*)ptr
;
356 if (vptr
== request
->callback_ctx
) {
357 Debug((DEBUG_DNS
, "Removing request %p with vptr %p", request
, vptr
));
358 rem_request(request
);
364 /** Send a message to all of our nameservers.
365 * @param[in] msg Message to send.
366 * @param[in] len Length of message.
367 * @param[in] rcount Maximum number of servers to ask.
368 * @return Number of servers that were successfully asked.
371 send_res_msg(const char *msg
, int len
, int rcount
)
375 int max_queries
= IRCD_MIN(irc_nscount
, rcount
);
377 /* RES_PRIMARY option is not implemented
378 * if (res.options & RES_PRIMARY || 0 == max_queries)
380 if (max_queries
== 0)
383 for (i
= 0; i
< max_queries
; i
++) {
384 int fd
= irc_in_addr_is_ipv4(&irc_nsaddr_list
[i
].addr
) ? s_fd(&res_socket_v4
) : s_fd(&res_socket_v6
);
385 if (os_sendto_nonb(fd
, msg
, len
, NULL
, 0, &irc_nsaddr_list
[i
]) == IO_SUCCESS
)
392 /** Find a DNS request by ID.
393 * @param[in] id Identifier to find.
394 * @return Matching DNS request, or NULL if none are found.
396 static struct reslist
*
400 struct reslist
*request
;
402 for (ptr
= request_list
.next
; ptr
!= &request_list
; ptr
= ptr
->next
)
404 request
= (struct reslist
*)ptr
;
406 if (request
->id
== id
) {
407 Debug((DEBUG_DNS
, "find_id(%d) -> %p", id
, request
));
412 Debug((DEBUG_DNS
, "find_id(%d) -> NULL", id
));
416 /** Try to look up address for a hostname, trying IPv6 (T_AAAA) first.
417 * @param[in] name Hostname to look up.
418 * @param[in] query Callback information.
421 gethost_byname(const char *name
, dns_callback_f callback
, void *ctx
)
423 do_query_name(callback
, ctx
, name
, NULL
, T_AAAA
);
426 /** Try to look up hostname for an address.
427 * @param[in] addr Address to look up.
428 * @param[in] query Callback information.
431 gethost_byaddr(const struct irc_in_addr
*addr
, dns_callback_f callback
, void *ctx
)
433 do_query_number(callback
, ctx
, addr
, NULL
);
436 /** Send a query to look up the address for a name.
437 * @param[in] query Callback information.
438 * @param[in] name Hostname to look up.
439 * @param[in] request DNS lookup structure (may be NULL).
440 * @param[in] type Preferred request type.
443 do_query_name(dns_callback_f callback
, void *ctx
, const char *name
,
444 struct reslist
*request
, int type
)
446 char host_name
[HOSTLEN
+ 1];
448 ircd_strncpy(host_name
, name
, HOSTLEN
);
449 add_local_domain(host_name
, HOSTLEN
);
453 request
= make_request(callback
, ctx
);
454 DupString(request
->name
, host_name
);
457 request
->state
= REQ_AAAA
;
460 request
->state
= REQ_A
;
463 request
->type
= type
;
464 Debug((DEBUG_DNS
, "Requesting DNS %s %s as %p", (request
->state
== REQ_AAAA
? "AAAA" : "A"), host_name
, request
));
465 query_name(host_name
, C_IN
, type
, request
);
468 /** Send a query to look up the name for an address.
469 * @param[in] query Callback information.
470 * @param[in] addr Address to look up.
471 * @param[in] request DNS lookup structure (may be NULL).
474 do_query_number(dns_callback_f callback
, void *ctx
, const struct irc_in_addr
*addr
,
475 struct reslist
*request
)
478 const unsigned char *cp
;
480 if (irc_in_addr_is_ipv4(addr
))
482 cp
= (const unsigned char*)&addr
->in6_16
[6];
483 ircd_snprintf(NULL
, ipbuf
, sizeof(ipbuf
), "%u.%u.%u.%u.in-addr.arpa.",
484 (unsigned int)(cp
[3]), (unsigned int)(cp
[2]),
485 (unsigned int)(cp
[1]), (unsigned int)(cp
[0]));
491 if (request
!= NULL
&& request
->state
== REQ_INT
)
496 cp
= (const unsigned char *)&addr
->in6_16
[0];
497 ircd_snprintf(NULL
, ipbuf
, sizeof(ipbuf
),
498 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
499 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.%s.",
500 (unsigned int)(cp
[15]&0xf), (unsigned int)(cp
[15]>>4),
501 (unsigned int)(cp
[14]&0xf), (unsigned int)(cp
[14]>>4),
502 (unsigned int)(cp
[13]&0xf), (unsigned int)(cp
[13]>>4),
503 (unsigned int)(cp
[12]&0xf), (unsigned int)(cp
[12]>>4),
504 (unsigned int)(cp
[11]&0xf), (unsigned int)(cp
[11]>>4),
505 (unsigned int)(cp
[10]&0xf), (unsigned int)(cp
[10]>>4),
506 (unsigned int)(cp
[9]&0xf), (unsigned int)(cp
[9]>>4),
507 (unsigned int)(cp
[8]&0xf), (unsigned int)(cp
[8]>>4),
508 (unsigned int)(cp
[7]&0xf), (unsigned int)(cp
[7]>>4),
509 (unsigned int)(cp
[6]&0xf), (unsigned int)(cp
[6]>>4),
510 (unsigned int)(cp
[5]&0xf), (unsigned int)(cp
[5]>>4),
511 (unsigned int)(cp
[4]&0xf), (unsigned int)(cp
[4]>>4),
512 (unsigned int)(cp
[3]&0xf), (unsigned int)(cp
[3]>>4),
513 (unsigned int)(cp
[2]&0xf), (unsigned int)(cp
[2]>>4),
514 (unsigned int)(cp
[1]&0xf), (unsigned int)(cp
[1]>>4),
515 (unsigned int)(cp
[0]&0xf), (unsigned int)(cp
[0]>>4), intarpa
);
519 request
= make_request(callback
, ctx
);
520 request
->state
= REQ_PTR
;
521 request
->type
= T_PTR
;
522 memcpy(&request
->addr
, addr
, sizeof(request
->addr
));
523 request
->name
= (char *)MyMalloc(HOSTLEN
+ 1);
525 Debug((DEBUG_DNS
, "Requesting DNS PTR %s as %p", ipbuf
, request
));
526 query_name(ipbuf
, C_IN
, T_PTR
, request
);
529 /** Generate a query based on class, type and name.
530 * @param[in] name Domain name to look up.
531 * @param[in] query_class Query class (see RFC 1035).
532 * @param[in] type Query type (see RFC 1035).
533 * @param[in] request DNS request structure.
536 query_name(const char *name
, int query_class
, int type
,
537 struct reslist
*request
)
542 memset(buf
, 0, sizeof(buf
));
544 if ((request_len
= irc_res_mkquery(name
, query_class
, type
,
545 (unsigned char *)buf
, sizeof(buf
))) > 0)
547 HEADER
*header
= (HEADER
*)buf
;
550 * generate an unique id
551 * NOTE: we don't have to worry about converting this to and from
552 * network byte order, the nameserver does not interpret this value
553 * and returns it unchanged
557 header
->id
= (header
->id
+ ircrandom()) & 0xffff;
558 } while (find_id(header
->id
));
559 request
->id
= header
->id
;
562 request
->sent
+= send_res_msg(buf
, request_len
, request
->sends
);
563 check_resolver_timeout(request
->sentat
+ request
->timeout
);
567 /** Send a failed DNS lookup request again.
568 * @param[in] request Request to resend.
571 resend_query(struct reslist
*request
)
573 if (request
->resend
== 0)
576 switch(request
->type
)
579 do_query_number(NULL
, NULL
, &request
->addr
, request
);
582 do_query_name(NULL
, NULL
, request
->name
, request
, request
->type
);
585 /* didn't work, try A */
586 if (request
->state
== REQ_AAAA
)
587 do_query_name(NULL
, NULL
, request
->name
, request
, T_A
);
593 /** Process the answer for a lookup request.
594 * @param[in] request DNS request that got an answer.
595 * @param[in] header Header of DNS response.
596 * @param[in] buf DNS response body.
597 * @param[in] eob Pointer to end of DNS response.
598 * @return Number of answers read from \a buf.
601 proc_answer(struct reslist
*request
, HEADER
* header
, char* buf
, char* eob
)
603 char hostbuf
[HOSTLEN
+ 100]; /* working buffer */
604 unsigned char *current
; /* current position in buf */
605 int query_class
; /* answer class */
606 int type
; /* answer type */
607 int n
; /* temp count */
610 current
= (unsigned char *)buf
+ sizeof(HEADER
);
612 for (; header
->qdcount
> 0; --header
->qdcount
)
614 if ((n
= irc_dn_skipname(current
, (unsigned char *)eob
)) < 0)
617 current
+= (size_t) n
+ QFIXEDSZ
;
621 * process each answer sent to us blech.
623 while (header
->ancount
> 0 && (char *)current
< eob
)
627 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
, current
,
628 hostbuf
, sizeof(hostbuf
));
640 * no more answers left
645 hostbuf
[HOSTLEN
] = '\0';
647 /* With Address arithmetic you have to be very anal
648 * this code was not working on alpha due to that
649 * (spotted by rodder/jailbird/dianora)
651 current
+= (size_t) n
;
653 if (!(((char *)current
+ ANSWER_FIXED_SIZE
) < eob
))
656 type
= irc_ns_get16(current
);
657 current
+= TYPE_SIZE
;
659 query_class
= irc_ns_get16(current
);
660 current
+= CLASS_SIZE
;
664 rd_length
= irc_ns_get16(current
);
665 current
+= RDLENGTH_SIZE
;
668 * Wait to set request->type until we verify this structure
673 if (request
->type
!= T_A
)
677 * check for invalid rd_length or too many addresses
679 if (rd_length
!= sizeof(struct in_addr
))
681 memset(&request
->addr
, 0, sizeof(request
->addr
));
682 memcpy(&request
->addr
.in6_16
[6], current
, sizeof(struct in_addr
));
686 if (request
->type
!= T_AAAA
)
688 if (rd_length
!= sizeof(struct irc_in_addr
))
690 memcpy(&request
->addr
, current
, sizeof(struct irc_in_addr
));
694 if (request
->type
!= T_PTR
)
696 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
,
697 current
, hostbuf
, sizeof(hostbuf
));
699 return(0); /* broken message */
701 return(0); /* no more answers left */
703 ircd_strncpy(request
->name
, hostbuf
, HOSTLEN
);
707 case T_CNAME
: /* first check we already haven't started looking
709 if (request
->type
!= T_PTR
)
712 if (request
->state
== REQ_CNAME
)
714 n
= irc_dn_expand((unsigned char *)buf
, (unsigned char *)eob
,
715 current
, hostbuf
, sizeof(hostbuf
));
722 request
->state
= REQ_CNAME
;
723 current
+= rd_length
;
727 /* XXX I'd rather just throw away the entire bogus thing
728 * but its possible its just a broken nameserver with still
729 * valid answers. But lets do some rudimentary logging for now...
731 log_write(LS_RESOLVER
, L_ERROR
, 0, "irc_res.c bogus type %d", type
);
733 if ((char*)current
+ rd_length
>= (char*)current
)
734 current
+= rd_length
;
745 /** Read a DNS reply from the nameserver and process it.
746 * @param[in] ev I/O activity event for resolver socket.
749 res_readreply(struct Event
*ev
)
751 struct irc_sockaddr lsin
;
753 char buf
[sizeof(HEADER
) + MAXPACKET
];
755 struct reslist
*request
= NULL
;
759 assert((ev_socket(ev
) == &res_socket_v4
) || (ev_socket(ev
) == &res_socket_v6
));
760 sock
= ev_socket(ev
);
762 if (IO_SUCCESS
!= os_recvfrom_nonb(s_fd(sock
), buf
, sizeof(buf
), &rc
, &lsin
)
763 || (rc
<= sizeof(HEADER
)))
767 * check against possibly fake replies
769 if (!res_ourserver(&lsin
))
773 * convert DNS reply reader from Network byte order to CPU byte order.
775 header
= (HEADER
*)buf
;
776 header
->ancount
= ntohs(header
->ancount
);
777 header
->qdcount
= ntohs(header
->qdcount
);
778 header
->nscount
= ntohs(header
->nscount
);
779 header
->arcount
= ntohs(header
->arcount
);
782 * response for an id which we have already received an answer for
783 * just ignore this response.
785 if (0 == (request
= find_id(header
->id
)))
788 if ((header
->rcode
!= NO_ERRORS
) || (header
->ancount
== 0))
790 if (SERVFAIL
== header
->rcode
)
791 resend_query(request
);
795 * If we haven't already tried this, and we're looking up AAAA, try A
799 if (request
->state
== REQ_AAAA
&& request
->type
== T_AAAA
)
801 request
->timeout
+= feature_int(FEAT_IRCD_RES_TIMEOUT
);
802 resend_query(request
);
804 else if (request
->type
== T_PTR
&& request
->state
!= REQ_INT
&&
805 !irc_in_addr_is_ipv4(&request
->addr
))
807 request
->state
= REQ_INT
;
808 request
->timeout
+= feature_int(FEAT_IRCD_RES_TIMEOUT
);
809 resend_query(request
);
814 * If a bad error was returned, we stop here and don't send
815 * send any more (no retries granted).
817 Debug((DEBUG_DNS
, "Request %p has bad response (state %d type %d rcode %d)", request
, request
->state
, request
->type
, header
->rcode
));
818 (*request
->callback
)(request
->callback_ctx
, NULL
, NULL
);
819 rem_request(request
);
826 * If this fails there was an error decoding the received packet,
827 * try it again and hope it works the next time.
829 answer_count
= proc_answer(request
, header
, buf
, buf
+ rc
);
833 if (request
->type
== T_PTR
)
835 if (request
->name
== NULL
)
838 * got a PTR response with no name, something bogus is happening
839 * don't bother trying again, the client address doesn't resolve
841 Debug((DEBUG_DNS
, "Request %p PTR had empty name", request
));
842 (*request
->callback
)(request
->callback_ctx
, NULL
, NULL
);
843 rem_request(request
);
848 * Lookup the 'authoritative' name that we were given for the
852 if (!irc_in_addr_is_ipv4(&request
->addr
))
853 do_query_name(request
->callback
, request
->callback_ctx
, request
->name
, NULL
, T_AAAA
);
856 do_query_name(request
->callback
, request
->callback_ctx
, request
->name
, NULL
, T_A
);
857 Debug((DEBUG_DNS
, "Request %p switching to forward resolution", request
));
858 rem_request(request
);
863 * got a name and address response, client resolved
865 (*request
->callback
)(request
->callback_ctx
, &request
->addr
, request
->name
);
866 Debug((DEBUG_DNS
, "Request %p got forward resolution", request
));
867 rem_request(request
);
870 else if (!request
->sent
)
872 /* XXX - we got a response for a query we didn't send with a valid id?
873 * this should never happen, bail here and leave the client unresolved
877 /* XXX don't leak it */
878 Debug((DEBUG_DNS
, "Request %p was unexpected(!)", request
));
879 rem_request(request
);
883 /** Statistics callback to list DNS servers.
884 * @param[in] source_p Client requesting statistics.
885 * @param[in] sd Stats descriptor for request (ignored).
886 * @param[in] param Extra parameter from user (ignored).
889 report_dns_servers(struct Client
*source_p
, const struct StatDesc
*sd
, char *param
)
894 for (i
= 0; i
< irc_nscount
; i
++)
896 ircd_ntoa_r(ipaddr
, &irc_nsaddr_list
[i
].addr
);
897 send_reply(source_p
, RPL_STATSALINE
, ipaddr
);
901 /** Report memory usage to a client.
902 * @param[in] sptr Client requesting information.
903 * @return Total memory used by pending requests.
906 cres_mem(struct Client
* sptr
)
909 struct reslist
*request
;
910 size_t request_mem
= 0;
911 int request_count
= 0;
913 if (request_list
.next
) {
914 for (dlink
= request_list
.next
; dlink
!= &request_list
; dlink
= dlink
->next
) {
915 request
= (struct reslist
*)dlink
;
916 request_mem
+= sizeof(*request
);
918 request_mem
+= strlen(request
->name
) + 1;
923 send_reply(sptr
, SND_EXPLICIT
| RPL_STATSDEBUG
,
924 ":Resolver: requests %d(%d)", request_count
, request_mem
);