mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-14 00:49:59 -04:00
[v9_10] fix ECS family 0 handling
4341. [bug] Correct the handling of ECS options with address family 0. [RT #41377]
This commit is contained in:
parent
c25c284caa
commit
a95ec4fb11
8 changed files with 101 additions and 43 deletions
3
CHANGES
3
CHANGES
|
|
@ -1,6 +1,9 @@
|
|||
4342. [bug] 'rndc flushtree' could fail to clean the tree if there
|
||||
wasn't a node at the specified name. [RT #41846]
|
||||
|
||||
4341. [bug] Correct the handling of ECS options with
|
||||
address family 0. [RT #41377]
|
||||
|
||||
4338. [bug] Reimplement change 4324 as it wasn't properly doing
|
||||
all the required book keeping. [RT #41941]
|
||||
|
||||
|
|
|
|||
|
|
@ -587,13 +587,15 @@ causes fields not to be split at all\&. The default is 56 characters, or 44 char
|
|||
This query option toggles the printing of statistics: when the query was made, the size of the reply and so on\&. The default behavior is to print the query statistics\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB+[no]subnet=addr[/netmask]\fR
|
||||
\fB+[no]subnet=addr[/prefix\-length]\fR
|
||||
.RS 4
|
||||
Send (don\*(Aqt send) an EDNS Client Subnet option with the specified IP address or network prefix\&.
|
||||
.sp
|
||||
\fBdig +subnet=0\&.0\&.0\&.0/0\fR, or simply
|
||||
\fBdig +subnet=0\fR
|
||||
for short, sends a Client Subnet option with an empty address and a source prefix length of zero, which signals a resolver that the EDNS Client Subnet option should not be used when resolving this query\&.
|
||||
for short, sends an EDNS client\-subnet option with an empty address and a source prefix\-length of zero, which signals a resolver that the client\*(Aqs address information must
|
||||
\fInot\fR
|
||||
be used when resolving this query\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB+[no]tcp\fR
|
||||
|
|
|
|||
|
|
@ -977,19 +977,20 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>+[no]subnet=addr[/netmask]</option></term>
|
||||
<term><option>+[no]subnet=addr[/prefix-length]</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Send (don't send) an EDNS Client Subnet option with the
|
||||
specified IP address or network prefix.
|
||||
specified IP address or network prefix.
|
||||
</para>
|
||||
<para>
|
||||
<command>dig +subnet=0.0.0.0/0</command>, or simply
|
||||
<command>dig +subnet=0</command> for short, sends a
|
||||
Client Subnet option with an empty address and a
|
||||
source prefix length of zero, which signals a resolver
|
||||
that the EDNS Client Subnet option should not be used
|
||||
when resolving this query.
|
||||
<command>dig +subnet=0</command> for short, sends an EDNS
|
||||
client-subnet option with an empty address and a source
|
||||
prefix-length of zero, which signals a resolver that
|
||||
the client's address information must
|
||||
<emphasis>not</emphasis> be used when resolving
|
||||
this query.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
|
|||
|
|
@ -590,19 +590,20 @@
|
|||
so on. The default behavior is to print the query
|
||||
statistics.
|
||||
</p></dd>
|
||||
<dt><span class="term"><code class="option">+[no]subnet=addr[/netmask]</code></span></dt>
|
||||
<dt><span class="term"><code class="option">+[no]subnet=addr[/prefix-length]</code></span></dt>
|
||||
<dd>
|
||||
<p>
|
||||
Send (don't send) an EDNS Client Subnet option with the
|
||||
specified IP address or network prefix.
|
||||
specified IP address or network prefix.
|
||||
</p>
|
||||
<p>
|
||||
<span class="command"><strong>dig +subnet=0.0.0.0/0</strong></span>, or simply
|
||||
<span class="command"><strong>dig +subnet=0</strong></span> for short, sends a
|
||||
Client Subnet option with an empty address and a
|
||||
source prefix length of zero, which signals a resolver
|
||||
that the EDNS Client Subnet option should not be used
|
||||
when resolving this query.
|
||||
<span class="command"><strong>dig +subnet=0</strong></span> for short, sends an EDNS
|
||||
client-subnet option with an empty address and a source
|
||||
prefix-length of zero, which signals a resolver that
|
||||
the client's address information must
|
||||
<span class="emphasis"><em>not</em></span> be used when resolving
|
||||
this query.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><span class="term"><code class="option">+[no]tcp</code></span></dt>
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,7 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
|||
isc_sockaddr_t *sa = NULL;
|
||||
struct in_addr in4;
|
||||
struct in6_addr in6;
|
||||
isc_uint32_t netmask = 0xffffffff;
|
||||
isc_uint32_t prefix_length = 0xffffffff;
|
||||
char *slash = NULL;
|
||||
isc_boolean_t parsed = ISC_FALSE;
|
||||
char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
|
||||
|
|
@ -1076,13 +1076,16 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
|||
slash = strchr(buf, '/');
|
||||
if (slash != NULL) {
|
||||
*slash = '\0';
|
||||
result = isc_parse_uint32(&netmask, slash + 1, 10);
|
||||
result = isc_parse_uint32(&prefix_length, slash + 1, 10);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fatal("invalid prefix length in '%s': %s\n",
|
||||
value, isc_result_totext(result));
|
||||
}
|
||||
} else if (strcmp(value, "0") == 0) {
|
||||
netmask = 0;
|
||||
}
|
||||
|
||||
if (strcmp(buf, "0") == 0) {
|
||||
parsed = ISC_TRUE;
|
||||
prefix_length = 0;
|
||||
}
|
||||
|
||||
sa = isc_mem_allocate(mctx, sizeof(*sa));
|
||||
|
|
@ -1091,14 +1094,14 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
|||
if (inet_pton(AF_INET6, buf, &in6) == 1) {
|
||||
parsed = ISC_TRUE;
|
||||
isc_sockaddr_fromin6(sa, &in6, 0);
|
||||
if (netmask > 128)
|
||||
netmask = 128;
|
||||
if (prefix_length > 128)
|
||||
prefix_length = 128;
|
||||
} else if (inet_pton(AF_INET, buf, &in4) == 1) {
|
||||
parsed = ISC_TRUE;
|
||||
isc_sockaddr_fromin(sa, &in4, 0);
|
||||
if (netmask > 32)
|
||||
netmask = 32;
|
||||
} else if (netmask != 0xffffffff) {
|
||||
if (prefix_length > 32)
|
||||
prefix_length = 32;
|
||||
} else if (prefix_length != 0xffffffff && prefix_length != 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
|
||||
|
|
@ -1110,14 +1113,17 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
|
|||
}
|
||||
}
|
||||
|
||||
if (netmask > 32)
|
||||
netmask = 32;
|
||||
if (prefix_length > 32)
|
||||
prefix_length = 32;
|
||||
}
|
||||
|
||||
if (!parsed)
|
||||
fatal("invalid address '%s'", value);
|
||||
|
||||
sa->length = netmask;
|
||||
sa->length = prefix_length;
|
||||
if (prefix_length == 0)
|
||||
sa->type.sa.sa_family = AF_UNSPEC;
|
||||
|
||||
*sap = sa;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
|
@ -2467,7 +2473,7 @@ setup_lookup(dig_lookup_t *lookup) {
|
|||
}
|
||||
|
||||
if (lookup->ecs_addr != NULL) {
|
||||
isc_uint8_t addr[16], family;
|
||||
isc_uint8_t addr[16], family, proto;
|
||||
isc_uint32_t plen;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sin;
|
||||
|
|
@ -2485,17 +2491,29 @@ setup_lookup(dig_lookup_t *lookup) {
|
|||
opts[i].length = (isc_uint16_t) addrl + 4;
|
||||
check_result(result, "isc_buffer_allocate");
|
||||
isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
|
||||
if (sa->sa_family == AF_INET) {
|
||||
|
||||
/* If prefix length is zero, don't set family */
|
||||
proto = sa->sa_family;
|
||||
if (plen == 0)
|
||||
proto = AF_UNSPEC;
|
||||
|
||||
switch (proto) {
|
||||
case AF_UNSPEC:
|
||||
INSIST(plen == 0);
|
||||
family = 0;
|
||||
break;
|
||||
case AF_INET:
|
||||
family = 1;
|
||||
sin = (struct sockaddr_in *) sa;
|
||||
memcpy(addr, &sin->sin_addr, 4);
|
||||
if ((plen % 8) != 0)
|
||||
addr[addrl-1] &=
|
||||
~0 << (8 - (plen % 8));
|
||||
} else {
|
||||
memmove(addr, &sin->sin_addr, 4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
family = 2;
|
||||
sin6 = (struct sockaddr_in6 *) sa;
|
||||
memcpy(addr, &sin6->sin6_addr, 16);
|
||||
memmove(addr, &sin6->sin6_addr, 16);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
}
|
||||
|
||||
/* Mask off last address byte */
|
||||
|
|
|
|||
|
|
@ -1678,7 +1678,7 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
|||
isc_buffer_t db;
|
||||
|
||||
/*
|
||||
* If we have already seen a ECS option skip this ECS option.
|
||||
* If we have already seen a SIT option skip this SIT option.
|
||||
*/
|
||||
if ((client->attributes & NS_CLIENTATTR_WANTSIT) != 0) {
|
||||
isc_buffer_forward(buf, (isc_uint32_t)optlen);
|
||||
|
|
|
|||
|
|
@ -3234,6 +3234,9 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
|
|||
addrlen = isc_buffer_getuint8(ecsbuf);
|
||||
scopelen = isc_buffer_getuint8(ecsbuf);
|
||||
|
||||
if (addrlen == 0 && family != 0)
|
||||
return (DNS_R_OPTERR);
|
||||
|
||||
addrbytes = (addrlen + 7) / 8;
|
||||
if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
|
||||
return (DNS_R_OPTERR);
|
||||
|
|
@ -3246,15 +3249,23 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
|
|||
for (i = 0; i < addrbytes; i ++)
|
||||
addr[i] = isc_buffer_getuint8(ecsbuf);
|
||||
|
||||
if (family == 1) {
|
||||
switch (family) {
|
||||
case 0:
|
||||
if (addrlen != 0U || scopelen != 0U)
|
||||
return (DNS_R_OPTERR);
|
||||
strlcpy(addr_text, "0", sizeof(addr_text));
|
||||
break;
|
||||
case 1:
|
||||
if (addrlen > 32 || scopelen > 32)
|
||||
return (DNS_R_OPTERR);
|
||||
inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
|
||||
} else if (family == 2) {
|
||||
break;
|
||||
case 2:
|
||||
if (addrlen > 128 || scopelen > 128)
|
||||
return (DNS_R_OPTERR);
|
||||
inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
snprintf(addr_text, sizeof(addr_text),
|
||||
"Unsupported family %u", family);
|
||||
ADD_STRING(target, addr_text);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2004, 2005, 2007, 2009, 2011-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 2004, 2005, 2007, 2009, 2011-2016 Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (C) 1998-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
|
|
@ -15,8 +15,6 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
|
||||
|
||||
/* RFC2671 */
|
||||
|
|
@ -135,7 +133,24 @@ fromwire_opt(ARGS_FROMWIRE) {
|
|||
isc_region_consume(&sregion, 1);
|
||||
scope = uint8_fromregion(&sregion);
|
||||
isc_region_consume(&sregion, 1);
|
||||
|
||||
if (addrlen == 0U && family != 0U)
|
||||
return (DNS_R_OPTERR);
|
||||
|
||||
switch (family) {
|
||||
case 0:
|
||||
/*
|
||||
* XXXMUKS: In queries and replies, if
|
||||
* FAMILY is set to 0, SOURCE
|
||||
* PREFIX-LENGTH and SCOPE PREFIX-LENGTH
|
||||
* must be 0 and ADDRESS should not be
|
||||
* present as the address and prefix
|
||||
* lengths don't make sense because the
|
||||
* family is unknown.
|
||||
*/
|
||||
if (addrlen != 0U || scope != 0U)
|
||||
return (DNS_R_OPTERR);
|
||||
break;
|
||||
case 1:
|
||||
if (addrlen > 32U || scope > 32U)
|
||||
return (DNS_R_OPTERR);
|
||||
|
|
@ -144,6 +159,8 @@ fromwire_opt(ARGS_FROMWIRE) {
|
|||
if (addrlen > 128U || scope > 128U)
|
||||
return (DNS_R_OPTERR);
|
||||
break;
|
||||
default:
|
||||
return (DNS_R_OPTERR);
|
||||
}
|
||||
addrbytes = (addrlen + 7) / 8;
|
||||
if (addrbytes + 4 != length)
|
||||
|
|
@ -166,6 +183,11 @@ fromwire_opt(ARGS_FROMWIRE) {
|
|||
return (DNS_R_OPTERR);
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
case DNS_OPT_COOKIE:
|
||||
if (length != 8 && (length < 16 || length > 40))
|
||||
return (DNS_R_OPTERR);
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
default:
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in a new issue