summaryrefslogtreecommitdiff
path: root/lib/dns/rdata/generic/opt_41.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/rdata/generic/opt_41.c')
-rw-r--r--lib/dns/rdata/generic/opt_41.c46
1 files changed, 39 insertions, 7 deletions
diff --git a/lib/dns/rdata/generic/opt_41.c b/lib/dns/rdata/generic/opt_41.c
index fa349f1f5808..afb25b63ba81 100644
--- a/lib/dns/rdata/generic/opt_41.c
+++ b/lib/dns/rdata/generic/opt_41.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2007, 2009, 2012 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2009, 2012-2014 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1998-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -93,6 +93,7 @@ static inline isc_result_t
fromwire_opt(ARGS_FROMWIRE) {
isc_region_t sregion;
isc_region_t tregion;
+ isc_uint16_t opt;
isc_uint16_t length;
unsigned int total;
@@ -108,17 +109,48 @@ fromwire_opt(ARGS_FROMWIRE) {
while (sregion.length != 0) {
if (sregion.length < 4)
return (ISC_R_UNEXPECTEDEND);
- /*
- * Eat the 16bit option code. There is nothing to
- * be done with it currently.
- */
+ opt = uint16_fromregion(&sregion);
isc_region_consume(&sregion, 2);
length = uint16_fromregion(&sregion);
isc_region_consume(&sregion, 2);
total += 4;
if (sregion.length < length)
return (ISC_R_UNEXPECTEDEND);
- isc_region_consume(&sregion, length);
+ switch (opt) {
+ case DNS_OPT_CLIENT_SUBNET: {
+ isc_uint16_t family;
+ isc_uint8_t addrlen;
+ isc_uint8_t scope;
+ isc_uint8_t addrbytes;
+
+ if (length < 4)
+ return (DNS_R_FORMERR);
+ family = uint16_fromregion(&sregion);
+ isc_region_consume(&sregion, 2);
+ addrlen = uint8_fromregion(&sregion);
+ isc_region_consume(&sregion, 1);
+ scope = uint8_fromregion(&sregion);
+ isc_region_consume(&sregion, 1);
+ switch (family) {
+ case 1:
+ if (addrlen > 32U || scope > 32U)
+ return (DNS_R_FORMERR);
+ break;
+ case 2:
+ if (addrlen > 128U || scope > 128U)
+ return (DNS_R_FORMERR);
+ break;
+ }
+ addrbytes = (addrlen + 7) / 8;
+ if (addrbytes + 4 != length)
+ return (DNS_R_FORMERR);
+ isc_region_consume(&sregion, addrbytes);
+ break;
+ }
+ default:
+ isc_region_consume(&sregion, length);
+ break;
+ }
total += length;
}
@@ -126,7 +158,7 @@ fromwire_opt(ARGS_FROMWIRE) {
isc_buffer_availableregion(target, &tregion);
if (tregion.length < total)
return (ISC_R_NOSPACE);
- memcpy(tregion.base, sregion.base, total);
+ memmove(tregion.base, sregion.base, total);
isc_buffer_forward(source, total);
isc_buffer_add(target, total);