diff --git a/CHANGES b/CHANGES index db3dd178e3..fd9ed4ae2f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +2353. [func] Add support for Name Server ID (RFC 5001). + 'dig +nsid' requests NSID from server. + 'request-nsid yes;' causes recursive server to send + NSID requests to upstream servers. Server responds + to NSID requests with the string configured by + 'server-id' option. [RT #17091] + 2352. [bug] Various GSS_API fixups. [RT #17729] 2351. [bug] convertxsl.pl generated very long lines. [RT #17906] diff --git a/bin/dig/dig.c b/bin/dig/dig.c index 623b93dd30..46404c841d 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.c,v 1.220 2008/02/05 23:47:08 tbox Exp $ */ +/* $Id: dig.c,v 1.221 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -194,6 +194,7 @@ help(void) { " +[no]identify (ID responders in short answers)\n" " +[no]trace (Trace delegation down from root)\n" " +[no]dnssec (Request DNSSEC records)\n" +" +[no]nsid (Request Name Server ID)\n" #ifdef DIG_SIGCHASE " +[no]sigchase (Chase DNSSEC signatures)\n" " +trusted-key=#### (Trusted Key when chasing DNSSEC sigs)\n" @@ -860,21 +861,33 @@ plus_option(char *option, isc_boolean_t is_batchfile, goto invalid_option; ndots = parse_uint(value, "ndots", MAXNDOTS); break; - case 's': /* nssearch */ - FULLCHECK("nssearch"); - lookup->ns_search_only = state; - if (state) { - lookup->trace_root = ISC_TRUE; - lookup->recurse = ISC_TRUE; - lookup->identify = ISC_TRUE; - lookup->stats = ISC_FALSE; - lookup->comments = ISC_FALSE; - lookup->section_additional = ISC_FALSE; - lookup->section_authority = ISC_FALSE; - lookup->section_question = ISC_FALSE; - lookup->rdtype = dns_rdatatype_ns; - lookup->rdtypeset = ISC_TRUE; - short_form = ISC_TRUE; + case 's': + switch (cmd[2]) { + case 'i': /* nsid */ + FULLCHECK("nsid"); + if (state && lookup->edns == -1) + lookup->edns = 0; + lookup->nsid = state; + break; + case 's': /* nssearch */ + FULLCHECK("nssearch"); + lookup->ns_search_only = state; + if (state) { + lookup->trace_root = ISC_TRUE; + lookup->recurse = ISC_TRUE; + lookup->identify = ISC_TRUE; + lookup->stats = ISC_FALSE; + lookup->comments = ISC_FALSE; + lookup->section_additional = ISC_FALSE; + lookup->section_authority = ISC_FALSE; + lookup->section_question = ISC_FALSE; + lookup->rdtype = dns_rdatatype_ns; + lookup->rdtypeset = ISC_TRUE; + short_form = ISC_TRUE; + } + break; + default: + goto invalid_option; } break; default: diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index d43d6b1cc8..2a7e9b020d 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dighost.c,v 1.308 2008/01/18 23:46:57 tbox Exp $ */ +/* $Id: dighost.c,v 1.309 2008/04/03 02:01:08 marka Exp $ */ /*! \file * \note @@ -724,6 +724,7 @@ make_empty_lookup(void) { looknew->servfail_stops = ISC_TRUE; looknew->besteffort = ISC_TRUE; looknew->dnssec = ISC_FALSE; + looknew->nsid = ISC_FALSE; #ifdef DIG_SIGCHASE looknew->sigchase = ISC_FALSE; #if DIG_SIGCHASE_TD @@ -803,6 +804,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { looknew->servfail_stops = lookold->servfail_stops; looknew->besteffort = lookold->besteffort; looknew->dnssec = lookold->dnssec; + looknew->nsid = lookold->nsid; #ifdef DIG_SIGCHASE looknew->sigchase = lookold->sigchase; #if DIG_SIGCHASE_TD @@ -1155,11 +1157,11 @@ setup_libs(void) { /*% * Add EDNS0 option record to a message. Currently, the only supported - * options are UDP buffer size and the DO bit. + * options are UDP buffer size, the DO bit, and NSID request. */ static void add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns, - isc_boolean_t dnssec) + isc_boolean_t dnssec, isc_boolean_t nsid) { dns_rdataset_t *rdataset = NULL; dns_rdatalist_t *rdatalist = NULL; @@ -1182,8 +1184,19 @@ add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns, rdatalist->ttl = edns << 16; if (dnssec) rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO; - rdata->data = NULL; - rdata->length = 0; + if (nsid) { + unsigned char data[4]; + isc_buffer_t buf; + + isc_buffer_init(&buf, data, sizeof(data)); + isc_buffer_putuint16(&buf, DNS_OPT_NSID); + isc_buffer_putuint16(&buf, 0); + rdata->data = data; + rdata->length = sizeof(data); + } else { + rdata->data = NULL; + rdata->length = 0; + } ISC_LIST_INIT(rdatalist->rdata); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); dns_rdatalist_tordataset(rdatalist, rdataset); @@ -1998,7 +2011,7 @@ setup_lookup(dig_lookup_t *lookup) { if (lookup->edns < 0) lookup->edns = 0; add_opt(lookup->sendmsg, lookup->udpsize, - lookup->edns, lookup->dnssec); + lookup->edns, lookup->dnssec, lookup->nsid); } result = dns_message_rendersection(lookup->sendmsg, diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 4c4608dff6..e5b814aa36 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dig.h,v 1.105 2007/06/18 23:47:17 tbox Exp $ */ +/* $Id: dig.h,v 1.106 2008/04/03 02:01:08 marka Exp $ */ #ifndef DIG_H #define DIG_H @@ -102,7 +102,7 @@ typedef struct dig_searchlist dig_searchlist_t; /*% The dig_lookup structure */ struct dig_lookup { isc_boolean_t - pending, /*%< Pending a successful answer */ + pending, /*%< Pending a successful answer */ waiting_connect, doing_xfr, ns_search_only, /*%< dig +nssearch, host -C */ @@ -129,27 +129,28 @@ struct dig_lookup { need_search, done_as_is, besteffort, - dnssec; + dnssec, + nsid; /*% Name Server ID (RFC 5001) */ #ifdef DIG_SIGCHASE isc_boolean_t sigchase; #if DIG_SIGCHASE_TD - isc_boolean_t do_topdown, - trace_root_sigchase, - rdtype_sigchaseset, - rdclass_sigchaseset; + isc_boolean_t do_topdown, + trace_root_sigchase, + rdtype_sigchaseset, + rdclass_sigchaseset; /* Name we are going to validate RRset */ - char textnamesigchase[MXNAME]; + char textnamesigchase[MXNAME]; #endif #endif - + char textname[MXNAME]; /*% Name we're going to be looking up */ char cmdline[MXNAME]; dns_rdatatype_t rdtype; dns_rdatatype_t qrdtype; #if DIG_SIGCHASE_TD - dns_rdatatype_t rdtype_sigchase; - dns_rdatatype_t qrdtype_sigchase; - dns_rdataclass_t rdclass_sigchase; + dns_rdatatype_t rdtype_sigchase; + dns_rdatatype_t qrdtype_sigchase; + dns_rdataclass_t rdclass_sigchase; #endif dns_rdataclass_t rdclass; isc_boolean_t rdtypeset; @@ -231,7 +232,7 @@ struct dig_searchlist { }; #ifdef DIG_SIGCHASE struct dig_message { - dns_message_t *msg; + dns_message_t *msg; ISC_LINK(dig_message_t) link; }; #endif @@ -249,7 +250,7 @@ extern dig_searchlistlist_t search_list; extern unsigned int extrabytes; extern isc_boolean_t check_ra, have_ipv4, have_ipv6, specified_source, - usesearch, showsearch, qr; + usesearch, showsearch, qr; extern in_port_t port; extern unsigned int timeout; extern isc_mem_t *mctx; diff --git a/bin/named/bind9.xsl.h b/bin/named/bind9.xsl.h index 795fffd61e..b26ca2cb50 100644 --- a/bin/named/bind9.xsl.h +++ b/bin/named/bind9.xsl.h @@ -1,5 +1,5 @@ /* - * Generated by convertxsl.pl 1.10 2008/04/02 03:35:13 marka Exp + * Generated by convertxsl.pl 1.11 2008/04/02 23:46:57 tbox Exp * From bind9.xsl 1.15 2008/04/01 23:47:10 tbox Exp */ static char msg[] = diff --git a/bin/named/client.c b/bin/named/client.c index db6e634585..eab2fc18a1 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.254 2008/03/31 05:00:29 marka Exp $ */ +/* $Id: client.c,v 1.255 2008/04/03 02:01:08 marka Exp $ */ #include @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -954,11 +955,9 @@ ns_client_send(ns_client_t *client) { result = dns_message_renderbegin(client->message, &cctx, &buffer); if (result != ISC_R_SUCCESS) goto done; + if (client->opt != NULL) { result = dns_message_setopt(client->message, client->opt); - /* - * XXXRTH dns_message_setopt() should probably do this... - */ client->opt = NULL; if (result != ISC_R_SUCCESS) goto done; @@ -1190,11 +1189,46 @@ client_addopt(ns_client_t *client) { */ rdatalist->ttl = (client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE); - /* - * No EDNS options in the default case. - */ - rdata->data = NULL; - rdata->length = 0; + /* Set EDNS options if applicable */ + if (client->attributes & NS_CLIENTATTR_WANTNSID && + (ns_g_server->server_id != NULL || + ns_g_server->server_usehostname)) { + /* + * Space required for NSID data: + * 2 bytes for opt code + * + 2 bytes for NSID length + * + NSID itself + */ + char nsid[BUFSIZ]; + isc_buffer_t *buffer = NULL; + + if (ns_g_server->server_usehostname) { + isc_result_t result; + result = ns_os_gethostname(nsid, sizeof(nsid)); + if (result != ISC_R_SUCCESS) { + goto no_nsid; + } + } else { + strncpy(nsid, ns_g_server->server_id, sizeof(nsid)); + } + + rdata->length = strlen(nsid) + 4; + result = isc_buffer_allocate(client->mctx, &buffer, + rdata->length); + if (result != ISC_R_SUCCESS) + goto no_nsid; + + isc_buffer_putuint16(buffer, DNS_OPT_NSID); + isc_buffer_putuint16(buffer, strlen(nsid)); + isc_buffer_putstr(buffer, nsid); + rdata->data = buffer->base; + dns_message_takebuffer(client->message, &buffer); + } else { +no_nsid: + rdata->data = NULL; + rdata->length = 0; + } + rdata->rdclass = rdatalist->rdclass; rdata->type = rdatalist->type; rdata->flags = 0; @@ -1302,6 +1336,8 @@ client_request(isc_task_t *task, isc_event_t *event) { dns_messageid_t id; unsigned int flags; isc_boolean_t notimp; + dns_rdata_t rdata; + isc_uint16_t optcode; REQUIRE(event != NULL); client = event->ev_arg; @@ -1524,6 +1560,24 @@ client_request(isc_task_t *task, isc_event_t *event) { ns_client_error(client, result); goto cleanup; } + + /* Check for NSID request */ + result = dns_rdataset_first(opt); + if (result == ISC_R_SUCCESS) { + dns_rdata_init(&rdata); + dns_rdataset_current(opt, &rdata); + if (rdata.length >= 2) { + isc_buffer_t nsidbuf; + isc_buffer_init(&nsidbuf, + rdata.data, rdata.length); + isc_buffer_add(&nsidbuf, rdata.length); + optcode = isc_buffer_getuint16(&nsidbuf); + if (optcode == DNS_OPT_NSID) + client->attributes |= + NS_CLIENTATTR_WANTNSID; + } + } + /* * Create an OPT for our reply. */ diff --git a/bin/named/config.c b/bin/named/config.c index c5e70b95aa..8f48760482 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: config.c,v 1.85 2008/04/02 02:37:41 marka Exp $ */ +/* $Id: config.c,v 1.86 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -99,6 +99,7 @@ options {\n\ use-ixfr true;\n\ edns-udp-size 4096;\n\ max-udp-size 4096;\n\ + request-nsid false;\n\ \n\ /* view */\n\ allow-notify {none;};\n\ diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index 8562616df0..b4be639ae2 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.h,v 1.85 2008/01/18 23:46:57 tbox Exp $ */ +/* $Id: client.h,v 1.86 2008/04/03 02:01:08 marka Exp $ */ #ifndef NAMED_CLIENT_H #define NAMED_CLIENT_H 1 @@ -166,6 +166,7 @@ struct ns_client { #define NS_CLIENTATTR_PKTINFO 0x04 /*%< pktinfo is valid */ #define NS_CLIENTATTR_MULTICAST 0x08 /*%< recv'd from multicast */ #define NS_CLIENTATTR_WANTDNSSEC 0x10 /*%< include dnssec records */ +#define NS_CLIENTATTR_WANTNSID 0x20 /*%< include nameserver ID */ extern unsigned int ns_client_requests; diff --git a/bin/named/server.c b/bin/named/server.c index 9ea2f88b6c..fb018b6ce9 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.503 2008/03/31 05:00:29 marka Exp $ */ +/* $Id: server.c,v 1.504 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -729,6 +729,11 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { if (obj != NULL) CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); + obj = NULL; + (void)cfg_map_get(cpeer, "request-nsid", &obj); + if (obj != NULL) + CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj))); + obj = NULL; (void)cfg_map_get(cpeer, "edns", &obj); if (obj != NULL) @@ -1656,6 +1661,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, INSIST(result == ISC_R_SUCCESS); view->provideixfr = cfg_obj_asboolean(obj); + obj = NULL; + result = ns_config_get(maps, "request-nsid", &obj); + INSIST(result == ISC_R_SUCCESS); + view->requestnsid = cfg_obj_asboolean(obj); + obj = NULL; result = ns_config_get(maps, "max-clients-per-query", &obj); INSIST(result == ISC_R_SUCCESS); @@ -3465,8 +3475,12 @@ load_configuration(const char *filename, ns_server_t *server, result = ns_config_get(maps, "server-id", &obj); server->server_usehostname = ISC_FALSE; if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { - server->server_usehostname = ISC_TRUE; + /* The parser translates "hostname" to ISC_TRUE */ + server->server_usehostname = cfg_obj_asboolean(obj); + result = setstring(server, &server->server_id, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); } else if (result == ISC_R_SUCCESS) { + /* Found a quoted string */ CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); } else { result = setstring(server, &server->server_id, NULL); diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 9aa72c440f..8c4afc1a23 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -7533,9 +7533,10 @@ query-source-v6 address * port *; server-id - The ID of the server should report via a query of - the name ID.SERVER - with type TXT, class CHAOS. + The ID the server should report when receiving a Name + Server Identifier (NSID) query, or a query of the name + ID.SERVER with type + TXT, class CHAOS. The primary purpose of such queries is to identify which of a group of anycast servers is actually answering your queries. Specifying server-id none; diff --git a/lib/bind/include/arpa/nameser.h b/lib/bind/include/arpa/nameser.h index b6d34aab0f..977e4f5c53 100644 --- a/lib/bind/include/arpa/nameser.h +++ b/lib/bind/include/arpa/nameser.h @@ -49,7 +49,7 @@ */ /* - * $Id: nameser.h,v 1.8 2005/04/27 04:56:16 sra Exp $ + * $Id: nameser.h,v 1.9 2008/04/03 02:01:08 marka Exp $ */ #ifndef _ARPA_NAMESER_H_ @@ -427,9 +427,10 @@ typedef enum __ns_cert_types { #define NS_NXT_MAX 127 /*% - * EDNS0 extended flags, host order. + * EDNS0 extended flags and option codes, host order. */ #define NS_OPT_DNSSEC_OK 0x8000U +#define NS_OPT_NSID 3 /*% * Inline versions of get/put short/long. Pointer is advanced. diff --git a/lib/bind/include/resolv.h b/lib/bind/include/resolv.h index bb5863e919..5baed6ce69 100644 --- a/lib/bind/include/resolv.h +++ b/lib/bind/include/resolv.h @@ -50,7 +50,7 @@ /*% * @(#)resolv.h 8.1 (Berkeley) 6/2/93 - * $Id: resolv.h,v 1.23 2005/08/25 04:41:46 marka Exp $ + * $Id: resolv.h,v 1.24 2008/04/03 02:01:08 marka Exp $ */ #ifndef _RESOLV_H_ @@ -250,6 +250,7 @@ union res_sockaddr_union { #define RES_NOCHECKNAME 0x00008000 /*%< do not check names for sanity. */ #define RES_KEEPTSIG 0x00010000 /*%< do not strip TSIG records */ #define RES_BLAST 0x00020000 /*%< blast all recursive servers */ +#define RES_NSID 0x00040000 /*%< request name server ID */ #define RES_NOTLDQUERY 0x00100000 /*%< don't unqualified name as a tld */ #define RES_USE_DNSSEC 0x00200000 /*%< use DNSSEC using OK bit in OPT */ /* #define RES_DEBUG2 0x00400000 */ /* nslookup internal */ @@ -396,6 +397,7 @@ extern const struct res_sym __p_rcode_syms[]; #define sym_ntos __sym_ntos #define sym_ston __sym_ston #define res_nopt __res_nopt +#define res_nopt_rdata __res_nopt_rdata #define res_ndestroy __res_ndestroy #define res_nametoclass __res_nametoclass #define res_nametotype __res_nametotype @@ -482,6 +484,8 @@ int res_findzonecut2 __P((res_state, const char *, ns_class, int, union res_sockaddr_union *, int)); void res_nclose __P((res_state)); int res_nopt __P((res_state, int, u_char *, int, int)); +int res_nopt_rdata __P((res_state, int, u_char *, int, u_char *, + u_short, u_short, u_char *)); void res_send_setqhook __P((res_send_qhook)); void res_send_setrhook __P((res_send_rhook)); int __res_vinit __P((res_state, int)); diff --git a/lib/bind/resolv/res_debug.c b/lib/bind/resolv/res_debug.c index b12a112ff0..36ae36059a 100644 --- a/lib/bind/resolv/res_debug.c +++ b/lib/bind/resolv/res_debug.c @@ -95,7 +95,7 @@ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; -static const char rcsid[] = "$Id: res_debug.c,v 1.15 2005/07/28 06:51:50 marka Exp $"; +static const char rcsid[] = "$Id: res_debug.c,v 1.16 2008/04/03 02:01:08 marka Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -189,10 +189,56 @@ do_section(const res_state statp, p_type(ns_rr_type(rr)), p_class(ns_rr_class(rr))); else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) { + u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr); u_int32_t ttl = ns_rr_ttl(rr); + fprintf(file, "; EDNS: version: %u, udp=%u, flags=%04x\n", (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff); + + while (rdatalen >= 4) { + const u_char *cp = ns_rr_rdata(rr); + int i; + + GETSHORT(optcode, cp); + GETSHORT(optlen, cp); + + if (optcode == NS_OPT_NSID) { + fputs("; NSID: ", file); + if (optlen == 0) { + fputs("; NSID\n", file); + } else { + fputs("; NSID: ", file); + for (i = 0; i < optlen; i++) + fprintf(file, "%02x ", + cp[i]); + fputs(" (",file); + for (i = 0; i < optlen; i++) + fprintf(file, "%c", + isprint(cp[i])? + cp[i] : '.'); + fputs(")\n", file); + } + } else { + if (optlen == 0) { + fprintf(file, "; OPT=%u\n", + optcode); + } else { + fprintf(file, "; OPT=%u: ", + optcode); + for (i = 0; i < optlen; i++) + fprintf(file, "%02x ", + cp[i]); + fputs(" (",file); + for (i = 0; i < optlen; i++) + fprintf(file, "%c", + isprint(cp[i]) ? + cp[i] : '.'); + fputs(")\n", file); + } + } + rdatalen -= 4 + optlen; + } } else { n = ns_sprintrr(handle, &rr, NULL, NULL, buf, buflen); @@ -204,7 +250,7 @@ do_section(const res_state statp, buf = malloc(buflen += 1024); if (buf == NULL) { fprintf(file, - ";; memory allocation failure\n"); + ";; memory allocation failure\n"); return; } continue; @@ -381,7 +427,7 @@ const struct res_sym __p_default_section_syms[] = { {ns_s_an, "ANSWER", (char *)0}, {ns_s_ns, "AUTHORITY", (char *)0}, {ns_s_ar, "ADDITIONAL", (char *)0}, - {0, (char *)0, (char *)0} + {0, (char *)0, (char *)0} }; const struct res_sym __p_update_section_syms[] = { @@ -389,7 +435,7 @@ const struct res_sym __p_update_section_syms[] = { {S_PREREQ, "PREREQUISITE", (char *)0}, {S_UPDATE, "UPDATE", (char *)0}, {S_ADDT, "ADDITIONAL", (char *)0}, - {0, (char *)0, (char *)0} + {0, (char *)0, (char *)0} }; const struct res_sym __p_key_syms[] = { @@ -617,6 +663,7 @@ p_option(u_long option) { case RES_USE_INET6: return "inet6"; #ifdef RES_USE_EDNS0 /*%< KAME extension */ case RES_USE_EDNS0: return "edns0"; + case RES_NSID: return "nsid"; #endif #ifdef RES_USE_DNAME case RES_USE_DNAME: return "dname"; diff --git a/lib/bind/resolv/res_mkquery.c b/lib/bind/resolv/res_mkquery.c index 09133baf42..cd986364a1 100644 --- a/lib/bind/resolv/res_mkquery.c +++ b/lib/bind/resolv/res_mkquery.c @@ -70,7 +70,7 @@ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; -static const char rcsid[] = "$Id: res_mkquery.c,v 1.6 2005/04/27 04:56:42 sra Exp $"; +static const char rcsid[] = "$Id: res_mkquery.c,v 1.7 2008/04/03 02:01:08 marka Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -203,9 +203,6 @@ res_nmkquery(res_state statp, #ifdef RES_USE_EDNS0 /* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */ -#ifndef T_OPT -#define T_OPT 41 -#endif int res_nopt(res_state statp, @@ -230,13 +227,14 @@ res_nopt(res_state statp, if ((ep - cp) < 1 + RRFIXEDSZ) return (-1); - *cp++ = 0; /*%< "." */ - ns_put16(T_OPT, cp); /*%< TYPE */ + *cp++ = 0; /*%< "." */ + ns_put16(ns_t_opt, cp); /*%< TYPE */ cp += INT16SZ; - ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */ + ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */ cp += INT16SZ; - *cp++ = NOERROR; /*%< extended RCODE */ - *cp++ = 0; /*%< EDNS version */ + *cp++ = NOERROR; /*%< extended RCODE */ + *cp++ = 0; /*%< EDNS version */ + if (statp->options & RES_USE_DNSSEC) { #ifdef DEBUG if (statp->options & RES_DEBUG) @@ -246,12 +244,60 @@ res_nopt(res_state statp, } ns_put16(flags, cp); cp += INT16SZ; - ns_put16(0, cp); /*%< RDLEN */ + + ns_put16(0U, cp); /*%< RDLEN */ cp += INT16SZ; + hp->arcount = htons(ntohs(hp->arcount) + 1); return (cp - buf); } + +/* + * Construct variable data (RDATA) block for OPT psuedo-RR, append it + * to the buffer, then update the RDLEN field (previously set to zero by + * res_nopt()) with the new RDATA length. + */ +int +res_nopt_rdata(res_state statp, + int n0, /*%< current offset in buffer */ + u_char *buf, /*%< buffer to put query */ + int buflen, /*%< size of buffer */ + u_char *rdata, /*%< ptr to start of opt rdata */ + u_short code, /*%< OPTION-CODE */ + u_short len, /*%< OPTION-LENGTH */ + u_char *data) /*%< OPTION_DATA */ +{ + register u_char *cp, *ep; + +#ifdef DEBUG + if ((statp->options & RES_DEBUG) != 0U) + printf(";; res_nopt_rdata()\n"); +#endif + + cp = buf + n0; + ep = buf + buflen; + + if ((ep - cp) < (4 + len)) + return (-1); + + if (rdata < (buf + 2) || rdata >= ep) + return (-1); + + ns_put16(code, cp); + cp += INT16SZ; + + ns_put16(len, cp); + cp += INT16SZ; + + memcpy(cp, data, len); + cp += len; + + len = cp - rdata; + ns_put16(len, rdata - 2); /* Update RDLEN field */ + + return (cp - buf); +} #endif /*! \file */ diff --git a/lib/bind/resolv/res_query.c b/lib/bind/resolv/res_query.c index 8dd68e8d66..50ba1e7619 100644 --- a/lib/bind/resolv/res_query.c +++ b/lib/bind/resolv/res_query.c @@ -70,7 +70,7 @@ #if defined(LIBC_SCCS) && !defined(lint) static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; -static const char rcsid[] = "$Id: res_query.c,v 1.8 2005/04/27 04:56:42 sra Exp $"; +static const char rcsid[] = "$Id: res_query.c,v 1.9 2008/04/03 02:01:08 marka Exp $"; #endif /* LIBC_SCCS and not lint */ #include "port_before.h" @@ -116,8 +116,9 @@ res_nquery(res_state statp, { u_char buf[MAXPACKET]; HEADER *hp = (HEADER *) answer; - int n; u_int oflags; + u_char *rdata; + int n; oflags = statp->_flags; @@ -132,8 +133,14 @@ again: buf, sizeof(buf)); #ifdef RES_USE_EDNS0 if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 && - (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) + (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC|RES_NSID))) { n = res_nopt(statp, n, buf, sizeof(buf), anslen); + rdata = &buf[n]; + if (n > 0 && (statp->options & RES_NSID) != 0) { + n = res_nopt_rdata(statp, n, buf, sizeof(buf), rdata, + NS_OPT_NSID, 0, NULL); + } + } #endif if (n <= 0) { #ifdef DEBUG @@ -143,6 +150,7 @@ again: RES_SET_H_ERRNO(statp, NO_RECOVERY); return (n); } + n = res_nsend(statp, buf, n, answer, anslen); if (n < 0) { #ifdef RES_USE_EDNS0 diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 07235da8cb..4d310b673f 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.137 2007/06/27 04:10:44 marka Exp $ */ +/* $Id: dispatch.c,v 1.138 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -45,22 +45,23 @@ typedef ISC_LIST(dns_dispentry_t) dns_displist_t; -typedef struct dns_nsid { - isc_uint16_t nsid_state; - isc_uint16_t *nsid_vtable; - isc_uint16_t *nsid_pool; - isc_uint16_t nsid_a1, nsid_a2, nsid_a3; - isc_uint16_t nsid_c1, nsid_c2, nsid_c3; - isc_uint16_t nsid_state2; - isc_boolean_t nsid_usepool; -} dns_nsid_t; +/* transaction ID */ +typedef struct dns_tid { + isc_uint16_t tid_state; + isc_uint16_t *tid_vtable; + isc_uint16_t *tid_pool; + isc_uint16_t tid_a1, tid_a2, tid_a3; + isc_uint16_t tid_c1, tid_c2, tid_c3; + isc_uint16_t tid_state2; + isc_boolean_t tid_usepool; +} dns_tid_t; typedef struct dns_qid { unsigned int magic; unsigned int qid_nbuckets; /*%< hash table size */ unsigned int qid_increment; /*%< id increment on collision */ isc_mutex_t lock; - dns_nsid_t nsid; + dns_tid_t tid; dns_displist_t *qid_table; /*%< the table itself */ } dns_qid_t; @@ -169,7 +170,7 @@ static void destroy_disp(isc_task_t *task, isc_event_t *event); static void udp_recv(isc_task_t *, isc_event_t *); static void tcp_recv(isc_task_t *, isc_event_t *); static void startrecv(dns_dispatch_t *); -static dns_messageid_t dns_randomid(dns_nsid_t *); +static dns_messageid_t dns_randomid(dns_tid_t *); static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t); static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); static void *allocate_udp_buffer(dns_dispatch_t *disp); @@ -193,9 +194,10 @@ static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, unsigned int increment, isc_boolean_t usepool, dns_qid_t **qidp); static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp); -static isc_uint16_t nsid_next(dns_nsid_t *nsid); -static isc_result_t nsid_init(isc_mem_t *mctx, dns_nsid_t *nsid, isc_boolean_t usepool); -static void nsid_destroy(isc_mem_t *mctx, dns_nsid_t *nsid); +static isc_uint16_t tid_next(dns_tid_t *tid); +static isc_result_t tid_init(isc_mem_t *mctx, dns_tid_t *tid, + isc_boolean_t usepool); +static void tid_destroy(isc_mem_t *mctx, dns_tid_t *tid); #define LVL(x) ISC_LOG_DEBUG(x) @@ -280,10 +282,10 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, * framework for this purpose. */ static in_port_t -get_randomport(dns_nsid_t *nsid) { +get_randomport(dns_tid_t *tid) { isc_uint16_t p; - p = nsid_next(nsid); + p = tid_next(tid); /* XXX: should the range be configurable? */ return ((in_port_t)(1024 + (p % (65535 - 1024)))); @@ -293,10 +295,10 @@ get_randomport(dns_nsid_t *nsid) { * Return an unpredictable message ID. */ static dns_messageid_t -dns_randomid(dns_nsid_t *nsid) { +dns_randomid(dns_tid_t *tid) { isc_uint32_t id; - id = nsid_next(nsid); + id = tid_next(tid); return ((dns_messageid_t)id); } @@ -596,7 +598,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { isc_netaddr_fromsockaddr(&netaddr, &ev->address); if (disp->mgr->blackhole != NULL && dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, - NULL, &match, NULL) == ISC_R_SUCCESS && + NULL, &match, NULL) == ISC_R_SUCCESS && match > 0) { if (isc_log_wouldlog(dns_lctx, LVL(10))) { @@ -652,7 +654,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { if (resp == NULL) { free_buffer(disp, ev->region.base, ev->region.length); goto unlock; - } + } /* * Now that we have the original dispatch the query was sent @@ -662,7 +664,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { if (disp != resp->disp) { isc_sockaddr_t a1; isc_sockaddr_t a2; - + /* * Check that the socket types and ports match. */ @@ -675,11 +677,11 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { /* * If both dispatches are bound to an address then fail as - * the addresses can't be equal (enforced by the IP stack). + * the addresses can't be equal (enforced by the IP stack). * * Note under Linux a packet can be sent out via IPv4 socket * and the response be received via a IPv6 socket. - * + * * Requests sent out via IPv6 should always come back in * via IPv6. */ @@ -800,7 +802,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) { switch (tcpmsg->result) { case ISC_R_CANCELED: break; - + case ISC_R_EOF: dispatch_log(disp, LVL(90), "shutting down on EOF"); do_cancel(disp); @@ -1439,7 +1441,7 @@ qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, return (ISC_R_NOMEMORY); } - result = nsid_init(mgr->mctx, &qid->nsid, usepool); + result = tid_init(mgr->mctx, &qid->tid, usepool); if (result != ISC_R_SUCCESS) { isc_mem_put(mgr->mctx, qid->qid_table, buckets * sizeof(dns_displist_t)); @@ -1449,7 +1451,7 @@ qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, result = isc_mutex_init(&qid->lock); if (result != ISC_R_SUCCESS) { - nsid_destroy(mgr->mctx, &qid->nsid); + tid_destroy(mgr->mctx, &qid->tid); isc_mem_put(mgr->mctx, qid->qid_table, buckets * sizeof(dns_displist_t)); isc_mem_put(mgr->mctx, qid, sizeof(*qid)); @@ -1477,7 +1479,7 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { *qidp = NULL; qid->magic = 0; - nsid_destroy(mctx, &qid->nsid); + tid_destroy(mctx, &qid->tid); isc_mem_put(mctx, qid->qid_table, qid->qid_nbuckets * sizeof(dns_displist_t)); DESTROYLOCK(&qid->lock); @@ -1795,7 +1797,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, getsocket: if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) { isc_sockaddr_setport(&localaddr_bound, - get_randomport(&mgr->qid->nsid)); + get_randomport(&mgr->qid->tid)); if (blacklisted(mgr, NULL, &localaddr_bound)) { if (++k == 1024) attributes &= ~DNS_DISPATCHATTR_RANDOMPORT; @@ -1807,7 +1809,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, attributes &= ~DNS_DISPATCHATTR_RANDOMPORT; goto getsocket; } - } else + } else result = create_socket(sockmgr, localaddr, &sock); if (result != ISC_R_SUCCESS) goto deallocate_dispatch; @@ -1969,7 +1971,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest, */ qid = DNS_QID(disp); LOCK(&qid->lock); - id = dns_randomid(&qid->nsid); + id = dns_randomid(&qid->tid); bucket = dns_hash(qid, dest, id); ok = ISC_FALSE; for (i = 0; i < 64; i++) { @@ -2294,7 +2296,7 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { newsevent->timestamp = sevent->timestamp; newsevent->pktinfo = sevent->pktinfo; newsevent->attributes = sevent->attributes; - + isc_task_send(disp->task, ISC_EVENT_PTR(&newsevent)); } @@ -2381,26 +2383,26 @@ dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) { * the pool. */ -#define NSID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */ +#define TID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */ /* * Pick one of the next 4096 IDs in the pool. * There is a tradeoff here between randomness and how often and ID is reused. */ -#define NSID_LOOKAHEAD 4096 /* Must be a power of 2 */ -#define NSID_SHUFFLE_ONLY 1 /* algorithm 1 */ -#define NSID_USE_POOL 2 /* algorithm 2 */ -#define NSID_HASHSHIFT 3 -#define NSID_HASHROTATE(v) \ - (((v) << NSID_HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - NSID_HASHSHIFT))) +#define TID_LOOKAHEAD 4096 /* Must be a power of 2 */ +#define TID_SHUFFLE_ONLY 1 /* algorithm 1 */ +#define TID_USE_POOL 2 /* algorithm 2 */ +#define TID_HASHSHIFT 3 +#define TID_HASHROTATE(v) \ + (((v) << TID_HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - TID_HASHSHIFT))) -static isc_uint32_t nsid_hash_state; +static isc_uint32_t tid_hash_state; /* * Keep a running hash of various bits of data that we'll use to * stir the ID pool or perturb the ID generator */ static void -nsid_hash(void *data, size_t len) { +tid_hash(void *data, size_t len) { unsigned char *p = data; /* * Hash function similar to the one we use for hashing names. @@ -2412,12 +2414,12 @@ nsid_hash(void *data, size_t len) { * fast. */ /* - * We don't care about locking access to nsid_hash_state. + * We don't care about locking access to tid_hash_state. * In fact races make the result even more non deteministic. */ while (len-- > 0U) { - nsid_hash_state = NSID_HASHROTATE(nsid_hash_state); - nsid_hash_state += *p++; + tid_hash_state = TID_HASHROTATE(tid_hash_state); + tid_hash_state += *p++; } } @@ -2426,7 +2428,7 @@ nsid_hash(void *data, size_t len) { * in order of increasing serial correlation bounds (so trim from * the end). */ -static const isc_uint16_t nsid_multiplier_table[] = { +static const isc_uint16_t tid_multiplier_table[] = { 17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421, 26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437, 39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805, @@ -2562,159 +2564,168 @@ static const isc_uint16_t nsid_multiplier_table[] = { 10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533 }; -#define NSID_MULT_TABLE_SIZE \ - ((sizeof nsid_multiplier_table)/(sizeof nsid_multiplier_table[0])) -#define NSID_RANGE_MASK (NSID_LOOKAHEAD - 1) -#define NSID_POOL_MASK 0xFFFF /* used to wrap the pool index */ -#define NSID_SHUFFLE_ONLY 1 -#define NSID_USE_POOL 2 +#define TID_MULT_TABLE_SIZE \ + ((sizeof tid_multiplier_table) / \ + (sizeof tid_multiplier_table[0])) +#define TID_RANGE_MASK (TID_LOOKAHEAD - 1) +#define TID_POOL_MASK 0xFFFF /* used to wrap the pool index */ +#define TID_SHUFFLE_ONLY 1 +#define TID_USE_POOL 2 static isc_uint16_t -nsid_next(dns_nsid_t *nsid) { - isc_uint16_t id, compressed_hash; +tid_next(dns_tid_t *tid) { + isc_uint16_t id, compressed_hash; isc_uint16_t j; - compressed_hash = ((nsid_hash_state >> 16) ^ - (nsid_hash_state)) & 0xFFFF; + compressed_hash = ((tid_hash_state >> 16) ^ + (tid_hash_state)) & 0xFFFF; - if (nsid->nsid_usepool) { - isc_uint16_t pick; + if (tid->tid_usepool) { + isc_uint16_t pick; - pick = compressed_hash & NSID_RANGE_MASK; - pick = (nsid->nsid_state + pick) & NSID_POOL_MASK; - id = nsid->nsid_pool[pick]; - if (pick != 0) { - /* Swap two IDs to stir the pool */ - nsid->nsid_pool[pick] = - nsid->nsid_pool[nsid->nsid_state]; - nsid->nsid_pool[nsid->nsid_state] = id; - } + pick = compressed_hash & TID_RANGE_MASK; + pick = (tid->tid_state + pick) & TID_POOL_MASK; + id = tid->tid_pool[pick]; + if (pick != 0) { + /* Swap two IDs to stir the pool */ + tid->tid_pool[pick] = + tid->tid_pool[tid->tid_state]; + tid->tid_pool[tid->tid_state] = id; + } - /* increment the base pointer into the pool */ - if (nsid->nsid_state == 65535) - nsid->nsid_state = 0; - else - nsid->nsid_state++; + /* increment the base pointer into the pool */ + if (tid->tid_state == 65535) + tid->tid_state = 0; + else + tid->tid_state++; } else { /* * This is the original Algorithm B - * j = ((u_long) NSID_SHUFFLE_TABLE_SIZE * nsid_state2) >> 16; + * j = ((u_long) + * QUERID_SHUFFLE_TABLE_SIZE * tid_state2) >> 16; * * We'll perturb it with some random stuff ... */ - j = ((isc_uint32_t) NSID_SHUFFLE_TABLE_SIZE * - (nsid->nsid_state2 ^ compressed_hash)) >> 16; - nsid->nsid_state2 = id = nsid->nsid_vtable[j]; - nsid->nsid_state = (((isc_uint32_t) nsid->nsid_a1 * nsid->nsid_state) + - nsid->nsid_c1) & 0xFFFF; - nsid->nsid_vtable[j] = nsid->nsid_state; + j = ((isc_uint32_t) TID_SHUFFLE_TABLE_SIZE * + (tid->tid_state2 ^ compressed_hash)) >> 16; + tid->tid_state2 = id = tid->tid_vtable[j]; + tid->tid_state = (((isc_uint32_t) tid->tid_a1 * + tid->tid_state) + + tid->tid_c1) & 0xFFFF; + tid->tid_vtable[j] = tid->tid_state; } - /* Now lets obfuscate ... */ - id = (((isc_uint32_t) nsid->nsid_a2 * id) + nsid->nsid_c2) & 0xFFFF; - id = (((isc_uint32_t) nsid->nsid_a3 * id) + nsid->nsid_c3) & 0xFFFF; + /* Now lets obfuscate ... */ + id = (((isc_uint32_t) tid->tid_a2 * id) + + tid->tid_c2) & 0xFFFF; + id = (((isc_uint32_t) tid->tid_a3 * id) + + tid->tid_c3) & 0xFFFF; - return (id); + return (id); } static isc_result_t -nsid_init(isc_mem_t *mctx, dns_nsid_t *nsid, isc_boolean_t usepool) { - isc_time_t now; - pid_t mypid; - isc_uint16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx; - int i; +tid_init(isc_mem_t *mctx, dns_tid_t *tid, isc_boolean_t usepool) { + isc_time_t now; + pid_t mypid; + isc_uint16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx; + int i; isc_time_now(&now); - mypid = getpid(); + mypid = getpid(); - /* Initialize the state */ - memset(nsid, 0, sizeof(*nsid)); - nsid_hash(&now, sizeof now); - nsid_hash(&mypid, sizeof mypid); + /* Initialize the state */ + memset(tid, 0, sizeof(*tid)); + tid_hash(&now, sizeof now); + tid_hash(&mypid, sizeof mypid); - /* - * Select our random number generators and initial seed. - * We could really use more random bits at this point, - * but we'll try to make a silk purse out of a sows ear ... - */ - /* generator 1 */ - a1ndx = ((isc_uint32_t) NSID_MULT_TABLE_SIZE * - (nsid_hash_state & 0xFFFF)) >> 16; - nsid->nsid_a1 = nsid_multiplier_table[a1ndx]; - c1ndx = (nsid_hash_state >> 9) & 0x7FFF; - nsid->nsid_c1 = 2 * c1ndx + 1; + /* + * Select our random number generators and initial seed. + * We could really use more random bits at this point, + * but we'll try to make a silk purse out of a sows ear ... + */ + /* generator 1 */ + a1ndx = ((isc_uint32_t) TID_MULT_TABLE_SIZE * + (tid_hash_state & 0xFFFF)) >> 16; + tid->tid_a1 = tid_multiplier_table[a1ndx]; + c1ndx = (tid_hash_state >> 9) & 0x7FFF; + tid->tid_c1 = 2 * c1ndx + 1; - /* generator 2, distinct from 1 */ - a2ndx = ((isc_uint32_t) (NSID_MULT_TABLE_SIZE - 1) * - ((nsid_hash_state >> 10) & 0xFFFF)) >> 16; - if (a2ndx >= a1ndx) - a2ndx++; - nsid->nsid_a2 = nsid_multiplier_table[a2ndx]; - c2ndx = nsid_hash_state % 32767; - if (c2ndx >= c1ndx) - c2ndx++; - nsid->nsid_c2 = 2*c2ndx + 1; + /* generator 2, distinct from 1 */ + a2ndx = ((isc_uint32_t) (TID_MULT_TABLE_SIZE - 1) * + ((tid_hash_state >> 10) & 0xFFFF)) >> 16; + if (a2ndx >= a1ndx) + a2ndx++; + tid->tid_a2 = tid_multiplier_table[a2ndx]; + c2ndx = tid_hash_state % 32767; + if (c2ndx >= c1ndx) + c2ndx++; + tid->tid_c2 = 2*c2ndx + 1; - /* generator 3, distinct from 1 and 2 */ - a3ndx = ((isc_uint32_t) (NSID_MULT_TABLE_SIZE - 2) * - ((nsid_hash_state >> 20) & 0xFFFF)) >> 16; - if (a3ndx >= a1ndx || a3ndx >= a2ndx) - a3ndx++; - if (a3ndx >= a1ndx && a3ndx >= a2ndx) - a3ndx++; - nsid->nsid_a3 = nsid_multiplier_table[a3ndx]; - c3ndx = nsid_hash_state % 32766; - if (c3ndx >= c1ndx || c3ndx >= c2ndx) - c3ndx++; - if (c3ndx >= c1ndx && c3ndx >= c2ndx) - c3ndx++; - nsid->nsid_c3 = 2*c3ndx + 1; + /* generator 3, distinct from 1 and 2 */ + a3ndx = ((isc_uint32_t) (TID_MULT_TABLE_SIZE - 2) * + ((tid_hash_state >> 20) & 0xFFFF)) >> 16; + if (a3ndx >= a1ndx || a3ndx >= a2ndx) + a3ndx++; + if (a3ndx >= a1ndx && a3ndx >= a2ndx) + a3ndx++; + tid->tid_a3 = tid_multiplier_table[a3ndx]; + c3ndx = tid_hash_state % 32766; + if (c3ndx >= c1ndx || c3ndx >= c2ndx) + c3ndx++; + if (c3ndx >= c1ndx && c3ndx >= c2ndx) + c3ndx++; + tid->tid_c3 = 2*c3ndx + 1; - nsid->nsid_state = - ((nsid_hash_state >> 16) ^ (nsid_hash_state)) & 0xFFFF; + tid->tid_state = + ((tid_hash_state >> 16) ^ (tid_hash_state)) & 0xFFFF; - nsid->nsid_usepool = usepool; - if (nsid->nsid_usepool) { - nsid->nsid_pool = isc_mem_get(mctx, 0x10000 * sizeof(isc_uint16_t)); - if (nsid->nsid_pool == NULL) + tid->tid_usepool = usepool; + if (tid->tid_usepool) { + tid->tid_pool = isc_mem_get(mctx, + 0x10000 * sizeof(isc_uint16_t)); + if (tid->tid_pool == NULL) return (ISC_R_NOMEMORY); - for (i = 0; ; i++) { - nsid->nsid_pool[i] = nsid->nsid_state; - nsid->nsid_state = - (((u_long) nsid->nsid_a1 * nsid->nsid_state) + - nsid->nsid_c1) & 0xFFFF; - if (i == 0xFFFF) - break; - } - } else { - nsid->nsid_vtable = isc_mem_get(mctx, NSID_SHUFFLE_TABLE_SIZE * - (sizeof(isc_uint16_t)) ); - if (nsid->nsid_vtable == NULL) - return (ISC_R_NOMEMORY); - - for (i = 0; i < NSID_SHUFFLE_TABLE_SIZE; i++) { - nsid->nsid_vtable[i] = nsid->nsid_state; - nsid->nsid_state = - (((isc_uint32_t) nsid->nsid_a1 * nsid->nsid_state) + - nsid->nsid_c1) & 0xFFFF; + for (i = 0; ; i++) { + tid->tid_pool[i] = tid->tid_state; + tid->tid_state = + (((u_long) tid->tid_a1 * + tid->tid_state) + + tid->tid_c1) & 0xFFFF; + if (i == 0xFFFF) + break; } - nsid->nsid_state2 = nsid->nsid_state; - } + } else { + tid->tid_vtable = isc_mem_get(mctx, TID_SHUFFLE_TABLE_SIZE * + (sizeof(isc_uint16_t)) ); + if (tid->tid_vtable == NULL) + return (ISC_R_NOMEMORY); + + for (i = 0; i < TID_SHUFFLE_TABLE_SIZE; i++) { + tid->tid_vtable[i] = tid->tid_state; + tid->tid_state = + (((isc_uint32_t) tid->tid_a1 * + tid->tid_state) + + tid->tid_c1) & 0xFFFF; + } + tid->tid_state2 = tid->tid_state; + } return (ISC_R_SUCCESS); } static void -nsid_destroy(isc_mem_t *mctx, dns_nsid_t *nsid) { - if (nsid->nsid_usepool) - isc_mem_put(mctx, nsid->nsid_pool, +tid_destroy(isc_mem_t *mctx, dns_tid_t *tid) { + if (tid->tid_usepool) + isc_mem_put(mctx, tid->tid_pool, 0x10000 * sizeof(isc_uint16_t)); else - isc_mem_put(mctx, nsid->nsid_vtable, - NSID_SHUFFLE_TABLE_SIZE * (sizeof(isc_uint16_t)) ); - memset(nsid, 0, sizeof(*nsid)); + isc_mem_put(mctx, tid->tid_vtable, + TID_SHUFFLE_TABLE_SIZE * + (sizeof(isc_uint16_t)) ); + memset(tid, 0, sizeof(*tid)); } void dns_dispatch_hash(void *data, size_t len) { - nsid_hash(data, len); + tid_hash(data, len); } diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 2d487fa134..5dd952a311 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.h,v 1.123 2007/06/19 23:47:17 tbox Exp $ */ +/* $Id: message.h,v 1.124 2008/04/03 02:01:08 marka Exp $ */ #ifndef DNS_MESSAGE_H #define DNS_MESSAGE_H 1 @@ -101,8 +101,12 @@ #define DNS_MESSAGEFLAG_AD 0x0020U #define DNS_MESSAGEFLAG_CD 0x0010U +/*%< EDNS0 extended message flags */ #define DNS_MESSAGEEXTFLAG_DO 0x8000U +/*%< EDNS0 extended OPT codes */ +#define DNS_OPT_NSID 0x0003 /*%< NSID opt code */ + #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD) #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) @@ -771,7 +775,7 @@ dns_message_addname(dns_message_t *msg, dns_name_t *name, void dns_message_removename(dns_message_t *msg, dns_name_t *name, - dns_section_t section); + dns_section_t section); /*%< * Remove a existing name from a given section. * @@ -1031,7 +1035,7 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt); *\li The OPT record has either been freed or ownership of it has * been transferred to the message. * - *\li If ISC_R_SUCCESS was returned, the OPT record will be rendered + *\li If ISC_R_SUCCESS was returned, the OPT record will be rendered * when dns_message_renderend() is called. * * Returns: @@ -1315,7 +1319,7 @@ dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, *\li order_arg is NULL if and only if order is NULL. */ -void +void dns_message_settimeadjust(dns_message_t *msg, int timeadjust); /*%< * Adjust the time used to sign/verify a message by timeadjust. @@ -1325,7 +1329,7 @@ dns_message_settimeadjust(dns_message_t *msg, int timeadjust); *\li msg be a valid message. */ -int +int dns_message_gettimeadjust(dns_message_t *msg); /*%< * Return the current time adjustment. diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h index a28c55e5ef..20a900cc4a 100644 --- a/lib/dns/include/dns/peer.h +++ b/lib/dns/include/dns/peer.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: peer.h,v 1.31 2007/06/19 23:47:17 tbox Exp $ */ +/* $Id: peer.h,v 1.32 2008/04/03 02:01:08 marka Exp $ */ #ifndef DNS_PEER_H #define DNS_PEER_H 1 @@ -73,10 +73,11 @@ struct dns_peer { isc_boolean_t provide_ixfr; isc_boolean_t request_ixfr; isc_boolean_t support_edns; + isc_boolean_t request_nsid; dns_name_t *key; isc_sockaddr_t *transfer_source; - isc_sockaddr_t *notify_source; - isc_sockaddr_t *query_source; + isc_sockaddr_t *notify_source; + isc_sockaddr_t *query_source; isc_uint16_t udpsize; /* recieve size */ isc_uint16_t maxudp; /* transmit size */ @@ -149,6 +150,12 @@ dns_peer_setprovideixfr(dns_peer_t *peer, isc_boolean_t newval); isc_result_t dns_peer_getprovideixfr(dns_peer_t *peer, isc_boolean_t *retval); +isc_result_t +dns_peer_setrequestnsid(dns_peer_t *peer, isc_boolean_t newval); + +isc_result_t +dns_peer_getrequestnsid(dns_peer_t *peer, isc_boolean_t *retval); + isc_result_t dns_peer_setsupportedns(dns_peer_t *peer, isc_boolean_t newval); diff --git a/lib/dns/include/dns/rdatalist.h b/lib/dns/include/dns/rdatalist.h index e241548872..c701540159 100644 --- a/lib/dns/include/dns/rdatalist.h +++ b/lib/dns/include/dns/rdatalist.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist.h,v 1.20 2007/06/19 23:47:17 tbox Exp $ */ +/* $Id: rdatalist.h,v 1.21 2008/04/03 02:01:08 marka Exp $ */ #ifndef DNS_RDATALIST_H #define DNS_RDATALIST_H 1 @@ -98,6 +98,27 @@ dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, *\li #ISC_R_SUCCESS */ +isc_result_t +dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset, + dns_rdatalist_t **rdatalist); +/*%< + * Point 'rdatalist' to the rdatalist in 'rdataset'. + * + * Requires: + * + *\li 'rdatalist' is a pointer to a NULL dns_rdatalist_t pointer. + * + *\li 'rdataset' is a valid rdataset associated with an rdatalist. + * + * Ensures, + * on success, + * + *\li 'rdatalist' is pointed to the rdatalist in rdataset. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + ISC_LANG_ENDDECLS #endif /* DNS_RDATALIST_H */ diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 5c190aa995..3ed8c04e43 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.h,v 1.56 2007/06/18 23:47:42 tbox Exp $ */ +/* $Id: resolver.h,v 1.57 2008/04/03 02:01:08 marka Exp $ */ #ifndef DNS_RESOLVER_H #define DNS_RESOLVER_H 1 @@ -93,7 +93,8 @@ typedef struct dns_fetchevent { #define DNS_FETCHOPT_FORWARDONLY 0x10 /*%< Only use forwarders. */ #define DNS_FETCHOPT_NOVALIDATE 0x20 /*%< Disable validation. */ #define DNS_FETCHOPT_EDNS512 0x40 /*%< Advertise a 512 byte - UDP buffer. */ + UDP buffer. */ +#define DNS_FETCHOPT_WANTNSID 0x80 /*%< Request NSID */ #define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000 #define DNS_FETCHOPT_EDNSVERSIONMASK 0xff000000 @@ -470,7 +471,7 @@ dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur, isc_boolean_t dns_resolver_getzeronosoattl(dns_resolver_t *resolver); - + void dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state); @@ -491,7 +492,7 @@ dns_resolver_createdispatchpool(dns_resolver_t *res, unsigned int ndisps, * Requires: * *\li 'res' is a valid resolver that has not been frozen. Also it must have - * either the _USEDISPATCHPOOL4 or _USEDISPATCHPOOL6 option. + * either the _USEDISPATCHPOOL4 or _USEDISPATCHPOOL6 option. * *\li 'taskmgr' is a valid task manager. * diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 4964bd1f6d..7b95cc9aef 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.107 2007/06/18 23:47:42 tbox Exp $ */ +/* $Id: view.h,v 1.108 2008/04/03 02:01:08 marka Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 @@ -124,6 +124,7 @@ struct dns_view { dns_acl_t * sortlist; isc_boolean_t requestixfr; isc_boolean_t provideixfr; + isc_boolean_t requestnsid; dns_ttl_t maxcachettl; dns_ttl_t maxncachettl; in_port_t dstport; @@ -596,7 +597,7 @@ dns_viewlist_find(dns_viewlist_t *list, const char *name, isc_result_t dns_viewlist_findzone(dns_viewlist_t *list, dns_name_t *name, isc_boolean_t allclasses, - dns_rdataclass_t rdclass, dns_zone_t **zonep); + dns_rdataclass_t rdclass, dns_zone_t **zonep); /*%< * Search zone with 'name' in view with 'rdclass' in viewlist 'list' @@ -632,7 +633,7 @@ dns_view_loadnew(dns_view_t *view, isc_boolean_t stop); /*%< * Load zones attached to this view. dns_view_load() loads * all zones whose master file has changed since the last - * load; dns_view_loadnew() loads only zones that have never + * load; dns_view_loadnew() loads only zones that have never * been loaded. * * If 'stop' is ISC_TRUE, stop on the first error and return it. @@ -708,7 +709,7 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp); * easily obtainable by other means. * * Requires: - * + * *\li 'view' is valid. * *\li 'fp' refers to a file open for writing. @@ -751,7 +752,7 @@ isc_result_t dns_view_adddelegationonly(dns_view_t *view, dns_name_t *name); /*%< * Add the given name to the delegation only table. - * + * * * Requires: *\li 'view' is valid. @@ -766,7 +767,7 @@ isc_result_t dns_view_excludedelegationonly(dns_view_t *view, dns_name_t *name); /*%< * Add the given name to be excluded from the root-delegation-only. - * + * * * Requires: *\li 'view' is valid. diff --git a/lib/dns/message.c b/lib/dns/message.c index c1d8a589c8..4ad60aba4b 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: message.c,v 1.241 2008/04/02 02:37:42 marka Exp $ */ +/* $Id: message.c,v 1.242 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -24,6 +24,7 @@ ***/ #include +#include #include #include @@ -1488,14 +1489,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, rdataset->ttl = ttl; } - /* - * XXXMLG Perform a totally ugly hack here to pull - * the rdatalist out of the private field in the rdataset, - * and append this rdata to the rdatalist's linked list - * of rdata. - */ - rdatalist = (dns_rdatalist_t *)(rdataset->private1); - + /* Append this rdata to the rdataset. */ + dns_rdatalist_fromrdataset(rdataset, &rdatalist); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); /* @@ -3128,6 +3123,10 @@ dns_message_pseudosectiontotext(dns_message_t *msg, isc_result_t result; char buf[sizeof("1234567890")]; isc_uint32_t mbz; + dns_rdata_t rdata; + isc_buffer_t optbuf; + isc_uint16_t optcode, optlen; + unsigned char *optdata; REQUIRE(DNS_MESSAGE_VALID(msg)); REQUIRE(target != NULL); @@ -3157,6 +3156,50 @@ dns_message_pseudosectiontotext(dns_message_t *msg, ADD_STRING(target, "; udp: "); snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass); ADD_STRING(target, buf); + + result = dns_rdataset_first(ps); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + + /* Print EDNS info, if any */ + dns_rdata_init(&rdata); + dns_rdataset_current(ps, &rdata); + if (rdata.length < 4) + return (ISC_R_SUCCESS); + + isc_buffer_init(&optbuf, rdata.data, rdata.length); + isc_buffer_add(&optbuf, rdata.length); + optcode = isc_buffer_getuint16(&optbuf); + optlen = isc_buffer_getuint16(&optbuf); + + if (optcode == DNS_OPT_NSID) { + ADD_STRING(target, "; NSID"); + } else { + ADD_STRING(target, "; OPT="); + sprintf(buf, "%u", optcode); + ADD_STRING(target, buf); + } + + if (optlen != 0) { + int i; + ADD_STRING(target, ": "); + + optdata = rdata.data + 4; + for (i = 0; i < optlen; i++) { + sprintf(buf, "%02x ", optdata[i]); + ADD_STRING(target, buf); + } + for (i = 0; i < optlen; i++) { + ADD_STRING(target, " ("); + if (isprint(optdata[i])) + isc_buffer_putmem(target, &optdata[i], + 1); + else + isc_buffer_putmem(target, ".", 1); + ADD_STRING(target, ")"); + } + } + ADD_STRING(target, "\n"); return (ISC_R_SUCCESS); case DNS_PSEUDOSECTION_TSIG: ps = dns_message_gettsig(msg, &name); diff --git a/lib/dns/peer.c b/lib/dns/peer.c index 8ed3385949..7e20caa8b3 100644 --- a/lib/dns/peer.c +++ b/lib/dns/peer.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: peer.c,v 1.29 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: peer.c,v 1.30 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -42,6 +42,7 @@ #define SUPPORT_EDNS_BIT 5 #define SERVER_UDPSIZE_BIT 6 #define SERVER_MAXUDP_BIT 7 +#define REQUEST_NSID_BIT 8 static void peerlist_delete(dns_peerlist_t **list); @@ -146,7 +147,7 @@ dns_peerlist_addpeer(dns_peerlist_t *peers, dns_peer_t *peer) { ISC_LIST_INSERTBEFORE(peers->elements, p, peer, next); else ISC_LIST_APPEND(peers->elements, peer, next); - + } isc_result_t @@ -213,7 +214,7 @@ dns_peer_new(isc_mem_t *mem, isc_netaddr_t *addr, dns_peer_t **peerptr) { isc_result_t dns_peer_newprefix(isc_mem_t *mem, isc_netaddr_t *addr, unsigned int prefixlen, dns_peer_t **peerptr) -{ +{ dns_peer_t *peer; REQUIRE(peerptr != NULL); @@ -415,6 +416,32 @@ dns_peer_getsupportedns(dns_peer_t *peer, isc_boolean_t *retval) { return (ISC_R_NOTFOUND); } +isc_result_t +dns_peer_setrequestnsid(dns_peer_t *peer, isc_boolean_t newval) { + isc_boolean_t existed; + + REQUIRE(DNS_PEER_VALID(peer)); + + existed = DNS_BIT_CHECK(REQUEST_NSID_BIT, &peer->bitflags); + + peer->request_nsid = newval; + DNS_BIT_SET(REQUEST_NSID_BIT, &peer->bitflags); + + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); +} + +isc_result_t +dns_peer_getrequestnsid(dns_peer_t *peer, isc_boolean_t *retval) { + REQUIRE(DNS_PEER_VALID(peer)); + REQUIRE(retval != NULL); + + if (DNS_BIT_CHECK(REQUEST_NSID_BIT, &peer->bitflags)) { + *retval = peer->request_nsid; + return (ISC_R_SUCCESS); + } else + return (ISC_R_NOTFOUND); +} + isc_result_t dns_peer_settransfers(dns_peer_t *peer, isc_uint32_t newval) { isc_boolean_t existed; @@ -544,7 +571,7 @@ dns_peer_settransfersource(dns_peer_t *peer, } if (transfer_source != NULL) { peer->transfer_source = isc_mem_get(peer->mem, - sizeof(*peer->transfer_source)); + sizeof(*peer->transfer_source)); if (peer->transfer_source == NULL) return (ISC_R_NOMEMORY); @@ -577,7 +604,7 @@ dns_peer_setnotifysource(dns_peer_t *peer, } if (notify_source != NULL) { peer->notify_source = isc_mem_get(peer->mem, - sizeof(*peer->notify_source)); + sizeof(*peer->notify_source)); if (peer->notify_source == NULL) return (ISC_R_NOMEMORY); @@ -608,7 +635,7 @@ dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source) { } if (query_source != NULL) { peer->query_source = isc_mem_get(peer->mem, - sizeof(*peer->query_source)); + sizeof(*peer->query_source)); if (peer->query_source == NULL) return (ISC_R_NOMEMORY); @@ -649,11 +676,11 @@ dns_peer_getudpsize(dns_peer_t *peer, isc_uint16_t *udpsize) { REQUIRE(udpsize != NULL); if (DNS_BIT_CHECK(SERVER_UDPSIZE_BIT, &peer->bitflags)) { - *udpsize = peer->udpsize; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } + *udpsize = peer->udpsize; + return (ISC_R_SUCCESS); + } else { + return (ISC_R_NOTFOUND); + } } isc_result_t @@ -677,9 +704,9 @@ dns_peer_getmaxudp(dns_peer_t *peer, isc_uint16_t *maxudp) { REQUIRE(maxudp != NULL); if (DNS_BIT_CHECK(SERVER_MAXUDP_BIT, &peer->bitflags)) { - *maxudp = peer->maxudp; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } + *maxudp = peer->maxudp; + return (ISC_R_SUCCESS); + } else { + return (ISC_R_NOTFOUND); + } } diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c index 4c775d2aa4..9fa2fd6cc2 100644 --- a/lib/dns/rdatalist.c +++ b/lib/dns/rdatalist.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist.c,v 1.33 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: rdatalist.c,v 1.34 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -88,6 +88,16 @@ dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, return (ISC_R_SUCCESS); } +isc_result_t +dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset, + dns_rdatalist_t **rdatalist) +{ + REQUIRE(rdatalist != NULL && rdataset != NULL); + *rdatalist = rdataset->private1; + + return (ISC_R_SUCCESS); +} + void isc__rdatalist_disassociate(dns_rdataset_t *rdataset) { UNUSED(rdataset); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index e8347a8386..9b827c8482 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.363 2008/04/02 02:56:23 marka Exp $ */ +/* $Id: resolver.c,v 1.364 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -223,7 +223,7 @@ struct fetchctx { /*% * Look aside state for DS lookups. */ - dns_name_t nsname; + dns_name_t nsname; dns_fetch_t * nsfetch; dns_rdataset_t nsrrset; @@ -994,7 +994,8 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) { } static inline isc_result_t -fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize) +fctx_addopt(dns_message_t *message, unsigned int version, + isc_uint16_t udpsize, isc_boolean_t request_nsid) { dns_rdataset_t *rdataset; dns_rdatalist_t *rdatalist; @@ -1030,10 +1031,23 @@ fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize) rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO; /* - * No EDNS options. + * Set EDNS options if applicable */ - rdata->data = NULL; - rdata->length = 0; + if (request_nsid) { + /* Send empty NSID option (RFC5001) */ + unsigned char data[4]; + isc_buffer_t buf; + + isc_buffer_init(&buf, data, sizeof(data)); + isc_buffer_putuint16(&buf, DNS_OPT_NSID); + isc_buffer_putuint16(&buf, 0); + rdata->data = data; + rdata->length = sizeof(data); + } else { + rdata->data = NULL; + rdata->length = 0; + } + rdata->rdclass = rdatalist->rdclass; rdata->type = rdatalist->type; rdata->flags = 0; @@ -1549,6 +1563,7 @@ resquery_send(resquery_t *query) { unsigned int version = 0; /* Default version. */ unsigned int flags; isc_uint16_t udpsize = res->udpsize; + isc_boolean_t reqnsid = ISC_FALSE; flags = query->addrinfo->flags; if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) { @@ -1559,8 +1574,17 @@ resquery_send(resquery_t *query) { udpsize = 512; else if (peer != NULL) (void)dns_peer_getudpsize(peer, &udpsize); - result = fctx_addopt(fctx->qmessage, version, udpsize); - if (result != ISC_R_SUCCESS) { + + /* request NSID for current view or peer? */ + if (peer != NULL) + (void) dns_peer_getrequestnsid(peer, &reqnsid); + reqnsid = (reqnsid || res->view->requestnsid); + + result = fctx_addopt(fctx->qmessage, version, + udpsize, reqnsid); + if (reqnsid && result == ISC_R_SUCCESS) { + query->options |= DNS_FETCHOPT_WANTNSID; + } else { /* * We couldn't add the OPT, but we'll press on. * We're not using EDNS0, so set the NOEDNS0 @@ -5469,6 +5493,65 @@ checknames(dns_message_t *message) { checknamessection(message, DNS_SECTION_ADDITIONAL); } +/* + * Log server NSID at log level 'level' + */ +static isc_result_t +log_nsid(dns_rdataset_t *opt, resquery_t *query, int level, isc_mem_t *mctx) +{ + static const char hex[17] = "0123456789abcdef"; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_uint16_t optcode, nsid_len, buflen, i; + isc_result_t result; + isc_buffer_t nsidbuf; + dns_rdata_t rdata; + unsigned char *p, *buf, *nsid; + + /* Extract rdata from OPT rdataset */ + result = dns_rdataset_first(opt); + if (result != ISC_R_SUCCESS) + return (ISC_R_FAILURE); + + dns_rdata_init(&rdata); + dns_rdataset_current(opt, &rdata); + if (rdata.length < 4) + return (ISC_R_FAILURE); + + /* Check for NSID */ + isc_buffer_init(&nsidbuf, rdata.data, rdata.length); + isc_buffer_add(&nsidbuf, rdata.length); + optcode = isc_buffer_getuint16(&nsidbuf); + nsid_len = isc_buffer_getuint16(&nsidbuf); + if (optcode != DNS_OPT_NSID || nsid_len == 0) + return (ISC_R_FAILURE); + + /* Allocate buffer for storing hex version of the NSID */ + buflen = nsid_len * 2 + 1; + buf = isc_mem_get(mctx, buflen); + if (buf == NULL) + return (ISC_R_NOSPACE); + + /* Convert to hex */ + p = buf; + nsid = rdata.data + 4; + for (i = 0; i < nsid_len; i++) { + *p++ = hex[(nsid[0] >> 4) & 0xf]; + *p++ = hex[nsid[0] & 0xf]; + nsid++; + } + *p = '\0'; + + isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf, + sizeof(addrbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, level, + "received NSID '%s' from %s", buf, addrbuf); + + /* Clean up */ + isc_mem_put(mctx, buf, buflen); + return (ISC_R_SUCCESS); +} + static void log_packet(dns_message_t *message, int level, isc_mem_t *mctx) { isc_buffer_t buffer; @@ -5514,6 +5597,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { isc_boolean_t keep_trying, get_nameservers, resend; isc_boolean_t truncated; dns_message_t *message; + dns_rdataset_t *opt; fetchctx_t *fctx; dns_name_t *fname; dns_fixedname_t foundname; @@ -5674,11 +5758,20 @@ resquery_response(isc_task_t *task, isc_event_t *event) { } } + /* * Log the incoming packet. */ log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx); + /* + * Did we request NSID? If so, and if the response contains + * NSID data, log it at INFO level. + */ + opt = dns_message_getopt(message); + if (opt != NULL && (query->options & DNS_FETCHOPT_WANTNSID) != 0) + log_nsid(opt, query, ISC_LOG_INFO, fctx->res->mctx); + /* * If the message is signed, check the signature. If not, this * returns success anyway. @@ -5779,12 +5872,10 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ result = DNS_R_YXDOMAIN; } else if (message->rcode == dns_rcode_badvers) { - dns_rdataset_t *opt; unsigned int flags, mask; unsigned int version; resend = ISC_TRUE; - opt = dns_message_getopt(message); version = (opt->ttl >> 16) & 0xff; flags = (version << DNS_FETCHOPT_EDNSVERSIONSHIFT) | DNS_FETCHOPT_EDNSVERSIONSET; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 2ad569c736..8bc3204188 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.476 2008/04/02 02:37:42 marka Exp $ */ +/* $Id: zone.c,v 1.477 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -6357,7 +6357,7 @@ create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, } static isc_result_t -add_opt(dns_message_t *message, isc_uint16_t udpsize) { +add_opt(dns_message_t *message, isc_uint16_t udpsize, isc_boolean_t reqnsid) { dns_rdataset_t *rdataset = NULL; dns_rdatalist_t *rdatalist = NULL; dns_rdata_t *rdata = NULL; @@ -6387,11 +6387,21 @@ add_opt(dns_message_t *message, isc_uint16_t udpsize) { */ rdatalist->ttl = 0; - /* - * No EDNS options. - */ - rdata->data = NULL; - rdata->length = 0; + /* Set EDNS options if applicable */ + if (reqnsid) { + unsigned char data[4]; + isc_buffer_t buf; + + isc_buffer_init(&buf, data, sizeof(data)); + isc_buffer_putuint16(&buf, DNS_OPT_NSID); + isc_buffer_putuint16(&buf, 0); + rdata->data = data; + rdata->length = sizeof(data); + } else { + rdata->data = NULL; + rdata->length = 0; + } + rdata->rdclass = rdatalist->rdclass; rdata->type = rdatalist->type; rdata->flags = 0; @@ -6426,7 +6436,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { isc_uint32_t options; isc_boolean_t cancel = ISC_TRUE; int timeout; - isc_boolean_t have_xfrsource; + isc_boolean_t have_xfrsource, reqnsid; isc_uint16_t udpsize = SEND_BUFFER_SIZE; REQUIRE(DNS_ZONE_VALID(zone)); @@ -6495,6 +6505,9 @@ soa_query(isc_task_t *task, isc_event_t *event) { udpsize = dns_resolver_getudpsize(zone->view->resolver); (void)dns_peer_getudpsize(peer, &udpsize); + result = dns_peer_getrequestnsid(peer, &reqnsid); + reqnsid = (result == ISC_R_SUCCESS && reqnsid) || + zone->view->requestnsid; } } @@ -6526,7 +6539,7 @@ soa_query(isc_task_t *task, isc_event_t *event) { DNS_REQUESTOPT_TCP : 0; if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - result = add_opt(message, udpsize); + result = add_opt(message, udpsize, reqnsid); if (result != ISC_R_SUCCESS) zone_debuglog(zone, me, 1, "unable to add opt record: %s", @@ -6590,7 +6603,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { dns_tsigkey_t *key = NULL; dns_dbnode_t *node = NULL; int timeout; - isc_boolean_t have_xfrsource = ISC_FALSE; + isc_boolean_t have_xfrsource = ISC_FALSE, reqnsid; isc_uint16_t udpsize = SEND_BUFFER_SIZE; REQUIRE(DNS_ZONE_VALID(zone)); @@ -6719,11 +6732,14 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { udpsize = dns_resolver_getudpsize(zone->view->resolver); (void)dns_peer_getudpsize(peer, &udpsize); + result = dns_peer_getrequestnsid(peer, &reqnsid); + reqnsid = (result == ISC_R_SUCCESS && reqnsid) || + zone->view->requestnsid; } } if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { - result = add_opt(message, udpsize); + result = add_opt(message, udpsize, reqnsid); if (result != ISC_R_SUCCESS) zone_debuglog(zone, me, 1, "unable to add opt record: %s", diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index b58495d267..8a195a8276 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: namedconf.c,v 1.86 2008/04/02 02:37:42 marka Exp $ */ +/* $Id: namedconf.c,v 1.87 2008/04/03 02:01:08 marka Exp $ */ /*! \file */ @@ -734,67 +734,68 @@ static cfg_type_t cfg_type_lookaside = { static cfg_clausedef_t view_clauses[] = { + { "acache-cleaning-interval", &cfg_type_uint32, 0 }, + { "acache-enable", &cfg_type_boolean, 0 }, + { "additional-from-auth", &cfg_type_boolean, 0 }, + { "additional-from-cache", &cfg_type_boolean, 0 }, { "allow-query-cache", &cfg_type_bracketed_aml, 0 }, { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 }, { "allow-recursion", &cfg_type_bracketed_aml, 0 }, { "allow-recursion-on", &cfg_type_bracketed_aml, 0 }, { "allow-v6-synthesis", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE }, - { "sortlist", &cfg_type_bracketed_aml, 0 }, - { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP }, { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT }, - { "minimal-responses", &cfg_type_boolean, 0 }, - { "recursion", &cfg_type_boolean, 0 }, - { "rrset-order", &cfg_type_rrsetorder, 0 }, - { "provide-ixfr", &cfg_type_boolean, 0 }, - { "request-ixfr", &cfg_type_boolean, 0 }, + { "cache-file", &cfg_type_qstring, 0 }, + { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI }, + { "cleaning-interval", &cfg_type_uint32, 0 }, + { "clients-per-query", &cfg_type_uint32, 0 }, + { "disable-algorithms", &cfg_type_disablealgorithm, + CFG_CLAUSEFLAG_MULTI }, + { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, + { "dnssec-accept-expired", &cfg_type_boolean, 0 }, + { "dnssec-enable", &cfg_type_boolean, 0 }, + { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI }, + { "dnssec-must-be-secure", &cfg_type_mustbesecure, + CFG_CLAUSEFLAG_MULTI }, + { "dnssec-validation", &cfg_type_boolean, 0 }, + { "dual-stack-servers", &cfg_type_nameportiplist, 0 }, + { "edns-udp-size", &cfg_type_uint32, 0 }, + { "empty-contact", &cfg_type_astring, 0 }, + { "empty-server", &cfg_type_astring, 0 }, + { "empty-zones-enable", &cfg_type_boolean, 0 }, { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, - { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, - { "additional-from-auth", &cfg_type_boolean, 0 }, - { "additional-from-cache", &cfg_type_boolean, 0 }, + { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 }, + { "lame-ttl", &cfg_type_uint32, 0 }, + { "max-acache-size", &cfg_type_sizenodefault, 0 }, + { "max-cache-size", &cfg_type_size, 0 }, + { "max-cache-ttl", &cfg_type_uint32, 0 }, + { "max-clients-per-query", &cfg_type_uint32, 0 }, + { "max-ncache-ttl", &cfg_type_uint32, 0 }, + { "max-udp-size", &cfg_type_uint32, 0 }, + { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, + { "minimal-responses", &cfg_type_boolean, 0 }, + { "preferred-glue", &cfg_type_astring, 0 }, + { "provide-ixfr", &cfg_type_boolean, 0 }, /* * Note that the query-source option syntax is different * from the other -source options. */ { "query-source", &cfg_type_querysource4, 0 }, { "query-source-v6", &cfg_type_querysource6, 0 }, - { "cleaning-interval", &cfg_type_uint32, 0 }, - { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, - { "lame-ttl", &cfg_type_uint32, 0 }, - { "max-ncache-ttl", &cfg_type_uint32, 0 }, - { "max-cache-ttl", &cfg_type_uint32, 0 }, - { "transfer-format", &cfg_type_transferformat, 0 }, - { "max-cache-size", &cfg_type_size, 0 }, - { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI }, - { "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 }, - { "edns-udp-size", &cfg_type_uint32, 0 }, - { "max-udp-size", &cfg_type_uint32, 0 }, - { "root-delegation-only", &cfg_type_optional_exclude, 0 }, - { "disable-algorithms", &cfg_type_disablealgorithm, - CFG_CLAUSEFLAG_MULTI }, - { "dnssec-enable", &cfg_type_boolean, 0 }, - { "dnssec-validation", &cfg_type_boolean, 0 }, - { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI }, - { "dnssec-must-be-secure", &cfg_type_mustbesecure, - CFG_CLAUSEFLAG_MULTI }, - { "dnssec-accept-expired", &cfg_type_boolean, 0 }, - { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 }, - { "acache-enable", &cfg_type_boolean, 0 }, - { "acache-cleaning-interval", &cfg_type_uint32, 0 }, - { "max-acache-size", &cfg_type_sizenodefault, 0 }, - { "clients-per-query", &cfg_type_uint32, 0 }, - { "max-clients-per-query", &cfg_type_uint32, 0 }, - { "empty-server", &cfg_type_astring, 0 }, - { "empty-contact", &cfg_type_astring, 0 }, - { "empty-zones-enable", &cfg_type_boolean, 0 }, - { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI }, - { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 }, - { "use-queryport-pool", &cfg_type_boolean, 0 }, { "queryport-pool-ports", &cfg_type_uint32, 0 }, { "queryport-pool-updateinterval", &cfg_type_uint32, 0 }, + { "recursion", &cfg_type_boolean, 0 }, + { "request-ixfr", &cfg_type_boolean, 0 }, + { "request-nsid", &cfg_type_boolean, 0 }, + { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, + { "root-delegation-only", &cfg_type_optional_exclude, 0 }, + { "rrset-order", &cfg_type_rrsetorder, 0 }, + { "sortlist", &cfg_type_bracketed_aml, 0 }, + { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI }, + { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP }, + { "transfer-format", &cfg_type_transferformat, 0 }, + { "use-queryport-pool", &cfg_type_boolean, 0 }, + { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 }, { NULL, NULL, 0 } };