#ifndef RDATA_GENERIC_OPT_41_C
#define RDATA_GENERIC_OPT_41_C
static inline isc_result_t
totext_opt(ARGS_TOTEXT) {
isc_region_t r;
isc_region_t or;
uint16_t option;
uint16_t length;
char buf[sizeof("64000 64000")];
REQUIRE(rdata->type == dns_rdatatype_opt);
dns_rdata_toregion(rdata, &r);
while (r.length > 0) {
option = uint16_fromregion(&r);
isc_region_consume(&r, 2);
length = uint16_fromregion(&r);
isc_region_consume(&r, 2);
snprintf(buf, sizeof(buf), "%u %u", option, length);
RETERR(isc_str_tobuffer(buf, target));
INSIST(r.length >= length);
if (length > 0) {
if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
RETERR(isc_str_tobuffer(" (", target));
RETERR(isc_str_tobuffer(tctx->linebreak, target));
or = r;
or.length = length;
if (tctx->width == 0)
RETERR(isc_base64_totext(&or, 60, "", target));
else
RETERR(isc_base64_totext(&or, tctx->width - 2,
tctx->linebreak,
target));
isc_region_consume(&r, length);
if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
RETERR(isc_str_tobuffer(" )", target));
}
if (r.length > 0)
RETERR(isc_str_tobuffer(" ", target));
}
return (ISC_R_SUCCESS);
}
static inline isc_result_t
fromwire_opt(ARGS_FROMWIRE) {
isc_region_t sregion;
isc_region_t tregion;
uint16_t opt;
uint16_t length;
unsigned int total;
REQUIRE(type == dns_rdatatype_opt);
UNUSED(type);
UNUSED(rdclass);
UNUSED(dctx);
UNUSED(options);
isc_buffer_activeregion(source, &sregion);
if (sregion.length == 0)
return (ISC_R_SUCCESS);
total = 0;
while (sregion.length != 0) {
if (sregion.length < 4)
return (ISC_R_UNEXPECTEDEND);
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);
switch (opt) {
case DNS_OPT_CLIENT_SUBNET: {
uint16_t family;
uint8_t addrlen;
uint8_t scope;
uint8_t addrbytes;
if (length < 4)
return (DNS_R_OPTERR);
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 0:
if (addrlen != 0U || scope != 0U)
return (DNS_R_OPTERR);
break;
case 1:
if (addrlen > 32U || scope > 32U)
return (DNS_R_OPTERR);
break;
case 2:
if (addrlen > 128U || scope > 128U)
return (DNS_R_OPTERR);
break;
default:
return (DNS_R_OPTERR);
}
addrbytes = (addrlen + 7) / 8;
if (addrbytes + 4 != length)
return (DNS_R_OPTERR);
if (addrbytes != 0U && (addrlen % 8) != 0) {
uint8_t bits = ~0U << (8 - (addrlen % 8));
bits &= sregion.base[addrbytes - 1];
if (bits != sregion.base[addrbytes - 1])
return (DNS_R_OPTERR);
}
isc_region_consume(&sregion, addrbytes);
break;
}
case DNS_OPT_EXPIRE:
if (length != 0 && length != 4)
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;
case DNS_OPT_KEY_TAG:
if (length == 0 || (length % 2) != 0)
return (DNS_R_OPTERR);
isc_region_consume(&sregion, length);
break;
default:
isc_region_consume(&sregion, length);
break;
}
total += length;
}
isc_buffer_activeregion(source, &sregion);
isc_buffer_availableregion(target, &tregion);
if (tregion.length < total)
return (ISC_R_NOSPACE);
memmove(tregion.base, sregion.base, total);
isc_buffer_forward(source, total);
isc_buffer_add(target, total);
return (ISC_R_SUCCESS);
}
static inline isc_result_t
towire_opt(ARGS_TOWIRE) {
REQUIRE(rdata->type == dns_rdatatype_opt);
UNUSED(cctx);
return (isc_mem_tobuffer(target, rdata->data, rdata->length));
}
#endif