+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.
* 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 <config.h>
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;
- WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: named.docbook,v 1.5 2001/06/10 13:57:51 tale Exp $ -->
+<!-- $Id: named.docbook,v 1.6 2003/01/16 03:59:23 marka Exp $ -->
<refentry>
<refentryinfo>
<refsynopsisdiv>
<cmdsynopsis>
<command>named</command>
+ <arg><option>-4</option></arg>
+ <arg><option>-6</option></arg>
<arg><option>-c <replaceable class="parameter">config-file</replaceable></option></arg>
<arg><option>-d <replaceable class="parameter">debug-level</replaceable></option></arg>
<arg><option>-f</option></arg>
<title>OPTIONS</title>
<variablelist>
+ <varlistentry>
+ <term>-4</term>
+ <listitem>
+ <para>
+ Use IPv4 only even if the host machine is capable of IPv6.
+ <option>-4</option> and <option>-6</option> are mutually
+ exclusive.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-6</term>
+ <listitem>
+ <para>
+ Use IPv6 only even if the host machine is capable of IPv4.
+ <option>-4</option> and <option>-6</option> are mutually
+ exclusive.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>-c <replaceable class="parameter">config-file</replaceable></term>
<listitem>
* 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 <config.h>
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,
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;
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.
*/
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)
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.0//EN"
"http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd">
-<!-- File: $Id: Bv9ARM-book.xml,v 1.211 2003/01/13 04:24:27 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.212 2003/01/16 03:59:24 marka Exp $ -->
<book>
<title>BIND 9 Administrator Reference Manual</title>
<optional> maintain-ixfr-base <replaceable>yes_or_no</replaceable>; </optional>
<optional> forward ( <replaceable>only</replaceable> | <replaceable>first</replaceable> ); </optional>
<optional> forwarders { <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; <optional> <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ; ... </optional> }; </optional>
+ <optional> dual-stack-servers <optional>port <replaceable>ip_port</replaceable></optional> { ( <replaceable>domain_name</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> | <replaceable>ip_addr</replaceable> <optional>port <replaceable>ip_port</replaceable></optional> ) ; ... }; </optional>
<optional> check-names ( <replaceable>master</replaceable> | <replaceable>slave</replaceable> | <replaceable> response</replaceable> )( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
<optional> allow-notify { <replaceable>address_match_list</replaceable> }; </optional>
<optional> allow-query { <replaceable>address_match_list</replaceable> }; </optional>
or not forward at all, see <xref linkend="zone_statement_grammar"/>.</para>
</sect3>
+<sect3><title>6 to 4 Servers</title>
+<para>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.</para>
+
+<variablelist>
+<varlistentry><term><command>dual-stack-servers</command></term>
+<listitem><para>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 <command>dual-stack-servers</command> have no effect unless
+access to a transport has been disabled on the command line
+(e.g. <command>named -4</command>).</para></listitem>
+</varlistentry>
+</variablelist>
+</sect3>
+
<sect3 id="access_control"><title>Access Control</title>
<para>Access to the server can be restricted based on the IP address
* 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 <config.h>
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;
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.
(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)
* 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
* 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 */
* 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 <config.h>
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;
#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)
#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;
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;
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;
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;
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);
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;
}
}
+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);
}
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);
}
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
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");
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
fctx->fwdpolicy = forwarders->fwdpolicy;
}
}
-
+
while (sa != NULL) {
ai = NULL;
result = dns_adb_findaddrinfo(fctx->adb,
restart:
INSIST(ISC_LIST_EMPTY(fctx->finds));
+ INSIST(ISC_LIST_EMPTY(fctx->altfinds));
for (result = dns_rdataset_first(&fctx->nameservers);
result == ISC_R_SUCCESS;
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.
INSIST((stdoptions & DNS_ADBFIND_RETURNLAME) == 0);
stdoptions |= DNS_ADBFIND_RETURNLAME;
pruned = ISC_FALSE;
+ fctx_cleanupaltfinds(fctx);
fctx_cleanupfinds(fctx);
goto restart;
} else {
fctx_nextaddress(fetchctx_t *fctx) {
dns_adbfind_t *find;
dns_adbaddrinfo_t *addrinfo;
+ dns_adbaddrinfo_t *faddrinfo;
/*
* Return the next untried address, if any.
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;
}
}
- 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);
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;
}
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);
}
*/
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) {
/*
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);
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;
}
fctx_cancelqueries(fctx, ISC_TRUE);
fctx_cleanupfinds(fctx);
+ fctx_cleanupaltfinds(fctx);
fctx_cleanupforwaddrs(fctx);
+ fctx_cleanupaltaddrs(fctx);
}
/*
* Try again.
static void
destroy(dns_resolver_t *res) {
unsigned int i;
+ alternate_t *a;
REQUIRE(res->references == 0);
REQUIRE(!res->priming);
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));
}
res->view = view;
res->options = options;
res->lame_ttl = 0;
+ ISC_LIST_INIT(res->alternates);
res->nbuckets = ntasks;
res->activebuckets = ntasks;
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);
+}
* 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
#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
* 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 <config.h>
"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
* 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
*
* ISC_R_SUCCESS IPv4 is supported.
* ISC_R_NOTFOUND IPv4 is not supported.
+ * ISC_R_DISABLED IPv4 is disabled.
* ISC_R_UNEXPECTED
*/
*
* ISC_R_SUCCESS IPv6 is supported.
* ISC_R_NOTFOUND IPv6 is not supported.
+ * ISC_R_DISABLED IPv6 is disabled.
* ISC_R_UNEXPECTED
*/
* 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);
* 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 <config.h>
"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))
ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_SOCKET,
ISC_LOG_ERROR,
- "IPv6 support is disabled.");
+ "IPv6 is not supported.");
result = ISC_R_NOTFOUND;
}
}
#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;
+}
* 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
*
* ISC_R_SUCCESS IPv4 is supported.
* ISC_R_NOTFOUND IPv4 is not supported.
+ * ISC_R_DISABLED IPv4 is disabled.
* ISC_R_UNEXPECTED
*/
*
* ISC_R_SUCCESS IPv6 is supported.
* ISC_R_NOTFOUND IPv6 is not supported.
+ * ISC_R_DISABLED IPv6 is disabled.
* ISC_R_UNEXPECTED
*/
* 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);
* 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 <config.h>
#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;
+}
* 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 <config.h>
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 */
{ "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 }
};
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.
"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, "<quoted_string>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv4_address>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ cfg_print_chars(pctx, " | ", 3);
+ cfg_print_cstr(pctx, "<ipv6_address>");
+ cfg_print_chars(pctx, " ", 1);
+ cfg_print_cstr(pctx, "[port <integer>]");
+ 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
+};