a6_38.c 9.5 KB
Newer Older
Mark Andrews's avatar
Mark Andrews committed
1
/*
Brian Wellington's avatar
Brian Wellington committed
2
 * Copyright (C) 1999-2001  Internet Software Consortium.
3
 *
Mark Andrews's avatar
Mark Andrews committed
4 5 6
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
7
 *
8 9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Mark Andrews's avatar
Mark Andrews committed
16 17
 */

18
/* $Id: a6_38.c,v 1.42 2001/02/12 03:04:59 bwelling Exp $ */
Mark Andrews's avatar
Mark Andrews committed
19

20
/* draft-ietf-ipngwg-dns-lookups-03.txt */
Mark Andrews's avatar
Mark Andrews committed
21

22 23
#ifndef RDATA_IN_1_A6_28_C
#define RDATA_IN_1_A6_28_C
Mark Andrews's avatar
Mark Andrews committed
24

25
#include <isc/net.h>
Mark Andrews's avatar
Mark Andrews committed
26

27 28
#define RRTYPE_A6_ATTRIBUTES (0)

29
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
30
fromtext_in_a6(ARGS_FROMTEXT) {
Mark Andrews's avatar
Mark Andrews committed
31 32 33 34 35 36 37 38 39
	isc_token_t token;
	unsigned char addr[16];
	unsigned char prefixlen;
	unsigned char octets;
	unsigned char mask;
	dns_name_t name;
	isc_buffer_t buffer;

	REQUIRE(type == 38);
40
	REQUIRE(rdclass == 1);
Mark Andrews's avatar
Mark Andrews committed
41

42 43
	UNUSED(rdclass);

David Lawrence's avatar
David Lawrence committed
44 45 46
	/*
	 * Prefix length.
	 */
47 48
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
				      ISC_FALSE));
Mark Andrews's avatar
Mark Andrews committed
49
	if (token.value.as_ulong > 128)
David Lawrence's avatar
David Lawrence committed
50
		return (ISC_R_RANGE);
Mark Andrews's avatar
Mark Andrews committed
51

52
	prefixlen = (unsigned char)token.value.as_ulong;
Mark Andrews's avatar
Mark Andrews committed
53 54
	RETERR(mem_tobuffer(target, &prefixlen, 1));

David Lawrence's avatar
David Lawrence committed
55 56 57
	/*
	 * Suffix.
	 */
Mark Andrews's avatar
Mark Andrews committed
58
	if (prefixlen != 128) {
David Lawrence's avatar
David Lawrence committed
59 60 61
		/*
		 * Prefix 0..127.
		 */
Mark Andrews's avatar
Mark Andrews committed
62
		octets = prefixlen/8;
David Lawrence's avatar
David Lawrence committed
63 64 65
		/*
		 * Octets 0..15.
		 */
66 67 68
		RETERR(isc_lex_getmastertoken(lexer, &token,
					      isc_tokentype_string,
					      ISC_FALSE));
69
		if (inet_pton(AF_INET6, token.value.as_pointer, addr) != 1)
70
			return (DNS_R_BADAAAA);
Mark Andrews's avatar
Mark Andrews committed
71 72 73 74 75 76
		mask = 0xff >> (prefixlen % 8);
		addr[octets] &= mask;
		RETERR(mem_tobuffer(target, &addr[octets], 16 - octets));
	}

	if (prefixlen == 0)
77
		return (ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
78

79 80
	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
				      ISC_FALSE));
Mark Andrews's avatar
Mark Andrews committed
81
	dns_name_init(&name, NULL);
82
	buffer_fromregion(&buffer, &token.value.as_region);
Mark Andrews's avatar
Mark Andrews committed
83 84 85 86
	origin = (origin != NULL) ? origin : dns_rootname;
	return (dns_name_fromtext(&name, &buffer, origin, downcase, target));
}

87
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
88
totext_in_a6(ARGS_TOTEXT) {
89
	isc_region_t sr, ar;
Mark Andrews's avatar
Mark Andrews committed
90 91 92 93 94 95 96 97 98 99
	unsigned char addr[16];
	unsigned char prefixlen;
	unsigned char octets;
	unsigned char mask;
	char buf[sizeof "128"];
	dns_name_t name;
	dns_name_t prefix;
	isc_boolean_t sub;

	REQUIRE(rdata->type == 38);
100
	REQUIRE(rdata->rdclass == 1);
101
	REQUIRE(rdata->length != 0);
Mark Andrews's avatar
Mark Andrews committed
102 103 104 105 106 107 108 109 110 111 112

	dns_rdata_toregion(rdata, &sr);
	prefixlen = sr.base[0];
	INSIST(prefixlen <= 128);
	isc_region_consume(&sr, 1);
	sprintf(buf, "%u", prefixlen);
	RETERR(str_totext(buf, target));
	RETERR(str_totext(" ", target));

	if (prefixlen != 128) {
		octets = prefixlen/8;
Bob Halley's avatar
lint  
Bob Halley committed
113
		memset(addr, 0, sizeof addr);
Mark Andrews's avatar
Mark Andrews committed
114 115 116
		memcpy(&addr[octets], sr.base, 16 - octets);
		mask = 0xff >> (prefixlen % 8);
		addr[octets] &= mask;
117 118 119
		ar.base = addr;
		ar.length = sizeof(addr);
		RETERR(inet_totext(AF_INET6, &ar, target));
Mark Andrews's avatar
Mark Andrews committed
120 121 122 123
		isc_region_consume(&sr, 16 - octets);
	}

	if (prefixlen == 0)
124
		return (ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
125 126 127 128 129

	RETERR(str_totext(" ", target));
	dns_name_init(&name, NULL);
	dns_name_init(&prefix, NULL);
	dns_name_fromregion(&name, &sr);
130
	sub = name_prefix(&name, tctx->origin, &prefix);
James Brister's avatar
James Brister committed
131
	return (dns_name_totext(&prefix, sub, target));
Mark Andrews's avatar
Mark Andrews committed
132 133
}

134
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
135
fromwire_in_a6(ARGS_FROMWIRE) {
Mark Andrews's avatar
Mark Andrews committed
136 137 138 139 140 141 142
	isc_region_t sr;
	unsigned char prefixlen;
	unsigned char octets;
	unsigned char mask;
	dns_name_t name;

	REQUIRE(type == 38);
143
	REQUIRE(rdclass == 1);
Mark Andrews's avatar
Mark Andrews committed
144

145 146
	UNUSED(rdclass);

147
	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
Mark Andrews's avatar
Mark Andrews committed
148

149
	isc_buffer_activeregion(source, &sr);
David Lawrence's avatar
David Lawrence committed
150 151 152
	/*
	 * Prefix length.
	 */
Mark Andrews's avatar
Mark Andrews committed
153
	if (sr.length < 1)
154
		return (ISC_R_UNEXPECTEDEND);
Mark Andrews's avatar
Mark Andrews committed
155 156
	prefixlen = sr.base[0];
	if (prefixlen > 128)
David Lawrence's avatar
David Lawrence committed
157
		return (ISC_R_RANGE);
Mark Andrews's avatar
Mark Andrews committed
158 159 160 161
	isc_region_consume(&sr, 1);
	RETERR(mem_tobuffer(target, &prefixlen, 1));
	isc_buffer_forward(source, 1);

David Lawrence's avatar
David Lawrence committed
162 163 164
	/*
	 * Suffix.
	 */
Mark Andrews's avatar
Mark Andrews committed
165 166 167
	if (prefixlen != 128) {
		octets = 16 - prefixlen / 8;
		if (sr.length < octets)
168
			return (ISC_R_UNEXPECTEDEND);
Mark Andrews's avatar
Mark Andrews committed
169
		mask = 0xff >> (prefixlen % 8);
David Lawrence's avatar
David Lawrence committed
170
		sr.base[0] &= mask;	/* Ensure pad bits are zero. */
Mark Andrews's avatar
Mark Andrews committed
171 172 173 174 175
		RETERR(mem_tobuffer(target, sr.base, octets));
		isc_buffer_forward(source, octets);
	}

	if (prefixlen == 0)
176
		return (ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
177 178 179 180 181

	dns_name_init(&name, NULL);
	return (dns_name_fromwire(&name, source, dctx, downcase, target));
}

182
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
183
towire_in_a6(ARGS_TOWIRE) {
Mark Andrews's avatar
Mark Andrews committed
184 185
	isc_region_t sr;
	dns_name_t name;
186
	dns_offsets_t offsets;
Mark Andrews's avatar
Mark Andrews committed
187 188 189 190
	unsigned char prefixlen;
	unsigned char octets;

	REQUIRE(rdata->type == 38);
191
	REQUIRE(rdata->rdclass == 1);
192
	REQUIRE(rdata->length != 0);
Mark Andrews's avatar
Mark Andrews committed
193

194
	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
Mark Andrews's avatar
Mark Andrews committed
195 196 197 198 199 200 201 202 203
	dns_rdata_toregion(rdata, &sr);
	prefixlen = sr.base[0];
	INSIST(prefixlen <= 128);

	octets = 1 + 16 - prefixlen / 8;
	RETERR(mem_tobuffer(target, sr.base, octets));
	isc_region_consume(&sr, octets);

	if (prefixlen == 0)
204
		return (ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
205

206
	dns_name_init(&name, offsets);
Mark Andrews's avatar
Mark Andrews committed
207 208 209 210
	dns_name_fromregion(&name, &sr);
	return (dns_name_towire(&name, cctx, target));
}

211
static inline int
David Lawrence's avatar
David Lawrence committed
212
compare_in_a6(ARGS_COMPARE) {
213
	int order;
214
	unsigned char prefixlen1, prefixlen2;
Mark Andrews's avatar
Mark Andrews committed
215 216 217 218 219
	unsigned char octets;
	dns_name_t name1;
	dns_name_t name2;
	isc_region_t region1;
	isc_region_t region2;
220

Mark Andrews's avatar
Mark Andrews committed
221
	REQUIRE(rdata1->type == rdata2->type);
222
	REQUIRE(rdata1->rdclass == rdata2->rdclass);
Mark Andrews's avatar
Mark Andrews committed
223
	REQUIRE(rdata1->type == 38);
224
	REQUIRE(rdata1->rdclass == 1);
225 226
	REQUIRE(rdata1->length != 0);
	REQUIRE(rdata2->length != 0);
Mark Andrews's avatar
Mark Andrews committed
227 228 229

	dns_rdata_toregion(rdata1, &region1);
	dns_rdata_toregion(rdata2, &region2);
230 231 232 233 234 235 236 237 238 239 240 241 242 243
	prefixlen1 = region1.base[0];
	prefixlen2 = region2.base[0];
	isc_region_consume(&region1, 1);
	isc_region_consume(&region2, 1);
	if (prefixlen1 < prefixlen2)
		return (-1);
	else if (prefixlen1 > prefixlen2)
		return (1);
	/*
	 * Prefix lengths are equal.
	 */
	octets = 16 - prefixlen1 / 8;

	if (octets > 0) {
244 245
		order = memcmp(region1.base, region2.base, octets);
		if (order < 0)
246
			return (-1);
247
		else if (order > 0)
248 249 250 251 252
			return (1);
		/*
		 * Address suffixes are equal.
		 */
		if (prefixlen1 == 0)
253
			return (order);
254 255 256
		isc_region_consume(&region1, octets);
		isc_region_consume(&region2, octets);
	}
Mark Andrews's avatar
Mark Andrews committed
257 258 259 260 261

	dns_name_init(&name1, NULL);
	dns_name_init(&name2, NULL);
	dns_name_fromregion(&name1, &region1);
	dns_name_fromregion(&name2, &region2);
262
	return (dns_name_rdatacompare(&name1, &name2));
Mark Andrews's avatar
Mark Andrews committed
263 264
}

265
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
266
fromstruct_in_a6(ARGS_FROMSTRUCT) {
267
	dns_rdata_in_a6_t *a6 = source;
268 269 270 271 272
	isc_region_t region;
	int octets;
	isc_uint8_t bits;
	isc_uint8_t first;
	isc_uint8_t mask;
Mark Andrews's avatar
Mark Andrews committed
273

274
	REQUIRE(type == 38);
275
	REQUIRE(rdclass == 1);
276 277 278
	REQUIRE(source != NULL);
	REQUIRE(a6->common.rdtype == type);
	REQUIRE(a6->common.rdclass == rdclass);
Mark Andrews's avatar
Mark Andrews committed
279

280 281
	UNUSED(rdclass);

282
	if (a6->prefixlen > 128)
David Lawrence's avatar
David Lawrence committed
283
		return (ISC_R_RANGE);
284

285
	RETERR(uint8_tobuffer(a6->prefixlen, target));
286

287
	/* Suffix */
288
	if (a6->prefixlen != 128) {
289 290 291 292 293 294 295 296 297 298 299 300
		octets = 16 - a6->prefixlen / 8;
		bits = a6->prefixlen % 8;
		if (bits != 0) {
			mask = 0xffU >> bits;
			first = a6->in6_addr.s6_addr[16 - octets] & mask;
			RETERR(uint8_tobuffer(first, target));
			octets--;
		}
		if (octets > 0)
			RETERR(mem_tobuffer(target,
					    a6->in6_addr.s6_addr + 16 - octets,
					    octets));
301 302
	}

303 304 305 306
	if (a6->prefixlen == 0)
		return (ISC_R_SUCCESS);
	dns_name_toregion(&a6->prefix, &region);
	return (isc_buffer_copyregion(target, &region));
Mark Andrews's avatar
Mark Andrews committed
307 308
}

309
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
310
tostruct_in_a6(ARGS_TOSTRUCT) {
311 312 313 314
	dns_rdata_in_a6_t *a6 = target;
	unsigned char octets;
	dns_name_t name;
	isc_region_t r;
Mark Andrews's avatar
Mark Andrews committed
315 316

	REQUIRE(rdata->type == 38);
317
	REQUIRE(rdata->rdclass == 1);
318
	REQUIRE(target != NULL);
319
	REQUIRE(rdata->length != 0);
Mark Andrews's avatar
Mark Andrews committed
320

321 322 323
	a6->common.rdclass = rdata->rdclass;
	a6->common.rdtype = rdata->type;
	ISC_LINK_INIT(&a6->common, link);
Mark Andrews's avatar
Mark Andrews committed
324

325 326 327 328 329 330
	dns_rdata_toregion(rdata, &r);

	a6->prefixlen = uint8_fromregion(&r);
	isc_region_consume(&r, 1);
	memset(a6->in6_addr.s6_addr, 0, sizeof(a6->in6_addr.s6_addr));

David Lawrence's avatar
David Lawrence committed
331 332 333
	/*
	 * Suffix.
	 */
334 335 336 337 338 339 340
	if (a6->prefixlen != 128) {
		octets = 16 - a6->prefixlen / 8;
		INSIST(r.length >= octets);
		memcpy(a6->in6_addr.s6_addr + 16 - octets, r.base, octets);
		isc_region_consume(&r, octets);
	}

David Lawrence's avatar
David Lawrence committed
341 342 343
	/*
	 * Prefix.
	 */
344 345 346 347 348 349 350 351
	dns_name_init(&a6->prefix, NULL);
	if (a6->prefixlen != 0) {
		dns_name_init(&name, NULL);
		dns_name_fromregion(&name, &r);
		RETERR(name_duporclone(&name, mctx, &a6->prefix));
	}
	a6->mctx = mctx;
	return (ISC_R_SUCCESS);
Mark Andrews's avatar
Mark Andrews committed
352
}
353

354
static inline void
David Lawrence's avatar
David Lawrence committed
355
freestruct_in_a6(ARGS_FREESTRUCT) {
356 357
	dns_rdata_in_a6_t *a6 = source;

358
	REQUIRE(source != NULL);
359 360 361 362 363
	REQUIRE(a6->common.rdclass == 1);
	REQUIRE(a6->common.rdtype == 38);

	if (a6->mctx == NULL)
		return;
364

365 366 367
	if (dns_name_dynamic(&a6->prefix))
		dns_name_free(&a6->prefix, a6->mctx);
	a6->mctx = NULL;
368
}
369

370
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
371
additionaldata_in_a6(ARGS_ADDLDATA) {
372 373 374
	REQUIRE(rdata->type == 38);
	REQUIRE(rdata->rdclass == 1);

375 376 377
	UNUSED(rdata);
	UNUSED(add);
	UNUSED(arg);
378

379
	return (ISC_R_SUCCESS);
380 381
}

382
static inline isc_result_t
David Lawrence's avatar
David Lawrence committed
383
digest_in_a6(ARGS_DIGEST) {
384 385
	isc_region_t r1, r2;
	unsigned char prefixlen, octets;
386
	isc_result_t result;
387 388 389 390 391 392 393 394 395 396 397 398
	dns_name_t name;

	REQUIRE(rdata->type == 38);
	REQUIRE(rdata->rdclass == 1);

	dns_rdata_toregion(rdata, &r1);
	r2 = r1;
	prefixlen = r1.base[0];
	octets = 1 + 16 - prefixlen / 8;

	r1.length = octets;
	result = (digest)(arg, &r1);
399
	if (result != ISC_R_SUCCESS)
400 401
		return (result);
	if (prefixlen == 0)
402
		return (ISC_R_SUCCESS);
403 404 405 406 407 408 409

	isc_region_consume(&r2, octets);
	dns_name_init(&name, NULL);
	dns_name_fromregion(&name, &r2);
	return (dns_name_digest(&name, digest, arg));
}

410
#endif	/* RDATA_IN_1_A6_38_C */