--- 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
overhead of locks that are only held briefly.
[RT #37329]
if (sa->sa_family == AF_INET) {
family = 1;
sin = (struct sockaddr_in *) sa;
- memcpy(addr, &sin->sin_addr, 4);
+ memmove(addr, &sin->sin_addr, 4);
if ((plen % 8) != 0)
addr[addrl-1] &=
~0 << (8 - (plen % 8));
} else {
family = 2;
sin6 = (struct sockaddr_in6 *) sa;
- memcpy(addr, &sin6->sin6_addr, 16);
+ memmove(addr, &sin6->sin6_addr, 16);
}
/* Mask off last address byte */
isc_uint16_t family;
isc_uint8_t addrlen, addrbytes, scope, *paddr;
isc_netaddr_t caddr;
- int i;
/*
* If we have already seen a ECS option skip this ECS option.
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));
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:
- if (addrlen > 32U)
- goto invalid_length;
+ if (addrlen > 32U) {
+ 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;
break;
case 2:
if (addrlen > 128U) {
- 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 %s",
- addrlen, family == 1 ? "IPv4" : "IPv6");
+ "address length (%u) for IPv6",
+ addrlen);
return (DNS_R_OPTERR);
}
caddr.family = AF_INET6;
}
paddr = (isc_uint8_t *) &caddr.type;
- for (i = 0; i < addrbytes; i++) {
- paddr[i] = isc_buffer_getuint8(buf);
- optlen--;
- }
-
- if (addrbytes != 0U && (addrlen % 8) != 0) {
- isc_uint8_t bits = ~0 << (8 - (addrlen % 8));
- bits &= paddr[addrbytes - 1];
- if (bits != paddr[addrbytes - 1])
- return (DNS_R_OPTERR);
+ if (addrbytes != 0U) {
+ memmove(paddr, isc_buffer_current(buf), addrbytes);
+ isc_buffer_forward(buf, addrbytes);
+ optlen -= addrbytes;
+
+ if ((addrlen % 8) != 0) {
+ isc_uint8_t bits = ~0 << (8 - (addrlen % 8));
+ bits &= paddr[addrbytes - 1];
+ if (bits != paddr[addrbytes - 1])
+ return (DNS_R_OPTERR);
+ }
}
memmove(&client->ecs_addr, &caddr, sizeof(caddr));
if (sa->sa_family == AF_INET) {
family = 1;
sin = (struct sockaddr_in *) sa;
- memcpy(addr, &sin->sin_addr, 4);
+ memmove(addr, &sin->sin_addr, 4);
if ((plen % 8) != 0)
addr[addrl-1] &=
~0 << (8 - (plen % 8));
} else {
family = 2;
sin6 = (struct sockaddr_in6 *) sa;
- memcpy(addr, &sin6->sin6_addr, 16);
+ memmove(addr, &sin6->sin6_addr, 16);
}
/* Mask off last address byte */
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);
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);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id$ */
-
/* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
/* RFC2671 */
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);