| /* |
| * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu> |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * The original DNS code is due to Adam Langley with heavy |
| * modifications by Nick Mathewson. Adam put his DNS software in the |
| * public domain. You can find his original copyright below. Please, |
| * aware that the code as part of libevent is governed by the 3-clause |
| * BSD license above. |
| * |
| * This software is Public Domain. To view a copy of the public domain dedication, |
| * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to |
| * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. |
| * |
| * I ask and expect, but do not require, that all derivative works contain an |
| * attribution similar to: |
| * Parts developed by Adam Langley <agl@imperialviolet.org> |
| * |
| * You may wish to replace the word "Parts" with something else depending on |
| * the amount of original code. |
| * |
| * (Derivative works does not include programs which link against, run or include |
| * the source verbatim in their source distributions) |
| */ |
| |
| /** @file evdns.h |
| * |
| * Welcome, gentle reader |
| * |
| * Async DNS lookups are really a whole lot harder than they should be, |
| * mostly stemming from the fact that the libc resolver has never been |
| * very good at them. Before you use this library you should see if libc |
| * can do the job for you with the modern async call getaddrinfo_a |
| * (see http://www.imperialviolet.org/page25.html#e498). Otherwise, |
| * please continue. |
| * |
| * This code is based on libevent and you must call event_init before |
| * any of the APIs in this file. You must also seed the OpenSSL random |
| * source if you are using OpenSSL for ids (see below). |
| * |
| * This library is designed to be included and shipped with your source |
| * code. You statically link with it. You should also test for the |
| * existence of strtok_r and define HAVE_STRTOK_R if you have it. |
| * |
| * The DNS protocol requires a good source of id numbers and these |
| * numbers should be unpredictable for spoofing reasons. There are |
| * three methods for generating them here and you must define exactly |
| * one of them. In increasing order of preference: |
| * |
| * DNS_USE_GETTIMEOFDAY_FOR_ID: |
| * Using the bottom 16 bits of the usec result from gettimeofday. This |
| * is a pretty poor solution but should work anywhere. |
| * DNS_USE_CPU_CLOCK_FOR_ID: |
| * Using the bottom 16 bits of the nsec result from the CPU's time |
| * counter. This is better, but may not work everywhere. Requires |
| * POSIX realtime support and you'll need to link against -lrt on |
| * glibc systems at least. |
| * DNS_USE_OPENSSL_FOR_ID: |
| * Uses the OpenSSL RAND_bytes call to generate the data. You must |
| * have seeded the pool before making any calls to this library. |
| * |
| * The library keeps track of the state of nameservers and will avoid |
| * them when they go down. Otherwise it will round robin between them. |
| * |
| * Quick start guide: |
| * #include "evdns.h" |
| * void callback(int result, char type, int count, int ttl, |
| * void *addresses, void *arg); |
| * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); |
| * evdns_resolve("www.hostname.com", 0, callback, NULL); |
| * |
| * When the lookup is complete the callback function is called. The |
| * first argument will be one of the DNS_ERR_* defines in evdns.h. |
| * Hopefully it will be DNS_ERR_NONE, in which case type will be |
| * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time |
| * which the data can be cached for (in seconds), addresses will point |
| * to an array of uint32_t's and arg will be whatever you passed to |
| * evdns_resolve. |
| * |
| * Searching: |
| * |
| * In order for this library to be a good replacement for glibc's resolver it |
| * supports searching. This involves setting a list of default domains, in |
| * which names will be queried for. The number of dots in the query name |
| * determines the order in which this list is used. |
| * |
| * Searching appears to be a single lookup from the point of view of the API, |
| * although many DNS queries may be generated from a single call to |
| * evdns_resolve. Searching can also drastically slow down the resolution |
| * of names. |
| * |
| * To disable searching: |
| * 1. Never set it up. If you never call evdns_resolv_conf_parse or |
| * evdns_search_add then no searching will occur. |
| * |
| * 2. If you do call evdns_resolv_conf_parse then don't pass |
| * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). |
| * |
| * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. |
| * |
| * The order of searches depends on the number of dots in the name. If the |
| * number is greater than the ndots setting then the names is first tried |
| * globally. Otherwise each search domain is appended in turn. |
| * |
| * The ndots setting can either be set from a resolv.conf, or by calling |
| * evdns_search_ndots_set. |
| * |
| * For example, with ndots set to 1 (the default) and a search domain list of |
| * ["myhome.net"]: |
| * Query: www |
| * Order: www.myhome.net, www. |
| * |
| * Query: www.abc |
| * Order: www.abc., www.abc.myhome.net |
| * |
| * Internals: |
| * |
| * Requests are kept in two queues. The first is the inflight queue. In |
| * this queue requests have an allocated transaction id and nameserver. |
| * They will soon be transmitted if they haven't already been. |
| * |
| * The second is the waiting queue. The size of the inflight ring is |
| * limited and all other requests wait in waiting queue for space. This |
| * bounds the number of concurrent requests so that we don't flood the |
| * nameserver. Several algorithms require a full walk of the inflight |
| * queue and so bounding its size keeps thing going nicely under huge |
| * (many thousands of requests) loads. |
| * |
| * If a nameserver loses too many requests it is considered down and we |
| * try not to use it. After a while we send a probe to that nameserver |
| * (a lookup for google.com) and, if it replies, we consider it working |
| * again. If the nameserver fails a probe we wait longer to try again |
| * with the next probe. |
| */ |
| |
| #ifndef EVENTDNS_H |
| #define EVENTDNS_H |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* For integer types. */ |
| #include <evutil.h> |
| |
| /** Error codes 0-5 are as described in RFC 1035. */ |
| #define DNS_ERR_NONE 0 |
| /** The name server was unable to interpret the query */ |
| #define DNS_ERR_FORMAT 1 |
| /** The name server was unable to process this query due to a problem with the |
| * name server */ |
| #define DNS_ERR_SERVERFAILED 2 |
| /** The domain name does not exist */ |
| #define DNS_ERR_NOTEXIST 3 |
| /** The name server does not support the requested kind of query */ |
| #define DNS_ERR_NOTIMPL 4 |
| /** The name server refuses to reform the specified operation for policy |
| * reasons */ |
| #define DNS_ERR_REFUSED 5 |
| /** The reply was truncated or ill-formated */ |
| #define DNS_ERR_TRUNCATED 65 |
| /** An unknown error occurred */ |
| #define DNS_ERR_UNKNOWN 66 |
| /** Communication with the server timed out */ |
| #define DNS_ERR_TIMEOUT 67 |
| /** The request was canceled because the DNS subsystem was shut down. */ |
| #define DNS_ERR_SHUTDOWN 68 |
| |
| #define DNS_IPv4_A 1 |
| #define DNS_PTR 2 |
| #define DNS_IPv6_AAAA 3 |
| |
| #define DNS_QUERY_NO_SEARCH 1 |
| |
| #define DNS_OPTION_SEARCH 1 |
| #define DNS_OPTION_NAMESERVERS 2 |
| #define DNS_OPTION_MISC 4 |
| #define DNS_OPTIONS_ALL 7 |
| |
| /** |
| * The callback that contains the results from a lookup. |
| * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA |
| * - count contains the number of addresses of form type |
| * - ttl is the number of seconds the resolution may be cached for. |
| * - addresses needs to be cast according to type |
| */ |
| typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); |
| |
| /** |
| Initialize the asynchronous DNS library. |
| |
| This function initializes support for non-blocking name resolution by |
| calling evdns_resolv_conf_parse() on UNIX and |
| evdns_config_windows_nameservers() on Windows. |
| |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_shutdown() |
| */ |
| int evdns_init(void); |
| |
| |
| /** |
| Shut down the asynchronous DNS resolver and terminate all active requests. |
| |
| If the 'fail_requests' option is enabled, all active requests will return |
| an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise, |
| the requests will be silently discarded. |
| |
| @param fail_requests if zero, active requests will be aborted; if non-zero, |
| active requests will return DNS_ERR_SHUTDOWN. |
| @see evdns_init() |
| */ |
| void evdns_shutdown(int fail_requests); |
| |
| |
| /** |
| Convert a DNS error code to a string. |
| |
| @param err the DNS error code |
| @return a string containing an explanation of the error code |
| */ |
| const char *evdns_err_to_string(int err); |
| |
| |
| /** |
| Add a nameserver. |
| |
| The address should be an IPv4 address in network byte order. |
| The type of address is chosen so that it matches in_addr.s_addr. |
| |
| @param address an IP address in network byte order |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_nameserver_ip_add() |
| */ |
| int evdns_nameserver_add(unsigned long int address); |
| |
| |
| /** |
| Get the number of configured nameservers. |
| |
| This returns the number of configured nameservers (not necessarily the |
| number of running nameservers). This is useful for double-checking |
| whether our calls to the various nameserver configuration functions |
| have been successful. |
| |
| @return the number of configured nameservers |
| @see evdns_nameserver_add() |
| */ |
| int evdns_count_nameservers(void); |
| |
| |
| /** |
| Remove all configured nameservers, and suspend all pending resolves. |
| |
| Resolves will not necessarily be re-attempted until evdns_resume() is called. |
| |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_resume() |
| */ |
| int evdns_clear_nameservers_and_suspend(void); |
| |
| |
| /** |
| Resume normal operation and continue any suspended resolve requests. |
| |
| Re-attempt resolves left in limbo after an earlier call to |
| evdns_clear_nameservers_and_suspend(). |
| |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_clear_nameservers_and_suspend() |
| */ |
| int evdns_resume(void); |
| |
| |
| /** |
| Add a nameserver. |
| |
| This wraps the evdns_nameserver_add() function by parsing a string as an IP |
| address and adds it as a nameserver. |
| |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_nameserver_add() |
| */ |
| int evdns_nameserver_ip_add(const char *ip_as_string); |
| |
| |
| /** |
| Lookup an A record for a given name. |
| |
| @param name a DNS hostname |
| @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. |
| @param callback a callback function to invoke when the request is completed |
| @param ptr an argument to pass to the callback function |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() |
| */ |
| int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); |
| |
| |
| /** |
| Lookup an AAAA record for a given name. |
| |
| @param name a DNS hostname |
| @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. |
| @param callback a callback function to invoke when the request is completed |
| @param ptr an argument to pass to the callback function |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6() |
| */ |
| int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); |
| |
| struct in_addr; |
| struct in6_addr; |
| |
| /** |
| Lookup a PTR record for a given IP address. |
| |
| @param in an IPv4 address |
| @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. |
| @param callback a callback function to invoke when the request is completed |
| @param ptr an argument to pass to the callback function |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_resolve_reverse_ipv6() |
| */ |
| int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); |
| |
| |
| /** |
| Lookup a PTR record for a given IPv6 address. |
| |
| @param in an IPv6 address |
| @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query. |
| @param callback a callback function to invoke when the request is completed |
| @param ptr an argument to pass to the callback function |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_resolve_reverse_ipv6() |
| */ |
| int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); |
| |
| |
| /** |
| Set the value of a configuration option. |
| |
| The currently available configuration options are: |
| |
| ndots, timeout, max-timeouts, max-inflight, and attempts |
| |
| @param option the name of the configuration option to be modified |
| @param val the value to be set |
| @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC |
| @return 0 if successful, or -1 if an error occurred |
| */ |
| int evdns_set_option(const char *option, const char *val, int flags); |
| |
| |
| /** |
| Parse a resolv.conf file. |
| |
| The 'flags' parameter determines what information is parsed from the |
| resolv.conf file. See the man page for resolv.conf for the format of this |
| file. |
| |
| The following directives are not parsed from the file: sortlist, rotate, |
| no-check-names, inet6, debug. |
| |
| If this function encounters an error, the possible return values are: 1 = |
| failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of |
| memory, 5 = short read from file, 6 = no nameservers listed in the file |
| |
| @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| |
| DNS_OPTIONS_ALL |
| @param filename the path to the resolv.conf file |
| @return 0 if successful, or various positive error codes if an error |
| occurred (see above) |
| @see resolv.conf(3), evdns_config_windows_nameservers() |
| */ |
| int evdns_resolv_conf_parse(int flags, const char *const filename); |
| |
| |
| /** |
| Obtain nameserver information using the Windows API. |
| |
| Attempt to configure a set of nameservers based on platform settings on |
| a win32 host. Preferentially tries to use GetNetworkParams; if that fails, |
| looks in the registry. |
| |
| @return 0 if successful, or -1 if an error occurred |
| @see evdns_resolv_conf_parse() |
| */ |
| #ifdef WIN32 |
| int evdns_config_windows_nameservers(void); |
| #endif |
| |
| |
| /** |
| Clear the list of search domains. |
| */ |
| void evdns_search_clear(void); |
| |
| |
| /** |
| Add a domain to the list of search domains |
| |
| @param domain the domain to be added to the search list |
| */ |
| void evdns_search_add(const char *domain); |
| |
| |
| /** |
| Set the 'ndots' parameter for searches. |
| |
| Sets the number of dots which, when found in a name, causes |
| the first query to be without any search domain. |
| |
| @param ndots the new ndots parameter |
| */ |
| void evdns_search_ndots_set(const int ndots); |
| |
| /** |
| A callback that is invoked when a log message is generated |
| |
| @param is_warning indicates if the log message is a 'warning' |
| @param msg the content of the log message |
| */ |
| typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); |
| |
| |
| /** |
| Set the callback function to handle log messages. |
| |
| @param fn the callback to be invoked when a log message is generated |
| */ |
| void evdns_set_log_fn(evdns_debug_log_fn_type fn); |
| |
| /** |
| Set a callback that will be invoked to generate transaction IDs. By |
| default, we pick transaction IDs based on the current clock time. |
| |
| @param fn the new callback, or NULL to use the default. |
| */ |
| void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)); |
| |
| #define DNS_NO_SEARCH 1 |
| |
| /* |
| * Structures and functions used to implement a DNS server. |
| */ |
| |
| struct evdns_server_request { |
| int flags; |
| int nquestions; |
| struct evdns_server_question **questions; |
| }; |
| struct evdns_server_question { |
| int type; |
| #ifdef __cplusplus |
| int dns_question_class; |
| #else |
| /* You should refer to this field as "dns_question_class". The |
| * name "class" works in C for backward compatibility, and will be |
| * removed in a future version. (1.5 or later). */ |
| int class; |
| #define dns_question_class class |
| #endif |
| char name[1]; |
| }; |
| typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); |
| #define EVDNS_ANSWER_SECTION 0 |
| #define EVDNS_AUTHORITY_SECTION 1 |
| #define EVDNS_ADDITIONAL_SECTION 2 |
| |
| #define EVDNS_TYPE_A 1 |
| #define EVDNS_TYPE_NS 2 |
| #define EVDNS_TYPE_CNAME 5 |
| #define EVDNS_TYPE_SOA 6 |
| #define EVDNS_TYPE_PTR 12 |
| #define EVDNS_TYPE_MX 15 |
| #define EVDNS_TYPE_TXT 16 |
| #define EVDNS_TYPE_AAAA 28 |
| |
| #define EVDNS_QTYPE_AXFR 252 |
| #define EVDNS_QTYPE_ALL 255 |
| |
| #define EVDNS_CLASS_INET 1 |
| |
| struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); |
| void evdns_close_server_port(struct evdns_server_port *port); |
| |
| int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data); |
| int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); |
| int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); |
| int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); |
| int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); |
| |
| int evdns_server_request_respond(struct evdns_server_request *req, int err); |
| int evdns_server_request_drop(struct evdns_server_request *req); |
| struct sockaddr; |
| int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* !EVENTDNS_H */ |