Commit d7b9756a authored by Evan Hunt's avatar Evan Hunt

[master] ENDS client-subnet in dig

3749.	[func]		"dig +subnet" sends an EDNS client subnet option
			containing the specified address/prefix when
                        querying. (Thanks to Wilmer van der Gaast.)
                        [RT #35415]
parent 1361e038
3749. [func] "dig +subnet" sends an EDNS client subnet option
containing the specified address/prefix when
querying. (Thanks to Wilmer van der Gaast.)
[RT #35415]
3748. [test] Use delve to test dns_client interfaces. [RT #35383] 3748. [test] Use delve to test dns_client interfaces. [RT #35383]
3747. [bug] A race condition could lead to a core dump when 3747. [bug] A race condition could lead to a core dump when
......
...@@ -127,6 +127,8 @@ BIND 9.10.0 ...@@ -127,6 +127,8 @@ BIND 9.10.0
zones. This can simplify the process of rolling DNSSEC keys zones. This can simplify the process of rolling DNSSEC keys
by guaranteeing that cached signatures will have expired by guaranteeing that cached signatures will have expired
within the specified amount of time. within the specified amount of time.
- "dig +subnet" sends an EDNS client-subnet option when
querying.
- New "dnssec-coverage" tool to check DNSSEC key coverage - New "dnssec-coverage" tool to check DNSSEC key coverage
for a zone and report if a lapse in signing coverage has for a zone and report if a lapse in signing coverage has
been inadvertently scheduled. been inadvertently scheduled.
......
...@@ -192,6 +192,7 @@ help(void) { ...@@ -192,6 +192,7 @@ help(void) {
" +domain=### (Set default domainname)\n" " +domain=### (Set default domainname)\n"
" +bufsize=### (Set EDNS0 Max UDP packet size)\n" " +bufsize=### (Set EDNS0 Max UDP packet size)\n"
" +ndots=### (Set NDOTS value)\n" " +ndots=### (Set NDOTS value)\n"
" +subnet=addr (Set edns-client-subnet option)\n"
" +[no]edns[=###] (Set EDNS version) [0]\n" " +[no]edns[=###] (Set EDNS version) [0]\n"
" +[no]search (Set whether to use searchlist)\n" " +[no]search (Set whether to use searchlist)\n"
" +[no]showsearch (Search with intermediate results)\n" " +[no]showsearch (Search with intermediate results)\n"
...@@ -1156,6 +1157,23 @@ plus_option(char *option, isc_boolean_t is_batchfile, ...@@ -1156,6 +1157,23 @@ plus_option(char *option, isc_boolean_t is_batchfile,
FULLCHECK("stats"); FULLCHECK("stats");
lookup->stats = state; lookup->stats = state;
break; break;
case 'u': /* subnet */
FULLCHECK("subnet");
if (state && value == NULL)
goto need_value;
if (!state) {
if (lookup->ecs_addr != NULL) {
isc_mem_free(mctx, lookup->ecs_addr);
lookup->ecs_addr = NULL;
}
break;
}
if (lookup->edns == -1)
lookup->edns = 0;
result = parse_netprefix(&lookup->ecs_addr, value);
if (result != ISC_R_SUCCESS)
fatal("Couldn't parse client");
break;
default: default:
goto invalid_option; goto invalid_option;
} }
......
...@@ -936,6 +936,16 @@ ...@@ -936,6 +936,16 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>+[no]subnet=addr/prefix<option></term>
<listitem>
<para>
Send an EDNS Client Subnet option with the speciifed
IP address or network prefix.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
......
...@@ -78,14 +78,13 @@ ...@@ -78,14 +78,13 @@
#include <isc/lang.h> #include <isc/lang.h>
#include <isc/log.h> #include <isc/log.h>
#include <isc/netaddr.h> #include <isc/netaddr.h>
#ifdef DIG_SIGCHASE
#include <isc/netdb.h> #include <isc/netdb.h>
#endif
#include <isc/parseint.h> #include <isc/parseint.h>
#include <isc/print.h> #include <isc/print.h>
#include <isc/random.h> #include <isc/random.h>
#include <isc/result.h> #include <isc/result.h>
#include <isc/serial.h> #include <isc/serial.h>
#include <isc/sockaddr.h>
#include <isc/string.h> #include <isc/string.h>
#include <isc/task.h> #include <isc/task.h>
#include <isc/timer.h> #include <isc/timer.h>
...@@ -807,6 +806,7 @@ make_empty_lookup(void) { ...@@ -807,6 +806,7 @@ make_empty_lookup(void) {
looknew->new_search = ISC_FALSE; looknew->new_search = ISC_FALSE;
looknew->done_as_is = ISC_FALSE; looknew->done_as_is = ISC_FALSE;
looknew->need_search = ISC_FALSE; looknew->need_search = ISC_FALSE;
looknew->ecs_addr = NULL;
#ifdef ISC_PLATFORM_USESIT #ifdef ISC_PLATFORM_USESIT
looknew->sitvalue = NULL; looknew->sitvalue = NULL;
#endif #endif
...@@ -891,6 +891,12 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { ...@@ -891,6 +891,12 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
looknew->need_search = lookold->need_search; looknew->need_search = lookold->need_search;
looknew->done_as_is = lookold->done_as_is; looknew->done_as_is = lookold->done_as_is;
if (lookold->ecs_addr != NULL) {
size_t len = sizeof(isc_sockaddr_t);
looknew->ecs_addr = isc_mem_allocate(mctx, len);
memmove(looknew->ecs_addr, lookold->ecs_addr, len);
}
if (servers) if (servers)
clone_server_list(lookold->my_server_list, clone_server_list(lookold->my_server_list,
&looknew->my_server_list); &looknew->my_server_list);
...@@ -1005,6 +1011,65 @@ parse_bits(char *arg, const char *desc, isc_uint32_t max) { ...@@ -1005,6 +1011,65 @@ parse_bits(char *arg, const char *desc, isc_uint32_t max) {
return (tmp); return (tmp);
} }
isc_result_t
parse_netprefix(isc_sockaddr_t **sap, const char *value) {
isc_result_t result = ISC_R_SUCCESS;
isc_sockaddr_t *sa = NULL;
struct in_addr in4;
struct in6_addr in6;
isc_uint32_t netmask = 0;
char *slash = NULL;
isc_boolean_t parsed = ISC_FALSE;
if ((slash = strchr(value, '/'))) {
*slash = '\0';
result = isc_parse_uint32(&netmask, slash + 1, 10);
if (result != ISC_R_SUCCESS) {
*slash = '/';
fatal("invalid prefix length '%s': %s\n",
value, isc_result_totext(result));
}
}
sa = isc_mem_allocate(mctx, sizeof(*sa));
if (inet_pton(AF_INET6, value, &in6) == 1) {
isc_sockaddr_fromin6(sa, &in6, 0);
parsed = ISC_TRUE;
if (netmask == 0 || netmask > 128)
netmask = 128;
} else if (inet_pton(AF_INET, value, &in4) == 1) {
parsed = ISC_TRUE;
isc_sockaddr_fromin(sa, &in4, 0);
if (netmask == 0 || netmask > 32)
netmask = 32;
} else if (netmask != 0) {
char buf[64];
int i;
strlcpy(buf, value, sizeof(buf));
for (i = 0; i < 3; i++) {
strlcat(buf, ".0", sizeof(buf));
if (inet_pton(AF_INET, buf, &in4) == 1) {
parsed = ISC_TRUE;
isc_sockaddr_fromin(sa, &in4, 0);
break;
}
}
}
if (slash != NULL)
*slash = '/';
if (!parsed)
fatal("invalid address '%s'", value);
sa->length = netmask;
*sap = sa;
return (ISC_R_SUCCESS);
}
/* /*
* Parse HMAC algorithm specification * Parse HMAC algorithm specification
...@@ -1394,7 +1459,8 @@ setup_libs(void) { ...@@ -1394,7 +1459,8 @@ setup_libs(void) {
/*% /*%
* Add EDNS0 option record to a message. Currently, the only supported * Add EDNS0 option record to a message. Currently, the only supported
* options are UDP buffer size, the DO bit, and NSID request. * options are UDP buffer size, the DO bit, and EDNS options
* (e.g., NSID, SIT, client-subnet)
*/ */
static void static void
add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns, add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns,
...@@ -1568,6 +1634,9 @@ destroy_lookup(dig_lookup_t *lookup) { ...@@ -1568,6 +1634,9 @@ destroy_lookup(dig_lookup_t *lookup) {
if (lookup->tsigctx != NULL) if (lookup->tsigctx != NULL)
dst_context_destroy(&lookup->tsigctx); dst_context_destroy(&lookup->tsigctx);
if (lookup->ecs_addr != NULL)
isc_mem_free(mctx, lookup->ecs_addr);
isc_mem_free(mctx, lookup); isc_mem_free(mctx, lookup);
} }
...@@ -2022,6 +2091,10 @@ setup_lookup(dig_lookup_t *lookup) { ...@@ -2022,6 +2091,10 @@ setup_lookup(dig_lookup_t *lookup) {
isc_buffer_t b; isc_buffer_t b;
dns_compress_t cctx; dns_compress_t cctx;
char store[MXNAME]; char store[MXNAME];
char ecsbuf[20];
#ifdef ISC_PLATFORM_USESIT
char sitbuf[256];
#endif
#ifdef WITH_IDN #ifdef WITH_IDN
idn_result_t mr; idn_result_t mr;
char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME]; char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
...@@ -2273,14 +2346,18 @@ setup_lookup(dig_lookup_t *lookup) { ...@@ -2273,14 +2346,18 @@ setup_lookup(dig_lookup_t *lookup) {
result = dns_message_renderbegin(lookup->sendmsg, &cctx, result = dns_message_renderbegin(lookup->sendmsg, &cctx,
&lookup->renderbuf); &lookup->renderbuf);
check_result(result, "dns_message_renderbegin"); check_result(result, "dns_message_renderbegin");
if (lookup->udpsize > 0 || lookup->dnssec || lookup->edns > -1) { if (lookup->udpsize > 0 || lookup->dnssec ||
#define EDNSOPTS 2 lookup->edns > -1 || lookup->ecs_addr != NULL)
{
#define EDNSOPTS 3
dns_ednsopt_t opts[EDNSOPTS]; dns_ednsopt_t opts[EDNSOPTS];
int i = 0; int i = 0;
if (lookup->udpsize == 0) if (lookup->udpsize == 0)
lookup->udpsize = 4096; lookup->udpsize = 4096;
if (lookup->edns < 0) if (lookup->edns < 0)
lookup->edns = 0; lookup->edns = 0;
if (lookup->nsid) { if (lookup->nsid) {
INSIST(i < EDNSOPTS); INSIST(i < EDNSOPTS);
opts[i].code = DNS_OPT_NSID; opts[i].code = DNS_OPT_NSID;
...@@ -2288,15 +2365,56 @@ setup_lookup(dig_lookup_t *lookup) { ...@@ -2288,15 +2365,56 @@ setup_lookup(dig_lookup_t *lookup) {
opts[i].value = NULL; opts[i].value = NULL;
i++; i++;
} }
if (lookup->ecs_addr != NULL) {
isc_uint32_t prefixlen;
struct sockaddr *sa;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
size_t addrl;
isc_buffer_t b;
sa = &lookup->ecs_addr->type.sa;
prefixlen = lookup->ecs_addr->length;
/* Round up prefix len to a multiple of 8 */
addrl = (prefixlen + 7) / 8;
INSIST(i < EDNSOPTS);
opts[i].code = DNS_OPT_CLIENT_SUBNET;
opts[i].length = addrl + 4;
check_result(result, "isc_buffer_allocate");
isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
if (sa->sa_family == AF_INET) {
sin = (struct sockaddr_in *) sa;
isc_buffer_putuint16(&b, 1);
isc_buffer_putuint8(&b, prefixlen);
isc_buffer_putuint8(&b, 0);
isc_buffer_putmem(&b,
(isc_uint8_t *) &sin->sin_addr,
addrl);
} else {
sin6 = (struct sockaddr_in6 *) sa;
isc_buffer_putuint16(&b, 2);
isc_buffer_putuint8(&b, prefixlen);
isc_buffer_putuint8(&b, 0);
isc_buffer_putmem(&b,
(isc_uint8_t *) &sin6->sin6_addr,
addrl);
}
opts[i].value = (isc_uint8_t *) ecsbuf;
i++;
}
#ifdef ISC_PLATFORM_USESIT #ifdef ISC_PLATFORM_USESIT
if (lookup->sit) { if (lookup->sit) {
INSIST(i < EDNSOPTS); INSIST(i < EDNSOPTS);
opts[i].code = DNS_OPT_SIT; opts[i].code = DNS_OPT_SIT;
if (lookup->sitvalue != NULL) { if (lookup->sitvalue != NULL) {
char bb[256];
isc_buffer_t b; isc_buffer_t b;
isc_buffer_init(&b, bb, sizeof(bb)); isc_buffer_init(&b, sitbuf, sizeof(sitbuf));
result = isc_hex_decodestring(lookup->sitvalue, result = isc_hex_decodestring(lookup->sitvalue,
&b); &b);
check_result(result, "isc_hex_decodestring"); check_result(result, "isc_hex_decodestring");
...@@ -2310,6 +2428,7 @@ setup_lookup(dig_lookup_t *lookup) { ...@@ -2310,6 +2428,7 @@ setup_lookup(dig_lookup_t *lookup) {
i++; i++;
} }
#endif #endif
add_opt(lookup->sendmsg, lookup->udpsize, add_opt(lookup->sendmsg, lookup->udpsize,
lookup->edns, lookup->dnssec, opts, i); lookup->edns, lookup->dnssec, opts, i);
} }
...@@ -2377,6 +2496,7 @@ setup_lookup(dig_lookup_t *lookup) { ...@@ -2377,6 +2496,7 @@ setup_lookup(dig_lookup_t *lookup) {
ISC_LINK_INIT(query, link); ISC_LINK_INIT(query, link);
ISC_LIST_ENQUEUE(lookup->q, query, link); ISC_LIST_ENQUEUE(lookup->q, query, link);
} }
/* XXX qrflag, print_query, etc... */ /* XXX qrflag, print_query, etc... */
if (!ISC_LIST_EMPTY(lookup->q) && qr) { if (!ISC_LIST_EMPTY(lookup->q) && qr) {
extrabytes = 0; extrabytes = 0;
......
...@@ -187,6 +187,7 @@ isc_boolean_t sigchase; ...@@ -187,6 +187,7 @@ isc_boolean_t sigchase;
isc_buffer_t *querysig; isc_buffer_t *querysig;
isc_uint32_t msgcounter; isc_uint32_t msgcounter;
dns_fixedname_t fdomain; dns_fixedname_t fdomain;
isc_sockaddr_t *ecs_addr;
#ifdef ISC_PLATFORM_USESIT #ifdef ISC_PLATFORM_USESIT
char *sitvalue; char *sitvalue;
#endif #endif
...@@ -343,6 +344,9 @@ isc_result_t ...@@ -343,6 +344,9 @@ isc_result_t
parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max, parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
const char *desc); const char *desc);
isc_result_t
parse_netprefix(isc_sockaddr_t **sap, const char *value);
void void
parse_hmac(const char *hmacstr); parse_hmac(const char *hmacstr);
......
...@@ -3191,6 +3191,43 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, ...@@ -3191,6 +3191,43 @@ dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
return (result); return (result);
} }
static isc_result_t
render_ecs(isc_buffer_t *optbuf, isc_buffer_t *target) {
int i;
char addr[16], addr_text[64];
isc_uint16_t family;
isc_uint8_t addrlen, addrbytes, scopelen;
INSIST(isc_buffer_remaininglength(optbuf) >= 4);
family = isc_buffer_getuint16(optbuf);
addrlen = isc_buffer_getuint8(optbuf);
scopelen = isc_buffer_getuint8(optbuf);
addrbytes = (addrlen + 7) / 8;
INSIST(isc_buffer_remaininglength(optbuf) >= addrbytes);
memset(addr, 0, sizeof(addr));
for (i = 0; i < addrbytes; i ++)
addr[i] = isc_buffer_getuint8(optbuf);
if (family == 1)
inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
else if (family == 2)
inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
else {
snprintf(addr_text, sizeof(addr_text),
"Unsupported family %d",
family);
ADD_STRING(target, addr_text);
return (ISC_R_SUCCESS);
}
ADD_STRING(target, addr_text);
sprintf(addr_text, "/%d/%d", addrlen, scopelen);
ADD_STRING(target, addr_text);
return (ISC_R_SUCCESS);
}
isc_result_t isc_result_t
dns_message_pseudosectiontotext(dns_message_t *msg, dns_message_pseudosectiontotext(dns_message_t *msg,
dns_pseudosection_t section, dns_pseudosection_t section,
...@@ -3257,6 +3294,11 @@ dns_message_pseudosectiontotext(dns_message_t *msg, ...@@ -3257,6 +3294,11 @@ dns_message_pseudosectiontotext(dns_message_t *msg,
ADD_STRING(target, "; NSID"); ADD_STRING(target, "; NSID");
} else if (optcode == DNS_OPT_SIT) { } else if (optcode == DNS_OPT_SIT) {
ADD_STRING(target, "; SIT"); ADD_STRING(target, "; SIT");
} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
ADD_STRING(target, "; CLIENT-SUBNET: ");
render_ecs(&optbuf, target);
ADD_STRING(target, "\n");
break;
} else { } else {
ADD_STRING(target, "; OPT="); ADD_STRING(target, "; OPT=");
sprintf(buf, "%u", optcode); sprintf(buf, "%u", optcode);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment