1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjlib-util/resolver.h>
21 #include <pjlib-util/errno.h>
22 #include <pj/compat/socket.h>
23 #include <pj/assert.h>
24 #include <pj/ctype.h>
25 #include <pj/except.h>
26 #include <pj/hash.h>
27 #include <pj/ioqueue.h>
28 #include <pj/log.h>
29 #include <pj/os.h>
30 #include <pj/pool.h>
31 #include <pj/pool_buf.h>
32 #include <pj/rand.h>
33 #include <pj/string.h>
34 #include <pj/sock.h>
35 #include <pj/timer.h>
36 
37 
38 #define THIS_FILE	    "resolver.c"
39 
40 
41 /* Check that maximum DNS nameservers is not too large.
42  * This has got todo with the datatype to index the nameserver in the query.
43  */
44 #if PJ_DNS_RESOLVER_MAX_NS > 256
45 #   error "PJ_DNS_RESOLVER_MAX_NS is too large (max=256)"
46 #endif
47 
48 
49 #define RES_HASH_TABLE_SIZE 127		/**< Hash table size (must be 2^n-1 */
50 #define PORT		    53		/**< Default NS port.		    */
51 #define Q_HASH_TABLE_SIZE   127		/**< Query hash table size	    */
52 #define TIMER_SIZE	    127		/**< Initial number of timers.	    */
53 #define MAX_FD		    3		/**< Maximum internal sockets.	    */
54 
55 #define RES_BUF_SZ	    PJ_DNS_RESOLVER_RES_BUF_SIZE
56 #define UDPSZ		    PJ_DNS_RESOLVER_MAX_UDP_SIZE
57 #define TMP_SZ		    PJ_DNS_RESOLVER_TMP_BUF_SIZE
58 
59 
60 /* Nameserver state */
61 enum ns_state
62 {
63     STATE_PROBING,
64     STATE_ACTIVE,
65     STATE_BAD,
66 };
67 
68 static const char *state_names[3] =
69 {
70     "Probing",
71     "Active",
72     "Bad"
73 };
74 
75 
76 /*
77  * Each nameserver entry.
78  * A name server is identified by its socket address (IP and port).
79  * Each NS will have a flag to indicate whether it's properly functioning.
80  */
81 struct nameserver
82 {
83     pj_sockaddr     addr;		/**< Server address.		    */
84 
85     enum ns_state   state;		/**< Nameserver state.		    */
86     pj_time_val	    state_expiry;	/**< Time set next state.	    */
87     pj_time_val	    rt_delay;		/**< Response time.		    */
88 
89 
90     /* For calculating rt_delay: */
91     pj_uint16_t	    q_id;		/**< Query ID.			    */
92     pj_time_val	    sent_time;		/**< Time this query is sent.	    */
93 };
94 
95 
96 /* Child query list head
97  * See comments on pj_dns_async_query below.
98  */
99 struct query_head
100 {
101     PJ_DECL_LIST_MEMBER(pj_dns_async_query);
102 };
103 
104 
105 /* Key to look for outstanding query and/or cached response */
106 struct res_key
107 {
108     pj_uint16_t		     qtype;		    /**< Query type.	    */
109     char		     name[PJ_MAX_HOSTNAME]; /**< Name being queried */
110 };
111 
112 
113 /*
114  * This represents each asynchronous query entry.
115  * This entry will be put in two hash tables, the first one keyed on the DNS
116  * transaction ID to match response with the query, and the second one keyed
117  * on "res_key" structure above to match a new request against outstanding
118  * requests.
119  *
120  * An asynchronous entry may have child entries; child entries are subsequent
121  * queries to the same resource while there is pending query on the same
122  * DNS resource name and type. When a query has child entries, once the
123  * response is received (or error occurs), the response will trigger callback
124  * invocations for all childs entries.
125  *
126  * Note: when application cancels the query, the callback member will be
127  *       set to NULL, but for simplicity, the query will be let running.
128  */
129 struct pj_dns_async_query
130 {
131     PJ_DECL_LIST_MEMBER(pj_dns_async_query);	/**< List member.	    */
132 
133     pj_dns_resolver	*resolver;	/**< The resolver instance.	    */
134     pj_uint16_t		 id;		/**< Transaction ID.		    */
135 
136     unsigned		 transmit_cnt;	/**< Number of transmissions.	    */
137 
138     struct res_key	 key;		/**< Key to index this query.	    */
139     pj_hash_entry_buf	 hbufid;	/**< Hash buffer 1		    */
140     pj_hash_entry_buf	 hbufkey;	/**< Hash buffer 2		    */
141     pj_timer_entry	 timer_entry;	/**< Timer to manage timeouts	    */
142     unsigned		 options;	/**< Query options.		    */
143     void		*user_data;	/**< Application data.		    */
144     pj_dns_callback	*cb;		/**< Callback to be called.	    */
145     struct query_head	 child_head;	/**< Child queries list head.	    */
146 };
147 
148 
149 /* This structure is used to keep cached response entry.
150  * The cache is a hash table keyed on "res_key" structure above.
151  */
152 struct cached_res
153 {
154     PJ_DECL_LIST_MEMBER(struct cached_res);
155 
156     pj_pool_t		    *pool;	    /**< Cache's pool.		    */
157     struct res_key	     key;	    /**< Resource key.		    */
158     pj_hash_entry_buf	     hbuf;	    /**< Hash buffer		    */
159     pj_time_val		     expiry_time;   /**< Expiration time.	    */
160     pj_dns_parsed_packet    *pkt;	    /**< The response packet.	    */
161     unsigned		     ref_cnt;	    /**< Reference counter.	    */
162 };
163 
164 
165 /* Resolver entry */
166 struct pj_dns_resolver
167 {
168     pj_str_t		 name;		/**< Resolver instance name for id. */
169 
170     /* Internals */
171     pj_pool_t		*pool;		/**< Internal pool.		    */
172     pj_grp_lock_t	*grp_lock;	/**< Group lock protection.	    */
173     pj_bool_t		 own_timer;	/**< Do we own timer?		    */
174     pj_timer_heap_t	*timer;		/**< Timer instance.		    */
175     pj_bool_t		 own_ioqueue;	/**< Do we own ioqueue?		    */
176     pj_ioqueue_t	*ioqueue;	/**< Ioqueue instance.		    */
177     char		 tmp_pool[TMP_SZ];/**< Temporary pool buffer.	    */
178 
179     /* Socket */
180     pj_sock_t		 udp_sock;	/**< UDP socket.		    */
181     pj_ioqueue_key_t	*udp_key;	/**< UDP socket ioqueue key.	    */
182     unsigned char	 udp_rx_pkt[UDPSZ];/**< UDP receive buffer.	    */
183     unsigned char	 udp_tx_pkt[UDPSZ];/**< UDP transmit buffer.	    */
184     pj_ioqueue_op_key_t	 udp_op_rx_key;	/**< UDP read operation key.	    */
185     pj_ioqueue_op_key_t	 udp_op_tx_key;	/**< UDP write operation key.	    */
186     pj_sockaddr		 udp_src_addr;	/**< Source address of packet	    */
187     int			 udp_addr_len;	/**< Source address length.	    */
188 
189 #if PJ_HAS_IPV6
190     /* IPv6 socket */
191     pj_sock_t		 udp6_sock;	/**< UDP socket.		    */
192     pj_ioqueue_key_t	*udp6_key;	/**< UDP socket ioqueue key.	    */
193     unsigned char	 udp6_rx_pkt[UDPSZ];/**< UDP receive buffer.	    */
194     //unsigned char	 udp6_tx_pkt[UDPSZ];/**< UDP transmit buffer.	    */
195     pj_ioqueue_op_key_t	 udp6_op_rx_key;/**< UDP read operation key.	    */
196     pj_ioqueue_op_key_t	 udp6_op_tx_key;/**< UDP write operation key.	    */
197     pj_sockaddr		 udp6_src_addr;	/**< Source address of packet	    */
198     int			 udp6_addr_len;	/**< Source address length.	    */
199 #endif
200 
201     /* Settings */
202     pj_dns_settings	 settings;	/**< Resolver settings.		    */
203 
204     /* Nameservers */
205     unsigned		 ns_count;	/**< Number of name servers.	    */
206     struct nameserver	 ns[PJ_DNS_RESOLVER_MAX_NS];	/**< Array of NS.   */
207 
208     /* Last DNS transaction ID used. */
209     pj_uint16_t		 last_id;
210 
211     /* Hash table for cached response */
212     pj_hash_table_t	*hrescache;	/**< Cached response in hash table  */
213 
214     /* Pending asynchronous query, hashed by transaction ID. */
215     pj_hash_table_t	*hquerybyid;
216 
217     /* Pending asynchronous query, hashed by "res_key" */
218     pj_hash_table_t	*hquerybyres;
219 
220     /* Query entries free list */
221     struct query_head	 query_free_nodes;
222 };
223 
224 
225 /* Callback from ioqueue when packet is received */
226 static void on_read_complete(pj_ioqueue_key_t *key,
227                              pj_ioqueue_op_key_t *op_key,
228                              pj_ssize_t bytes_read);
229 
230 /* Callback to be called when query has timed out */
231 static void on_timeout( pj_timer_heap_t *timer_heap,
232 			struct pj_timer_entry *entry);
233 
234 /* Select which nameserver to use */
235 static pj_status_t select_nameservers(pj_dns_resolver *resolver,
236 				      unsigned *count,
237 				      unsigned servers[]);
238 
239 /* Destructor */
240 static void dns_resolver_on_destroy(void *member);
241 
242 /* Close UDP socket */
close_sock(pj_dns_resolver * resv)243 static void close_sock(pj_dns_resolver *resv)
244 {
245     /* Close existing socket */
246     if (resv->udp_key != NULL) {
247 	pj_ioqueue_unregister(resv->udp_key);
248 	resv->udp_key = NULL;
249 	resv->udp_sock = PJ_INVALID_SOCKET;
250     } else if (resv->udp_sock != PJ_INVALID_SOCKET) {
251 	pj_sock_close(resv->udp_sock);
252 	resv->udp_sock = PJ_INVALID_SOCKET;
253     }
254 
255 #if PJ_HAS_IPV6
256     if (resv->udp6_key != NULL) {
257 	pj_ioqueue_unregister(resv->udp6_key);
258 	resv->udp6_key = NULL;
259 	resv->udp6_sock = PJ_INVALID_SOCKET;
260     } else if (resv->udp6_sock != PJ_INVALID_SOCKET) {
261 	pj_sock_close(resv->udp6_sock);
262 	resv->udp6_sock = PJ_INVALID_SOCKET;
263     }
264 #endif
265 }
266 
267 
268 /* Initialize UDP socket */
init_sock(pj_dns_resolver * resv)269 static pj_status_t init_sock(pj_dns_resolver *resv)
270 {
271     pj_ioqueue_callback socket_cb;
272     pj_sockaddr bound_addr;
273     pj_ssize_t rx_pkt_size;
274     pj_status_t status;
275 
276     /* Create the UDP socket */
277     status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
278     if (status != PJ_SUCCESS)
279 	return status;
280 
281     /* Bind to any address/port */
282     status = pj_sock_bind_in(resv->udp_sock, 0, 0);
283     if (status != PJ_SUCCESS)
284 	return status;
285 
286     /* Register to ioqueue */
287     pj_bzero(&socket_cb, sizeof(socket_cb));
288     socket_cb.on_read_complete = &on_read_complete;
289     status = pj_ioqueue_register_sock2(resv->pool, resv->ioqueue,
290 				       resv->udp_sock, resv->grp_lock,
291 				       resv, &socket_cb, &resv->udp_key);
292     if (status != PJ_SUCCESS)
293 	return status;
294 
295     pj_ioqueue_op_key_init(&resv->udp_op_rx_key, sizeof(resv->udp_op_rx_key));
296     pj_ioqueue_op_key_init(&resv->udp_op_tx_key, sizeof(resv->udp_op_tx_key));
297 
298     /* Start asynchronous read to the UDP socket */
299     rx_pkt_size = sizeof(resv->udp_rx_pkt);
300     resv->udp_addr_len = sizeof(resv->udp_src_addr);
301     status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_rx_key,
302 				 resv->udp_rx_pkt, &rx_pkt_size,
303 				 PJ_IOQUEUE_ALWAYS_ASYNC,
304 				 &resv->udp_src_addr, &resv->udp_addr_len);
305     if (status != PJ_EPENDING)
306 	return status;
307 
308 
309 #if PJ_HAS_IPV6
310     /* Also setup IPv6 socket */
311 
312     /* Create the UDP socket */
313     status = pj_sock_socket(pj_AF_INET6(), pj_SOCK_DGRAM(), 0,
314 			    &resv->udp6_sock);
315     if (status != PJ_SUCCESS) {
316 	/* Skip IPv6 socket on system without IPv6 (see ticket #1953) */
317 	if (status == PJ_STATUS_FROM_OS(OSERR_EAFNOSUPPORT)) {
318 	    PJ_LOG(3,(resv->name.ptr,
319 		      "System does not support IPv6, resolver will "
320 		      "ignore any IPv6 nameservers"));
321 	    return PJ_SUCCESS;
322 	}
323 	return status;
324     }
325 
326     /* Bind to any address/port */
327     pj_sockaddr_init(pj_AF_INET6(), &bound_addr, NULL, 0);
328     status = pj_sock_bind(resv->udp6_sock, &bound_addr,
329 			  pj_sockaddr_get_len(&bound_addr));
330     if (status != PJ_SUCCESS)
331 	return status;
332 
333     /* Register to ioqueue */
334     pj_bzero(&socket_cb, sizeof(socket_cb));
335     socket_cb.on_read_complete = &on_read_complete;
336     status = pj_ioqueue_register_sock2(resv->pool, resv->ioqueue,
337 				       resv->udp6_sock, resv->grp_lock,
338 				       resv, &socket_cb, &resv->udp6_key);
339     if (status != PJ_SUCCESS)
340 	return status;
341 
342     pj_ioqueue_op_key_init(&resv->udp6_op_rx_key,
343 			   sizeof(resv->udp6_op_rx_key));
344     pj_ioqueue_op_key_init(&resv->udp6_op_tx_key,
345 			   sizeof(resv->udp6_op_tx_key));
346 
347     /* Start asynchronous read to the UDP socket */
348     rx_pkt_size = sizeof(resv->udp6_rx_pkt);
349     resv->udp6_addr_len = sizeof(resv->udp6_src_addr);
350     status = pj_ioqueue_recvfrom(resv->udp6_key, &resv->udp6_op_rx_key,
351 				 resv->udp6_rx_pkt, &rx_pkt_size,
352 				 PJ_IOQUEUE_ALWAYS_ASYNC,
353 				 &resv->udp6_src_addr, &resv->udp6_addr_len);
354     if (status != PJ_EPENDING)
355 	return status;
356 #else
357     PJ_UNUSED_ARG(bound_addr);
358 #endif
359 
360     return PJ_SUCCESS;
361 }
362 
363 
364 /* Initialize DNS settings with default values */
pj_dns_settings_default(pj_dns_settings * s)365 PJ_DEF(void) pj_dns_settings_default(pj_dns_settings *s)
366 {
367     pj_bzero(s, sizeof(pj_dns_settings));
368     s->qretr_delay = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY;
369     s->qretr_count = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT;
370     s->cache_max_ttl = PJ_DNS_RESOLVER_MAX_TTL;
371     s->good_ns_ttl = PJ_DNS_RESOLVER_GOOD_NS_TTL;
372     s->bad_ns_ttl = PJ_DNS_RESOLVER_BAD_NS_TTL;
373 }
374 
375 
376 /*
377  * Create the resolver.
378  */
pj_dns_resolver_create(pj_pool_factory * pf,const char * name,unsigned options,pj_timer_heap_t * timer,pj_ioqueue_t * ioqueue,pj_dns_resolver ** p_resolver)379 PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
380 					    const char *name,
381 					    unsigned options,
382 					    pj_timer_heap_t *timer,
383 					    pj_ioqueue_t *ioqueue,
384 					    pj_dns_resolver **p_resolver)
385 {
386     pj_pool_t *pool;
387     pj_dns_resolver *resv;
388     pj_status_t status;
389 
390     /* Sanity check */
391     PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL);
392 
393     if (name == NULL)
394 	name = THIS_FILE;
395 
396     /* Create and initialize resolver instance */
397     pool = pj_pool_create(pf, name, 4000, 4000, NULL);
398     if (!pool)
399 	return PJ_ENOMEM;
400 
401     /* Create pool and name */
402     resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver);
403     resv->pool = pool;
404     resv->udp_sock = PJ_INVALID_SOCKET;
405     pj_strdup2_with_null(pool, &resv->name, name);
406 
407     /* Create group lock */
408     status = pj_grp_lock_create_w_handler(pool, NULL, resv,
409 					  &dns_resolver_on_destroy,
410 					  &resv->grp_lock);
411     if (status != PJ_SUCCESS)
412 	goto on_error;
413 
414     pj_grp_lock_add_ref(resv->grp_lock);
415 
416     /* Timer, ioqueue, and settings */
417     resv->timer = timer;
418     resv->ioqueue = ioqueue;
419     resv->last_id = 1;
420 
421     pj_dns_settings_default(&resv->settings);
422     resv->settings.options = options;
423 
424     /* Create the timer heap if one is not specified */
425     if (resv->timer == NULL) {
426 	resv->own_timer = PJ_TRUE;
427 	status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer);
428 	if (status != PJ_SUCCESS)
429 	    goto on_error;
430     }
431 
432     /* Create the ioqueue if one is not specified */
433     if (resv->ioqueue == NULL) {
434 	resv->own_ioqueue = PJ_TRUE;
435 	status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue);
436 	if (status != PJ_SUCCESS)
437 	    goto on_error;
438     }
439 
440     /* Response cache hash table */
441     resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE);
442 
443     /* Query hash table and free list. */
444     resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
445     resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
446     pj_list_init(&resv->query_free_nodes);
447 
448     /* Initialize the UDP socket */
449     status = init_sock(resv);
450     if (status != PJ_SUCCESS)
451 	goto on_error;
452 
453     /* Looks like everything is okay */
454     *p_resolver = resv;
455     return PJ_SUCCESS;
456 
457 on_error:
458     pj_dns_resolver_destroy(resv, PJ_FALSE);
459     return status;
460 }
461 
462 
dns_resolver_on_destroy(void * member)463 void dns_resolver_on_destroy(void *member)
464 {
465     pj_dns_resolver *resolver = (pj_dns_resolver*)member;
466     pj_pool_safe_release(&resolver->pool);
467 }
468 
469 
470 /*
471  * Destroy DNS resolver instance.
472  */
pj_dns_resolver_destroy(pj_dns_resolver * resolver,pj_bool_t notify)473 PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver,
474 					     pj_bool_t notify)
475 {
476     pj_hash_iterator_t it_buf, *it;
477     PJ_ASSERT_RETURN(resolver, PJ_EINVAL);
478 
479     if (notify) {
480 	/*
481 	 * Notify pending queries if requested.
482 	 */
483 	it = pj_hash_first(resolver->hquerybyid, &it_buf);
484 	while (it) {
485 	    pj_dns_async_query *q = (pj_dns_async_query *)
486 	    			    pj_hash_this(resolver->hquerybyid, it);
487 	    pj_dns_async_query *cq;
488 	    if (q->cb)
489 		(*q->cb)(q->user_data, PJ_ECANCELLED, NULL);
490 
491 	    cq = q->child_head.next;
492 	    while (cq != (pj_dns_async_query*)&q->child_head) {
493 		if (cq->cb)
494 		    (*cq->cb)(cq->user_data, PJ_ECANCELLED, NULL);
495 		cq = cq->next;
496 	    }
497 	    it = pj_hash_next(resolver->hquerybyid, it);
498 	}
499     }
500 
501     /* Destroy cached entries */
502     it = pj_hash_first(resolver->hrescache, &it_buf);
503     while (it) {
504 	struct cached_res *cache;
505 
506 	cache = (struct cached_res*) pj_hash_this(resolver->hrescache, it);
507 	pj_hash_set(NULL, resolver->hrescache, &cache->key,
508 		    sizeof(cache->key), 0, NULL);
509 	pj_pool_release(cache->pool);
510 
511 	it = pj_hash_first(resolver->hrescache, &it_buf);
512     }
513 
514     if (resolver->own_timer && resolver->timer) {
515 	pj_timer_heap_destroy(resolver->timer);
516 	resolver->timer = NULL;
517     }
518 
519     close_sock(resolver);
520 
521     if (resolver->own_ioqueue && resolver->ioqueue) {
522 	pj_ioqueue_destroy(resolver->ioqueue);
523 	resolver->ioqueue = NULL;
524     }
525 
526     pj_grp_lock_dec_ref(resolver->grp_lock);
527 
528     return PJ_SUCCESS;
529 }
530 
531 
532 
533 /*
534  * Configure name servers for the DNS resolver.
535  */
pj_dns_resolver_set_ns(pj_dns_resolver * resolver,unsigned count,const pj_str_t servers[],const pj_uint16_t ports[])536 PJ_DEF(pj_status_t) pj_dns_resolver_set_ns( pj_dns_resolver *resolver,
537 					    unsigned count,
538 					    const pj_str_t servers[],
539 					    const pj_uint16_t ports[])
540 {
541     unsigned i;
542     pj_time_val now;
543     pj_status_t status;
544 
545     PJ_ASSERT_RETURN(resolver && count && servers, PJ_EINVAL);
546     PJ_ASSERT_RETURN(count < PJ_DNS_RESOLVER_MAX_NS, PJ_EINVAL);
547 
548     pj_grp_lock_acquire(resolver->grp_lock);
549 
550     if (count > PJ_DNS_RESOLVER_MAX_NS)
551 	count = PJ_DNS_RESOLVER_MAX_NS;
552 
553     resolver->ns_count = 0;
554     pj_bzero(resolver->ns, sizeof(resolver->ns));
555 
556     pj_gettimeofday(&now);
557 
558     for (i=0; i<count; ++i) {
559 	struct nameserver *ns = &resolver->ns[i];
560 
561 	status = pj_sockaddr_init(pj_AF_INET(), &ns->addr, &servers[i],
562 				  (pj_uint16_t)(ports ? ports[i] : PORT));
563 	if (status != PJ_SUCCESS)
564 	    status = pj_sockaddr_init(pj_AF_INET6(), &ns->addr, &servers[i],
565 				      (pj_uint16_t)(ports ? ports[i] : PORT));
566 	if (status != PJ_SUCCESS) {
567 	    pj_grp_lock_release(resolver->grp_lock);
568 	    return PJLIB_UTIL_EDNSINNSADDR;
569 	}
570 
571 	ns->state = STATE_ACTIVE;
572 	ns->state_expiry = now;
573 	ns->rt_delay.sec = 10;
574     }
575 
576     resolver->ns_count = count;
577 
578     pj_grp_lock_release(resolver->grp_lock);
579     return PJ_SUCCESS;
580 }
581 
582 
583 
584 /*
585  * Modify the resolver settings.
586  */
pj_dns_resolver_set_settings(pj_dns_resolver * resolver,const pj_dns_settings * st)587 PJ_DEF(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
588 						 const pj_dns_settings *st)
589 {
590     PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
591 
592     pj_grp_lock_acquire(resolver->grp_lock);
593     pj_memcpy(&resolver->settings, st, sizeof(*st));
594     pj_grp_lock_release(resolver->grp_lock);
595     return PJ_SUCCESS;
596 }
597 
598 
599 /*
600  * Get the resolver current settings.
601  */
pj_dns_resolver_get_settings(pj_dns_resolver * resolver,pj_dns_settings * st)602 PJ_DEF(pj_status_t) pj_dns_resolver_get_settings( pj_dns_resolver *resolver,
603 						  pj_dns_settings *st)
604 {
605     PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
606 
607     pj_grp_lock_acquire(resolver->grp_lock);
608     pj_memcpy(st, &resolver->settings, sizeof(*st));
609     pj_grp_lock_release(resolver->grp_lock);
610     return PJ_SUCCESS;
611 }
612 
613 
614 /*
615  * Poll for events from the resolver.
616  */
pj_dns_resolver_handle_events(pj_dns_resolver * resolver,const pj_time_val * timeout)617 PJ_DEF(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
618 					   const pj_time_val *timeout)
619 {
620     PJ_ASSERT_ON_FAIL(resolver, return);
621 
622     pj_grp_lock_acquire(resolver->grp_lock);
623     pj_timer_heap_poll(resolver->timer, NULL);
624     pj_grp_lock_release(resolver->grp_lock);
625 
626     pj_ioqueue_poll(resolver->ioqueue, timeout);
627 }
628 
629 
630 /* Get one query node from the free node, if any, or allocate
631  * a new one.
632  */
alloc_qnode(pj_dns_resolver * resolver,unsigned options,void * user_data,pj_dns_callback * cb)633 static pj_dns_async_query *alloc_qnode(pj_dns_resolver *resolver,
634 				       unsigned options,
635 				       void *user_data,
636 				       pj_dns_callback *cb)
637 {
638     pj_dns_async_query *q;
639 
640     /* Merge query options with resolver options */
641     options |= resolver->settings.options;
642 
643     if (!pj_list_empty(&resolver->query_free_nodes)) {
644 	q = resolver->query_free_nodes.next;
645 	pj_list_erase(q);
646 	pj_bzero(q, sizeof(*q));
647     } else {
648 	q = PJ_POOL_ZALLOC_T(resolver->pool, pj_dns_async_query);
649     }
650 
651     /* Init query */
652     q->resolver = resolver;
653     q->options = options;
654     q->user_data = user_data;
655     q->cb = cb;
656     pj_list_init(&q->child_head);
657 
658     return q;
659 }
660 
661 
662 /*
663  * Transmit query.
664  */
transmit_query(pj_dns_resolver * resolver,pj_dns_async_query * q)665 static pj_status_t transmit_query(pj_dns_resolver *resolver,
666 				  pj_dns_async_query *q)
667 {
668     unsigned pkt_size;
669     unsigned i, server_cnt, send_cnt;
670     unsigned servers[PJ_DNS_RESOLVER_MAX_NS];
671     pj_time_val now;
672     pj_str_t name;
673     pj_time_val delay;
674     pj_status_t status;
675 
676     /* Select which nameserver(s) to send requests to. */
677     server_cnt = PJ_ARRAY_SIZE(servers);
678     status = select_nameservers(resolver, &server_cnt, servers);
679     if (status != PJ_SUCCESS) {
680 	return status;
681     }
682 
683     if (server_cnt == 0) {
684 	return PJLIB_UTIL_EDNSNOWORKINGNS;
685     }
686 
687     /* Start retransmit/timeout timer for the query */
688     pj_assert(q->timer_entry.id == 0);
689     q->timer_entry.id = 1;
690     q->timer_entry.user_data = q;
691     q->timer_entry.cb = &on_timeout;
692 
693     delay.sec = 0;
694     delay.msec = resolver->settings.qretr_delay;
695     pj_time_val_normalize(&delay);
696     status = pj_timer_heap_schedule_w_grp_lock(resolver->timer,
697 					       &q->timer_entry,
698 					       &delay, 1,
699 					       resolver->grp_lock);
700     if (status != PJ_SUCCESS) {
701 	return status;
702     }
703 
704     /* Check if the socket is available for sending */
705     if (pj_ioqueue_is_pending(resolver->udp_key, &resolver->udp_op_tx_key)
706 #if PJ_HAS_IPV6
707 	|| (resolver->udp6_key &&
708 	    pj_ioqueue_is_pending(resolver->udp6_key,
709 				  &resolver->udp6_op_tx_key))
710 #endif
711 	)
712     {
713 	++q->transmit_cnt;
714 	PJ_LOG(4,(resolver->name.ptr,
715 		  "Socket busy in transmitting DNS %s query for %s%s",
716 		  pj_dns_get_type_name(q->key.qtype),
717 		  q->key.name,
718 		  (q->transmit_cnt < resolver->settings.qretr_count?
719 		   ", will try again later":"")));
720 	return PJ_SUCCESS;
721     }
722 
723     /* Create DNS query packet */
724     pkt_size = sizeof(resolver->udp_tx_pkt);
725     name = pj_str(q->key.name);
726     status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size,
727 			       q->id, q->key.qtype, &name);
728     if (status != PJ_SUCCESS) {
729 	pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
730 	return status;
731     }
732 
733     /* Get current time. */
734     pj_gettimeofday(&now);
735 
736     /* Send the packet to name servers */
737     send_cnt = 0;
738     for (i=0; i<server_cnt; ++i) {
739         char addr[PJ_INET6_ADDRSTRLEN];
740 	pj_ssize_t sent  = (pj_ssize_t) pkt_size;
741 	struct nameserver *ns = &resolver->ns[servers[i]];
742 
743 	if (ns->addr.addr.sa_family == pj_AF_INET()) {
744 	    status = pj_ioqueue_sendto(resolver->udp_key,
745 				       &resolver->udp_op_tx_key,
746 				       resolver->udp_tx_pkt, &sent, 0,
747 				       &ns->addr,
748 				       pj_sockaddr_get_len(&ns->addr));
749 	    if (status == PJ_SUCCESS || status == PJ_EPENDING)
750 		send_cnt++;
751 	}
752 #if PJ_HAS_IPV6
753 	else if (resolver->udp6_key) {
754 	    status = pj_ioqueue_sendto(resolver->udp6_key,
755 				       &resolver->udp6_op_tx_key,
756 				       resolver->udp_tx_pkt, &sent, 0,
757 				       &ns->addr,
758 				       pj_sockaddr_get_len(&ns->addr));
759 	    if (status == PJ_SUCCESS || status == PJ_EPENDING)
760 		send_cnt++;
761 	}
762 #endif
763 	else {
764 	    continue;
765 	}
766 
767 	PJ_PERROR(4,(resolver->name.ptr, status,
768 		  "%s %d bytes to NS %d (%s:%d): DNS %s query for %s",
769 		  (q->transmit_cnt==0? "Transmitting":"Re-transmitting"),
770 		  (int)pkt_size, servers[i],
771 		  pj_sockaddr_print(&ns->addr, addr, sizeof(addr), 2),
772 		  pj_sockaddr_get_port(&ns->addr),
773 		  pj_dns_get_type_name(q->key.qtype),
774 		  q->key.name));
775 
776 	if (ns->q_id == 0) {
777 	    ns->q_id = q->id;
778 	    ns->sent_time = now;
779 	}
780     }
781 
782     if (send_cnt == 0) {
783         pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
784 	return PJLIB_UTIL_EDNSNOWORKINGNS;
785     }
786 
787     ++q->transmit_cnt;
788 
789     return PJ_SUCCESS;
790 }
791 
792 
793 /*
794  * Initialize resource key for hash table lookup.
795  */
init_res_key(struct res_key * key,int type,const pj_str_t * name)796 static void init_res_key(struct res_key *key, int type, const pj_str_t *name)
797 {
798     unsigned i;
799     pj_size_t len;
800     char *dst = key->name;
801     const char *src = name->ptr;
802 
803     pj_bzero(key, sizeof(struct res_key));
804     key->qtype = (pj_uint16_t)type;
805 
806     len = name->slen;
807     if (len > PJ_MAX_HOSTNAME) len = PJ_MAX_HOSTNAME;
808 
809     /* Copy key, in lowercase */
810     for (i=0; i<len; ++i) {
811 	*dst++ = (char)pj_tolower(*src++);
812     }
813 }
814 
815 
816 /* Allocate new cache entry */
alloc_entry(pj_dns_resolver * resolver)817 static struct cached_res *alloc_entry(pj_dns_resolver *resolver)
818 {
819     pj_pool_t *pool;
820     struct cached_res *cache;
821 
822     pool = pj_pool_create(resolver->pool->factory, "dnscache",
823 			  RES_BUF_SZ, 256, NULL);
824     cache = PJ_POOL_ZALLOC_T(pool, struct cached_res);
825     cache->pool = pool;
826     cache->ref_cnt = 1;
827 
828     return cache;
829 }
830 
831 /* Re-allocate cache entry, to free cached packet */
reset_entry(struct cached_res ** p_cached)832 static void reset_entry(struct cached_res **p_cached)
833 {
834     pj_pool_t *pool;
835     struct cached_res *cache = *p_cached;
836     unsigned ref_cnt;
837 
838     pool = cache->pool;
839     ref_cnt = cache->ref_cnt;
840 
841     pj_pool_reset(pool);
842 
843     cache = PJ_POOL_ZALLOC_T(pool, struct cached_res);
844     cache->pool = pool;
845     cache->ref_cnt = ref_cnt;
846     *p_cached = cache;
847 }
848 
849 /* Put unused/expired cached entry to the free list */
free_entry(pj_dns_resolver * resolver,struct cached_res * cache)850 static void free_entry(pj_dns_resolver *resolver, struct cached_res *cache)
851 {
852     PJ_UNUSED_ARG(resolver);
853     pj_pool_release(cache->pool);
854 }
855 
856 
857 /*
858  * Create and start asynchronous DNS query for a single resource.
859  */
pj_dns_resolver_start_query(pj_dns_resolver * resolver,const pj_str_t * name,int type,unsigned options,pj_dns_callback * cb,void * user_data,pj_dns_async_query ** p_query)860 PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
861 						 const pj_str_t *name,
862 						 int type,
863 						 unsigned options,
864 						 pj_dns_callback *cb,
865 						 void *user_data,
866 						 pj_dns_async_query **p_query)
867 {
868     pj_time_val now;
869     struct res_key key;
870     struct cached_res *cache;
871     pj_dns_async_query *q, *p_q = NULL;
872     pj_uint32_t hval;
873     pj_status_t status = PJ_SUCCESS;
874 
875     /* Validate arguments */
876     PJ_ASSERT_RETURN(resolver && name && type, PJ_EINVAL);
877 
878     /* Check name is not too long. */
879     PJ_ASSERT_RETURN(name->slen>0 && name->slen < PJ_MAX_HOSTNAME,
880 		     PJ_ENAMETOOLONG);
881 
882     /* Check type */
883     PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL);
884 
885     /* Build resource key for looking up hash tables */
886     init_res_key(&key, type, name);
887 
888     /* Start working with the resolver */
889     pj_grp_lock_acquire(resolver->grp_lock);
890 
891     /* Get current time. */
892     pj_gettimeofday(&now);
893 
894     /* First, check if we have cached response for the specified name/type,
895      * and the cached entry has not expired.
896      */
897     hval = 0;
898     cache = (struct cached_res *) pj_hash_get(resolver->hrescache, &key,
899     					      sizeof(key), &hval);
900     if (cache) {
901 	/* We've found a cached entry. */
902 
903 	/* Check for expiration */
904 	if (PJ_TIME_VAL_GT(cache->expiry_time, now)) {
905 
906 	    /* Log */
907 	    PJ_LOG(5,(resolver->name.ptr,
908 		      "Picked up DNS %s record for %.*s from cache, ttl=%d",
909 		      pj_dns_get_type_name(type),
910 		      (int)name->slen, name->ptr,
911 		      (int)(cache->expiry_time.sec - now.sec)));
912 
913 	    /* Map DNS Rcode in the response into PJLIB status name space */
914 	    status = PJ_DNS_GET_RCODE(cache->pkt->hdr.flags);
915 	    status = PJ_STATUS_FROM_DNS_RCODE(status);
916 
917 	    /* Workaround for deadlock problem. Need to increment the cache's
918 	     * ref counter first before releasing mutex, so the cache won't be
919 	     * destroyed by other thread while in callback.
920 	     */
921 	    cache->ref_cnt++;
922 	    pj_grp_lock_release(resolver->grp_lock);
923 
924 	    /* This cached response is still valid. Just return this
925 	     * response to caller.
926 	     */
927 	    if (cb) {
928 		(*cb)(user_data, status, cache->pkt);
929 	    }
930 
931 	    /* Done. No host resolution is necessary */
932 	    pj_grp_lock_acquire(resolver->grp_lock);
933 
934 	    /* Decrement the ref counter. Also check if it is time to free
935 	     * the cache (as it has been expired).
936 	     */
937 	    cache->ref_cnt--;
938 	    if (cache->ref_cnt <= 0)
939 		free_entry(resolver, cache);
940 
941 	    /* Must return PJ_SUCCESS */
942 	    status = PJ_SUCCESS;
943 
944 	    /*
945 	     * We cannot write to *p_query after calling cb because what
946 	     * p_query points to may have been freed by cb.
947              * Refer to ticket #1974.
948 	     */
949 	    pj_grp_lock_release(resolver->grp_lock);
950 	    return status;
951 	}
952 
953 	/* At this point, we have a cached entry, but this entry has expired.
954 	 * Remove this entry from the cached list.
955 	 */
956 	pj_hash_set(NULL, resolver->hrescache, &key, sizeof(key), 0, NULL);
957 
958 	/* Also free the cache, if it is not being used (by callback). */
959 	cache->ref_cnt--;
960 	if (cache->ref_cnt <= 0)
961 	    free_entry(resolver, cache);
962 
963 	/* Must continue with creating a query now */
964     }
965 
966     /* Next, check if we have pending query on the same resource */
967     q = (pj_dns_async_query *) pj_hash_get(resolver->hquerybyres, &key,
968     					   sizeof(key), NULL);
969     if (q) {
970 	/* Yes, there's another pending query to the same key.
971 	 * Just create a new child query and add this query to
972 	 * pending query's child queries.
973 	 */
974 	pj_dns_async_query *nq;
975 
976 	nq = alloc_qnode(resolver, options, user_data, cb);
977 	pj_list_push_back(&q->child_head, nq);
978 
979 	/* Done. This child query will be notified once the "parent"
980 	 * query completes.
981 	 */
982 	p_q = nq;
983 	status = PJ_SUCCESS;
984 	goto on_return;
985     }
986 
987     /* There's no pending query to the same key, initiate a new one. */
988     q = alloc_qnode(resolver, options, user_data, cb);
989 
990     /* Save the ID and key */
991     /* TODO: dnsext-forgery-resilient: randomize id for security */
992     q->id = resolver->last_id++;
993     if (resolver->last_id == 0)
994 	resolver->last_id = 1;
995     pj_memcpy(&q->key, &key, sizeof(struct res_key));
996 
997     /* Send the query */
998     status = transmit_query(resolver, q);
999     if (status != PJ_SUCCESS) {
1000 	pj_list_push_back(&resolver->query_free_nodes, q);
1001 	goto on_return;
1002     }
1003 
1004     /* Add query entry to the hash tables */
1005     pj_hash_set_np(resolver->hquerybyid, &q->id, sizeof(q->id),
1006 		   0, q->hbufid, q);
1007     pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key),
1008 		   0, q->hbufkey, q);
1009 
1010     p_q = q;
1011 
1012 on_return:
1013     if (p_query)
1014 	*p_query = p_q;
1015 
1016     pj_grp_lock_release(resolver->grp_lock);
1017     return status;
1018 }
1019 
1020 
1021 /*
1022  * Cancel a pending query.
1023  */
pj_dns_resolver_cancel_query(pj_dns_async_query * query,pj_bool_t notify)1024 PJ_DEF(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
1025 						 pj_bool_t notify)
1026 {
1027     pj_dns_callback *cb;
1028 
1029     PJ_ASSERT_RETURN(query, PJ_EINVAL);
1030 
1031     pj_grp_lock_acquire(query->resolver->grp_lock);
1032 
1033     if (query->timer_entry.id == 1) {
1034 	pj_timer_heap_cancel_if_active(query->resolver->timer,
1035 				       &query->timer_entry, 0);
1036     }
1037 
1038     cb = query->cb;
1039     query->cb = NULL;
1040 
1041     if (notify)
1042 	(*cb)(query->user_data, PJ_ECANCELLED, NULL);
1043 
1044     pj_grp_lock_release(query->resolver->grp_lock);
1045     return PJ_SUCCESS;
1046 }
1047 
1048 
1049 /*
1050  * DNS response containing A packet.
1051  */
pj_dns_parse_a_response(const pj_dns_parsed_packet * pkt,pj_dns_a_record * rec)1052 PJ_DEF(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
1053 					    pj_dns_a_record *rec)
1054 {
1055     enum { MAX_SEARCH = 20 };
1056     pj_str_t hostname, alias = {NULL, 0}, *resname;
1057     pj_size_t bufstart = 0;
1058     pj_size_t bufleft = sizeof(rec->buf_);
1059     unsigned i, ansidx, search_cnt=0;
1060 
1061     PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL);
1062 
1063     /* Init the record */
1064     pj_bzero(rec, sizeof(pj_dns_a_record));
1065 
1066     /* Return error if there's error in the packet. */
1067     if (PJ_DNS_GET_RCODE(pkt->hdr.flags))
1068 	return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags));
1069 
1070     /* Return error if there's no query section */
1071     if (pkt->hdr.qdcount == 0)
1072 	return PJLIB_UTIL_EDNSINANSWER;
1073 
1074     /* Return error if there's no answer */
1075     if (pkt->hdr.anscount == 0)
1076 	return PJLIB_UTIL_EDNSNOANSWERREC;
1077 
1078     /* Get the hostname from the query. */
1079     hostname = pkt->q[0].name;
1080 
1081     /* Copy hostname to the record */
1082     if (hostname.slen > (int)bufleft) {
1083 	return PJ_ENAMETOOLONG;
1084     }
1085 
1086     pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen);
1087     rec->name.ptr = &rec->buf_[bufstart];
1088     rec->name.slen = hostname.slen;
1089 
1090     bufstart += hostname.slen;
1091     bufleft -= hostname.slen;
1092 
1093     /* Find the first RR which name matches the hostname */
1094     for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) {
1095 	if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0)
1096 	    break;
1097     }
1098 
1099     if (ansidx == pkt->hdr.anscount)
1100 	return PJLIB_UTIL_EDNSNOANSWERREC;
1101 
1102     resname = &hostname;
1103 
1104     /* Keep following CNAME records. */
1105     while (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME &&
1106 	   search_cnt++ < MAX_SEARCH)
1107     {
1108 	resname = &pkt->ans[ansidx].rdata.cname.name;
1109 
1110 	if (!alias.slen)
1111 	    alias = *resname;
1112 
1113 	for (i=0; i < pkt->hdr.anscount; ++i) {
1114 	    if (pj_stricmp(resname, &pkt->ans[i].name)==0) {
1115 		break;
1116 	    }
1117 	}
1118 
1119 	if (i==pkt->hdr.anscount)
1120 	    return PJLIB_UTIL_EDNSNOANSWERREC;
1121 
1122 	ansidx = i;
1123     }
1124 
1125     if (search_cnt >= MAX_SEARCH)
1126 	return PJLIB_UTIL_EDNSINANSWER;
1127 
1128     if (pkt->ans[ansidx].type != PJ_DNS_TYPE_A)
1129 	return PJLIB_UTIL_EDNSINANSWER;
1130 
1131     /* Copy alias to the record, if present. */
1132     if (alias.slen) {
1133 	if (alias.slen > (int)bufleft)
1134 	    return PJ_ENAMETOOLONG;
1135 
1136 	pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen);
1137 	rec->alias.ptr = &rec->buf_[bufstart];
1138 	rec->alias.slen = alias.slen;
1139 
1140 	bufstart += alias.slen;
1141 	bufleft -= alias.slen;
1142     }
1143 
1144     /* Get the IP addresses. */
1145     for (i=0; i < pkt->hdr.anscount; ++i) {
1146 	if (pkt->ans[i].type == PJ_DNS_TYPE_A &&
1147 	    pj_stricmp(&pkt->ans[i].name, resname)==0 &&
1148 	    rec->addr_count < PJ_DNS_MAX_IP_IN_A_REC)
1149 	{
1150 	    rec->addr[rec->addr_count++].s_addr =
1151 		pkt->ans[i].rdata.a.ip_addr.s_addr;
1152 	}
1153     }
1154 
1155     if (rec->addr_count == 0)
1156 	return PJLIB_UTIL_EDNSNOANSWERREC;
1157 
1158     return PJ_SUCCESS;
1159 }
1160 
1161 
1162 /*
1163  * DNS response containing A and/or AAAA packet.
1164  */
pj_dns_parse_addr_response(const pj_dns_parsed_packet * pkt,pj_dns_addr_record * rec)1165 PJ_DEF(pj_status_t) pj_dns_parse_addr_response(
1166 					    const pj_dns_parsed_packet *pkt,
1167 					    pj_dns_addr_record *rec)
1168 {
1169     enum { MAX_SEARCH = 20 };
1170     pj_str_t hostname, alias = {NULL, 0}, *resname;
1171     pj_size_t bufstart = 0;
1172     pj_size_t bufleft;
1173     unsigned i, ansidx, cnt=0;
1174 
1175     PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL);
1176 
1177     /* Init the record */
1178     pj_bzero(rec, sizeof(*rec));
1179 
1180     bufleft = sizeof(rec->buf_);
1181 
1182     /* Return error if there's error in the packet. */
1183     if (PJ_DNS_GET_RCODE(pkt->hdr.flags))
1184 	return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags));
1185 
1186     /* Return error if there's no query section */
1187     if (pkt->hdr.qdcount == 0)
1188 	return PJLIB_UTIL_EDNSINANSWER;
1189 
1190     /* Return error if there's no answer */
1191     if (pkt->hdr.anscount == 0)
1192 	return PJLIB_UTIL_EDNSNOANSWERREC;
1193 
1194     /* Get the hostname from the query. */
1195     hostname = pkt->q[0].name;
1196 
1197     /* Copy hostname to the record */
1198     if (hostname.slen > (int)bufleft) {
1199 	return PJ_ENAMETOOLONG;
1200     }
1201 
1202     pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen);
1203     rec->name.ptr = &rec->buf_[bufstart];
1204     rec->name.slen = hostname.slen;
1205 
1206     bufstart += hostname.slen;
1207     bufleft -= hostname.slen;
1208 
1209     /* Find the first RR which name matches the hostname. */
1210     for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) {
1211 	if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0)
1212 	    break;
1213     }
1214 
1215     if (ansidx == pkt->hdr.anscount)
1216 	return PJLIB_UTIL_EDNSNOANSWERREC;
1217 
1218     resname = &hostname;
1219 
1220     /* Keep following CNAME records. */
1221     while (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME &&
1222 	   cnt++ < MAX_SEARCH)
1223     {
1224 	resname = &pkt->ans[ansidx].rdata.cname.name;
1225 
1226 	if (!alias.slen)
1227 	    alias = *resname;
1228 
1229 	for (i=0; i < pkt->hdr.anscount; ++i) {
1230 	    if (pj_stricmp(resname, &pkt->ans[i].name)==0)
1231 		break;
1232 	}
1233 
1234 	if (i==pkt->hdr.anscount)
1235 	    return PJLIB_UTIL_EDNSNOANSWERREC;
1236 
1237 	ansidx = i;
1238     }
1239 
1240     if (cnt >= MAX_SEARCH)
1241 	return PJLIB_UTIL_EDNSINANSWER;
1242 
1243     if (pkt->ans[ansidx].type != PJ_DNS_TYPE_A &&
1244 	pkt->ans[ansidx].type != PJ_DNS_TYPE_AAAA)
1245     {
1246 	return PJLIB_UTIL_EDNSINANSWER;
1247     }
1248 
1249     /* Copy alias to the record, if present. */
1250     if (alias.slen) {
1251 	if (alias.slen > (int)bufleft)
1252 	    return PJ_ENAMETOOLONG;
1253 
1254 	pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen);
1255 	rec->alias.ptr = &rec->buf_[bufstart];
1256 	rec->alias.slen = alias.slen;
1257 
1258 	bufstart += alias.slen;
1259 	bufleft -= alias.slen;
1260     }
1261 
1262     /* Get the IP addresses. */
1263     cnt = 0;
1264     for (i=0; i < pkt->hdr.anscount && cnt < PJ_DNS_MAX_IP_IN_A_REC ; ++i) {
1265 	if ((pkt->ans[i].type == PJ_DNS_TYPE_A ||
1266 	     pkt->ans[i].type == PJ_DNS_TYPE_AAAA) &&
1267 	    pj_stricmp(&pkt->ans[i].name, resname)==0)
1268 	{
1269 	    if (pkt->ans[i].type == PJ_DNS_TYPE_A) {
1270 		rec->addr[cnt].af = pj_AF_INET();
1271 		rec->addr[cnt].ip.v4 = pkt->ans[i].rdata.a.ip_addr;
1272 	    } else {
1273 		rec->addr[cnt].af = pj_AF_INET6();
1274 		rec->addr[cnt].ip.v6 = pkt->ans[i].rdata.aaaa.ip_addr;
1275 	    }
1276 	    ++cnt;
1277 	}
1278     }
1279     rec->addr_count = cnt;
1280 
1281     if (cnt == 0)
1282 	return PJLIB_UTIL_EDNSNOANSWERREC;
1283 
1284     return PJ_SUCCESS;
1285 }
1286 
1287 
1288 /* Set nameserver state */
set_nameserver_state(pj_dns_resolver * resolver,unsigned index,enum ns_state state,const pj_time_val * now)1289 static void set_nameserver_state(pj_dns_resolver *resolver,
1290 				 unsigned index,
1291 				 enum ns_state state,
1292 				 const pj_time_val *now)
1293 {
1294     struct nameserver *ns = &resolver->ns[index];
1295     enum ns_state old_state = ns->state;
1296     char addr[PJ_INET6_ADDRSTRLEN];
1297 
1298     ns->state = state;
1299     ns->state_expiry = *now;
1300 
1301     if (state == STATE_PROBING)
1302 	ns->state_expiry.sec += ((resolver->settings.qretr_count + 2) *
1303 				 resolver->settings.qretr_delay) / 1000;
1304     else if (state == STATE_ACTIVE)
1305 	ns->state_expiry.sec += resolver->settings.good_ns_ttl;
1306     else
1307 	ns->state_expiry.sec += resolver->settings.bad_ns_ttl;
1308 
1309     PJ_LOG(5, (resolver->name.ptr, "Nameserver %s:%d state changed %s --> %s",
1310 	       pj_sockaddr_print(&ns->addr, addr, sizeof(addr), 2),
1311 	       pj_sockaddr_get_port(&ns->addr),
1312 	       state_names[old_state], state_names[state]));
1313 }
1314 
1315 
1316 /* Select which nameserver(s) to use. Note this may return multiple
1317  * name servers. The algorithm to select which nameservers to be
1318  * sent the request to is as follows:
1319  *  - select the first nameserver that is known to be good for the
1320  *    last PJ_DNS_RESOLVER_GOOD_NS_TTL interval.
1321  *  - for all NSes, if last_known_good >= PJ_DNS_RESOLVER_GOOD_NS_TTL,
1322  *    include the NS to re-check again that the server is still good,
1323  *    unless the NS is known to be bad in the last PJ_DNS_RESOLVER_BAD_NS_TTL
1324  *    interval.
1325  *  - for all NSes, if last_known_bad >= PJ_DNS_RESOLVER_BAD_NS_TTL,
1326  *    also include the NS to re-check again that the server is still bad.
1327  */
select_nameservers(pj_dns_resolver * resolver,unsigned * count,unsigned servers[])1328 static pj_status_t select_nameservers(pj_dns_resolver *resolver,
1329 				      unsigned *count,
1330 				      unsigned servers[])
1331 {
1332     unsigned i, max_count=*count;
1333     int min;
1334     pj_time_val now;
1335 
1336     pj_assert(max_count > 0);
1337 
1338     *count = 0;
1339     servers[0] = 0xFFFF;
1340 
1341     /* Check that nameservers are configured. */
1342     if (resolver->ns_count == 0)
1343 	return PJLIB_UTIL_EDNSNONS;
1344 
1345     pj_gettimeofday(&now);
1346 
1347     /* Select one Active nameserver with best response time. */
1348     for (min=-1, i=0; i<resolver->ns_count; ++i) {
1349 	struct nameserver *ns = &resolver->ns[i];
1350 
1351 	if (ns->state != STATE_ACTIVE)
1352 	    continue;
1353 
1354 	if (min == -1)
1355 	    min = i;
1356 	else if (PJ_TIME_VAL_LT(ns->rt_delay, resolver->ns[min].rt_delay))
1357 	    min = i;
1358     }
1359     if (min != -1) {
1360 	servers[0] = min;
1361 	++(*count);
1362     }
1363 
1364     /* Scan nameservers. */
1365     for (i=0; i<resolver->ns_count && *count < max_count; ++i) {
1366 	struct nameserver *ns = &resolver->ns[i];
1367 
1368 	if (PJ_TIME_VAL_LTE(ns->state_expiry, now)) {
1369 	    if (ns->state == STATE_PROBING) {
1370 		set_nameserver_state(resolver, i, STATE_BAD, &now);
1371 	    } else {
1372 		set_nameserver_state(resolver, i, STATE_PROBING, &now);
1373 		if ((int)i != min) {
1374 		    servers[*count] = i;
1375 		    ++(*count);
1376 		}
1377 	    }
1378 	} else if (ns->state == STATE_PROBING && (int)i != min) {
1379 	    servers[*count] = i;
1380 	    ++(*count);
1381 	}
1382     }
1383 
1384     return PJ_SUCCESS;
1385 }
1386 
1387 
1388 /* Update name server status */
report_nameserver_status(pj_dns_resolver * resolver,const pj_sockaddr * ns_addr,const pj_dns_parsed_packet * pkt)1389 static void report_nameserver_status(pj_dns_resolver *resolver,
1390 				     const pj_sockaddr *ns_addr,
1391 				     const pj_dns_parsed_packet *pkt)
1392 {
1393     unsigned i;
1394     int rcode;
1395     pj_uint32_t q_id;
1396     pj_time_val now;
1397     pj_bool_t is_good;
1398 
1399     /* Only mark nameserver as "bad" if it returned non-parseable response or
1400      * it returned the following status codes
1401      */
1402     if (pkt) {
1403 	rcode = PJ_DNS_GET_RCODE(pkt->hdr.flags);
1404 	q_id = pkt->hdr.id;
1405     } else {
1406 	rcode = 0;
1407 	q_id = (pj_uint32_t)-1;
1408     }
1409 
1410     /* Some nameserver is reported to respond with PJ_DNS_RCODE_SERVFAIL for
1411      * missing AAAA record, and the standard doesn't seem to specify that
1412      * SERVFAIL should prevent the server to be contacted again for other
1413      * queries. So let's not mark nameserver as bad for SERVFAIL response.
1414      */
1415     if (!pkt || /* rcode == PJ_DNS_RCODE_SERVFAIL || */
1416 	        rcode == PJ_DNS_RCODE_REFUSED ||
1417 	        rcode == PJ_DNS_RCODE_NOTAUTH)
1418     {
1419 	is_good = PJ_FALSE;
1420     } else {
1421 	is_good = PJ_TRUE;
1422     }
1423 
1424 
1425     /* Mark time */
1426     pj_gettimeofday(&now);
1427 
1428     /* Recheck all nameservers. */
1429     for (i=0; i<resolver->ns_count; ++i) {
1430 	struct nameserver *ns = &resolver->ns[i];
1431 
1432 	if (pj_sockaddr_cmp(&ns->addr, ns_addr) == 0) {
1433 	    if (q_id == ns->q_id) {
1434 		/* Calculate response time */
1435 		pj_time_val rt = now;
1436 		PJ_TIME_VAL_SUB(rt, ns->sent_time);
1437 		ns->rt_delay = rt;
1438 		ns->q_id = 0;
1439 	    }
1440 	    set_nameserver_state(resolver, i,
1441 				 (is_good ? STATE_ACTIVE : STATE_BAD), &now);
1442 	    break;
1443 	}
1444     }
1445 }
1446 
1447 
1448 /* Update response cache */
update_res_cache(pj_dns_resolver * resolver,const struct res_key * key,pj_status_t status,pj_bool_t set_expiry,const pj_dns_parsed_packet * pkt)1449 static void update_res_cache(pj_dns_resolver *resolver,
1450 			     const struct res_key *key,
1451 			     pj_status_t status,
1452 			     pj_bool_t set_expiry,
1453 			     const pj_dns_parsed_packet *pkt)
1454 {
1455     struct cached_res *cache;
1456     pj_uint32_t hval=0, ttl;
1457 
1458     /* If status is unsuccessful, clear the same entry from the cache */
1459     if (status != PJ_SUCCESS) {
1460 	cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1461 						  sizeof(*key), &hval);
1462 	/* Remove the entry before releasing its pool (see ticket #1710) */
1463 	pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1464 
1465 	/* Free the entry */
1466 	if (cache && --cache->ref_cnt <= 0)
1467 	    free_entry(resolver, cache);
1468     }
1469 
1470 
1471     /* Calculate expiration time. */
1472     if (set_expiry) {
1473 	if (pkt->hdr.anscount == 0 || status != PJ_SUCCESS) {
1474 	    /* If we don't have answers for the name, then give a different
1475 	     * ttl value (note: PJ_DNS_RESOLVER_INVALID_TTL may be zero,
1476 	     * which means that invalid names won't be kept in the cache)
1477 	     */
1478 	    ttl = PJ_DNS_RESOLVER_INVALID_TTL;
1479 
1480 	} else {
1481 	    /* Otherwise get the minimum TTL from the answers */
1482 	    unsigned i;
1483 	    ttl = 0xFFFFFFFF;
1484 	    for (i=0; i<pkt->hdr.anscount; ++i) {
1485 		if (pkt->ans[i].ttl < ttl)
1486 		    ttl = pkt->ans[i].ttl;
1487 	    }
1488 	}
1489     } else {
1490 	ttl = 0xFFFFFFFF;
1491     }
1492 
1493     /* Apply maximum TTL */
1494     if (ttl > resolver->settings.cache_max_ttl)
1495 	ttl = resolver->settings.cache_max_ttl;
1496 
1497     /* Get a cache response entry */
1498     cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1499     					      sizeof(*key), &hval);
1500 
1501     /* If TTL is zero, clear the same entry in the hash table */
1502     if (ttl == 0) {
1503 	/* Remove the entry before releasing its pool (see ticket #1710) */
1504 	pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1505 
1506 	/* Free the entry */
1507 	if (cache && --cache->ref_cnt <= 0)
1508 	    free_entry(resolver, cache);
1509 	return;
1510     }
1511 
1512     if (cache == NULL) {
1513 	cache = alloc_entry(resolver);
1514     } else {
1515 	/* Remove the entry before resetting its pool (see ticket #1710) */
1516 	pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1517 
1518 	if (cache->ref_cnt > 1) {
1519 	    /* When cache entry is being used by callback (to app),
1520 	     * just decrement ref_cnt so it will be freed after
1521 	     * the callback returns and allocate new entry.
1522 	     */
1523 	    cache->ref_cnt--;
1524 	    cache = alloc_entry(resolver);
1525 	} else {
1526 	    /* Reset cache to avoid bloated cache pool */
1527 	    reset_entry(&cache);
1528 	}
1529     }
1530 
1531     /* Duplicate the packet.
1532      * We don't need to keep the NS and AR sections from the packet,
1533      * so exclude from duplication. We do need to keep the Query
1534      * section since DNS A parser needs the query section to know
1535      * the name being requested.
1536      */
1537     pj_dns_packet_dup(cache->pool, pkt,
1538 		      PJ_DNS_NO_NS | PJ_DNS_NO_AR,
1539 		      &cache->pkt);
1540 
1541     /* Calculate expiration time */
1542     if (set_expiry) {
1543 	pj_gettimeofday(&cache->expiry_time);
1544 	cache->expiry_time.sec += ttl;
1545     } else {
1546 	cache->expiry_time.sec = 0x7FFFFFFFL;
1547 	cache->expiry_time.msec = 0;
1548     }
1549 
1550     /* Copy key to the cached response */
1551     pj_memcpy(&cache->key, key, sizeof(*key));
1552 
1553     /* Update the hash table */
1554     pj_hash_set_np(resolver->hrescache, &cache->key, sizeof(*key), hval,
1555 		   cache->hbuf, cache);
1556 
1557 }
1558 
1559 
1560 /* Callback to be called when query has timed out */
on_timeout(pj_timer_heap_t * timer_heap,struct pj_timer_entry * entry)1561 static void on_timeout( pj_timer_heap_t *timer_heap,
1562 			struct pj_timer_entry *entry)
1563 {
1564     pj_dns_resolver *resolver;
1565     pj_dns_async_query *q, *cq;
1566     pj_status_t status;
1567 
1568     PJ_UNUSED_ARG(timer_heap);
1569 
1570     q = (pj_dns_async_query *) entry->user_data;
1571     resolver = q->resolver;
1572 
1573     pj_grp_lock_acquire(resolver->grp_lock);
1574 
1575     /* Recheck that this query is still pending, since there is a slight
1576      * possibility of race condition (timer elapsed while at the same time
1577      * response arrives)
1578      */
1579     if (pj_hash_get(resolver->hquerybyid, &q->id, sizeof(q->id), NULL)==NULL) {
1580 	/* Yeah, this query is done. */
1581 	pj_grp_lock_release(resolver->grp_lock);
1582 	return;
1583     }
1584 
1585     /* Invalidate id. */
1586     q->timer_entry.id = 0;
1587 
1588     /* Check to see if we should retransmit instead of time out */
1589     if (q->transmit_cnt < resolver->settings.qretr_count) {
1590 	status = transmit_query(resolver, q);
1591 	if (status == PJ_SUCCESS) {
1592 	    pj_grp_lock_release(resolver->grp_lock);
1593 	    return;
1594 	} else {
1595 	    /* Error occurs */
1596 	    PJ_PERROR(4,(resolver->name.ptr, status,
1597 			 "Error transmitting request"));
1598 
1599 	    /* Let it fallback to timeout section below */
1600 	}
1601     }
1602 
1603     /* Clear hash table entries */
1604     pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
1605     pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
1606 
1607     /* Workaround for deadlock problem in #1565 (similar to #1108) */
1608     pj_grp_lock_release(resolver->grp_lock);
1609 
1610     /* Call application callback, if any. */
1611     if (q->cb)
1612 	(*q->cb)(q->user_data, PJ_ETIMEDOUT, NULL);
1613 
1614     /* Call application callback for child queries. */
1615     cq = q->child_head.next;
1616     while (cq != (void*)&q->child_head) {
1617 	if (cq->cb)
1618 	    (*cq->cb)(cq->user_data, PJ_ETIMEDOUT, NULL);
1619 	cq = cq->next;
1620     }
1621 
1622     /* Workaround for deadlock problem in #1565 (similar to #1108) */
1623     pj_grp_lock_acquire(resolver->grp_lock);
1624 
1625     /* Clear data */
1626     q->timer_entry.id = 0;
1627     q->user_data = NULL;
1628 
1629     /* Put child entries into recycle list */
1630     cq = q->child_head.next;
1631     while (cq != (void*)&q->child_head) {
1632 	pj_dns_async_query *next = cq->next;
1633 	pj_list_push_back(&resolver->query_free_nodes, cq);
1634 	cq = next;
1635     }
1636 
1637     /* Put query entry into recycle list */
1638     pj_list_push_back(&resolver->query_free_nodes, q);
1639 
1640     pj_grp_lock_release(resolver->grp_lock);
1641 }
1642 
1643 
1644 /* Callback from ioqueue when packet is received */
on_read_complete(pj_ioqueue_key_t * key,pj_ioqueue_op_key_t * op_key,pj_ssize_t bytes_read)1645 static void on_read_complete(pj_ioqueue_key_t *key,
1646                              pj_ioqueue_op_key_t *op_key,
1647                              pj_ssize_t bytes_read)
1648 {
1649     pj_dns_resolver *resolver;
1650     pj_pool_t *pool = NULL;
1651     pj_dns_parsed_packet *dns_pkt;
1652     pj_dns_async_query *q;
1653     char addr[PJ_INET6_ADDRSTRLEN];
1654     pj_sockaddr *src_addr;
1655     int *src_addr_len;
1656     unsigned char *rx_pkt;
1657     pj_ssize_t rx_pkt_size;
1658     pj_status_t status;
1659     PJ_USE_EXCEPTION;
1660 
1661 
1662     resolver = (pj_dns_resolver *) pj_ioqueue_get_user_data(key);
1663     pj_assert(resolver);
1664 
1665 #if PJ_HAS_IPV6
1666     if (key == resolver->udp6_key) {
1667 	src_addr = &resolver->udp6_src_addr;
1668 	src_addr_len = &resolver->udp6_addr_len;
1669 	rx_pkt = resolver->udp6_rx_pkt;
1670 	rx_pkt_size = sizeof(resolver->udp6_rx_pkt);
1671     } else
1672 #endif
1673     {
1674 	src_addr = &resolver->udp_src_addr;
1675 	src_addr_len = &resolver->udp_addr_len;
1676 	rx_pkt = resolver->udp_rx_pkt;
1677 	rx_pkt_size = sizeof(resolver->udp_rx_pkt);
1678     }
1679 
1680     pj_grp_lock_acquire(resolver->grp_lock);
1681 
1682 
1683     /* Check for errors */
1684     if (bytes_read < 0) {
1685 	status = (pj_status_t)-bytes_read;
1686 	PJ_PERROR(4,(resolver->name.ptr, status, "DNS resolver read error"));
1687 
1688 	goto read_next_packet;
1689     }
1690 
1691     PJ_LOG(5,(resolver->name.ptr,
1692 	      "Received %d bytes DNS response from %s:%d",
1693 	      (int)bytes_read,
1694 	      pj_sockaddr_print(src_addr, addr, sizeof(addr), 2),
1695 	      pj_sockaddr_get_port(src_addr)));
1696 
1697 
1698     /* Check for zero packet */
1699     if (bytes_read == 0)
1700 	goto read_next_packet;
1701 
1702     /* Create temporary pool from a fixed buffer */
1703     pool = pj_pool_create_on_buf("restmp", resolver->tmp_pool,
1704 				 sizeof(resolver->tmp_pool));
1705 
1706     /* Parse DNS response */
1707     status = -1;
1708     dns_pkt = NULL;
1709     PJ_TRY {
1710 	status = pj_dns_parse_packet(pool, rx_pkt,
1711 				     (unsigned)bytes_read, &dns_pkt);
1712     }
1713     PJ_CATCH_ANY {
1714 	status = PJ_ENOMEM;
1715     }
1716     PJ_END;
1717 
1718     /* Update nameserver status */
1719     report_nameserver_status(resolver, src_addr, dns_pkt);
1720 
1721     /* Handle parse error */
1722     if (status != PJ_SUCCESS) {
1723 	PJ_PERROR(3,(resolver->name.ptr, status,
1724 		     "Error parsing DNS response from %s:%d",
1725 		     pj_sockaddr_print(src_addr, addr, sizeof(addr), 2),
1726 		     pj_sockaddr_get_port(src_addr)));
1727 	goto read_next_packet;
1728     }
1729 
1730     /* Find the query based on the transaction ID */
1731     q = (pj_dns_async_query*)
1732         pj_hash_get(resolver->hquerybyid, &dns_pkt->hdr.id,
1733 		    sizeof(dns_pkt->hdr.id), NULL);
1734     if (!q) {
1735 	PJ_LOG(5,(resolver->name.ptr,
1736 		  "DNS response from %s:%d id=%d discarded",
1737 		  pj_sockaddr_print(src_addr, addr, sizeof(addr), 2),
1738 		  pj_sockaddr_get_port(src_addr),
1739 		  (unsigned)dns_pkt->hdr.id));
1740 	goto read_next_packet;
1741     }
1742 
1743     /* Map DNS Rcode in the response into PJLIB status name space */
1744     status = PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(dns_pkt->hdr.flags));
1745 
1746     /* Cancel query timeout timer. */
1747     pj_assert(q->timer_entry.id != 0);
1748     pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
1749     q->timer_entry.id = 0;
1750 
1751     /* Clear hash table entries */
1752     pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
1753     pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
1754 
1755     /* Workaround for deadlock problem in #1108 */
1756     pj_grp_lock_release(resolver->grp_lock);
1757 
1758     /* Notify applications first, to allow application to modify the
1759      * record before it is saved to the hash table.
1760      */
1761     if (q->cb)
1762 	(*q->cb)(q->user_data, status, dns_pkt);
1763 
1764     /* If query has subqueries, notify subqueries's application callback */
1765     if (!pj_list_empty(&q->child_head)) {
1766 	pj_dns_async_query *child_q;
1767 
1768 	child_q = q->child_head.next;
1769 	while (child_q != (pj_dns_async_query*)&q->child_head) {
1770 	    if (child_q->cb)
1771 		(*child_q->cb)(child_q->user_data, status, dns_pkt);
1772 	    child_q = child_q->next;
1773 	}
1774     }
1775 
1776     /* Workaround for deadlock problem in #1108 */
1777     pj_grp_lock_acquire(resolver->grp_lock);
1778 
1779     /* Truncated responses MUST NOT be saved (cached). */
1780     if (PJ_DNS_GET_TC(dns_pkt->hdr.flags) == 0) {
1781 	/* Save/update response cache. */
1782 	update_res_cache(resolver, &q->key, status, PJ_TRUE, dns_pkt);
1783     }
1784 
1785     /* Recycle query objects, starting with the child queries */
1786     if (!pj_list_empty(&q->child_head)) {
1787 	pj_dns_async_query *child_q;
1788 
1789 	child_q = q->child_head.next;
1790 	while (child_q != (pj_dns_async_query*)&q->child_head) {
1791 	    pj_dns_async_query *next = child_q->next;
1792 	    pj_list_erase(child_q);
1793 	    pj_list_push_back(&resolver->query_free_nodes, child_q);
1794 	    child_q = next;
1795 	}
1796     }
1797     pj_list_push_back(&resolver->query_free_nodes, q);
1798 
1799 read_next_packet:
1800     if (pool) {
1801 	/* needed just in case PJ_HAS_POOL_ALT_API is set */
1802 	pj_pool_release(pool);
1803     }
1804 
1805     status = pj_ioqueue_recvfrom(key, op_key, rx_pkt, &rx_pkt_size,
1806 				 PJ_IOQUEUE_ALWAYS_ASYNC,
1807 				 src_addr, src_addr_len);
1808 
1809     if (status != PJ_EPENDING && status != PJ_ECANCELLED) {
1810 	PJ_PERROR(4,(resolver->name.ptr, status,
1811 		     "DNS resolver ioqueue read error"));
1812 
1813 	pj_assert(!"Unhandled error");
1814     }
1815 
1816     pj_grp_lock_release(resolver->grp_lock);
1817 }
1818 
1819 
1820 /*
1821  * Put the specified DNS packet into DNS cache. This function is mainly used
1822  * for testing the resolver, however it can also be used to inject entries
1823  * into the resolver.
1824  */
pj_dns_resolver_add_entry(pj_dns_resolver * resolver,const pj_dns_parsed_packet * pkt,pj_bool_t set_ttl)1825 PJ_DEF(pj_status_t) pj_dns_resolver_add_entry( pj_dns_resolver *resolver,
1826 					       const pj_dns_parsed_packet *pkt,
1827 					       pj_bool_t set_ttl)
1828 {
1829     struct res_key key;
1830 
1831     /* Sanity check */
1832     PJ_ASSERT_RETURN(resolver && pkt, PJ_EINVAL);
1833 
1834     /* Packet must be a DNS response */
1835     PJ_ASSERT_RETURN(PJ_DNS_GET_QR(pkt->hdr.flags) & 1, PJ_EINVAL);
1836 
1837     /* Make sure there are answers in the packet */
1838     PJ_ASSERT_RETURN((pkt->hdr.anscount && pkt->ans) ||
1839 		      (pkt->hdr.qdcount && pkt->q),
1840 		     PJLIB_UTIL_EDNSNOANSWERREC);
1841 
1842     pj_grp_lock_acquire(resolver->grp_lock);
1843 
1844     /* Build resource key for looking up hash tables */
1845     pj_bzero(&key, sizeof(struct res_key));
1846     if (pkt->hdr.anscount) {
1847 	/* Make sure name is not too long. */
1848 	PJ_ASSERT_RETURN(pkt->ans[0].name.slen < PJ_MAX_HOSTNAME,
1849 			 PJ_ENAMETOOLONG);
1850 
1851 	init_res_key(&key, pkt->ans[0].type, &pkt->ans[0].name);
1852 
1853     } else {
1854 	/* Make sure name is not too long. */
1855 	PJ_ASSERT_RETURN(pkt->q[0].name.slen < PJ_MAX_HOSTNAME,
1856 			 PJ_ENAMETOOLONG);
1857 
1858 	init_res_key(&key, pkt->q[0].type, &pkt->q[0].name);
1859     }
1860 
1861     /* Insert entry. */
1862     update_res_cache(resolver, &key, PJ_SUCCESS, set_ttl, pkt);
1863 
1864     pj_grp_lock_release(resolver->grp_lock);
1865 
1866     return PJ_SUCCESS;
1867 }
1868 
1869 
1870 /*
1871  * Get the total number of response in the response cache.
1872  */
pj_dns_resolver_get_cached_count(pj_dns_resolver * resolver)1873 PJ_DEF(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver)
1874 {
1875     unsigned count;
1876 
1877     PJ_ASSERT_RETURN(resolver, 0);
1878 
1879     pj_grp_lock_acquire(resolver->grp_lock);
1880     count = pj_hash_count(resolver->hrescache);
1881     pj_grp_lock_release(resolver->grp_lock);
1882 
1883     return count;
1884 }
1885 
1886 
1887 /*
1888  * Dump resolver state to the log.
1889  */
pj_dns_resolver_dump(pj_dns_resolver * resolver,pj_bool_t detail)1890 PJ_DEF(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
1891 				  pj_bool_t detail)
1892 {
1893 #if PJ_LOG_MAX_LEVEL >= 3
1894     unsigned i;
1895     pj_time_val now;
1896 
1897     pj_grp_lock_acquire(resolver->grp_lock);
1898 
1899     pj_gettimeofday(&now);
1900 
1901     PJ_LOG(3,(resolver->name.ptr, " Dumping resolver state:"));
1902 
1903     PJ_LOG(3,(resolver->name.ptr, "  Name servers:"));
1904     for (i=0; i<resolver->ns_count; ++i) {
1905 	char addr[PJ_INET6_ADDRSTRLEN];
1906 	struct nameserver *ns = &resolver->ns[i];
1907 
1908 	PJ_LOG(3,(resolver->name.ptr,
1909 		  "   NS %d: %s:%d (state=%s until %ds, rtt=%d ms)",
1910 		  i,
1911 		  pj_sockaddr_print(&ns->addr, addr, sizeof(addr), 2),
1912 		  pj_sockaddr_get_port(&ns->addr),
1913 		  state_names[ns->state],
1914 		  ns->state_expiry.sec - now.sec,
1915 		  PJ_TIME_VAL_MSEC(ns->rt_delay)));
1916     }
1917 
1918     PJ_LOG(3,(resolver->name.ptr, "  Nb. of cached responses: %u",
1919 	      pj_hash_count(resolver->hrescache)));
1920     if (detail) {
1921 	pj_hash_iterator_t itbuf, *it;
1922 	it = pj_hash_first(resolver->hrescache, &itbuf);
1923 	while (it) {
1924 	    struct cached_res *cache;
1925 	    cache = (struct cached_res*)pj_hash_this(resolver->hrescache, it);
1926 	    PJ_LOG(3,(resolver->name.ptr,
1927 		      "   Type %s: %s",
1928 		      pj_dns_get_type_name(cache->key.qtype),
1929 		      cache->key.name));
1930 	    it = pj_hash_next(resolver->hrescache, it);
1931 	}
1932     }
1933     PJ_LOG(3,(resolver->name.ptr, "  Nb. of pending queries: %u (%u)",
1934 	      pj_hash_count(resolver->hquerybyid),
1935 	      pj_hash_count(resolver->hquerybyres)));
1936     if (detail) {
1937 	pj_hash_iterator_t itbuf, *it;
1938 	it = pj_hash_first(resolver->hquerybyid, &itbuf);
1939 	while (it) {
1940 	    struct pj_dns_async_query *q;
1941 	    q = (pj_dns_async_query*) pj_hash_this(resolver->hquerybyid, it);
1942 	    PJ_LOG(3,(resolver->name.ptr,
1943 		      "   Type %s: %s",
1944 		      pj_dns_get_type_name(q->key.qtype),
1945 		      q->key.name));
1946 	    it = pj_hash_next(resolver->hquerybyid, it);
1947 	}
1948     }
1949     PJ_LOG(3,(resolver->name.ptr, "  Nb. of pending query free nodes: %u",
1950 	      pj_list_size(&resolver->query_free_nodes)));
1951     PJ_LOG(3,(resolver->name.ptr, "  Nb. of timer entries: %u",
1952 	      pj_timer_heap_count(resolver->timer)));
1953     PJ_LOG(3,(resolver->name.ptr, "  Pool capacity: %d, used size: %d",
1954 	      pj_pool_get_capacity(resolver->pool),
1955 	      pj_pool_get_used_size(resolver->pool)));
1956 
1957     pj_grp_lock_release(resolver->grp_lock);
1958 #endif
1959 }
1960 
1961