mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-04 08:35:31 +00:00
[master] fix ECS with family==0
4341. [bug] Correct the handling of ECS options with address family 0. [RT #41377]
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -1,5 +1,8 @@
|
|||||||
--- 9.11.0a1 released ---
|
--- 9.11.0a1 released ---
|
||||||
|
|
||||||
|
4341. [bug] Correct the handling of ECS options with
|
||||||
|
address family 0. [RT #41377]
|
||||||
|
|
||||||
4340. [performance] Implement adaptive read-write locks, reducing the
|
4340. [performance] Implement adaptive read-write locks, reducing the
|
||||||
overhead of locks that are only held briefly.
|
overhead of locks that are only held briefly.
|
||||||
[RT #37329]
|
[RT #37329]
|
||||||
|
@@ -2527,14 +2527,14 @@ setup_lookup(dig_lookup_t *lookup) {
|
|||||||
if (sa->sa_family == AF_INET) {
|
if (sa->sa_family == AF_INET) {
|
||||||
family = 1;
|
family = 1;
|
||||||
sin = (struct sockaddr_in *) sa;
|
sin = (struct sockaddr_in *) sa;
|
||||||
memcpy(addr, &sin->sin_addr, 4);
|
memmove(addr, &sin->sin_addr, 4);
|
||||||
if ((plen % 8) != 0)
|
if ((plen % 8) != 0)
|
||||||
addr[addrl-1] &=
|
addr[addrl-1] &=
|
||||||
~0 << (8 - (plen % 8));
|
~0 << (8 - (plen % 8));
|
||||||
} else {
|
} else {
|
||||||
family = 2;
|
family = 2;
|
||||||
sin6 = (struct sockaddr_in6 *) sa;
|
sin6 = (struct sockaddr_in6 *) sa;
|
||||||
memcpy(addr, &sin6->sin6_addr, 16);
|
memmove(addr, &sin6->sin6_addr, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mask off last address byte */
|
/* Mask off last address byte */
|
||||||
|
@@ -1894,7 +1894,6 @@ process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
|||||||
isc_uint16_t family;
|
isc_uint16_t family;
|
||||||
isc_uint8_t addrlen, addrbytes, scope, *paddr;
|
isc_uint8_t addrlen, addrbytes, scope, *paddr;
|
||||||
isc_netaddr_t caddr;
|
isc_netaddr_t caddr;
|
||||||
int i;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have already seen a ECS option skip this ECS option.
|
* If we have already seen a ECS option skip this ECS option.
|
||||||
@@ -1929,21 +1928,51 @@ process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
|||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addrlen == 0 && family != 0) {
|
||||||
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||||
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
||||||
|
"EDNS client-subnet option: "
|
||||||
|
"source == 0 but family != 0");
|
||||||
|
return (DNS_R_OPTERR);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&caddr, 0, sizeof(caddr));
|
memset(&caddr, 0, sizeof(caddr));
|
||||||
switch (family) {
|
switch (family) {
|
||||||
|
case 0:
|
||||||
|
/*
|
||||||
|
* XXXMUKS: In queries, if FAMILY is set to 0, SOURCE
|
||||||
|
* 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) {
|
||||||
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||||
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
||||||
|
"EDNS client-subnet option: invalid "
|
||||||
|
"address length (%u) for FAMILY=0",
|
||||||
|
addrlen);
|
||||||
|
return (DNS_R_OPTERR);
|
||||||
|
}
|
||||||
|
caddr.family = AF_UNSPEC;
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (addrlen > 32U)
|
if (addrlen > 32U) {
|
||||||
goto invalid_length;
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||||
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
||||||
|
"EDNS client-subnet option: invalid "
|
||||||
|
"address length (%u) for IPv4",
|
||||||
|
addrlen);
|
||||||
|
return (DNS_R_OPTERR);
|
||||||
|
}
|
||||||
caddr.family = AF_INET;
|
caddr.family = AF_INET;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (addrlen > 128U) {
|
if (addrlen > 128U) {
|
||||||
invalid_length:
|
|
||||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
||||||
"EDNS client-subnet option: invalid "
|
"EDNS client-subnet option: invalid "
|
||||||
"address length (%u) for %s",
|
"address length (%u) for IPv6",
|
||||||
addrlen, family == 1 ? "IPv4" : "IPv6");
|
addrlen);
|
||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
}
|
}
|
||||||
caddr.family = AF_INET6;
|
caddr.family = AF_INET6;
|
||||||
@@ -1964,17 +1993,18 @@ process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paddr = (isc_uint8_t *) &caddr.type;
|
paddr = (isc_uint8_t *) &caddr.type;
|
||||||
for (i = 0; i < addrbytes; i++) {
|
if (addrbytes != 0U) {
|
||||||
paddr[i] = isc_buffer_getuint8(buf);
|
memmove(paddr, isc_buffer_current(buf), addrbytes);
|
||||||
optlen--;
|
isc_buffer_forward(buf, addrbytes);
|
||||||
}
|
optlen -= addrbytes;
|
||||||
|
|
||||||
if (addrbytes != 0U && (addrlen % 8) != 0) {
|
if ((addrlen % 8) != 0) {
|
||||||
isc_uint8_t bits = ~0 << (8 - (addrlen % 8));
|
isc_uint8_t bits = ~0 << (8 - (addrlen % 8));
|
||||||
bits &= paddr[addrbytes - 1];
|
bits &= paddr[addrbytes - 1];
|
||||||
if (bits != paddr[addrbytes - 1])
|
if (bits != paddr[addrbytes - 1])
|
||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memmove(&client->ecs_addr, &caddr, sizeof(caddr));
|
memmove(&client->ecs_addr, &caddr, sizeof(caddr));
|
||||||
client->ecs_addrlen = addrlen;
|
client->ecs_addrlen = addrlen;
|
||||||
|
@@ -611,14 +611,14 @@ sendquery(struct query *query, isc_task_t *task)
|
|||||||
if (sa->sa_family == AF_INET) {
|
if (sa->sa_family == AF_INET) {
|
||||||
family = 1;
|
family = 1;
|
||||||
sin = (struct sockaddr_in *) sa;
|
sin = (struct sockaddr_in *) sa;
|
||||||
memcpy(addr, &sin->sin_addr, 4);
|
memmove(addr, &sin->sin_addr, 4);
|
||||||
if ((plen % 8) != 0)
|
if ((plen % 8) != 0)
|
||||||
addr[addrl-1] &=
|
addr[addrl-1] &=
|
||||||
~0 << (8 - (plen % 8));
|
~0 << (8 - (plen % 8));
|
||||||
} else {
|
} else {
|
||||||
family = 2;
|
family = 2;
|
||||||
sin6 = (struct sockaddr_in6 *) sa;
|
sin6 = (struct sockaddr_in6 *) sa;
|
||||||
memcpy(addr, &sin6->sin6_addr, 16);
|
memmove(addr, &sin6->sin6_addr, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mask off last address byte */
|
/* Mask off last address byte */
|
||||||
|
@@ -3244,6 +3244,9 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
|
|||||||
addrlen = isc_buffer_getuint8(ecsbuf);
|
addrlen = isc_buffer_getuint8(ecsbuf);
|
||||||
scopelen = isc_buffer_getuint8(ecsbuf);
|
scopelen = isc_buffer_getuint8(ecsbuf);
|
||||||
|
|
||||||
|
if (addrlen == 0 && family != 0)
|
||||||
|
return (DNS_R_OPTERR);
|
||||||
|
|
||||||
addrbytes = (addrlen + 7) / 8;
|
addrbytes = (addrlen + 7) / 8;
|
||||||
if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
|
if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
|
||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
@@ -3256,15 +3259,23 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
|
|||||||
for (i = 0; i < addrbytes; i ++)
|
for (i = 0; i < addrbytes; i ++)
|
||||||
addr[i] = isc_buffer_getuint8(ecsbuf);
|
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)
|
if (addrlen > 32 || scopelen > 32)
|
||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
|
inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
|
||||||
} else if (family == 2) {
|
break;
|
||||||
|
case 2:
|
||||||
if (addrlen > 128 || scopelen > 128)
|
if (addrlen > 128 || scopelen > 128)
|
||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
|
inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
snprintf(addr_text, sizeof(addr_text),
|
snprintf(addr_text, sizeof(addr_text),
|
||||||
"Unsupported family %u", family);
|
"Unsupported family %u", family);
|
||||||
ADD_STRING(target, addr_text);
|
ADD_STRING(target, addr_text);
|
||||||
|
@@ -15,8 +15,6 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id$ */
|
|
||||||
|
|
||||||
/* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
|
/* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
|
||||||
|
|
||||||
/* RFC2671 */
|
/* RFC2671 */
|
||||||
@@ -135,7 +133,24 @@ fromwire_opt(ARGS_FROMWIRE) {
|
|||||||
isc_region_consume(&sregion, 1);
|
isc_region_consume(&sregion, 1);
|
||||||
scope = uint8_fromregion(&sregion);
|
scope = uint8_fromregion(&sregion);
|
||||||
isc_region_consume(&sregion, 1);
|
isc_region_consume(&sregion, 1);
|
||||||
|
|
||||||
|
if (addrlen == 0U && family != 0U)
|
||||||
|
return (DNS_R_OPTERR);
|
||||||
|
|
||||||
switch (family) {
|
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:
|
case 1:
|
||||||
if (addrlen > 32U || scope > 32U)
|
if (addrlen > 32U || scope > 32U)
|
||||||
return (DNS_R_OPTERR);
|
return (DNS_R_OPTERR);
|
||||||
|
Reference in New Issue
Block a user