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