From: Mark Andrews Date: Thu, 16 Jan 2003 03:59:28 +0000 (+0000) Subject: 1412. [func] You can now specify servers to be tried if a nameserver X-Git-Tag: v9.2.3rc1~104^2~165 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=0ffaee887ff5674b8c3bb0435ae838f641981706;p=thirdparty%2Fbind9.git 1412. [func] You can now specify servers to be tried if a nameserver has IPv6 address and you only support IPv4 or the reverse. See dual-stack-servers. --- diff --git a/CHANGES b/CHANGES index fa223fcce4b..005667c3068 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +1412. [func] You can now specify servers to be tried if a nameserver + has IPv6 address and you only support IPv4 or the + reverse. See dual-stack-servers. + 1411. [bug] empty nodes should stop wildcard matches. [RT #4802] 1410. [func] handle records that live in the parent zone, e.g. DS. diff --git a/bin/named/main.c b/bin/named/main.c index 8239bbc3ffa..ac7bae91e85 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.c,v 1.128 2002/05/03 05:28:19 marka Exp $ */ +/* $Id: main.c,v 1.129 2003/01/16 03:59:23 marka Exp $ */ #include @@ -329,14 +329,31 @@ static void parse_command_line(int argc, char *argv[]) { int ch; int port; + isc_boolean_t disable6 = ISC_FALSE; + isc_boolean_t disable4 = ISC_FALSE; save_command_line(argc, argv); isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, - "c:C:d:fgi:lm:n:N:p:P:st:u:vx:")) != - -1) { + "46c:C:d:fgi:lm:n:N:p:P:st:u:vx:")) != -1) { switch (ch) { + case '4': + if (disable4) + ns_main_earlyfatal("cannot specify -4 and -6"); + if (isc_net_probeipv4() != ISC_R_SUCCESS) + ns_main_earlyfatal("IPv4 not supported by OS"); + isc_net_disableipv6(); + disable6 = ISC_TRUE; + break; + case '6': + if (disable6) + ns_main_earlyfatal("cannot specify -4 and -6"); + if (isc_net_probeipv6() != ISC_R_SUCCESS) + ns_main_earlyfatal("IPv6 not supported by OS"); + isc_net_disableipv4(); + disable4 = ISC_TRUE; + break; case 'c': ns_g_conffile = isc_commandline_argument; lwresd_g_conffile = isc_commandline_argument; diff --git a/bin/named/named.docbook b/bin/named/named.docbook index fc0099f6424..5483691787d 100644 --- a/bin/named/named.docbook +++ b/bin/named/named.docbook @@ -16,7 +16,7 @@ - WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --> - + @@ -37,6 +37,8 @@ named + + @@ -70,6 +72,27 @@ OPTIONS + + -4 + + + Use IPv4 only even if the host machine is capable of IPv6. + and are mutually + exclusive. + + + + + + -6 + + + Use IPv6 only even if the host machine is capable of IPv4. + and are mutually + exclusive. + + + -c config-file diff --git a/bin/named/server.c b/bin/named/server.c index dc13eaef4eb..291ee84bd05 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.391 2002/11/27 09:52:45 marka Exp $ */ +/* $Id: server.c,v 1.392 2003/01/16 03:59:23 marka Exp $ */ #include @@ -137,6 +137,10 @@ static isc_result_t configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, cfg_obj_t *forwarders, cfg_obj_t *forwardtype); +static isc_result_t +configure_alternates(cfg_obj_t *config, dns_view_t *view, + cfg_obj_t *alternates); + static isc_result_t configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, @@ -558,6 +562,7 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *voptions = NULL; cfg_obj_t *forwardtype; cfg_obj_t *forwarders; + cfg_obj_t *alternates; cfg_obj_t *zonelist; cfg_obj_t *obj; cfg_listelt_t *element; @@ -748,6 +753,14 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, CHECK(configure_forward(config, view, dns_rootname, forwarders, forwardtype)); + /* + * Dual Stack Servers. + */ + alternates = NULL; + (void)ns_config_get(maps, "dual-stack-servers", &alternates); + if (alternates != NULL) + CHECK(configure_alternates(config, view, alternates)); + /* * We have default hints for class IN if we need them. */ @@ -987,6 +1000,91 @@ configure_hints(dns_view_t *view, const char *filename) { return (result); } +static isc_result_t +configure_alternates(cfg_obj_t *config, dns_view_t *view, + cfg_obj_t *alternates) +{ + cfg_obj_t *portobj; + cfg_obj_t *addresses; + cfg_listelt_t *element; + isc_result_t result = ISC_R_SUCCESS; + in_port_t port; + + /* + * Determine which port to send requests to. + */ + if (ns_g_lwresdonly && ns_g_port != 0) + port = ns_g_port; + else + CHECKM(ns_config_getport(config, &port), "port"); + + if (alternates != NULL) { + portobj = cfg_tuple_get(alternates, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + return (ISC_R_RANGE); + } + port = (in_port_t) val; + } + } + + addresses = NULL; + if (alternates != NULL) + addresses = cfg_tuple_get(alternates, "addresses"); + + for (element = cfg_list_first(addresses); + element != NULL; + element = cfg_list_next(element)) + { + cfg_obj_t *alternate = cfg_listelt_value(element); + isc_sockaddr_t sa; + + if (!cfg_obj_issockaddr(alternate)) { + dns_fixedname_t fixed; + dns_name_t *name; + char *str = cfg_obj_asstring(cfg_tuple_get(alternate, + "name")); + isc_buffer_t buffer; + in_port_t myport = port; + + isc_buffer_init(&buffer, str, strlen(str)); + isc_buffer_add(&buffer, strlen(str)); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + CHECK(dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL)); + + portobj = cfg_tuple_get(alternates, "port"); + if (cfg_obj_isuint32(portobj)) { + isc_uint32_t val = cfg_obj_asuint32(portobj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(portobj, ns_g_lctx, + ISC_LOG_ERROR, + "port '%u' out of range", + val); + return (ISC_R_RANGE); + } + myport = (in_port_t) val; + } + CHECK(dns_resolver_addalternate(view->resolver, NULL, + name, myport)); + continue; + } + + sa = *cfg_obj_assockaddr(alternate); + if (isc_sockaddr_getport(&sa) == 0) + isc_sockaddr_setport(&sa, port); + CHECK(dns_resolver_addalternate(view->resolver, &sa, + NULL, 0)); + } + + cleanup: + return (result); +} + static isc_result_t configure_forward(cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, cfg_obj_t *forwarders, cfg_obj_t *forwardtype) diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 48d547033c3..c2b07fbdadc 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -2,7 +2,7 @@ - + BIND 9 Administrator Reference Manual @@ -2717,6 +2717,7 @@ statement in the named.conf file: maintain-ixfr-base yes_or_no; forward ( only | first ); forwarders { ip_addr port ip_port ; ip_addr port ip_port ; ... }; + dual-stack-servers port ip_port { ( domain_name port ip_port | ip_addr port ip_port ) ; ... }; check-names ( master | slave | response )( warn | fail | ignore ); allow-notify { address_match_list }; allow-query { address_match_list }; @@ -3303,6 +3304,23 @@ or have a different forward only/first behavior, or not forward at all, see . +6 to 4 Servers +6 to 4 servers are used as servers of last resort to work around +problems in reachability due the lack of support for either IPv4 or IPv6 +on the host machine. + + +dual-stack-servers +Specifies host names / addresses of machines with access to +both IPv4 and IPv6 transports. If a hostname is used the server must be able +to resolve the name using only the transport it has. If the machine is dual +stacked then the dual-stack-servers have no effect unless +access to a transport has been disabled on the command line +(e.g. named -4). + + + + Access Control Access to the server can be restricted based on the IP address diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 2fa2c78c420..ee131074990 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: check.c,v 1.33 2002/04/26 00:40:28 marka Exp $ */ +/* $Id: check.c,v 1.34 2003/01/16 03:59:24 marka Exp $ */ #include @@ -143,6 +143,66 @@ check_order(cfg_obj_t *options, isc_log_t *logctx) { return (result); } +static isc_result_t +check_dual_stack(cfg_obj_t *options, isc_log_t *logctx) { + cfg_listelt_t *element; + cfg_obj_t *alternates = NULL; + cfg_obj_t *value; + cfg_obj_t *obj; + char *str; + dns_fixedname_t fixed; + dns_name_t *name; + isc_buffer_t buffer; + isc_result_t result = ISC_R_SUCCESS; + isc_result_t tresult; + + (void)cfg_map_get(options, "dual-stack-servers", &alternates); + + if (alternates == NULL) + return (ISC_R_SUCCESS); + + obj = cfg_tuple_get(alternates, "port"); + if (cfg_obj_isuint32(obj)) { + isc_uint32_t val = cfg_obj_asuint32(obj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + result = ISC_R_FAILURE; + } + } + obj = cfg_tuple_get(alternates, "addresses"); + for (element = cfg_list_first(obj); + element != NULL; + element = cfg_list_next(element)) { + value = cfg_listelt_value(element); + if (cfg_obj_issockaddr(value)) + continue; + obj = cfg_tuple_get(value, "name"); + str = cfg_obj_asstring(obj); + isc_buffer_init(&buffer, str, strlen(str)); + isc_buffer_add(&buffer, strlen(str)); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + tresult = dns_name_fromtext(name, &buffer, dns_rootname, + ISC_FALSE, NULL); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "bad name '%s'", str); + result = ISC_R_FAILURE; + } + obj = cfg_tuple_get(value, "port"); + if (cfg_obj_isuint32(obj)) { + isc_uint32_t val = cfg_obj_asuint32(obj); + if (val > ISC_UINT16_MAX) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "port '%u' out of range", val); + result = ISC_R_FAILURE; + } + } + } + return (result); +} + static isc_result_t check_forward(cfg_obj_t *options, isc_log_t *logctx) { cfg_obj_t *forward = NULL; @@ -697,6 +757,19 @@ check_viewconf(cfg_obj_t *config, cfg_obj_t *vconfig, dns_rdataclass_t vclass, if (check_forward(vconfig, logctx) != ISC_R_SUCCESS) result = ISC_R_FAILURE; } + /* + * Check that dual-stack-servers is reasonable. + */ + if (vconfig == NULL) { + cfg_obj_t *options = NULL; + (void)cfg_map_get(config, "options", &options); + if (options != NULL) + if (check_dual_stack(options, logctx) != ISC_R_SUCCESS) + result = ISC_R_FAILURE; + } else { + if (check_dual_stack(vconfig, logctx) != ISC_R_SUCCESS) + result = ISC_R_FAILURE; + } /* * Check that rrset-order is reasonable. @@ -755,6 +828,10 @@ bind9_check_namedconf(cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { (void)cfg_map_get(config, "view", &views); + if (views != NULL && options != NULL) + if (check_dual_stack(options, logctx) != ISC_R_SUCCESS) + result = ISC_R_FAILURE; + if (views == NULL) { if (check_viewconf(config, NULL, dns_rdataclass_in, logctx, mctx) != ISC_R_SUCCESS) diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 13483bcc7c8..076aea9dc18 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.h,v 1.35 2001/10/29 19:02:46 gson Exp $ */ +/* $Id: resolver.h,v 1.36 2003/01/16 03:59:25 marka Exp $ */ #ifndef DNS_RESOLVER_H #define DNS_RESOLVER_H 1 @@ -359,6 +359,18 @@ dns_resolver_nrunning(dns_resolver_t *resolver); * can continue even though a fetch has been canceled. */ +isc_result_t +dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt, + dns_name_t *name, in_port_t port); +/* + * Add alternate addresses to be tried in the event that the nameservers + * for a zone are not available in the address families supported by the + * operating system. + * + * Require: + * only one of 'name' or 'alt' to be valid. + */ + ISC_LANG_ENDDECLS #endif /* DNS_RESOLVER_H */ diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 21b8cba99cd..77c725f378c 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.258 2003/01/15 05:05:13 marka Exp $ */ +/* $Id: resolver.c,v 1.259 2003/01/16 03:59:25 marka Exp $ */ #include @@ -170,7 +170,10 @@ struct fetchctx { ISC_LIST(resquery_t) queries; dns_adbfindlist_t finds; dns_adbfind_t * find; + dns_adbfindlist_t altfinds; + dns_adbfind_t * altfind; dns_adbaddrinfolist_t forwaddrs; + dns_adbaddrinfolist_t altaddrs; isc_sockaddrlist_t forwarders; dns_fwdpolicy_t fwdpolicy; isc_sockaddrlist_t bad; @@ -210,14 +213,15 @@ struct fetchctx { #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!') #define VALID_FCTX(fctx) ISC_MAGIC_VALID(fctx, FCTX_MAGIC) -#define FCTX_ATTR_HAVEANSWER 0x01 -#define FCTX_ATTR_GLUING 0x02 -#define FCTX_ATTR_ADDRWAIT 0x04 -#define FCTX_ATTR_SHUTTINGDOWN 0x08 -#define FCTX_ATTR_WANTCACHE 0x10 -#define FCTX_ATTR_WANTNCACHE 0x20 -#define FCTX_ATTR_NEEDEDNS0 0x40 -#define FCTX_ATTR_TRIEDFIND 0x80 +#define FCTX_ATTR_HAVEANSWER 0x0001 +#define FCTX_ATTR_GLUING 0x0002 +#define FCTX_ATTR_ADDRWAIT 0x0004 +#define FCTX_ATTR_SHUTTINGDOWN 0x0008 +#define FCTX_ATTR_WANTCACHE 0x0010 +#define FCTX_ATTR_WANTNCACHE 0x0020 +#define FCTX_ATTR_NEEDEDNS0 0x0040 +#define FCTX_ATTR_TRIEDFIND 0x0080 +#define FCTX_ATTR_TRIEDALT 0x0100 #define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \ 0) @@ -231,6 +235,7 @@ struct fetchctx { #define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0) #define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0) #define TRIEDFIND(f) (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0) +#define TRIEDALT(f) (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0) struct dns_fetch { unsigned int magic; @@ -247,6 +252,18 @@ typedef struct fctxbucket { isc_boolean_t exiting; } fctxbucket_t; +typedef struct alternate { + isc_boolean_t isaddress; + union { + isc_sockaddr_t addr; + struct { + dns_name_t name; + in_port_t port; + } _n; + } _u; + ISC_LINK(struct alternate) link; +} alternate_t; + struct dns_resolver { /* Unlocked. */ unsigned int magic; @@ -266,6 +283,7 @@ struct dns_resolver { unsigned int nbuckets; fctxbucket_t * buckets; isc_uint32_t lame_ttl; + ISC_LIST(alternate_t) alternates; /* Locked by lock. */ unsigned int references; isc_boolean_t exiting; @@ -434,6 +452,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); + if (finish != NULL && TRIEDFIND(fctx)) for (find = ISC_LIST_HEAD(fctx->finds); find != NULL; @@ -445,6 +464,24 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); + if (finish != NULL && TRIEDALT(fctx)) { + for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); + addrinfo != NULL; + addrinfo = ISC_LIST_NEXT(addrinfo, publink)) + if (UNMARKED(addrinfo)) + dns_adb_adjustsrtt(fctx->adb, addrinfo, + 0, factor); + for (find = ISC_LIST_HEAD(fctx->altfinds); + find != NULL; + find = ISC_LIST_NEXT(find, publink)) + for (addrinfo = ISC_LIST_HEAD(find->list); + addrinfo != NULL; + addrinfo = ISC_LIST_NEXT(addrinfo, publink)) + if (UNMARKED(addrinfo)) + dns_adb_adjustsrtt(fctx->adb, addrinfo, + 0, factor); + } + if (query->dispentry != NULL) dns_dispatch_removeresponse(&query->dispentry, deventp); @@ -515,6 +552,22 @@ fctx_cleanupfinds(fetchctx_t *fctx) { fctx->find = NULL; } +static void +fctx_cleanupaltfinds(fetchctx_t *fctx) { + dns_adbfind_t *find, *next_find; + + REQUIRE(ISC_LIST_EMPTY(fctx->queries)); + + for (find = ISC_LIST_HEAD(fctx->altfinds); + find != NULL; + find = next_find) { + next_find = ISC_LIST_NEXT(find, publink); + ISC_LIST_UNLINK(fctx->altfinds, find, publink); + dns_adb_destroyfind(&find); + } + fctx->altfind = NULL; +} + static void fctx_cleanupforwaddrs(fetchctx_t *fctx) { dns_adbaddrinfo_t *addr, *next_addr; @@ -530,12 +583,29 @@ fctx_cleanupforwaddrs(fetchctx_t *fctx) { } } +static void +fctx_cleanupaltaddrs(fetchctx_t *fctx) { + dns_adbaddrinfo_t *addr, *next_addr; + + REQUIRE(ISC_LIST_EMPTY(fctx->queries)); + + for (addr = ISC_LIST_HEAD(fctx->altaddrs); + addr != NULL; + addr = next_addr) { + next_addr = ISC_LIST_NEXT(addr, publink); + ISC_LIST_UNLINK(fctx->altaddrs, addr, publink); + dns_adb_freeaddrinfo(fctx->adb, &addr); + } +} + static inline void fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) { FCTXTRACE("stopeverything"); fctx_cancelqueries(fctx, no_response); fctx_cleanupfinds(fctx); + fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); + fctx_cleanupaltaddrs(fctx); fctx_stoptimer(fctx); } @@ -1331,6 +1401,31 @@ mark_bad(fetchctx_t *fctx) { all_bad = ISC_FALSE; } + /* + * Mark any bad alternates. + */ + for (curr = ISC_LIST_HEAD(fctx->altfinds); + curr != NULL; + curr = ISC_LIST_NEXT(curr, publink)) { + for (addrinfo = ISC_LIST_HEAD(curr->list); + addrinfo != NULL; + addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { + if (bad_server(fctx, &addrinfo->sockaddr)) + addrinfo->flags |= FCTX_ADDRINFO_MARK; + else + all_bad = ISC_FALSE; + } + } + + for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); + addrinfo != NULL; + addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { + if (bad_server(fctx, &addrinfo->sockaddr)) + addrinfo->flags |= FCTX_ADDRINFO_MARK; + else + all_bad = ISC_FALSE; + } + return (all_bad); } @@ -1444,6 +1539,146 @@ sort_finds(fetchctx_t *fctx) { ISC_LIST_APPEND(sorted, best, publink); } fctx->finds = sorted; + + ISC_LIST_INIT(sorted); + while (!ISC_LIST_EMPTY(fctx->altfinds)) { + best = ISC_LIST_HEAD(fctx->altfinds); + bestaddrinfo = ISC_LIST_HEAD(best->list); + INSIST(bestaddrinfo != NULL); + curr = ISC_LIST_NEXT(best, publink); + while (curr != NULL) { + addrinfo = ISC_LIST_HEAD(curr->list); + INSIST(addrinfo != NULL); + if (addrinfo->srtt < bestaddrinfo->srtt) { + best = curr; + bestaddrinfo = addrinfo; + } + curr = ISC_LIST_NEXT(curr, publink); + } + ISC_LIST_UNLINK(fctx->altfinds, best, publink); + ISC_LIST_APPEND(sorted, best, publink); + } + fctx->altfinds = sorted; +} + +static void +findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, + unsigned int options, unsigned int flags, isc_stdtime_t now, + isc_boolean_t *pruned, isc_boolean_t *need_alternate) +{ + dns_adbaddrinfo_t *ai; + dns_adbfind_t *find; + dns_resolver_t *res; + isc_boolean_t unshared; + isc_result_t result; + + res = fctx->res; + unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0); + /* + * If this name is a subdomain of the query domain, tell + * the ADB to start looking at "." if it doesn't know the + * address. This keeps us from getting stuck if the + * nameserver is beneath the zone cut and we don't know its + * address (e.g. because the A record has expired). + * By restarting from ".", we ensure that any missing glue + * will be reestablished. + * + * A further optimization would be to get the ADB to start + * looking at the most enclosing zone cut above fctx->domain. + * We don't expect this situation to happen very frequently, + * so we've chosen the simple solution. + */ + if (dns_name_issubdomain(name, &fctx->domain)) + options |= DNS_ADBFIND_STARTATROOT; + options |= DNS_ADBFIND_GLUEOK; + options |= DNS_ADBFIND_HINTOK; + + /* + * See what we know about this address. + */ + find = NULL; + result = dns_adb_createfind(fctx->adb, + res->buckets[fctx->bucketnum].task, + fctx_finddone, fctx, name, + &fctx->domain, options, now, NULL, + res->view->dstport, &find); + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_ALIAS) { + /* + * XXXRTH Follow the CNAME/DNAME chain? + */ + dns_adb_destroyfind(&find); + } + } else if (!ISC_LIST_EMPTY(find->list)) { + /* + * We have at least some of the addresses for the + * name. + */ + INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); + sort_adbfind(find); + if (flags != 0 || port != 0) { + for (ai = ISC_LIST_HEAD(find->list); + ai != NULL; + ai = ISC_LIST_NEXT(ai, publink)) { + ai->flags |= flags; + if (port != 0) + isc_sockaddr_setport(&ai->sockaddr, + port); + } + } + if ((flags & FCTX_ADDRINFO_FORWARDER) != 0) + ISC_LIST_APPEND(fctx->altfinds, find, publink); + else + ISC_LIST_APPEND(fctx->finds, find, publink); + } else { + /* + * We don't know any of the addresses for this + * name. + */ + if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) { + /* + * We're looking for them and will get an + * event about it later. + */ + fctx->pending++; + /* + * Bootstrap. + */ + if (need_alternate != NULL && + !*need_alternate && unshared && + ((res->dispatchv4 == NULL && + find->result_v6 != DNS_R_NXDOMAIN) || + (res->dispatchv6 == NULL && + find->result_v4 != DNS_R_NXDOMAIN))) + *need_alternate = ISC_TRUE; + } else { + /* + * If we know there are no addresses for + * the family we are using then try to add + * an alternative server. + */ + if (need_alternate != NULL && !*need_alternate && + ((res->dispatchv4 == NULL && + find->result_v6 == DNS_R_NXRRSET) || + (res->dispatchv6 == NULL && + find->result_v4 == DNS_R_NXRRSET))) + *need_alternate = ISC_TRUE; + /* + * And ADB isn't going to send us any events + * either. This find loses. + */ + if ((find->options & DNS_ADBFIND_LAMEPRUNED) + != 0) { + /* + * The ADB pruned lame servers for + * this name. Remember that in case + * we get desperate later on. + */ + *pruned = ISC_TRUE; + } + dns_adb_destroyfind(&find); + } + } } static isc_result_t @@ -1452,12 +1687,13 @@ fctx_getaddresses(fetchctx_t *fctx) { isc_result_t result; dns_resolver_t *res; isc_stdtime_t now; - dns_adbfind_t *find; - unsigned int stdoptions, options; + unsigned int stdoptions; isc_sockaddr_t *sa; dns_adbaddrinfo_t *ai; isc_boolean_t pruned, all_bad; dns_rdata_ns_t ns; + isc_boolean_t need_alternate = ISC_FALSE; + isc_boolean_t unshared; FCTXTRACE("getaddresses"); @@ -1473,12 +1709,14 @@ fctx_getaddresses(fetchctx_t *fctx) { res = fctx->res; pruned = ISC_FALSE; stdoptions = 0; /* Keep compiler happy. */ + unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0); /* * Forwarders. */ INSIST(ISC_LIST_EMPTY(fctx->forwaddrs)); + INSIST(ISC_LIST_EMPTY(fctx->altaddrs)); /* * If this fctx has forwarders, use them; otherwise use any @@ -1495,7 +1733,7 @@ fctx_getaddresses(fetchctx_t *fctx) { fctx->fwdpolicy = forwarders->fwdpolicy; } } - + while (sa != NULL) { ai = NULL; result = dns_adb_findaddrinfo(fctx->adb, @@ -1549,6 +1787,7 @@ fctx_getaddresses(fetchctx_t *fctx) { restart: INSIST(ISC_LIST_EMPTY(fctx->finds)); + INSIST(ISC_LIST_EMPTY(fctx->altfinds)); for (result = dns_rdataset_first(&fctx->nameservers); result == ISC_R_SUCCESS; @@ -1562,84 +1801,51 @@ fctx_getaddresses(fetchctx_t *fctx) { if (result != ISC_R_SUCCESS) continue; - options = stdoptions; - /* - * If this name is a subdomain of the query domain, tell - * the ADB to start looking at "." if it doesn't know the - * address. This keeps us from getting stuck if the - * nameserver is beneath the zone cut and we don't know its - * address (e.g. because the A record has expired). - * By restarting from ".", we ensure that any missing glue - * will be reestablished. - * - * A further optimization would be to get the ADB to start - * looking at the most enclosing zone cut above fctx->domain. - * We don't expect this situation to happen very frequently, - * so we've chosen the simple solution. - */ - if (dns_name_issubdomain(&ns.name, &fctx->domain)) - options |= DNS_ADBFIND_STARTATROOT; - options |= DNS_ADBFIND_GLUEOK; - options |= DNS_ADBFIND_HINTOK; - - /* - * See what we know about this address. - */ - find = NULL; - result = dns_adb_createfind(fctx->adb, - res->buckets[fctx->bucketnum].task, - fctx_finddone, fctx, &ns.name, - &fctx->domain, options, now, NULL, - res->view->dstport, &find); - if (result != ISC_R_SUCCESS) { - if (result == DNS_R_ALIAS) { - /* - * XXXRTH Follow the CNAME/DNAME chain? - */ - dns_adb_destroyfind(&find); - } - } else if (!ISC_LIST_EMPTY(find->list)) { - /* - * We have at least some of the addresses for the - * name. - */ - INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); - sort_adbfind(find); - ISC_LIST_APPEND(fctx->finds, find, publink); - } else { - /* - * We don't know any of the addresses for this - * name. - */ - if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) { - /* - * We're looking for them and will get an - * event about it later. - */ - fctx->pending++; - } else { - /* - * And ADB isn't going to send us any events - * either. This find loses. - */ - if ((find->options & DNS_ADBFIND_LAMEPRUNED) - != 0) { - /* - * The ADB pruned lame servers for - * this name. Remember that in case - * we get desperate later on. - */ - pruned = ISC_TRUE; - } - dns_adb_destroyfind(&find); - } - } + findname(fctx, &ns.name, 0, stdoptions, 0, now, + &pruned, &need_alternate); dns_rdata_reset(&rdata); dns_rdata_freestruct(&ns); } if (result != ISC_R_NOMORE) return (result); + /* + * Do we need to use 6 to 4? + */ + if (need_alternate) { + int family; + alternate_t *a; + family = (res->dispatchv6 != NULL) ? AF_INET6 : AF_INET; + for (a = ISC_LIST_HEAD(fctx->res->alternates); + a != NULL; + a = ISC_LIST_NEXT(a, link)) { + if (!a->isaddress) { + findname(fctx, &a->_u._n.name, a->_u._n.port, + stdoptions, FCTX_ADDRINFO_FORWARDER, + now, &pruned, NULL); + continue; + } + if (isc_sockaddr_pf(&a->_u.addr) != family) + continue; + ai = NULL; + result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr, + &ai, 0); + if (result == ISC_R_SUCCESS) { + dns_adbaddrinfo_t *cur; + ai->flags |= FCTX_ADDRINFO_FORWARDER; + cur = ISC_LIST_HEAD(fctx->altaddrs); + while (cur != NULL && cur->srtt < ai->srtt) + cur = ISC_LIST_NEXT(cur, publink); + if (cur != NULL) + ISC_LIST_INSERTBEFORE(fctx->altaddrs, + cur, ai, publink); + else + ISC_LIST_APPEND(fctx->altaddrs, ai, + publink); + } + } + } + out: /* * Mark all known bad servers. @@ -1668,6 +1874,7 @@ fctx_getaddresses(fetchctx_t *fctx) { INSIST((stdoptions & DNS_ADBFIND_RETURNLAME) == 0); stdoptions |= DNS_ADBFIND_RETURNLAME; pruned = ISC_FALSE; + fctx_cleanupaltfinds(fctx); fctx_cleanupfinds(fctx); goto restart; } else { @@ -1756,6 +1963,7 @@ static inline dns_adbaddrinfo_t * fctx_nextaddress(fetchctx_t *fctx) { dns_adbfind_t *find; dns_adbaddrinfo_t *addrinfo; + dns_adbaddrinfo_t *faddrinfo; /* * Return the next untried address, if any. @@ -1767,6 +1975,8 @@ fctx_nextaddress(fetchctx_t *fctx) { for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { + if (!UNMARKED(addrinfo)) + continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; @@ -1775,11 +1985,12 @@ fctx_nextaddress(fetchctx_t *fctx) { } } - fctx->attributes |= FCTX_ATTR_TRIEDFIND; - /* * No forwarders. Move to the next find. */ + + fctx->attributes |= FCTX_ATTR_TRIEDFIND; + find = fctx->find; if (find == NULL) find = ISC_LIST_HEAD(fctx->finds); @@ -1797,6 +2008,8 @@ fctx_nextaddress(fetchctx_t *fctx) { for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { + if (!UNMARKED(addrinfo)) + continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; @@ -1811,6 +2024,73 @@ fctx_nextaddress(fetchctx_t *fctx) { } fctx->find = find; + if (addrinfo != NULL) + return (addrinfo); + + /* + * No nameservers left. Try alternates. + */ + + fctx->attributes |= FCTX_ATTR_TRIEDALT; + + find = fctx->altfind; + if (find == NULL) + find = ISC_LIST_HEAD(fctx->altfinds); + else { + find = ISC_LIST_NEXT(find, publink); + if (find == NULL) + find = ISC_LIST_HEAD(fctx->altfinds); + } + + /* + * Find the first unmarked addrinfo. + */ + addrinfo = NULL; + while (find != fctx->altfind) { + for (addrinfo = ISC_LIST_HEAD(find->list); + addrinfo != NULL; + addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { + if (!UNMARKED(addrinfo)) + continue; + possibly_mark(fctx, addrinfo); + if (UNMARKED(addrinfo)) { + addrinfo->flags |= FCTX_ADDRINFO_MARK; + break; + } + } + if (addrinfo != NULL) + break; + find = ISC_LIST_NEXT(find, publink); + if (find != fctx->altfind && find == NULL) + find = ISC_LIST_HEAD(fctx->altfinds); + } + + faddrinfo = addrinfo; + + /* + * See if we have a better alternate server by address. + */ + + for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); + addrinfo != NULL; + addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { + if (!UNMARKED(addrinfo)) + continue; + possibly_mark(fctx, addrinfo); + if (UNMARKED(addrinfo) && + (faddrinfo == NULL || + addrinfo->srtt < faddrinfo->srtt)) { + if (faddrinfo != NULL) + faddrinfo->flags &= ~FCTX_ADDRINFO_MARK; + addrinfo->flags |= FCTX_ADDRINFO_MARK; + break; + } + } + + if (addrinfo == NULL) { + addrinfo = faddrinfo; + fctx->altfind = find; + } return (addrinfo); } @@ -1831,7 +2111,9 @@ fctx_try(fetchctx_t *fctx) { */ fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); + fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); + fctx_cleanupaltaddrs(fctx); result = fctx_getaddresses(fctx); if (result == DNS_R_WAIT) { /* @@ -1880,6 +2162,7 @@ fctx_destroy(fetchctx_t *fctx) { REQUIRE(ISC_LIST_EMPTY(fctx->events)); REQUIRE(ISC_LIST_EMPTY(fctx->queries)); REQUIRE(ISC_LIST_EMPTY(fctx->finds)); + REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); REQUIRE(fctx->pending == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); REQUIRE(fctx->references == 0); @@ -2232,12 +2515,15 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, fctx->cloned = ISC_FALSE; ISC_LIST_INIT(fctx->queries); ISC_LIST_INIT(fctx->finds); + ISC_LIST_INIT(fctx->altfinds); ISC_LIST_INIT(fctx->forwaddrs); + ISC_LIST_INIT(fctx->altaddrs); ISC_LIST_INIT(fctx->forwarders); fctx->fwdpolicy = dns_fwdpolicy_none; ISC_LIST_INIT(fctx->bad); ISC_LIST_INIT(fctx->validators); fctx->find = NULL; + fctx->altfind = NULL; fctx->pending = 0; fctx->restarts = 0; fctx->timeouts = 0; @@ -4814,7 +5100,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); + fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); + fctx_cleanupaltaddrs(fctx); } /* * Try again. @@ -4884,6 +5172,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { static void destroy(dns_resolver_t *res) { unsigned int i; + alternate_t *a; REQUIRE(res->references == 0); REQUIRE(!res->priming); @@ -4907,6 +5196,12 @@ destroy(dns_resolver_t *res) { dns_dispatch_detach(&res->dispatchv4); if (res->dispatchv6 != NULL) dns_dispatch_detach(&res->dispatchv6); + while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) { + ISC_LIST_UNLINK(res->alternates, a, link); + if (!a->isaddress) + dns_name_free(&a->_u._n.name, res->mctx); + isc_mem_put(res->mctx, a, sizeof(*a)); + } res->magic = 0; isc_mem_put(res->mctx, res, sizeof(*res)); } @@ -4984,6 +5279,7 @@ dns_resolver_create(dns_view_t *view, res->view = view; res->options = options; res->lame_ttl = 0; + ISC_LIST_INIT(res->alternates); res->nbuckets = ntasks; res->activebuckets = ntasks; @@ -5596,3 +5892,35 @@ dns_resolver_nrunning(dns_resolver_t *resolver) { UNLOCK(&resolver->nlock); return (n); } + +isc_result_t +dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt, + dns_name_t *name, in_port_t port) { + alternate_t *a; + isc_result_t result; + + REQUIRE(VALID_RESOLVER(resolver)); + REQUIRE(!resolver->frozen); + REQUIRE((alt == NULL) ^ (name == NULL)); + + a = isc_mem_get(resolver->mctx, sizeof(*a)); + if (a == NULL) + return (ISC_R_NOMEMORY); + if (alt != NULL) { + a->isaddress = ISC_TRUE; + a->_u.addr = *alt; + } else { + a->isaddress = ISC_FALSE; + a->_u._n.port = port; + dns_name_init(&a->_u._n.name, NULL); + result = dns_name_dup(name, resolver->mctx, &a->_u._n.name); + if (result != ISC_R_SUCCESS) { + isc_mem_put(resolver->mctx, a, sizeof(*a)); + return (result); + } + } + ISC_LINK_INIT(a, link); + ISC_LIST_APPEND(resolver->alternates, a, link); + + return (ISC_R_SUCCESS); +} diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h index bf6b9925873..bc4769a3205 100644 --- a/lib/isc/include/isc/result.h +++ b/lib/isc/include/isc/result.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.59 2001/11/30 01:02:17 gson Exp $ */ +/* $Id: result.h,v 1.60 2003/01/16 03:59:26 marka Exp $ */ #ifndef ISC_RESULT_H #define ISC_RESULT_H 1 @@ -80,11 +80,12 @@ #define ISC_R_CONNECTIONRESET 54 /* connection reset */ #define ISC_R_SOFTQUOTA 55 /* soft quota reached */ #define ISC_R_BADNUMBER 56 /* not a valid number */ +#define ISC_R_DISABLED 57 /* disabled */ /* * Not a result code: the number of results. */ -#define ISC_R_NRESULTS 57 +#define ISC_R_NRESULTS 58 ISC_LANG_BEGINDECLS diff --git a/lib/isc/result.c b/lib/isc/result.c index 397bfad50d1..53cf8b39355 100644 --- a/lib/isc/result.c +++ b/lib/isc/result.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.c,v 1.59 2001/11/30 01:02:14 gson Exp $ */ +/* $Id: result.c,v 1.60 2003/01/16 03:59:25 marka Exp $ */ #include @@ -94,7 +94,8 @@ static const char *text[ISC_R_NRESULTS] = { "operation in progress", /* 53 */ "connection reset", /* 54 */ "soft quota reached", /* 55 */ - "not a valid number" /* 56 */ + "not a valid number", /* 56 */ + "disabled" /* 57 */ }; #define ISC_RESULT_RESULTSET 2 diff --git a/lib/isc/unix/include/isc/net.h b/lib/isc/unix/include/isc/net.h index 2997588eae3..7d6e3f9ed36 100644 --- a/lib/isc/unix/include/isc/net.h +++ b/lib/isc/unix/include/isc/net.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.h,v 1.36 2002/10/29 04:40:25 marka Exp $ */ +/* $Id: net.h,v 1.37 2003/01/16 03:59:27 marka Exp $ */ #ifndef ISC_NET_H #define ISC_NET_H 1 @@ -245,6 +245,7 @@ isc_net_probeipv4(void); * * ISC_R_SUCCESS IPv4 is supported. * ISC_R_NOTFOUND IPv4 is not supported. + * ISC_R_DISABLED IPv4 is disabled. * ISC_R_UNEXPECTED */ @@ -257,6 +258,7 @@ isc_net_probeipv6(void); * * ISC_R_SUCCESS IPv6 is supported. * ISC_R_NOTFOUND IPv6 is not supported. + * ISC_R_DISABLED IPv6 is disabled. * ISC_R_UNEXPECTED */ @@ -272,6 +274,18 @@ isc_net_probe_ipv6only(void); * ISC_R_UNEXPECTED */ +void +isc_net_disableipv4(void); + +void +isc_net_disableipv6(void); + +void +isc_net_enableipv4(void); + +void +isc_net_enableipv6(void); + #ifdef ISC_PLATFORM_NEEDNTOP const char * isc_net_ntop(int af, const void *src, char *dst, size_t size); diff --git a/lib/isc/unix/net.c b/lib/isc/unix/net.c index 61934683674..d27d6ee1cdf 100644 --- a/lib/isc/unix/net.c +++ b/lib/isc/unix/net.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.c,v 1.27 2002/12/24 05:12:50 marka Exp $ */ +/* $Id: net.c,v 1.28 2003/01/16 03:59:27 marka Exp $ */ #include @@ -95,7 +95,7 @@ try_proto(int domain) { "socket from the kernel failed."); isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, - "IPv6 support is disabled."); + "IPv6 is not supported."); result = ISC_R_NOTFOUND; } else { if (len == sizeof(struct sockaddr_in6)) @@ -111,7 +111,7 @@ try_proto(int domain) { ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, - "IPv6 support is disabled."); + "IPv6 is not supported."); result = ISC_R_NOTFOUND; } } @@ -247,3 +247,31 @@ isc_net_probe_ipv6only(void) { #endif return (ipv6only_result); } + +void +isc_net_disableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_SUCCESS) + ipv4_result = ISC_R_DISABLED; +} + +void +isc_net_disableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_SUCCESS) + ipv6_result = ISC_R_DISABLED; +} + +void +isc_net_enableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_DISABLED) + ipv4_result = ISC_R_SUCCESS; +} + +void +isc_net_enableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_DISABLED) + ipv6_result = ISC_R_SUCCESS; +} diff --git a/lib/isc/win32/include/isc/net.h b/lib/isc/win32/include/isc/net.h index 1f909362fde..ced83e5d79e 100644 --- a/lib/isc/win32/include/isc/net.h +++ b/lib/isc/win32/include/isc/net.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.h,v 1.18 2002/10/29 04:40:26 marka Exp $ */ +/* $Id: net.h,v 1.19 2003/01/16 03:59:28 marka Exp $ */ #ifndef ISC_NET_H #define ISC_NET_H 1 @@ -232,6 +232,7 @@ isc_net_probeipv4(void); * * ISC_R_SUCCESS IPv4 is supported. * ISC_R_NOTFOUND IPv4 is not supported. + * ISC_R_DISABLED IPv4 is disabled. * ISC_R_UNEXPECTED */ @@ -244,6 +245,7 @@ isc_net_probeipv6(void); * * ISC_R_SUCCESS IPv6 is supported. * ISC_R_NOTFOUND IPv6 is not supported. + * ISC_R_DISABLED IPv6 is disabled. * ISC_R_UNEXPECTED */ @@ -259,6 +261,18 @@ isc_net_probe_ipv6only(void); * ISC_R_UNEXPECTED */ +void +isc_net_disableipv4(void); + +void +isc_net_disableipv6(void); + +void +isc_net_enableipv4(void); + +void +isc_net_enableipv6(void); + #ifdef ISC_PLATFORM_NEEDNTOP const char * isc_net_ntop(int af, const void *src, char *dst, size_t size); diff --git a/lib/isc/win32/net.c b/lib/isc/win32/net.c index b5e0d4f685a..29c90f425a3 100644 --- a/lib/isc/win32/net.c +++ b/lib/isc/win32/net.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.c,v 1.6 2003/01/14 23:37:06 marka Exp $ */ +/* $Id: net.c,v 1.7 2003/01/16 03:59:27 marka Exp $ */ #include @@ -240,3 +240,31 @@ isc_net_probe_ipv6only(void) { #endif return (ipv6only_result); } + +void +isc_net_disableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_SUCCESS) + ipv4_result = ISC_R_DISABLED; +} + +void +isc_net_disableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_SUCCESS) + ipv6_result = ISC_R_DISABLED; +} + +void +isc_net_enableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_DISABLED) + ipv4_result = ISC_R_SUCCESS; +} + +void +isc_net_enableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_DISABLED) + ipv6_result = ISC_R_SUCCESS; +} diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 691e601479c..5c7e7fece8c 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.11 2002/11/27 09:52:58 marka Exp $ */ +/* $Id: namedconf.c,v 1.12 2003/01/16 03:59:28 marka Exp $ */ #include @@ -66,42 +66,45 @@ doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); static void doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); -static cfg_type_t cfg_type_optional_port; -static cfg_type_t cfg_type_bracketed_aml; static cfg_type_t cfg_type_acl; -static cfg_type_t cfg_type_portiplist; +static cfg_type_t cfg_type_addrmatchelt; +static cfg_type_t cfg_type_bracketed_aml; +static cfg_type_t cfg_type_bracketed_namesockaddrlist; +static cfg_type_t cfg_type_bracketed_sockaddrkeylist; static cfg_type_t cfg_type_bracketed_sockaddrlist; +static cfg_type_t cfg_type_controls; +static cfg_type_t cfg_type_controls_sockaddr; +static cfg_type_t cfg_type_destinationlist; +static cfg_type_t cfg_type_dialuptype; +static cfg_type_t cfg_type_key; +static cfg_type_t cfg_type_logfile; +static cfg_type_t cfg_type_logging; +static cfg_type_t cfg_type_logseverity; +static cfg_type_t cfg_type_lwres; +static cfg_type_t cfg_type_nameportiplist; +static cfg_type_t cfg_type_namesockaddr; +static cfg_type_t cfg_type_negated; +static cfg_type_t cfg_type_notifytype; +static cfg_type_t cfg_type_optional_class; +static cfg_type_t cfg_type_optional_facility; +static cfg_type_t cfg_type_optional_facility; static cfg_type_t cfg_type_optional_keyref; +static cfg_type_t cfg_type_optional_port; static cfg_type_t cfg_type_options; -static cfg_type_t cfg_type_view; -static cfg_type_t cfg_type_viewopts; -static cfg_type_t cfg_type_key; -static cfg_type_t cfg_type_server; -static cfg_type_t cfg_type_controls; -static cfg_type_t cfg_type_bracketed_sockaddrkeylist; +static cfg_type_t cfg_type_portiplist; static cfg_type_t cfg_type_querysource4; static cfg_type_t cfg_type_querysource6; static cfg_type_t cfg_type_querysource; +static cfg_type_t cfg_type_server; +static cfg_type_t cfg_type_server_key_kludge; +static cfg_type_t cfg_type_size; +static cfg_type_t cfg_type_sizenodefault; static cfg_type_t cfg_type_sockaddr4wild; static cfg_type_t cfg_type_sockaddr6wild; +static cfg_type_t cfg_type_view; +static cfg_type_t cfg_type_viewopts; static cfg_type_t cfg_type_zone; static cfg_type_t cfg_type_zoneopts; -static cfg_type_t cfg_type_logging; -static cfg_type_t cfg_type_optional_facility; -static cfg_type_t cfg_type_optional_class; -static cfg_type_t cfg_type_destinationlist; -static cfg_type_t cfg_type_size; -static cfg_type_t cfg_type_sizenodefault; -static cfg_type_t cfg_type_negated; -static cfg_type_t cfg_type_addrmatchelt; -static cfg_type_t cfg_type_server_key_kludge; -static cfg_type_t cfg_type_optional_facility; -static cfg_type_t cfg_type_logseverity; -static cfg_type_t cfg_type_logfile; -static cfg_type_t cfg_type_lwres; -static cfg_type_t cfg_type_controls_sockaddr; -static cfg_type_t cfg_type_notifytype; -static cfg_type_t cfg_type_dialuptype; /* tkey-dhkey */ @@ -556,6 +559,7 @@ view_clauses[] = { { "cache-file", &cfg_type_qstring, 0 }, { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, { "preferred-glue", &cfg_type_astring, 0 }, + { "dual-stack-servers", &cfg_type_nameportiplist, 0 }, { NULL, NULL, 0 } }; @@ -1259,7 +1263,6 @@ static cfg_type_t cfg_type_controls_sockaddr = { cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags }; - /* * Handle the special kludge syntax of the "keys" clause in the "server" * statement, which takes a single key with or without braces and semicolon. @@ -1582,3 +1585,92 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = { "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody, &cfg_rep_map, rndckey_clausesets }; + +static cfg_tuplefielddef_t nameport_fields[] = { + { "name", &cfg_type_astring, 0 }, + { "port", &cfg_type_optional_port, 0 }, + { NULL, NULL, 0 } +}; +static cfg_type_t cfg_type_nameport = { + "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, nameport_fields +}; + +static void +doc_namesockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { + UNUSED(type); + cfg_print_chars(pctx, "( ", 2); + cfg_print_cstr(pctx, ""); + cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, "[port ]"); + cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, ""); + cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, "[port ]"); + cfg_print_chars(pctx, " | ", 3); + cfg_print_cstr(pctx, ""); + cfg_print_chars(pctx, " ", 1); + cfg_print_cstr(pctx, "[port ]"); + cfg_print_chars(pctx, " )", 2); +} + +static isc_result_t +parse_namesockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) +{ + isc_result_t result; + cfg_obj_t *obj = NULL; + UNUSED(type); + + CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); + if (pctx->token.type == isc_tokentype_string || + pctx->token.type == isc_tokentype_qstring) { + if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK)) + CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret)); + else { + const cfg_tuplefielddef_t *fields = + cfg_type_nameport.of; + CHECK(cfg_create_tuple(pctx, &cfg_type_nameport, + &obj)); + CHECK(cfg_parse_obj(pctx, fields[0].type, + &obj->value.tuple[0])); + CHECK(cfg_parse_obj(pctx, fields[1].type, + &obj->value.tuple[1])); + *ret = obj; + obj = NULL; + } + } else { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected IP match list element"); + return (ISC_R_UNEXPECTEDTOKEN); + } + cleanup: + CLEANUP_OBJ(obj); + return (result); +} + +static cfg_type_t cfg_type_namesockaddr = { + "namesockaddr_element", parse_namesockaddr, NULL, doc_namesockaddr, + NULL, NULL +}; + +static cfg_type_t cfg_type_bracketed_namesockaddrlist = { + "bracketed_namesockaddrlist", cfg_parse_bracketed_list, + cfg_print_bracketed_list, cfg_doc_bracketed_list, + &cfg_rep_list, &cfg_type_namesockaddr +}; + +/* + * A list of socket addresses or named with an optional default port, + * as used in the dual-stack-servers option. E.g., + * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }" + */ +static cfg_tuplefielddef_t nameportiplist_fields[] = { + { "port", &cfg_type_optional_port, 0 }, + { "addresses", &cfg_type_bracketed_namesockaddrlist, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_nameportiplist = { + "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, nameportiplist_fields +};