1 /* $NetBSD: opt_41.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1998-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
22 /* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
26 #ifndef RDATA_GENERIC_OPT_41_C
27 #define RDATA_GENERIC_OPT_41_C
29 #define RRTYPE_OPT_ATTRIBUTES (DNS_RDATATYPEATTR_SINGLETON | \
30 DNS_RDATATYPEATTR_META | \
31 DNS_RDATATYPEATTR_NOTQUESTION)
33 static inline isc_result_t
34 fromtext_opt(ARGS_FROMTEXT
) {
36 * OPT records do not have a text format.
49 return (ISC_R_NOTIMPLEMENTED
);
52 static inline isc_result_t
53 totext_opt(ARGS_TOTEXT
) {
58 char buf
[sizeof("64000 64000")];
61 * OPT records do not have a text format.
64 REQUIRE(rdata
->type
== 41);
66 dns_rdata_toregion(rdata
, &r
);
67 while (r
.length
> 0) {
68 option
= uint16_fromregion(&r
);
69 isc_region_consume(&r
, 2);
70 length
= uint16_fromregion(&r
);
71 isc_region_consume(&r
, 2);
72 sprintf(buf
, "%u %u", option
, length
);
73 RETERR(str_totext(buf
, target
));
74 INSIST(r
.length
>= length
);
76 if ((tctx
->flags
& DNS_STYLEFLAG_MULTILINE
) != 0)
77 RETERR(str_totext(" (", target
));
78 RETERR(str_totext(tctx
->linebreak
, target
));
81 if (tctx
->width
== 0) /* No splitting */
82 RETERR(isc_base64_totext(&or, 60, "", target
));
84 RETERR(isc_base64_totext(&or, tctx
->width
- 2,
87 isc_region_consume(&r
, length
);
88 if ((tctx
->flags
& DNS_STYLEFLAG_MULTILINE
) != 0)
89 RETERR(str_totext(" )", target
));
92 RETERR(str_totext(" ", target
));
95 return (ISC_R_SUCCESS
);
98 static inline isc_result_t
99 fromwire_opt(ARGS_FROMWIRE
) {
100 isc_region_t sregion
;
101 isc_region_t tregion
;
113 isc_buffer_activeregion(source
, &sregion
);
115 while (sregion
.length
!= 0) {
116 if (sregion
.length
< 4)
117 return (ISC_R_UNEXPECTEDEND
);
118 opt
= uint16_fromregion(&sregion
);
119 isc_region_consume(&sregion
, 2);
120 length
= uint16_fromregion(&sregion
);
121 isc_region_consume(&sregion
, 2);
123 if (sregion
.length
< length
)
124 return (ISC_R_UNEXPECTEDEND
);
126 case DNS_OPT_CLIENT_SUBNET
: {
130 isc_uint8_t addrbytes
;
133 return (DNS_R_FORMERR
);
134 family
= uint16_fromregion(&sregion
);
135 isc_region_consume(&sregion
, 2);
136 addrlen
= uint8_fromregion(&sregion
);
137 isc_region_consume(&sregion
, 1);
138 scope
= uint8_fromregion(&sregion
);
139 isc_region_consume(&sregion
, 1);
142 if (addrlen
> 32U || scope
> 32U)
143 return (DNS_R_FORMERR
);
146 if (addrlen
> 128U || scope
> 128U)
147 return (DNS_R_FORMERR
);
150 addrbytes
= (addrlen
+ 7) / 8;
151 if (addrbytes
+ 4 != length
)
152 return (DNS_R_FORMERR
);
153 isc_region_consume(&sregion
, addrbytes
);
158 * Request has zero length. Response is 32 bits.
160 if (length
!= 0 && length
!= 4)
161 return (DNS_R_FORMERR
);
162 isc_region_consume(&sregion
, length
);
165 isc_region_consume(&sregion
, length
);
171 isc_buffer_activeregion(source
, &sregion
);
172 isc_buffer_availableregion(target
, &tregion
);
173 if (tregion
.length
< total
)
174 return (ISC_R_NOSPACE
);
175 memmove(tregion
.base
, sregion
.base
, total
);
176 isc_buffer_forward(source
, total
);
177 isc_buffer_add(target
, total
);
179 return (ISC_R_SUCCESS
);
182 static inline isc_result_t
183 towire_opt(ARGS_TOWIRE
) {
185 REQUIRE(rdata
->type
== 41);
189 return (mem_tobuffer(target
, rdata
->data
, rdata
->length
));
193 compare_opt(ARGS_COMPARE
) {
197 REQUIRE(rdata1
->type
== rdata2
->type
);
198 REQUIRE(rdata1
->rdclass
== rdata2
->rdclass
);
199 REQUIRE(rdata1
->type
== 41);
201 dns_rdata_toregion(rdata1
, &r1
);
202 dns_rdata_toregion(rdata2
, &r2
);
203 return (isc_region_compare(&r1
, &r2
));
206 static inline isc_result_t
207 fromstruct_opt(ARGS_FROMSTRUCT
) {
208 dns_rdata_opt_t
*opt
= source
;
213 REQUIRE(source
!= NULL
);
214 REQUIRE(opt
->common
.rdtype
== type
);
215 REQUIRE(opt
->common
.rdclass
== rdclass
);
216 REQUIRE(opt
->options
!= NULL
|| opt
->length
== 0);
221 region
.base
= opt
->options
;
222 region
.length
= opt
->length
;
223 while (region
.length
>= 4) {
224 isc_region_consume(®ion
, 2); /* opt */
225 length
= uint16_fromregion(®ion
);
226 isc_region_consume(®ion
, 2);
227 if (region
.length
< length
)
228 return (ISC_R_UNEXPECTEDEND
);
229 isc_region_consume(®ion
, length
);
231 if (region
.length
!= 0)
232 return (ISC_R_UNEXPECTEDEND
);
234 return (mem_tobuffer(target
, opt
->options
, opt
->length
));
237 static inline isc_result_t
238 tostruct_opt(ARGS_TOSTRUCT
) {
239 dns_rdata_opt_t
*opt
= target
;
242 REQUIRE(rdata
->type
== 41);
243 REQUIRE(target
!= NULL
);
245 opt
->common
.rdclass
= rdata
->rdclass
;
246 opt
->common
.rdtype
= rdata
->type
;
247 ISC_LINK_INIT(&opt
->common
, link
);
249 dns_rdata_toregion(rdata
, &r
);
250 opt
->length
= r
.length
;
251 opt
->options
= mem_maybedup(mctx
, r
.base
, r
.length
);
252 if (opt
->options
== NULL
)
253 return (ISC_R_NOMEMORY
);
257 return (ISC_R_SUCCESS
);
261 freestruct_opt(ARGS_FREESTRUCT
) {
262 dns_rdata_opt_t
*opt
= source
;
264 REQUIRE(source
!= NULL
);
265 REQUIRE(opt
->common
.rdtype
== 41);
267 if (opt
->mctx
== NULL
)
270 if (opt
->options
!= NULL
)
271 isc_mem_free(opt
->mctx
, opt
->options
);
275 static inline isc_result_t
276 additionaldata_opt(ARGS_ADDLDATA
) {
277 REQUIRE(rdata
->type
== 41);
283 return (ISC_R_SUCCESS
);
286 static inline isc_result_t
287 digest_opt(ARGS_DIGEST
) {
290 * OPT records are not digested.
293 REQUIRE(rdata
->type
== 41);
299 return (ISC_R_NOTIMPLEMENTED
);
302 static inline isc_boolean_t
303 checkowner_opt(ARGS_CHECKOWNER
) {
311 return (dns_name_equal(name
, dns_rootname
));
314 static inline isc_boolean_t
315 checknames_opt(ARGS_CHECKNAMES
) {
317 REQUIRE(rdata
->type
== 41);
327 casecompare_opt(ARGS_COMPARE
) {
328 return (compare_opt(rdata1
, rdata2
));
332 dns_rdata_opt_first(dns_rdata_opt_t
*opt
) {
334 REQUIRE(opt
!= NULL
);
335 REQUIRE(opt
->common
.rdtype
== 41);
336 REQUIRE(opt
->options
!= NULL
|| opt
->length
== 0);
338 if (opt
->length
== 0)
339 return (ISC_R_NOMORE
);
342 return (ISC_R_SUCCESS
);
346 dns_rdata_opt_next(dns_rdata_opt_t
*opt
) {
350 REQUIRE(opt
!= NULL
);
351 REQUIRE(opt
->common
.rdtype
== 41);
352 REQUIRE(opt
->options
!= NULL
&& opt
->length
!= 0);
353 REQUIRE(opt
->offset
< opt
->length
);
355 INSIST(opt
->offset
+ 4 <= opt
->length
);
356 r
.base
= opt
->options
+ opt
->offset
+ 2;
357 r
.length
= opt
->length
- opt
->offset
- 2;
358 length
= uint16_fromregion(&r
);
359 INSIST(opt
->offset
+ 4 + length
<= opt
->length
);
360 opt
->offset
= opt
->offset
+ 4 + length
;
361 if (opt
->offset
== opt
->length
)
362 return (ISC_R_NOMORE
);
363 return (ISC_R_SUCCESS
);
367 dns_rdata_opt_current(dns_rdata_opt_t
*opt
, dns_rdata_opt_opcode_t
*opcode
) {
370 REQUIRE(opt
!= NULL
);
371 REQUIRE(opcode
!= NULL
);
372 REQUIRE(opt
->common
.rdtype
== 41);
373 REQUIRE(opt
->options
!= NULL
);
374 REQUIRE(opt
->offset
< opt
->length
);
376 INSIST(opt
->offset
+ 4 <= opt
->length
);
377 r
.base
= opt
->options
+ opt
->offset
;
378 r
.length
= opt
->length
- opt
->offset
;
380 opcode
->opcode
= uint16_fromregion(&r
);
381 isc_region_consume(&r
, 2);
382 opcode
->length
= uint16_fromregion(&r
);
383 isc_region_consume(&r
, 2);
384 opcode
->data
= r
.base
;
385 INSIST(opt
->offset
+ 4 + opcode
->length
<= opt
->length
);
387 return (ISC_R_SUCCESS
);
390 #endif /* RDATA_GENERIC_OPT_41_C */