From cf47f86b74fe5f60b21458f14503657e6f6a4476 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Mon, 9 Oct 2006 00:48:42 +0000 Subject: [PATCH] put the evdns documentation into the header file. pathetic start of evdns manpage. a little bit more testing and debug output for the DNS regression test. add a BSD copyright to evdns.h with appropriate explanations. svn:r239 --- evdns.3 | 295 +++++++++++++++++++++++++++++++++++++++++++++ evdns.c | 186 ---------------------------- evdns.h | 231 ++++++++++++++++++++++++++++++++++- evhttp.h | 3 +- test/regress_dns.c | 35 +++++- 5 files changed, 560 insertions(+), 190 deletions(-) create mode 100644 evdns.3 diff --git a/evdns.3 b/evdns.3 new file mode 100644 index 00000000..4381d9b1 --- /dev/null +++ b/evdns.3 @@ -0,0 +1,295 @@ +.\" +.\" Copyright (c) 2006 Niels Provos +.\" 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 ``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. +.\" +.Dd October 7, 2006 +.Dt EVDNS 3 +.Os +.Sh NAME +.Nm evdns_init +.Nm evdns_shutdown +.Nm evdns_err_to_string +.Nm evdns_nameserver_add +.Nm evdns_count_nameservers +.Nm evdns_clear_nameservers_and_suspend +.Nm evdns_resume +.Nm evdns_nameserver_ip_add +.Nm evdns_resolve_ipv4 +.Nm evdns_resolve_reverse +.Nm evdns_resolv_conf_parse +.Nm evdns_config_windows_nameservers +.Nm evdns_search_clear +.Nm evdns_search_add +.Nm evdns_search_ndots_set +.Nm evdns_set_log_fn +.Nd asynchronous functions for DNS resolution. +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Fd #include +.Ft int +.Fn evdns_init +.Ft void +.Fn evdns_shutdown "int fail_requests" +.Ft "const char *" +.Fn evdns_err_to_string "int err" +.Ft int +.Fn evdns_nameserver_add "unsigned long int address" +.Ft int +.Fn evdns_count_nameservers +.Ft int +.Fn evdns_clear_nameservers_and_suspend +.Ft int +.Fn evdns_resume +.Ft int +.Fn evdns_nameserver_ip_add(const char *ip_as_string); +.Ft int +.Fn evdns_resolve_ipv4 "const char *name" "int flags" "evdns_callback_type callback" "void *ptr" +.Ft int +.Fn evdns_resolve_reverse "struct in_addr *in" "int flags" "evdns_callback_type callback" "void *ptr" +.Ft int +.Fn evdns_resolv_conf_parse "int flags" "const char *" +.Ft void +.Fn evdns_search_clear +.Ft void +.Fn evdns_search_add "const char *domain" +.Ft void +.Fn evdns_search_ndots_set "const int ndots" +.Ft void +.Fn evdns_set_log_fn "evdns_debug_log_fn_type fn" +.Ft int +.Fn evdns_config_windows_nameservers +.Sh DESCRIPTION +Welcome, gentle reader +.Pp +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. +.Pp +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). +.Pp +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. +.Pp +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: +.Pp +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. +.Pp +The library keeps track of the state of nameservers and will avoid +them when they go down. Otherwise it will round robin between them. +.Pp +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); +.Pp +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. +.Pp +Searching: +.Pp +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. +.Pp +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. +.Pp +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. +.Pp + 2. If you do call evdns_resolv_conf_parse then don't pass + DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). +.Pp + 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. +.Pp +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. +.Pp +The ndots setting can either be set from a resolv.conf, or by calling +evdns_search_ndots_set. +.Pp +For example, with ndots set to 1 (the default) and a search domain list of +["myhome.net"]: + Query: www + Order: www.myhome.net, www. +.Pp + Query: www.abc + Order: www.abc., www.abc.myhome.net +.Pp +API reference: +.Pp +int evdns_nameserver_add(unsigned long int address) + Add a nameserver. The address should be an IP address in + network byte order. The type of address is chosen so that + it matches in_addr.s_addr. + Returns non-zero on error. +.Pp +int evdns_nameserver_ip_add(const char *ip_as_string) + This wraps the above function by parsing a string as an IP + address and adds it as a nameserver. + Returns non-zero on error +.Pp +int evdns_resolve(const char *name, int flags, + evdns_callback_type callback, + void *ptr) + Resolve a name. The name parameter should be a DNS name. + The flags parameter should be 0, or DNS_QUERY_NO_SEARCH + which disables searching for this query. (see defn of + searching above). +.Pp + The callback argument is a function which is called when + this query completes and ptr is an argument which is passed + to that callback function. +.Pp + Returns non-zero on error +.Pp +void evdns_search_clear() + Clears the list of search domains +.Pp +void evdns_search_add(const char *domain) + Add a domain to the list of search domains +.Pp +void evdns_search_ndots_set(int ndots) + Set the number of dots which, when found in a name, causes + the first query to be without any search domain. +.Pp +int evdns_count_nameservers(void) + Return 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. +.Pp +int evdns_clear_nameservers_and_suspend(void) + Remove all currently configured nameservers, and suspend all pending + resolves. Resolves will not necessarily be re-attempted until + evdns_resume() is called. +.Pp +int evdns_resume(void) + Re-attempt resolves left in limbo after an earlier call to + evdns_clear_nameservers_and_suspend(). +.Pp +int evdns_config_windows_nameservers(void) + 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. Returns 0 on success, nonzero on failure. +.Pp +int evdns_resolv_conf_parse(int flags, const char *filename) + Parse a resolv.conf like file from the given filename. +.Pp + See the man page for resolv.conf for the format of this file. + The flags argument determines what information is parsed from + this file: + DNS_OPTION_SEARCH - domain, search and ndots options + DNS_OPTION_NAMESERVERS - nameserver lines + DNS_OPTION_MISC - timeout and attempts options + DNS_OPTIONS_ALL - all of the above + The following directives are not parsed from the file: + sortlist, rotate, no-check-names, inet6, debug +.Pp + Returns non-zero on error: + 0 no errors + 1 failed to open file + 2 failed to stat file + 3 file too large + 4 out of memory + 5 short read from file +.Pp +Internals: +.Pp +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. +.Pp +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. +.Pp +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. +.Sh SEE ALSO +.Xr event 3 , +.Xr gethostbyname 3 , +.Xr resolv.conf 5 +.Sh HISTORY +The +.Nm evdns +API was developed by Adam Langley on top of the +.Nm libevent +API. +The code was integrate into +.Nm Tor +by Nick Mathewson and finally put into +.Nm libevent +itself by Niels Provos. +.Sh AUTHORS +The +.Nm evdns +API and code was written by Adam Langley with significant +contributions by Nick Mathewson. +.Sh BUGS +This documentation is neither complete nor authoritative. +If you are in doubt about the usage of this API then +check the source code to find out how it works, write +up the missing piece of documentation and send it to +me for inclusion in this man page. diff --git a/evdns.c b/evdns.c index 60f0bcf6..0d852e61 100644 --- a/evdns.c +++ b/evdns.c @@ -32,192 +32,6 @@ * the source verbatim in their source distributions) * * Version: 0.1b - * - * - * 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 - * - * API reference: - * - * int evdns_nameserver_add(unsigned long int address) - * Add a nameserver. The address should be an IP address in - * network byte order. The type of address is chosen so that - * it matches in_addr.s_addr. - * Returns non-zero on error. - * - * int evdns_nameserver_ip_add(const char *ip_as_string) - * This wraps the above function by parsing a string as an IP - * address and adds it as a nameserver. - * Returns non-zero on error - * - * int evdns_resolve(const char *name, int flags, - * evdns_callback_type callback, - * void *ptr) - * Resolve a name. The name parameter should be a DNS name. - * The flags parameter should be 0, or DNS_QUERY_NO_SEARCH - * which disables searching for this query. (see defn of - * searching above). - * - * The callback argument is a function which is called when - * this query completes and ptr is an argument which is passed - * to that callback function. - * - * Returns non-zero on error - * - * void evdns_search_clear() - * Clears the list of search domains - * - * void evdns_search_add(const char *domain) - * Add a domain to the list of search domains - * - * void evdns_search_ndots_set(int ndots) - * Set the number of dots which, when found in a name, causes - * the first query to be without any search domain. - * - * int evdns_count_nameservers(void) - * Return 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. - * - * int evdns_clear_nameservers_and_suspend(void) - * Remove all currently configured nameservers, and suspend all pending - * resolves. Resolves will not necessarily be re-attempted until - * evdns_resume() is called. - * - * int evdns_resume(void) - * Re-attempt resolves left in limbo after an earlier call to - * evdns_clear_nameservers_and_suspend(). - * - * int evdns_config_windows_nameservers(void) - * 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. Returns 0 on success, nonzero on failure. - * - * int evdns_resolv_conf_parse(int flags, const char *filename) - * Parse a resolv.conf like file from the given filename. - * - * See the man page for resolv.conf for the format of this file. - * The flags argument determines what information is parsed from - * this file: - * DNS_OPTION_SEARCH - domain, search and ndots options - * DNS_OPTION_NAMESERVERS - nameserver lines - * DNS_OPTION_MISC - timeout and attempts options - * DNS_OPTIONS_ALL - all of the above - * The following directives are not parsed from the file: - * sortlist, rotate, no-check-names, inet6, debug - * - * Returns non-zero on error: - * 0 no errors - * 1 failed to open file - * 2 failed to stat file - * 3 file too large - * 4 out of memory - * 5 short read from file - * - * 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. */ #include diff --git a/evdns.h b/evdns.h index f631d545..2c328cfb 100644 --- a/evdns.h +++ b/evdns.h @@ -1,4 +1,38 @@ -/* This software is Public Domain. To view a copy of the public domain dedication, +/* + * Copyright (c) 2006 Niels Provos + * 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. * @@ -13,6 +47,194 @@ * the source verbatim in their source distributions) */ +/* + * + * 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 + * + * API reference: + * + * int evdns_nameserver_add(unsigned long int address) + * Add a nameserver. The address should be an IP address in + * network byte order. The type of address is chosen so that + * it matches in_addr.s_addr. + * Returns non-zero on error. + * + * int evdns_nameserver_ip_add(const char *ip_as_string) + * This wraps the above function by parsing a string as an IP + * address and adds it as a nameserver. + * Returns non-zero on error + * + * int evdns_resolve(const char *name, int flags, + * evdns_callback_type callback, + * void *ptr) + * Resolve a name. The name parameter should be a DNS name. + * The flags parameter should be 0, or DNS_QUERY_NO_SEARCH + * which disables searching for this query. (see defn of + * searching above). + * + * The callback argument is a function which is called when + * this query completes and ptr is an argument which is passed + * to that callback function. + * + * Returns non-zero on error + * + * void evdns_search_clear() + * Clears the list of search domains + * + * void evdns_search_add(const char *domain) + * Add a domain to the list of search domains + * + * void evdns_search_ndots_set(int ndots) + * Set the number of dots which, when found in a name, causes + * the first query to be without any search domain. + * + * int evdns_count_nameservers(void) + * Return 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. + * + * int evdns_clear_nameservers_and_suspend(void) + * Remove all currently configured nameservers, and suspend all pending + * resolves. Resolves will not necessarily be re-attempted until + * evdns_resume() is called. + * + * int evdns_resume(void) + * Re-attempt resolves left in limbo after an earlier call to + * evdns_clear_nameservers_and_suspend(). + * + * int evdns_config_windows_nameservers(void) + * 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. Returns 0 on success, nonzero on failure. + * + * int evdns_resolv_conf_parse(int flags, const char *filename) + * Parse a resolv.conf like file from the given filename. + * + * See the man page for resolv.conf for the format of this file. + * The flags argument determines what information is parsed from + * this file: + * DNS_OPTION_SEARCH - domain, search and ndots options + * DNS_OPTION_NAMESERVERS - nameserver lines + * DNS_OPTION_MISC - timeout and attempts options + * DNS_OPTIONS_ALL - all of the above + * The following directives are not parsed from the file: + * sortlist, rotate, no-check-names, inet6, debug + * + * Returns non-zero on error: + * 0 no errors + * 1 failed to open file + * 2 failed to stat file + * 3 file too large + * 4 out of memory + * 5 short read from file + * + * 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 @@ -49,6 +271,13 @@ #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 + * - 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); int evdns_init(void); diff --git a/evhttp.h b/evhttp.h index 620ea3fd..cb3b2cf4 100644 --- a/evhttp.h +++ b/evhttp.h @@ -82,7 +82,8 @@ void evhttp_send_reply(struct evhttp_request *, int, const char *, /* Interfaces for making requests */ enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD }; -/* Creates a new request object that needs to be filled in with the request +/* + * Creates a new request object that needs to be filled in with the request * parameters. The callback is executed when the request completed or an * error occurred. */ diff --git a/test/regress_dns.c b/test/regress_dns.c index 370592cf..ce941878 100644 --- a/test/regress_dns.c +++ b/test/regress_dns.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #endif #include @@ -63,8 +64,38 @@ void dns_gethostbyname_cb(int result, char type, int count, int ttl, void *addresses, void *arg) { - if (result == DNS_ERR_NONE) - dns_ok = 1; + dns_ok = 0; + + if (result != DNS_ERR_NONE) + goto out; + + fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl); + + switch (type) { + case DNS_IPv4_A: { + struct in_addr *in_addrs = addresses; + int i; + /* a resolution that's not valid does not help */ + if (ttl < 0) + goto out; + for (i = 0; i < count; ++i) + fprintf(stderr, "%s ", inet_ntoa(in_addrs[0])); + break; + } + case DNS_PTR: + /* may get at most one PTR */ + if (count != 1) + goto out; + + fprintf(stderr, "%s ", *(char **)addresses); + break; + default: + goto out; + } + + dns_ok = 1; + +out: event_loopexit(NULL); }