1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */ 18 19 /* RFC2671 */ 20 21 #ifndef RDATA_GENERIC_OPT_41_C 22 #define RDATA_GENERIC_OPT_41_C 23 24 static inline isc_result_t 25 totext_opt(ARGS_TOTEXT) { 26 isc_region_t r; 27 isc_region_t or; 28 uint16_t option; 29 uint16_t length; 30 char buf[sizeof("64000 64000")]; 31 32 /* 33 * OPT records do not have a text format. 34 */ 35 36 REQUIRE(rdata->type == dns_rdatatype_opt); 37 38 dns_rdata_toregion(rdata, &r); 39 while (r.length > 0) { 40 option = uint16_fromregion(&r); 41 isc_region_consume(&r, 2); 42 length = uint16_fromregion(&r); 43 isc_region_consume(&r, 2); 44 snprintf(buf, sizeof(buf), "%u %u", option, length); 45 RETERR(isc_str_tobuffer(buf, target)); 46 INSIST(r.length >= length); 47 if (length > 0) { 48 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 49 RETERR(isc_str_tobuffer(" (", target)); 50 RETERR(isc_str_tobuffer(tctx->linebreak, target)); 51 or = r; 52 or.length = length; 53 if (tctx->width == 0) /* No splitting */ 54 RETERR(isc_base64_totext(&or, 60, "", target)); 55 else 56 RETERR(isc_base64_totext(&or, tctx->width - 2, 57 tctx->linebreak, 58 target)); 59 isc_region_consume(&r, length); 60 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 61 RETERR(isc_str_tobuffer(" )", target)); 62 } 63 if (r.length > 0) 64 RETERR(isc_str_tobuffer(" ", target)); 65 } 66 67 return (ISC_R_SUCCESS); 68 } 69 70 static inline isc_result_t 71 fromwire_opt(ARGS_FROMWIRE) { 72 isc_region_t sregion; 73 isc_region_t tregion; 74 uint16_t opt; 75 uint16_t length; 76 unsigned int total; 77 78 REQUIRE(type == dns_rdatatype_opt); 79 80 UNUSED(type); 81 UNUSED(rdclass); 82 UNUSED(dctx); 83 UNUSED(options); 84 85 isc_buffer_activeregion(source, &sregion); 86 if (sregion.length == 0) 87 return (ISC_R_SUCCESS); 88 total = 0; 89 while (sregion.length != 0) { 90 if (sregion.length < 4) 91 return (ISC_R_UNEXPECTEDEND); 92 opt = uint16_fromregion(&sregion); 93 isc_region_consume(&sregion, 2); 94 length = uint16_fromregion(&sregion); 95 isc_region_consume(&sregion, 2); 96 total += 4; 97 if (sregion.length < length) 98 return (ISC_R_UNEXPECTEDEND); 99 switch (opt) { 100 case DNS_OPT_CLIENT_SUBNET: { 101 uint16_t family; 102 uint8_t addrlen; 103 uint8_t scope; 104 uint8_t addrbytes; 105 106 if (length < 4) 107 return (DNS_R_OPTERR); 108 family = uint16_fromregion(&sregion); 109 isc_region_consume(&sregion, 2); 110 addrlen = uint8_fromregion(&sregion); 111 isc_region_consume(&sregion, 1); 112 scope = uint8_fromregion(&sregion); 113 isc_region_consume(&sregion, 1); 114 115 switch (family) { 116 case 0: 117 /* 118 * XXXMUKS: In queries and replies, if 119 * FAMILY is set to 0, SOURCE 120 * PREFIX-LENGTH and SCOPE PREFIX-LENGTH 121 * must be 0 and ADDRESS should not be 122 * present as the address and prefix 123 * lengths don't make sense because the 124 * family is unknown. 125 */ 126 if (addrlen != 0U || scope != 0U) 127 return (DNS_R_OPTERR); 128 break; 129 case 1: 130 if (addrlen > 32U || scope > 32U) 131 return (DNS_R_OPTERR); 132 break; 133 case 2: 134 if (addrlen > 128U || scope > 128U) 135 return (DNS_R_OPTERR); 136 break; 137 default: 138 return (DNS_R_OPTERR); 139 } 140 addrbytes = (addrlen + 7) / 8; 141 if (addrbytes + 4 != length) 142 return (DNS_R_OPTERR); 143 144 if (addrbytes != 0U && (addrlen % 8) != 0) { 145 uint8_t bits = ~0U << (8 - (addrlen % 8)); 146 bits &= sregion.base[addrbytes - 1]; 147 if (bits != sregion.base[addrbytes - 1]) 148 return (DNS_R_OPTERR); 149 } 150 isc_region_consume(&sregion, addrbytes); 151 break; 152 } 153 case DNS_OPT_EXPIRE: 154 /* 155 * Request has zero length. Response is 32 bits. 156 */ 157 if (length != 0 && length != 4) 158 return (DNS_R_OPTERR); 159 isc_region_consume(&sregion, length); 160 break; 161 case DNS_OPT_COOKIE: 162 if (length != 8 && (length < 16 || length > 40)) 163 return (DNS_R_OPTERR); 164 isc_region_consume(&sregion, length); 165 break; 166 case DNS_OPT_KEY_TAG: 167 if (length == 0 || (length % 2) != 0) 168 return (DNS_R_OPTERR); 169 isc_region_consume(&sregion, length); 170 break; 171 default: 172 isc_region_consume(&sregion, length); 173 break; 174 } 175 total += length; 176 } 177 178 isc_buffer_activeregion(source, &sregion); 179 isc_buffer_availableregion(target, &tregion); 180 if (tregion.length < total) 181 return (ISC_R_NOSPACE); 182 memmove(tregion.base, sregion.base, total); 183 isc_buffer_forward(source, total); 184 isc_buffer_add(target, total); 185 186 return (ISC_R_SUCCESS); 187 } 188 189 static inline isc_result_t 190 towire_opt(ARGS_TOWIRE) { 191 192 REQUIRE(rdata->type == dns_rdatatype_opt); 193 194 UNUSED(cctx); 195 196 return (isc_mem_tobuffer(target, rdata->data, rdata->length)); 197 } 198 199 #endif /* RDATA_GENERIC_OPT_41_C */ 200