1/*
2 * Copyright (C) 2005, 2007, 2009, 2011, 2012  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/* $Id$ */
18
19#ifndef RDATA_GENERIC_IPSECKEY_45_C
20#define RDATA_GENERIC_IPSECKEY_45_C
21
22#include <string.h>
23
24#include <isc/net.h>
25
26#define RRTYPE_IPSECKEY_ATTRIBUTES (0)
27
28static inline isc_result_t
29fromtext_ipseckey(ARGS_FROMTEXT) {
30	isc_token_t token;
31	dns_name_t name;
32	isc_buffer_t buffer;
33	unsigned int gateway;
34	struct in_addr addr;
35	unsigned char addr6[16];
36	isc_region_t region;
37
38	REQUIRE(type == 45);
39
40	UNUSED(type);
41	UNUSED(rdclass);
42	UNUSED(callbacks);
43
44	/*
45	 * Precedence.
46	 */
47	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
48				      ISC_FALSE));
49	if (token.value.as_ulong > 0xffU)
50		RETTOK(ISC_R_RANGE);
51	RETERR(uint8_tobuffer(token.value.as_ulong, target));
52
53	/*
54	 * Gateway type.
55	 */
56	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
57				      ISC_FALSE));
58	if (token.value.as_ulong > 0x3U)
59		RETTOK(ISC_R_RANGE);
60	RETERR(uint8_tobuffer(token.value.as_ulong, target));
61	gateway = token.value.as_ulong;
62
63	/*
64	 * Algorithm.
65	 */
66	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
67				      ISC_FALSE));
68	if (token.value.as_ulong > 0xffU)
69		RETTOK(ISC_R_RANGE);
70	RETERR(uint8_tobuffer(token.value.as_ulong, target));
71
72	/*
73	 * Gateway.
74	 */
75	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
76				      ISC_FALSE));
77
78	switch (gateway) {
79	case 0:
80		if (strcmp(DNS_AS_STR(token), ".") != 0)
81			RETTOK(DNS_R_SYNTAX);
82		break;
83
84	case 1:
85		if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
86			RETTOK(DNS_R_BADDOTTEDQUAD);
87		isc_buffer_availableregion(target, &region);
88		if (region.length < 4)
89			return (ISC_R_NOSPACE);
90		memcpy(region.base, &addr, 4);
91		isc_buffer_add(target, 4);
92		break;
93
94	case 2:
95		if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1)
96			RETTOK(DNS_R_BADAAAA);
97		isc_buffer_availableregion(target, &region);
98		if (region.length < 16)
99			return (ISC_R_NOSPACE);
100		memcpy(region.base, addr6, 16);
101		isc_buffer_add(target, 16);
102		break;
103
104	case 3:
105		dns_name_init(&name, NULL);
106		buffer_fromregion(&buffer, &token.value.as_region);
107		origin = (origin != NULL) ? origin : dns_rootname;
108		RETTOK(dns_name_fromtext(&name, &buffer, origin,
109					 options, target));
110		break;
111	}
112
113	/*
114	 * Public key.
115	 */
116	return (isc_base64_tobuffer(lexer, target, -1));
117}
118
119static inline isc_result_t
120totext_ipseckey(ARGS_TOTEXT) {
121	isc_region_t region;
122	dns_name_t name;
123	char buf[sizeof("255 ")];
124	unsigned short num;
125	unsigned short gateway;
126
127	REQUIRE(rdata->type == 45);
128	REQUIRE(rdata->length >= 3);
129
130	dns_name_init(&name, NULL);
131
132	if (rdata->data[1] > 3U)
133		return (ISC_R_NOTIMPLEMENTED);
134
135	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
136		RETERR(str_totext("( ", target));
137
138	/*
139	 * Precedence.
140	 */
141	dns_rdata_toregion(rdata, &region);
142	num = uint8_fromregion(&region);
143	isc_region_consume(&region, 1);
144	sprintf(buf, "%u ", num);
145	RETERR(str_totext(buf, target));
146
147	/*
148	 * Gateway type.
149	 */
150	gateway = uint8_fromregion(&region);
151	isc_region_consume(&region, 1);
152	sprintf(buf, "%u ", gateway);
153	RETERR(str_totext(buf, target));
154
155	/*
156	 * Algorithm.
157	 */
158	num = uint8_fromregion(&region);
159	isc_region_consume(&region, 1);
160	sprintf(buf, "%u ", num);
161	RETERR(str_totext(buf, target));
162
163	/*
164	 * Gateway.
165	 */
166	switch (gateway) {
167	case 0:
168		RETERR(str_totext(".", target));
169		break;
170
171	case 1:
172		RETERR(inet_totext(AF_INET, &region, target));
173		isc_region_consume(&region, 4);
174		break;
175
176	case 2:
177		RETERR(inet_totext(AF_INET6, &region, target));
178		isc_region_consume(&region, 16);
179		break;
180
181	case 3:
182		dns_name_fromregion(&name, &region);
183		RETERR(dns_name_totext(&name, ISC_FALSE, target));
184		isc_region_consume(&region, name_length(&name));
185		break;
186	}
187
188	/*
189	 * Key.
190	 */
191	if (region.length > 0U) {
192		RETERR(str_totext(tctx->linebreak, target));
193		RETERR(isc_base64_totext(&region, tctx->width - 2,
194					 tctx->linebreak, target));
195	}
196
197	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
198		RETERR(str_totext(" )", target));
199	return (ISC_R_SUCCESS);
200}
201
202static inline isc_result_t
203fromwire_ipseckey(ARGS_FROMWIRE) {
204	dns_name_t name;
205	isc_region_t region;
206
207	REQUIRE(type == 45);
208
209	UNUSED(type);
210	UNUSED(rdclass);
211
212	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
213
214	dns_name_init(&name, NULL);
215
216	isc_buffer_activeregion(source, &region);
217	if (region.length < 3)
218		return (ISC_R_UNEXPECTEDEND);
219
220	switch (region.base[1]) {
221	case 0:
222		isc_buffer_forward(source, region.length);
223		return (mem_tobuffer(target, region.base, region.length));
224
225	case 1:
226		if (region.length < 7)
227			return (ISC_R_UNEXPECTEDEND);
228		isc_buffer_forward(source, region.length);
229		return (mem_tobuffer(target, region.base, region.length));
230
231	case 2:
232		if (region.length < 19)
233			return (ISC_R_UNEXPECTEDEND);
234		isc_buffer_forward(source, region.length);
235		return (mem_tobuffer(target, region.base, region.length));
236
237	case 3:
238		RETERR(mem_tobuffer(target, region.base, 3));
239		isc_buffer_forward(source, 3);
240		RETERR(dns_name_fromwire(&name, source, dctx, options, target));
241		isc_buffer_activeregion(source, &region);
242		isc_buffer_forward(source, region.length);
243		return(mem_tobuffer(target, region.base, region.length));
244
245	default:
246		return (ISC_R_NOTIMPLEMENTED);
247	}
248}
249
250static inline isc_result_t
251towire_ipseckey(ARGS_TOWIRE) {
252	isc_region_t region;
253
254	REQUIRE(rdata->type == 45);
255	REQUIRE(rdata->length != 0);
256
257	UNUSED(cctx);
258
259	dns_rdata_toregion(rdata, &region);
260	return (mem_tobuffer(target, region.base, region.length));
261}
262
263static inline int
264compare_ipseckey(ARGS_COMPARE) {
265	isc_region_t region1;
266	isc_region_t region2;
267
268	REQUIRE(rdata1->type == rdata2->type);
269	REQUIRE(rdata1->rdclass == rdata2->rdclass);
270	REQUIRE(rdata1->type == 45);
271	REQUIRE(rdata1->length >= 3);
272	REQUIRE(rdata2->length >= 3);
273
274	dns_rdata_toregion(rdata1, &region1);
275	dns_rdata_toregion(rdata2, &region2);
276
277	return (isc_region_compare(&region1, &region2));
278}
279
280static inline isc_result_t
281fromstruct_ipseckey(ARGS_FROMSTRUCT) {
282	dns_rdata_ipseckey_t *ipseckey = source;
283	isc_region_t region;
284	isc_uint32_t n;
285
286	REQUIRE(type == 45);
287	REQUIRE(source != NULL);
288	REQUIRE(ipseckey->common.rdtype == type);
289	REQUIRE(ipseckey->common.rdclass == rdclass);
290
291	UNUSED(type);
292	UNUSED(rdclass);
293
294	if (ipseckey->gateway_type > 3U)
295		return (ISC_R_NOTIMPLEMENTED);
296
297	RETERR(uint8_tobuffer(ipseckey->precedence, target));
298	RETERR(uint8_tobuffer(ipseckey->gateway_type, target));
299	RETERR(uint8_tobuffer(ipseckey->algorithm, target));
300
301	switch  (ipseckey->gateway_type) {
302	case 0:
303		break;
304
305	case 1:
306		n = ntohl(ipseckey->in_addr.s_addr);
307		RETERR(uint32_tobuffer(n, target));
308		break;
309
310	case 2:
311		RETERR(mem_tobuffer(target, ipseckey->in6_addr.s6_addr, 16));
312		break;
313
314	case 3:
315		dns_name_toregion(&ipseckey->gateway, &region);
316		RETERR(isc_buffer_copyregion(target, &region));
317		break;
318	}
319
320	return (mem_tobuffer(target, ipseckey->key, ipseckey->keylength));
321}
322
323static inline isc_result_t
324tostruct_ipseckey(ARGS_TOSTRUCT) {
325	isc_region_t region;
326	dns_rdata_ipseckey_t *ipseckey = target;
327	dns_name_t name;
328	isc_uint32_t n;
329
330	REQUIRE(rdata->type == 45);
331	REQUIRE(target != NULL);
332	REQUIRE(rdata->length >= 3);
333
334	if (rdata->data[1] > 3U)
335		return (ISC_R_NOTIMPLEMENTED);
336
337	ipseckey->common.rdclass = rdata->rdclass;
338	ipseckey->common.rdtype = rdata->type;
339	ISC_LINK_INIT(&ipseckey->common, link);
340
341	dns_name_init(&name, NULL);
342	dns_rdata_toregion(rdata, &region);
343
344	ipseckey->precedence = uint8_fromregion(&region);
345	isc_region_consume(&region, 1);
346
347	ipseckey->gateway_type = uint8_fromregion(&region);
348	isc_region_consume(&region, 1);
349
350	ipseckey->algorithm = uint8_fromregion(&region);
351	isc_region_consume(&region, 1);
352
353	switch (ipseckey->gateway_type) {
354	case 0:
355		break;
356
357	case 1:
358		n = uint32_fromregion(&region);
359		ipseckey->in_addr.s_addr = htonl(n);
360		isc_region_consume(&region, 4);
361		break;
362
363	case 2:
364		memcpy(ipseckey->in6_addr.s6_addr, region.base, 16);
365		isc_region_consume(&region, 16);
366		break;
367
368	case 3:
369		dns_name_init(&ipseckey->gateway, NULL);
370		dns_name_fromregion(&name, &region);
371		RETERR(name_duporclone(&name, mctx, &ipseckey->gateway));
372		isc_region_consume(&region, name_length(&name));
373		break;
374	}
375
376	ipseckey->keylength = region.length;
377	if (ipseckey->keylength != 0U) {
378		ipseckey->key = mem_maybedup(mctx, region.base,
379					     ipseckey->keylength);
380		if (ipseckey->key == NULL) {
381			if (ipseckey->gateway_type == 3)
382				dns_name_free(&ipseckey->gateway,
383					      ipseckey->mctx);
384			return (ISC_R_NOMEMORY);
385		}
386	} else
387		ipseckey->key = NULL;
388
389	ipseckey->mctx = mctx;
390	return (ISC_R_SUCCESS);
391}
392
393static inline void
394freestruct_ipseckey(ARGS_FREESTRUCT) {
395	dns_rdata_ipseckey_t *ipseckey = source;
396
397	REQUIRE(source != NULL);
398	REQUIRE(ipseckey->common.rdtype == 45);
399
400	if (ipseckey->mctx == NULL)
401		return;
402
403	if (ipseckey->gateway_type == 3)
404		dns_name_free(&ipseckey->gateway, ipseckey->mctx);
405
406	if (ipseckey->key != NULL)
407		isc_mem_free(ipseckey->mctx, ipseckey->key);
408
409	ipseckey->mctx = NULL;
410}
411
412static inline isc_result_t
413additionaldata_ipseckey(ARGS_ADDLDATA) {
414
415	REQUIRE(rdata->type == 45);
416
417	UNUSED(rdata);
418	UNUSED(add);
419	UNUSED(arg);
420
421	return (ISC_R_SUCCESS);
422}
423
424static inline isc_result_t
425digest_ipseckey(ARGS_DIGEST) {
426	isc_region_t region;
427
428	REQUIRE(rdata->type == 45);
429
430	dns_rdata_toregion(rdata, &region);
431	return ((digest)(arg, &region));
432}
433
434static inline isc_boolean_t
435checkowner_ipseckey(ARGS_CHECKOWNER) {
436
437	REQUIRE(type == 45);
438
439	UNUSED(name);
440	UNUSED(type);
441	UNUSED(rdclass);
442	UNUSED(wildcard);
443
444	return (ISC_TRUE);
445}
446
447static inline isc_boolean_t
448checknames_ipseckey(ARGS_CHECKNAMES) {
449
450	REQUIRE(rdata->type == 45);
451
452	UNUSED(rdata);
453	UNUSED(owner);
454	UNUSED(bad);
455
456	return (ISC_TRUE);
457}
458
459static inline int
460casecompare_ipseckey(ARGS_COMPARE) {
461	isc_region_t region1;
462	isc_region_t region2;
463	dns_name_t name1;
464	dns_name_t name2;
465	int order;
466
467	REQUIRE(rdata1->type == rdata2->type);
468	REQUIRE(rdata1->rdclass == rdata2->rdclass);
469	REQUIRE(rdata1->type == 45);
470	REQUIRE(rdata1->length >= 3);
471	REQUIRE(rdata2->length >= 3);
472
473	dns_rdata_toregion(rdata1, &region1);
474	dns_rdata_toregion(rdata2, &region2);
475
476	if (memcmp(region1.base, region2.base, 3) != 0 || region1.base[1] != 3)
477		return (isc_region_compare(&region1, &region2));
478
479	dns_name_init(&name1, NULL);
480	dns_name_init(&name2, NULL);
481
482	isc_region_consume(&region1, 3);
483	isc_region_consume(&region2, 3);
484
485	dns_name_fromregion(&name1, &region1);
486	dns_name_fromregion(&name2, &region2);
487
488	order = dns_name_rdatacompare(&name1, &name2);
489	if (order != 0)
490		return (order);
491
492	isc_region_consume(&region1, name_length(&name1));
493	isc_region_consume(&region2, name_length(&name2));
494
495	return (isc_region_compare(&region1, &region2));
496}
497
498#endif	/* RDATA_GENERIC_IPSECKEY_45_C */
499