Merge from vendor branch SENDMAIL:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / rdata / in_1 / a6_38.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: a6_38.c,v 1.46.2.3 2004/03/09 06:11:35 marka Exp $ */
19
20 /* RFC2874 */
21
22 #ifndef RDATA_IN_1_A6_28_C
23 #define RDATA_IN_1_A6_28_C
24
25 #include <isc/net.h>
26
27 #define RRTYPE_A6_ATTRIBUTES (0)
28
29 static inline isc_result_t
30 fromtext_in_a6(ARGS_FROMTEXT) {
31         isc_token_t token;
32         unsigned char addr[16];
33         unsigned char prefixlen;
34         unsigned char octets;
35         unsigned char mask;
36         dns_name_t name;
37         isc_buffer_t buffer;
38
39         REQUIRE(type == 38);
40         REQUIRE(rdclass == 1);
41
42         UNUSED(type);
43         UNUSED(rdclass);
44         UNUSED(callbacks);
45
46         /*
47          * Prefix length.
48          */
49         RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
50                                       ISC_FALSE));
51         if (token.value.as_ulong > 128U)
52                 RETTOK(ISC_R_RANGE);
53
54         prefixlen = (unsigned char)token.value.as_ulong;
55         RETERR(mem_tobuffer(target, &prefixlen, 1));
56
57         /*
58          * Suffix.
59          */
60         if (prefixlen != 128) {
61                 /*
62                  * Prefix 0..127.
63                  */
64                 octets = prefixlen/8;
65                 /*
66                  * Octets 0..15.
67                  */
68                 RETERR(isc_lex_getmastertoken(lexer, &token,
69                                               isc_tokentype_string,
70                                               ISC_FALSE));
71                 if (inet_pton(AF_INET6, token.value.as_pointer, addr) != 1)
72                         RETTOK(DNS_R_BADAAAA);
73                 mask = 0xff >> (prefixlen % 8);
74                 addr[octets] &= mask;
75                 RETERR(mem_tobuffer(target, &addr[octets], 16 - octets));
76         }
77
78         if (prefixlen == 0)
79                 return (ISC_R_SUCCESS);
80
81         RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
82                                       ISC_FALSE));
83         dns_name_init(&name, NULL);
84         buffer_fromregion(&buffer, &token.value.as_region);
85         origin = (origin != NULL) ? origin : dns_rootname;
86         RETTOK(dns_name_fromtext(&name, &buffer, origin, downcase, target));
87         return (ISC_R_SUCCESS);
88 }
89
90 static inline isc_result_t
91 totext_in_a6(ARGS_TOTEXT) {
92         isc_region_t sr, ar;
93         unsigned char addr[16];
94         unsigned char prefixlen;
95         unsigned char octets;
96         unsigned char mask;
97         char buf[sizeof "128"];
98         dns_name_t name;
99         dns_name_t prefix;
100         isc_boolean_t sub;
101
102         REQUIRE(rdata->type == 38);
103         REQUIRE(rdata->rdclass == 1);
104         REQUIRE(rdata->length != 0);
105
106         dns_rdata_toregion(rdata, &sr);
107         prefixlen = sr.base[0];
108         INSIST(prefixlen <= 128);
109         isc_region_consume(&sr, 1);
110         sprintf(buf, "%u", prefixlen);
111         RETERR(str_totext(buf, target));
112         RETERR(str_totext(" ", target));
113
114         if (prefixlen != 128) {
115                 octets = prefixlen/8;
116                 memset(addr, 0, sizeof addr);
117                 memcpy(&addr[octets], sr.base, 16 - octets);
118                 mask = 0xff >> (prefixlen % 8);
119                 addr[octets] &= mask;
120                 ar.base = addr;
121                 ar.length = sizeof(addr);
122                 RETERR(inet_totext(AF_INET6, &ar, target));
123                 isc_region_consume(&sr, 16 - octets);
124         }
125
126         if (prefixlen == 0)
127                 return (ISC_R_SUCCESS);
128
129         RETERR(str_totext(" ", target));
130         dns_name_init(&name, NULL);
131         dns_name_init(&prefix, NULL);
132         dns_name_fromregion(&name, &sr);
133         sub = name_prefix(&name, tctx->origin, &prefix);
134         return (dns_name_totext(&prefix, sub, target));
135 }
136
137 static inline isc_result_t
138 fromwire_in_a6(ARGS_FROMWIRE) {
139         isc_region_t sr;
140         unsigned char prefixlen;
141         unsigned char octets;
142         unsigned char mask;
143         dns_name_t name;
144
145         REQUIRE(type == 38);
146         REQUIRE(rdclass == 1);
147
148         UNUSED(type);
149         UNUSED(rdclass);
150
151         dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
152
153         isc_buffer_activeregion(source, &sr);
154         /*
155          * Prefix length.
156          */
157         if (sr.length < 1)
158                 return (ISC_R_UNEXPECTEDEND);
159         prefixlen = sr.base[0];
160         if (prefixlen > 128)
161                 return (ISC_R_RANGE);
162         isc_region_consume(&sr, 1);
163         RETERR(mem_tobuffer(target, &prefixlen, 1));
164         isc_buffer_forward(source, 1);
165
166         /*
167          * Suffix.
168          */
169         if (prefixlen != 128) {
170                 octets = 16 - prefixlen / 8;
171                 if (sr.length < octets)
172                         return (ISC_R_UNEXPECTEDEND);
173                 mask = 0xff >> (prefixlen % 8);
174                 sr.base[0] &= mask;     /* Ensure pad bits are zero. */
175                 RETERR(mem_tobuffer(target, sr.base, octets));
176                 isc_buffer_forward(source, octets);
177         }
178
179         if (prefixlen == 0)
180                 return (ISC_R_SUCCESS);
181
182         dns_name_init(&name, NULL);
183         return (dns_name_fromwire(&name, source, dctx, downcase, target));
184 }
185
186 static inline isc_result_t
187 towire_in_a6(ARGS_TOWIRE) {
188         isc_region_t sr;
189         dns_name_t name;
190         dns_offsets_t offsets;
191         unsigned char prefixlen;
192         unsigned char octets;
193
194         REQUIRE(rdata->type == 38);
195         REQUIRE(rdata->rdclass == 1);
196         REQUIRE(rdata->length != 0);
197
198         dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
199         dns_rdata_toregion(rdata, &sr);
200         prefixlen = sr.base[0];
201         INSIST(prefixlen <= 128);
202
203         octets = 1 + 16 - prefixlen / 8;
204         RETERR(mem_tobuffer(target, sr.base, octets));
205         isc_region_consume(&sr, octets);
206
207         if (prefixlen == 0)
208                 return (ISC_R_SUCCESS);
209
210         dns_name_init(&name, offsets);
211         dns_name_fromregion(&name, &sr);
212         return (dns_name_towire(&name, cctx, target));
213 }
214
215 static inline int
216 compare_in_a6(ARGS_COMPARE) {
217         int order;
218         unsigned char prefixlen1, prefixlen2;
219         unsigned char octets;
220         dns_name_t name1;
221         dns_name_t name2;
222         isc_region_t region1;
223         isc_region_t region2;
224
225         REQUIRE(rdata1->type == rdata2->type);
226         REQUIRE(rdata1->rdclass == rdata2->rdclass);
227         REQUIRE(rdata1->type == 38);
228         REQUIRE(rdata1->rdclass == 1);
229         REQUIRE(rdata1->length != 0);
230         REQUIRE(rdata2->length != 0);
231
232         dns_rdata_toregion(rdata1, &region1);
233         dns_rdata_toregion(rdata2, &region2);
234         prefixlen1 = region1.base[0];
235         prefixlen2 = region2.base[0];
236         isc_region_consume(&region1, 1);
237         isc_region_consume(&region2, 1);
238         if (prefixlen1 < prefixlen2)
239                 return (-1);
240         else if (prefixlen1 > prefixlen2)
241                 return (1);
242         /*
243          * Prefix lengths are equal.
244          */
245         octets = 16 - prefixlen1 / 8;
246
247         if (octets > 0) {
248                 order = memcmp(region1.base, region2.base, octets);
249                 if (order < 0)
250                         return (-1);
251                 else if (order > 0)
252                         return (1);
253                 /*
254                  * Address suffixes are equal.
255                  */
256                 if (prefixlen1 == 0)
257                         return (order);
258                 isc_region_consume(&region1, octets);
259                 isc_region_consume(&region2, octets);
260         }
261
262         dns_name_init(&name1, NULL);
263         dns_name_init(&name2, NULL);
264         dns_name_fromregion(&name1, &region1);
265         dns_name_fromregion(&name2, &region2);
266         return (dns_name_rdatacompare(&name1, &name2));
267 }
268
269 static inline isc_result_t
270 fromstruct_in_a6(ARGS_FROMSTRUCT) {
271         dns_rdata_in_a6_t *a6 = source;
272         isc_region_t region;
273         int octets;
274         isc_uint8_t bits;
275         isc_uint8_t first;
276         isc_uint8_t mask;
277
278         REQUIRE(type == 38);
279         REQUIRE(rdclass == 1);
280         REQUIRE(source != NULL);
281         REQUIRE(a6->common.rdtype == type);
282         REQUIRE(a6->common.rdclass == rdclass);
283
284         UNUSED(type);
285         UNUSED(rdclass);
286
287         if (a6->prefixlen > 128)
288                 return (ISC_R_RANGE);
289
290         RETERR(uint8_tobuffer(a6->prefixlen, target));
291
292         /* Suffix */
293         if (a6->prefixlen != 128) {
294                 octets = 16 - a6->prefixlen / 8;
295                 bits = a6->prefixlen % 8;
296                 if (bits != 0) {
297                         mask = 0xffU >> bits;
298                         first = a6->in6_addr.s6_addr[16 - octets] & mask;
299                         RETERR(uint8_tobuffer(first, target));
300                         octets--;
301                 }
302                 if (octets > 0)
303                         RETERR(mem_tobuffer(target,
304                                             a6->in6_addr.s6_addr + 16 - octets,
305                                             octets));
306         }
307
308         if (a6->prefixlen == 0)
309                 return (ISC_R_SUCCESS);
310         dns_name_toregion(&a6->prefix, &region);
311         return (isc_buffer_copyregion(target, &region));
312 }
313
314 static inline isc_result_t
315 tostruct_in_a6(ARGS_TOSTRUCT) {
316         dns_rdata_in_a6_t *a6 = target;
317         unsigned char octets;
318         dns_name_t name;
319         isc_region_t r;
320
321         REQUIRE(rdata->type == 38);
322         REQUIRE(rdata->rdclass == 1);
323         REQUIRE(target != NULL);
324         REQUIRE(rdata->length != 0);
325
326         a6->common.rdclass = rdata->rdclass;
327         a6->common.rdtype = rdata->type;
328         ISC_LINK_INIT(&a6->common, link);
329
330         dns_rdata_toregion(rdata, &r);
331
332         a6->prefixlen = uint8_fromregion(&r);
333         isc_region_consume(&r, 1);
334         memset(a6->in6_addr.s6_addr, 0, sizeof(a6->in6_addr.s6_addr));
335
336         /*
337          * Suffix.
338          */
339         if (a6->prefixlen != 128) {
340                 octets = 16 - a6->prefixlen / 8;
341                 INSIST(r.length >= octets);
342                 memcpy(a6->in6_addr.s6_addr + 16 - octets, r.base, octets);
343                 isc_region_consume(&r, octets);
344         }
345
346         /*
347          * Prefix.
348          */
349         dns_name_init(&a6->prefix, NULL);
350         if (a6->prefixlen != 0) {
351                 dns_name_init(&name, NULL);
352                 dns_name_fromregion(&name, &r);
353                 RETERR(name_duporclone(&name, mctx, &a6->prefix));
354         }
355         a6->mctx = mctx;
356         return (ISC_R_SUCCESS);
357 }
358
359 static inline void
360 freestruct_in_a6(ARGS_FREESTRUCT) {
361         dns_rdata_in_a6_t *a6 = source;
362
363         REQUIRE(source != NULL);
364         REQUIRE(a6->common.rdclass == 1);
365         REQUIRE(a6->common.rdtype == 38);
366
367         if (a6->mctx == NULL)
368                 return;
369
370         if (dns_name_dynamic(&a6->prefix))
371                 dns_name_free(&a6->prefix, a6->mctx);
372         a6->mctx = NULL;
373 }
374
375 static inline isc_result_t
376 additionaldata_in_a6(ARGS_ADDLDATA) {
377         REQUIRE(rdata->type == 38);
378         REQUIRE(rdata->rdclass == 1);
379
380         UNUSED(rdata);
381         UNUSED(add);
382         UNUSED(arg);
383
384         return (ISC_R_SUCCESS);
385 }
386
387 static inline isc_result_t
388 digest_in_a6(ARGS_DIGEST) {
389         isc_region_t r1, r2;
390         unsigned char prefixlen, octets;
391         isc_result_t result;
392         dns_name_t name;
393
394         REQUIRE(rdata->type == 38);
395         REQUIRE(rdata->rdclass == 1);
396
397         dns_rdata_toregion(rdata, &r1);
398         r2 = r1;
399         prefixlen = r1.base[0];
400         octets = 1 + 16 - prefixlen / 8;
401
402         r1.length = octets;
403         result = (digest)(arg, &r1);
404         if (result != ISC_R_SUCCESS)
405                 return (result);
406         if (prefixlen == 0)
407                 return (ISC_R_SUCCESS);
408
409         isc_region_consume(&r2, octets);
410         dns_name_init(&name, NULL);
411         dns_name_fromregion(&name, &r2);
412         return (dns_name_digest(&name, digest, arg));
413 }
414
415 #endif  /* RDATA_IN_1_A6_38_C */