resolver.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #ifndef __PJLIB_UTIL_RESOLVER_H__
  20. #define __PJLIB_UTIL_RESOLVER_H__
  21. /**
  22. * @file resolver.h
  23. * @brief Asynchronous DNS resolver
  24. */
  25. #include <pjlib-util/dns.h>
  26. PJ_BEGIN_DECL
  27. /**
  28. * @defgroup PJ_DNS_RESOLVER DNS Asynchronous/Caching Resolution Engine
  29. * @ingroup PJ_DNS
  30. * @{
  31. *
  32. * This module manages the host/server resolution by performing asynchronous
  33. * DNS queries and caching the results in the cache. It uses PJLIB-UTIL
  34. * low-level DNS parsing functions (see @ref PJ_DNS) and currently supports
  35. * several types of DNS resource records such as A record (typical query with
  36. * gethostbyname()) and SRV record.
  37. *
  38. * \section PJ_DNS_RESOLVER_FEATURES Features
  39. *
  40. * \subsection PJ_DNS_RESOLVER_FEATURES_ASYNC Asynchronous Query and Query Aggregation
  41. *
  42. * The DNS queries are performed asychronously, with timeout setting
  43. * configured on per resolver instance basis. Application can issue multiple
  44. * asynchronous queries simultaneously. Subsequent queries to the same resource
  45. * (name and DNS resource type) while existing query is still pending will be
  46. * merged into one query, so that only one DNS request packet is issued.
  47. *
  48. * \subsection PJ_DNS_RESOLVER_FEATURES_RETRANSMISSION Query Retransmission
  49. *
  50. * Asynchronous query will be retransmitted if no response is received
  51. * within the preconfigured time. Once maximum retransmission count is
  52. * exceeded and no response is received, the query will time out and the
  53. * callback will be called when error status.
  54. *
  55. * \subsection PJ_DNS_RESOLVER_FEATURES_CACHING Response Caching with TTL
  56. *
  57. * The resolver instance caches the results returned by nameservers, to
  58. * enhance the performance by minimizing the message round-trip to the server.
  59. * The TTL of the cached resposne is calculated from minimum TTL value found
  60. * across all resource record (RR) TTL in the response and further more it can
  61. * be limited to some preconfigured maximum TTL in the resolver.
  62. *
  63. * Response caching can be disabled by setting the maximum TTL value of the
  64. * resolver to zero.
  65. *
  66. * \subsection PJ_DNS_RESOLVER_FEATURES_PARALLEL Parallel and Backup Name Servers
  67. *
  68. * When the resolver is configured with multiple nameservers, initially the
  69. * queries will be issued to multiple name servers simultaneously to probe
  70. * which servers are not active. Once the probing stage is done, subsequent
  71. * queries will be directed to only one ACTIVE server which provides the best
  72. * response time.
  73. *
  74. * Name servers are probed periodically to see which nameservers are active
  75. * and which are down. This probing is done when a query is sent, thus no
  76. * timer is needed to maintain this. Also probing will be done in parallel
  77. * so that there would be no additional delay for the query.
  78. *
  79. *
  80. * \subsection PJ_DNS_RESOLVER_FEATURES_REC Supported Resource Records
  81. *
  82. * The low-level DNS parsing utility (see @ref PJ_DNS) supports parsing of
  83. * the following DNS resource records (RR):
  84. * - DNS A record
  85. * - DNS SRV record
  86. * - DNS PTR record
  87. * - DNS NS record
  88. * - DNS CNAME record
  89. *
  90. * For other types of record, application can parse the raw resource
  91. * record data (rdata) from the parsed DNS packet (#pj_dns_parsed_packet).
  92. *
  93. *
  94. * \section PJ_DNS_RESOLVER_USING Using the Resolver
  95. *
  96. * To use the resolver, application first creates the resolver instance by
  97. * calling #pj_dns_resolver_create(). If application already has its own
  98. * timer and ioqueue instances, it can instruct the resolver to use these
  99. * instances so that application does not need to poll the resolver
  100. * periodically to process events. If application does not specify the
  101. * timer and ioqueue instance for the resolver, an internal timer and
  102. * ioqueue will be created by the resolver. And since the resolver does not
  103. * create it's own thread, application MUST poll the resolver periodically
  104. * by calling #pj_dns_resolver_handle_events() to allow events (network and
  105. * timer) to be processed.
  106. *
  107. * Next, application MUST configure the nameservers to be used by the
  108. * resolver, by calling #pj_dns_resolver_set_ns().
  109. *
  110. * Application performs asynchronous query by submitting the query with
  111. * #pj_dns_resolver_start_query(). Once the query completes (either
  112. * successfully or times out), the callback will be called.
  113. *
  114. * Application can cancel a pending query by calling #pj_dns_resolver_cancel_query().
  115. *
  116. * Resolver must be destroyed by calling #pj_dns_resolver_destroy() to
  117. * release all resources back to the system.
  118. *
  119. *
  120. * \section PJ_DNS_RESOLVER_LIMITATIONS Resolver Limitations
  121. *
  122. * Current implementation mainly suffers from a growing memory problem,
  123. * which mainly is caused by the response caching. Although there is only
  124. * one cache entry per {query, name} combination, these cache entry will
  125. * never get deleted since there is no timer is created to invalidate these
  126. * entries. So the more unique names being queried by application, there more
  127. * enties will be created in the response cache.
  128. *
  129. * Note that a single response entry will occupy about 600-700 bytes of
  130. * pool memory (the PJ_DNS_RESOLVER_RES_BUF_SIZE value plus internal
  131. * structure).
  132. *
  133. * Application can work around this problem by doing one of these:
  134. * - disable caching by setting PJ_DNS_RESOLVER_MAX_TTL and
  135. * PJ_DNS_RESOLVER_INVALID_TTL to zero.
  136. * - periodically query #pj_dns_resolver_get_cached_count() and destroy-
  137. * recreate the resolver to recycle the memory used by the resolver.
  138. *
  139. * Note that future improvement may solve this problem by introducing
  140. * expiration timer to the cached entries.
  141. *
  142. *
  143. * \section PJ_DNS_RESOLVER_REFERENCE Reference
  144. *
  145. * The PJLIB-UTIL resolver was built from the information in the following
  146. * standards:
  147. * - <A HREF="http://www.faqs.org/rfcs/rfc1035.html">
  148. * RFC 1035: "Domain names - implementation and specification"</A>
  149. * - <A HREF="http://www.faqs.org/rfcs/rfc2782.html">
  150. * RFC 2782: "A DNS RR for specifying the location of services (DNS SRV)"
  151. * </A>
  152. */
  153. /**
  154. * Opaque data type for DNS resolver object.
  155. */
  156. typedef struct pj_dns_resolver pj_dns_resolver;
  157. /**
  158. * Opaque data type for asynchronous DNS query object.
  159. */
  160. typedef struct pj_dns_async_query pj_dns_async_query;
  161. /**
  162. * Type of asynchronous callback which will be called when the asynchronous
  163. * query completes.
  164. *
  165. * @param user_data The user data set by application when creating the
  166. * asynchronous query.
  167. * @param status Status of the DNS resolution.
  168. * @param response The response packet received from the server. This
  169. * argument may be NULL when status is not PJ_SUCCESS.
  170. */
  171. typedef void pj_dns_callback(void *user_data,
  172. pj_status_t status,
  173. pj_dns_parsed_packet *response);
  174. /**
  175. * This structure describes resolver settings.
  176. */
  177. typedef struct pj_dns_settings
  178. {
  179. unsigned options; /**< Options flags. */
  180. unsigned qretr_delay; /**< Query retransmit delay in msec. */
  181. unsigned qretr_count; /**< Query maximum retransmission count. */
  182. unsigned cache_max_ttl; /**< Maximum TTL for cached responses. If the
  183. value is zero, caching is disabled. */
  184. unsigned good_ns_ttl; /**< See #PJ_DNS_RESOLVER_GOOD_NS_TTL */
  185. unsigned bad_ns_ttl; /**< See #PJ_DNS_RESOLVER_BAD_NS_TTL */
  186. } pj_dns_settings;
  187. /**
  188. * This structure represents DNS A record, as the result of parsing
  189. * DNS response packet using #pj_dns_parse_a_response().
  190. */
  191. typedef struct pj_dns_a_record
  192. {
  193. /** The target name being queried. */
  194. pj_str_t name;
  195. /** If target name corresponds to a CNAME entry, the alias contains
  196. * the value of the CNAME entry, otherwise it will be empty.
  197. */
  198. pj_str_t alias;
  199. /** Number of IP addresses. */
  200. unsigned addr_count;
  201. /** IP addresses of the host found in the response */
  202. pj_in_addr addr[PJ_DNS_MAX_IP_IN_A_REC];
  203. /** Internal buffer for hostname and alias. */
  204. char buf_[128];
  205. } pj_dns_a_record;
  206. /**
  207. * This structure represents DNS address record, i.e: DNS A and DNS AAAA
  208. * records, as the result of parsing DNS response packet using
  209. * #pj_dns_parse_addr_response().
  210. */
  211. typedef struct pj_dns_addr_record
  212. {
  213. /** The target name being queried. */
  214. pj_str_t name;
  215. /** If target name corresponds to a CNAME entry, the alias contains
  216. * the value of the CNAME entry, otherwise it will be empty.
  217. */
  218. pj_str_t alias;
  219. /** Number of IP addresses. */
  220. unsigned addr_count;
  221. /** IP addresses of the host found in the response */
  222. struct {
  223. /** IP address family */
  224. int af;
  225. /** IP address */
  226. union {
  227. /** IPv4 address */
  228. pj_in_addr v4;
  229. /** IPv6 address */
  230. pj_in6_addr v6;
  231. } ip;
  232. } addr[PJ_DNS_MAX_IP_IN_A_REC];
  233. /** Internal buffer for hostname and alias. */
  234. char buf_[128];
  235. } pj_dns_addr_record;
  236. /**
  237. * Set default values to the DNS settings.
  238. *
  239. * @param s The DNS settings to be initialized.
  240. */
  241. PJ_DECL(void) pj_dns_settings_default(pj_dns_settings *s);
  242. /**
  243. * Create DNS resolver instance. After the resolver is created, application
  244. * MUST configure the nameservers with #pj_dns_resolver_set_ns().
  245. *
  246. * When creating the resolver, application may specify both timer heap
  247. * and ioqueue instance, so that it doesn't need to poll the resolver
  248. * periodically.
  249. *
  250. * @param pf Pool factory where the memory pool will be created from.
  251. * @param name Optional resolver name to identify the instance in
  252. * the log.
  253. * @param options Optional options, must be zero for now.
  254. * @param timer Optional timer heap instance to be used by the resolver.
  255. * If timer heap is not specified, an internal timer will be
  256. * created, and application would need to poll the resolver
  257. * periodically.
  258. * @param ioqueue Optional I/O Queue instance to be used by the resolver.
  259. * If ioqueue is not specified, an internal one will be
  260. * created, and application would need to poll the resolver
  261. * periodically.
  262. * @param p_resolver Pointer to receive the resolver instance.
  263. *
  264. * @return PJ_SUCCESS on success, or the appropriate error code,
  265. */
  266. PJ_DECL(pj_status_t) pj_dns_resolver_create(pj_pool_factory *pf,
  267. const char *name,
  268. unsigned options,
  269. pj_timer_heap_t *timer,
  270. pj_ioqueue_t *ioqueue,
  271. pj_dns_resolver **p_resolver);
  272. /**
  273. * Update the name servers for the DNS resolver. The name servers MUST be
  274. * configured before any resolution can be done. The order of nameservers
  275. * specifies their priority; the first name server will be tried first
  276. * before the next in the list.
  277. *
  278. * @param resolver The resolver instance.
  279. * @param count Number of name servers in the array.
  280. * @param servers Array of name server IP addresses or hostnames. If
  281. * hostname is specified, the hostname must be resolvable
  282. * with pj_gethostbyname().
  283. * @param ports Optional array of ports. If this argument is NULL,
  284. * the nameserver will use default port.
  285. *
  286. * @return PJ_SUCCESS on success, or the appropriate error code,
  287. */
  288. PJ_DECL(pj_status_t) pj_dns_resolver_set_ns(pj_dns_resolver *resolver,
  289. unsigned count,
  290. const pj_str_t servers[],
  291. const pj_uint16_t ports[]);
  292. /**
  293. * Get the resolver current settings.
  294. *
  295. * @param resolver The resolver instance.
  296. * @param st Buffer to be filled up with resolver settings.
  297. *
  298. * @return The query timeout setting, in seconds.
  299. */
  300. PJ_DECL(pj_status_t) pj_dns_resolver_get_settings(pj_dns_resolver *resolver,
  301. pj_dns_settings *st);
  302. /**
  303. * Modify the resolver settings. Application should initialize the settings
  304. * by retrieving current settings first before applying new settings, to
  305. * ensure that all fields are initialized properly.
  306. *
  307. * @param resolver The resolver instance.
  308. * @param st The resolver settings.
  309. *
  310. * @return PJ_SUCCESS on success, or the appropriate error code,
  311. */
  312. PJ_DECL(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
  313. const pj_dns_settings *st);
  314. /**
  315. * Poll for events from the resolver. This function MUST be called
  316. * periodically when the resolver is using it's own timer or ioqueue
  317. * (in other words, when NULL is specified as either \a timer or
  318. * \a ioqueue argument in #pj_dns_resolver_create()).
  319. *
  320. * @param resolver The resolver instance.
  321. * @param timeout Maximum time to wait for event occurence. If this
  322. * argument is NULL, this function will wait forever
  323. * until events occur.
  324. */
  325. PJ_DECL(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
  326. const pj_time_val *timeout);
  327. /**
  328. * Destroy DNS resolver instance.
  329. *
  330. * @param resolver The resolver object to be destryed
  331. * @param notify If non-zero, all pending asynchronous queries will be
  332. * cancelled and its callback will be called. If FALSE,
  333. * then no callback will be called.
  334. *
  335. * @return PJ_SUCCESS on success, or the appropriate error code,
  336. */
  337. PJ_DECL(pj_status_t) pj_dns_resolver_destroy(pj_dns_resolver *resolver,
  338. pj_bool_t notify);
  339. /**
  340. * Create and start asynchronous DNS query for a single resource. Depending
  341. * on whether response cache is available, this function will either start
  342. * an asynchronous DNS query or call the callback immediately.
  343. *
  344. * If response is not available in the cache, an asynchronous query will be
  345. * started, and callback will be called at some time later when the query
  346. * completes. If \a p_query argument is not NULL, it will be filled with
  347. * the asynchronous query object.
  348. *
  349. * If response is available in the cache, the callback will be called
  350. * immediately before this function returns. In this case, if \a p_query
  351. * argument is not NULL, the value will be set to NULL since no new query
  352. * is started.
  353. *
  354. * @param resolver The resolver object.
  355. * @param name The name to be resolved.
  356. * @param type The type of resource (see #pj_dns_type constants).
  357. * @param options Optional options, must be zero for now.
  358. * @param cb Callback to be called when the query completes,
  359. * either successfully or with failure.
  360. * @param user_data Arbitrary user data to be associated with the query,
  361. * and which will be given back in the callback.
  362. * @param p_query Optional pointer to receive the query object, if one
  363. * was started. If this pointer is specified, a NULL will
  364. * be returned if response cache is available immediately.
  365. *
  366. * @return PJ_SUCCESS if either an asynchronous query has been
  367. * started successfully or response cache is available and
  368. * the user callback has been called.
  369. */
  370. PJ_DECL(pj_status_t) pj_dns_resolver_start_query(pj_dns_resolver *resolver,
  371. const pj_str_t *name,
  372. int type,
  373. unsigned options,
  374. pj_dns_callback *cb,
  375. void *user_data,
  376. pj_dns_async_query **p_query);
  377. /**
  378. * Cancel a pending query.
  379. *
  380. * @param query The pending asynchronous query to be cancelled.
  381. * @param notify If non-zero, the callback will be called with failure
  382. * status to notify that the query has been cancelled.
  383. *
  384. * @return PJ_SUCCESS on success, or the appropriate error code,
  385. */
  386. PJ_DECL(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
  387. pj_bool_t notify);
  388. /**
  389. * A utility function to parse a DNS response containing A records into
  390. * DNS A record.
  391. *
  392. * @param pkt The DNS response packet.
  393. * @param rec The structure to be initialized with the parsed
  394. * DNS A record from the packet.
  395. *
  396. * @return PJ_SUCCESS if response can be parsed successfully.
  397. */
  398. PJ_DECL(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
  399. pj_dns_a_record *rec);
  400. /**
  401. * A utility function to parse a DNS response containing AAAA records into
  402. * DNS AAAA record.
  403. *
  404. * @param pkt The DNS response packet.
  405. * @param rec The structure to be initialized with the parsed
  406. * DNS AAAA record from the packet.
  407. *
  408. * @return PJ_SUCCESS if response can be parsed successfully.
  409. */
  410. PJ_DECL(pj_status_t) pj_dns_parse_addr_response(
  411. const pj_dns_parsed_packet *pkt,
  412. pj_dns_addr_record *rec);
  413. /**
  414. * Put the specified DNS packet into DNS cache. This function is mainly used
  415. * for testing the resolver, however it can also be used to inject entries
  416. * into the resolver.
  417. *
  418. * The packet MUST contain either answer section or query section so that
  419. * it can be indexed.
  420. *
  421. * @param resolver The resolver instance.
  422. * @param pkt DNS packet to be added to the DNS cache. If the packet
  423. * matches existing entry, it will update the entry.
  424. * @param set_ttl If the value is PJ_FALSE, the entry will not expire
  425. * (so use with care). Otherwise cache expiration will be
  426. * calculated based on the TTL of the answeres.
  427. *
  428. * @return PJ_SUCCESS on success, or the appropriate error code.
  429. */
  430. PJ_DECL(pj_status_t) pj_dns_resolver_add_entry(pj_dns_resolver *resolver,
  431. const pj_dns_parsed_packet *pkt,
  432. pj_bool_t set_ttl);
  433. /**
  434. * Get the total number of response in the response cache.
  435. *
  436. * @param resolver The resolver instance.
  437. *
  438. * @return Current number of entries being stored in the response
  439. * cache.
  440. */
  441. PJ_DECL(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver);
  442. /**
  443. * Dump resolver state to the log.
  444. *
  445. * @param resolver The resolver instance.
  446. * @param detail Will print detailed entries.
  447. */
  448. PJ_DECL(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
  449. pj_bool_t detail);
  450. /**
  451. * @}
  452. */
  453. PJ_END_DECL
  454. #endif /* __PJLIB_UTIL_RESOLVER_H__ */