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
totext_opt(ARGS_TOTEXT)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
fromwire_opt(ARGS_FROMWIRE)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
towire_opt(ARGS_TOWIRE)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