rdata.c 47.2 KB
Newer Older
1
/*
David Lawrence's avatar
David Lawrence committed
2
 * Copyright (C) 1998-2000  Internet Software Consortium.
3
 *
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.
16
17
 */

18
/* $Id: rdata.c,v 1.131 2000/11/20 21:41:53 bwelling Exp $ */
19
20

#include <config.h>
21
#include <ctype.h>
22

23
#include <isc/base64.h>
24
#include <isc/hex.h>
25
#include <isc/lex.h>
26
#include <isc/mem.h>
Mark Andrews's avatar
Mark Andrews committed
27
#include <isc/print.h>
28
#include <isc/string.h>
Mark Andrews's avatar
Mark Andrews committed
29
#include <isc/util.h>
30

31
32
33
34
35
#include <dns/callbacks.h>
#include <dns/cert.h>
#include <dns/compress.h>
#include <dns/keyflags.h>
#include <dns/rcode.h>
36
#include <dns/rdata.h>
37
#include <dns/rdataclass.h>
38
#include <dns/rdatastruct.h>
39
#include <dns/rdatatype.h>
40
#include <dns/result.h>
Mark Andrews's avatar
Mark Andrews committed
41
#include <dns/secalg.h>
42
#include <dns/secproto.h>
43
44
#include <dns/time.h>
#include <dns/ttl.h>
45

46
#define RETERR(x) do { \
47
48
49
	isc_result_t _r = (x); \
	if (_r != ISC_R_SUCCESS) \
		return (_r); \
50
	} while (0)
51

52
#define ARGS_FROMTEXT	int rdclass, dns_rdatatype_t type, \
David Lawrence's avatar
David Lawrence committed
53
54
55
56
57
58
			isc_lex_t *lexer, dns_name_t *origin, \
			isc_boolean_t downcase, isc_buffer_t *target

#define ARGS_TOTEXT	dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, \
			isc_buffer_t *target

59
#define ARGS_FROMWIRE	int rdclass, dns_rdatatype_t type, \
David Lawrence's avatar
David Lawrence committed
60
61
62
63
64
65
66
67
			isc_buffer_t *source, dns_decompress_t *dctx, \
			isc_boolean_t downcase, isc_buffer_t *target

#define ARGS_TOWIRE	dns_rdata_t *rdata, dns_compress_t *cctx, \
			isc_buffer_t *target

#define ARGS_COMPARE	const dns_rdata_t *rdata1, const dns_rdata_t *rdata2

68
#define ARGS_FROMSTRUCT	int rdclass, dns_rdatatype_t type, \
David Lawrence's avatar
David Lawrence committed
69
70
71
72
73
74
75
76
77
78
79
			void *source, isc_buffer_t *target

#define ARGS_TOSTRUCT	dns_rdata_t *rdata, void *target, isc_mem_t *mctx

#define ARGS_FREESTRUCT void *source

#define ARGS_ADDLDATA	dns_rdata_t *rdata, dns_additionaldatafunc_t add, \
			void *arg

#define ARGS_DIGEST	dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg

80
/*
81
 * Context structure for the totext_ functions.
82
83
84
85
86
87
88
 * Contains formatting options for rdata-to-text
 * conversion.
 */
typedef struct dns_rdata_textctx {
	dns_name_t *origin;	/* Current origin, or NULL. */
	unsigned int flags;	/* DNS_STYLEFLAG_* */
	unsigned int width;	/* Width of rdata column. */
David Lawrence's avatar
David Lawrence committed
89
  	const char *linebreak;	/* Line break string. */
90
91
} dns_rdata_textctx_t;

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
static isc_result_t
txt_totext(isc_region_t *source, isc_buffer_t *target);

static isc_result_t
txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);

static isc_result_t
txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);

static isc_boolean_t
name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);

static unsigned int
name_length(dns_name_t *name);

static isc_result_t
David Lawrence's avatar
David Lawrence committed
108
str_totext(const char *source, isc_buffer_t *target);
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

static isc_boolean_t
buffer_empty(isc_buffer_t *source);

static void
buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);

static isc_result_t
uint32_tobuffer(isc_uint32_t, isc_buffer_t *target);

static isc_result_t
uint16_tobuffer(isc_uint32_t, isc_buffer_t *target);

static isc_result_t
uint8_tobuffer(isc_uint32_t, isc_buffer_t *target);

static isc_result_t
name_tobuffer(dns_name_t *name, isc_buffer_t *target);

static isc_uint32_t
uint32_fromregion(isc_region_t *region);

static isc_uint16_t
uint16_fromregion(isc_region_t *region);

static isc_uint8_t
uint8_fromregion(isc_region_t *region);

static isc_result_t
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);

static int
compare_region(isc_region_t *r1, isc_region_t *r2);

static int
hexvalue(char value);

static int
decvalue(char value);

static isc_result_t
btoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target);

static isc_result_t
atob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target);

static void
David Lawrence's avatar
David Lawrence committed
156
default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...);
157
158

static void
David Lawrence's avatar
David Lawrence committed
159
160
161
fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
	       dns_rdatacallbacks_t *callbacks, const char *name,
	       unsigned long line, isc_token_t *token, isc_result_t result);
162

163
164
165
static void
fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);

166
167
168
static isc_result_t
rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
	     isc_buffer_t *target);
169

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
static inline isc_result_t
name_duporclone(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {

	if (mctx != NULL)
                return (dns_name_dup(source, mctx, target));
	dns_name_clone(source, target);
	return (ISC_R_SUCCESS);
}

static inline void *
mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
	void *new;

	if (mctx == NULL)
		return (source);
	new = isc_mem_allocate(mctx, length);
	if (new != NULL)
		memcpy(new, source, length);
188

189
190
191
	return (new);
}

192
193
static const char hexdigits[] = "0123456789abcdef";
static const char decdigits[] = "0123456789";
194
195
196

#include "code.h"

197
198
199
#define META 0x0001
#define RESERVED 0x0002

200
201
202
203
204
205
206
207
208
209
210
211
#define RCODENAMES \
	/* standard rcodes */ \
	{ dns_rcode_noerror, "NOERROR", 0}, \
	{ dns_rcode_formerr, "FORMERR", 0}, \
	{ dns_rcode_servfail, "SERVFAIL", 0}, \
	{ dns_rcode_nxdomain, "NXDOMAIN", 0}, \
	{ dns_rcode_notimp, "NOTIMP", 0}, \
	{ dns_rcode_refused, "REFUSED", 0}, \
	{ dns_rcode_yxdomain, "YXDOMAIN", 0}, \
	{ dns_rcode_yxrrset, "YXRRSET", 0}, \
	{ dns_rcode_nxrrset, "NXRRSET", 0}, \
	{ dns_rcode_notauth, "NOTAUTH", 0}, \
212
213
214
	{ dns_rcode_notzone, "NOTZONE", 0},

#define ERCODENAMES \
215
	/* extended rcodes */ \
216
	{ dns_rcode_badvers, "BADVERS", 0}, \
217
218
	{ 0, NULL, 0 }

219
220
221
222
223
224
225
226
227
228
#define TSIGRCODENAMES \
	/* extended rcodes */ \
	{ dns_tsigerror_badsig, "BADSIG", 0}, \
	{ dns_tsigerror_badkey, "BADKEY", 0}, \
	{ dns_tsigerror_badtime, "BADTIME", 0}, \
	{ dns_tsigerror_badmode, "BADMODE", 0}, \
	{ dns_tsigerror_badname, "BADNAME", 0}, \
	{ dns_tsigerror_badalg, "BADALG", 0}, \
	{ 0, NULL, 0 }

229
230
/* RFC2538 section 2.1 */

Mark Andrews's avatar
Mark Andrews committed
231
#define CERTNAMES \
232
	{ 1, "PKIX", 0}, \
Mark Andrews's avatar
Mark Andrews committed
233
234
235
236
237
238
	{ 2, "SPKI", 0}, \
	{ 3, "PGP", 0}, \
	{ 253, "URI", 0}, \
	{ 254, "OID", 0}, \
	{ 0, NULL, 0}

239
/* RFC2535 section 7 */
Mark Andrews's avatar
Mark Andrews committed
240

Mark Andrews's avatar
Mark Andrews committed
241
#define SECALGNAMES \
Mark Andrews's avatar
Mark Andrews committed
242
243
244
245
246
247
248
	{ 1, "RSAMD5", 0 }, \
	{ 2, "DH", 0 }, \
	{ 3, "DSA", 0 }, \
	{ 4, "ECC", 0 }, \
	{ 252, "INDIRECT", 0 }, \
	{ 253, "PRIVATEDNS", 0 }, \
	{ 254, "PRIVATEOID", 0 }, \
Mark Andrews's avatar
Mark Andrews committed
249
250
	{ 0, NULL, 0}

251
252
253
254
255
256
257
258
259
260
/* RFC2535 section 7.1 */

#define SECPROTONAMES \
	{   0,    "NONE", 0 }, \
	{   1,    "TLS", 0 }, \
	{   2,    "EMAIL", 0 }, \
	{   3,    "DNSSEC", 0 }, \
	{   4,    "IPSEC", 0 }, \
	{ 255,    "ALL", 0 }, \
	{ 0, NULL, 0}
Mark Andrews's avatar
Mark Andrews committed
261

262
struct tbl {
263
	unsigned int	value;
David Lawrence's avatar
David Lawrence committed
264
265
	const char	*name;
	int		flags;
266
267
};

268
269
static struct tbl rcodes[] = { RCODENAMES ERCODENAMES };
static struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES };
270
271
272
static struct tbl certs[] = { CERTNAMES };
static struct tbl secalgs[] = { SECALGNAMES };
static struct tbl secprotos[] = { SECPROTONAMES };
273
274

static struct keyflag {
David Lawrence's avatar
David Lawrence committed
275
	const char *name;
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
	unsigned int value;
	unsigned int mask;
} keyflags[] = {
	{ "NOCONF", 0x4000, 0xC000 },
	{ "NOAUTH", 0x8000, 0xC000 },
	{ "NOKEY",  0xC000, 0xC000 },
	{ "FLAG2",  0x2000, 0x2000 },
	{ "EXTEND", 0x1000, 0x1000 },
	{ "FLAG4",  0x0800, 0x0800 },
	{ "FLAG5",  0x0400, 0x0400 },
	{ "USER",   0x0000, 0x0300 },
	{ "ZONE",   0x0100, 0x0300 },
	{ "HOST",   0x0200, 0x0300 },
	{ "NTYP3",  0x0300, 0x0300 },
	{ "FLAG8",  0x0080, 0x0080 },
	{ "FLAG9",  0x0040, 0x0040 },
	{ "FLAG10", 0x0020, 0x0020 },
	{ "FLAG11", 0x0010, 0x0010 },
	{ "SIG0",   0x0000, 0x000F },
	{ "SIG1",   0x0001, 0x000F },
	{ "SIG2",   0x0002, 0x000F },
	{ "SIG3",   0x0003, 0x000F },
	{ "SIG4",   0x0004, 0x000F },
	{ "SIG5",   0x0005, 0x000F },
	{ "SIG6",   0x0006, 0x000F },
	{ "SIG7",   0x0007, 0x000F },
	{ "SIG8",   0x0008, 0x000F },
	{ "SIG9",   0x0009, 0x000F },
	{ "SIG10",  0x000A, 0x000F },
	{ "SIG11",  0x000B, 0x000F },
	{ "SIG12",  0x000C, 0x000F },
	{ "SIG13",  0x000D, 0x000F },
	{ "SIG14",  0x000E, 0x000F },
	{ "SIG15",  0x000F, 0x000F },
310
	{ NULL,     0, 0 }
311
};
312

313
314
315
316
317
318
319
320
321
322
323
/***
 *** Initialization
 ***/

void
dns_rdata_init(dns_rdata_t *rdata) {

	REQUIRE(rdata != NULL);

	rdata->data = NULL;
	rdata->length = 0;
324
	rdata->rdclass = 0;
325
	rdata->type = 0;
Mark Andrews's avatar
Mark Andrews committed
326
	rdata->flags = 0;
327
328
329
330
	ISC_LINK_INIT(rdata, link);
	/* ISC_LIST_INIT(rdata->list); */
}

331
#define DNS_RDATA_INITIALIZED(rdata) \
332
333
334
335
336
337
	((rdata)->data == NULL && (rdata)->length == 0 && \
	 (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
	 !ISC_LINK_LINKED((rdata), link))
#define DNS_RDATA_VALIDFLAGS(rdata) \
	(((rdata)->flags & ~DNS_RDATA_UPDATE) == 0)

338
void
339
dns_rdata_reset(dns_rdata_t *rdata) {
340
341

	REQUIRE(!ISC_LINK_LINKED(rdata, link));
342
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
343
344
345
346
347
348
349
350

	rdata->data = NULL;
	rdata->length = 0;
	rdata->rdclass = 0;
	rdata->type = 0;
	rdata->flags = 0;
}

351
352
353
354
/***
 ***
 ***/

355
void
356
357
dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {

358
	REQUIRE(DNS_RDATA_INITIALIZED(target));
359
360
361
362

	REQUIRE(DNS_RDATA_VALIDFLAGS(src));
	REQUIRE(DNS_RDATA_VALIDFLAGS(target));

363
364
365
366
367
368
369
370
	target->data = src->data;
	target->length = src->length;
	target->rdclass = src->rdclass;
	target->type = src->type;
	target->flags = src->flags;
}


371
372
373
374
375
/***
 *** Comparisons
 ***/

int
David Lawrence's avatar
David Lawrence committed
376
dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
Mark Andrews's avatar
Mark Andrews committed
377
378
	int result = 0;
	isc_boolean_t use_default = ISC_FALSE;
379
380
381
382
383

	REQUIRE(rdata1 != NULL);
	REQUIRE(rdata2 != NULL);
	REQUIRE(rdata1->data != NULL);
	REQUIRE(rdata2->data != NULL);
384
385
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
386

387
388
	if (rdata1->rdclass != rdata2->rdclass)
		return (rdata1->rdclass < rdata2->rdclass ? -1 : 1);
389
390
391
392
393
394

	if (rdata1->type != rdata2->type)
		return (rdata1->type < rdata2->type ? -1 : 1);

	COMPARESWITCH

Mark Andrews's avatar
Mark Andrews committed
395
	if (use_default) {
Mark Andrews's avatar
Mark Andrews committed
396
397
398
399
400
401
		isc_region_t r1;
		isc_region_t r2;

		dns_rdata_toregion(rdata1, &r1);
		dns_rdata_toregion(rdata2, &r2);
		result = compare_region(&r1, &r2);
402
403
404
405
406
407
408
409
410
	}
	return (result);
}

/***
 *** Conversions
 ***/

void
411
dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
Mark Andrews's avatar
Mark Andrews committed
412
413
		     dns_rdatatype_t type, isc_region_t *r)
{
414

415
	REQUIRE(rdata != NULL);
416
	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
417
418
	REQUIRE(r != NULL);

419
420
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));

421
422
	rdata->data = r->base;
	rdata->length = r->length;
423
	rdata->rdclass = rdclass;
424
	rdata->type = type;
425
	rdata->flags = 0;
426
427
428
}

void
David Lawrence's avatar
David Lawrence committed
429
dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
430

431
432
	REQUIRE(rdata != NULL);
	REQUIRE(r != NULL);
433
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
434

435
436
437
438
	r->base = rdata->data;
	r->length = rdata->length;
}

439
isc_result_t
440
dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
Mark Andrews's avatar
Mark Andrews committed
441
442
443
444
		   dns_rdatatype_t type, isc_buffer_t *source,
		   dns_decompress_t *dctx, isc_boolean_t downcase,
		   isc_buffer_t *target)
{
445
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
446
447
448
	isc_region_t region;
	isc_buffer_t ss;
	isc_buffer_t st;
Mark Andrews's avatar
Mark Andrews committed
449
	isc_boolean_t use_default = ISC_FALSE;
Mark Andrews's avatar
Mark Andrews committed
450
	isc_uint32_t activelength;
451

452
	REQUIRE(dctx != NULL);
453
	if (rdata != NULL) {
454
		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
455
456
		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
	}
457

458
459
460
	ss = *source;
	st = *target;

Mark Andrews's avatar
Mark Andrews committed
461
462
463
	activelength = isc_buffer_activelength(source);
	INSIST(activelength < 65536);

464
465
	FROMWIRESWITCH

Mark Andrews's avatar
Mark Andrews committed
466
467
468
469
470
471
472
473
474
475
	if (use_default) {
		if (activelength > isc_buffer_availablelength(target))
			result = ISC_R_NOSPACE;
		else {
			isc_buffer_putmem(target, isc_buffer_current(source),
					  activelength);
			isc_buffer_forward(source, activelength);
			result = ISC_R_SUCCESS;
		}
	}
476

477
478
479
	/*
	 * We should have consumed all of our buffer.
	 */
480
	if (result == ISC_R_SUCCESS && !buffer_empty(source))
Mark Andrews's avatar
Mark Andrews committed
481
		result = DNS_R_EXTRADATA;
482

483
	if (rdata != NULL && result == ISC_R_SUCCESS) {
484
485
486
		region.base = isc_buffer_used(&st);
		region.length = isc_buffer_usedlength(target) -
				isc_buffer_usedlength(&st);
487
		dns_rdata_fromregion(rdata, rdclass, type, &region);
488
489
	}

490
	if (result != ISC_R_SUCCESS) {
491
492
493
494
495
496
		*source = ss;
		*target = st;
	}
	return (result);
}

497
isc_result_t
498
dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
Mark Andrews's avatar
Mark Andrews committed
499
500
	         isc_buffer_t *target)
{
501
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
Mark Andrews's avatar
Mark Andrews committed
502
	isc_boolean_t use_default = ISC_FALSE;
503
	isc_region_t tr;
Mark Andrews's avatar
Mark Andrews committed
504
	isc_buffer_t st;
505

506
	REQUIRE(rdata != NULL);
507
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
508

509
510
511
	/*
	 * Some DynDNS meta-RRs have empty rdata.
	 */
512
513
	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
		INSIST(rdata->length == 0);
514
		return (ISC_R_SUCCESS);
515
	}
516

Mark Andrews's avatar
Mark Andrews committed
517
	st = *target;
518

519
	TOWIRESWITCH
520

Mark Andrews's avatar
Mark Andrews committed
521
	if (use_default) {
522
		isc_buffer_availableregion(target, &tr);
523
		if (tr.length < rdata->length)
524
			return (ISC_R_NOSPACE);
525
526
		memcpy(tr.base, rdata->data, rdata->length);
		isc_buffer_add(target, rdata->length);
527
		return (ISC_R_SUCCESS);
528
	}
529
	if (result != ISC_R_SUCCESS) {
Mark Andrews's avatar
Mark Andrews committed
530
		*target = st;
531
532
		INSIST(target->used < 65536);
		dns_compress_rollback(cctx, (isc_uint16_t)target->used);
Mark Andrews's avatar
Mark Andrews committed
533
	}
534
535
536
	return (result);
}

537
static isc_result_t
538
539
rdata_valid(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
	    dns_rdatatype_t type)
Mark Andrews's avatar
Mark Andrews committed
540
{
541
	dns_decompress_t dctx;
542
	dns_rdata_t rdata = DNS_RDATA_INIT;
543
544
	isc_result_t result;

545
	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
546
547
548
	isc_buffer_setactive(src, isc_buffer_usedlength(src));
	result = dns_rdata_fromwire(&rdata, rdclass, type, src,
				    &dctx, ISC_FALSE, dest);
549
	dns_decompress_invalidate(&dctx);
550

Mark Andrews's avatar
Mark Andrews committed
551
552
553
	return (result);
}

554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
static isc_result_t
unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
		 isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target)
{
	isc_result_t result;
	isc_buffer_t *buf = NULL;
	isc_token_t token;

	if (dns_rdatatype_ismeta(type))
		return (DNS_R_METATYPE);

	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
					ISC_FALSE);
	if (result == ISC_R_SUCCESS && token.value.as_ulong > 65535)
		return (ISC_R_RANGE);
569
	result = isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
	if (result != ISC_R_SUCCESS)
		return (result);
	
	result = isc_hex_tobuffer(lexer, buf, token.value.as_ulong);
	if (result != ISC_R_SUCCESS)
	       goto failure;
	if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
		result = ISC_R_UNEXPECTEDEND;
		goto failure;
	}

	if (dns_rdatatype_isknown(type)) {
		result = rdata_valid(buf, target, rdclass, type);
	} else {
		isc_region_t r;
		isc_buffer_usedregion(buf, &r);
		result = isc_buffer_copyregion(target, &r);
	}
	if (result != ISC_R_SUCCESS)
		goto failure;

	isc_buffer_free(&buf);
	return (ISC_R_SUCCESS);

 failure:
	isc_buffer_free(&buf);
	return (result);
}

599
isc_result_t
600
dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
Mark Andrews's avatar
Mark Andrews committed
601
		   dns_rdatatype_t type, isc_lex_t *lexer,
602
		   dns_name_t *origin, isc_boolean_t downcase, isc_mem_t *mctx,
Mark Andrews's avatar
Mark Andrews committed
603
604
		   isc_buffer_t *target, dns_rdatacallbacks_t *callbacks)
{
605
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
606
607
	isc_region_t region;
	isc_buffer_t st;
Mark Andrews's avatar
Mark Andrews committed
608
	isc_token_t token;
Bob Halley's avatar
Bob Halley committed
609
	unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
610
			       ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
611
	char *name;
612
	unsigned long line;
David Lawrence's avatar
David Lawrence committed
613
	void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
614
	isc_result_t iresult;
615

616
	REQUIRE(origin == NULL || dns_name_isabsolute(origin) == ISC_TRUE);
617
	if (rdata != NULL) {
618
		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
619
620
		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
	}
621

622
623
	st = *target;

624
625
626
627
	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
					ISC_FALSE);
	if (result != ISC_R_SUCCESS)
		return (result);
628
629
630
	if (strcmp((char *)token.value.as_pointer, "\\#") == 0)
		result = unknown_fromtext(rdclass, type, lexer, mctx, target);
	else {
631
632
633
		isc_lex_ungettoken(lexer, &token);

		FROMTEXTSWITCH
Mark Andrews's avatar
Mark Andrews committed
634
	}
Mark Andrews's avatar
Mark Andrews committed
635

636
637
638
639
640
641
642
	if (callbacks == NULL)
		callback = NULL;
	else
		callback = callbacks->error;

	if (callback == NULL)
		callback = default_fromtext_callback;
Mark Andrews's avatar
Mark Andrews committed
643
644
645
	/*
	 * Consume to end of line / file.
	 * If not at end of line initially set error code.
646
	 * Call callback via fromtext_error once if there was an error.
Mark Andrews's avatar
Mark Andrews committed
647
648
	 */
	do {
649
650
		name = isc_lex_getsourcename(lexer);
		line = isc_lex_getsourceline(lexer);
651
652
		iresult = isc_lex_gettoken(lexer, options, &token);
		if (iresult != ISC_R_SUCCESS) {
653
			if (result == ISC_R_SUCCESS) {
654
				switch (iresult) {
655
				case ISC_R_NOMEMORY:
656
					result = ISC_R_NOMEMORY;
657
					break;
658
				case ISC_R_NOSPACE:
659
					result = ISC_R_NOSPACE;
660
661
662
					break;
				default:
					UNEXPECTED_ERROR(__FILE__, __LINE__,
663
					    "isc_lex_gettoken() failed: %s",
664
					    isc_result_totext(iresult));
665
					result = ISC_R_UNEXPECTED;
666
667
668
					break;
				}
			}
669
670
671
			if (callback != NULL)
				fromtext_error(callback, callbacks, name,
					       line, NULL, result);
Mark Andrews's avatar
Mark Andrews committed
672
673
674
			break;
		} else if (token.type != isc_tokentype_eol &&
			   token.type != isc_tokentype_eof) {
675
			if (result == ISC_R_SUCCESS)
Mark Andrews's avatar
Mark Andrews committed
676
				result = DNS_R_EXTRATOKEN;
677
678
679
680
681
			if (callback != NULL) {
				fromtext_error(callback, callbacks, name,
					       line, &token, result);
				callback = NULL;
			}
682
		} else if (result != ISC_R_SUCCESS && callback != NULL) {
683
684
685
			fromtext_error(callback, callbacks, name, line,
				       &token, result);
			break;
686
687
688
		} else {
			if (token.type == isc_tokentype_eof)
				fromtext_warneof(lexer, callbacks);
Mark Andrews's avatar
Mark Andrews committed
689
			break;
690
		}
Mark Andrews's avatar
Mark Andrews committed
691
	} while (1);
692

693
	if (rdata != NULL && result == ISC_R_SUCCESS) {
694
695
696
		region.base = isc_buffer_used(&st);
		region.length = isc_buffer_usedlength(target) -
				isc_buffer_usedlength(&st);
697
		dns_rdata_fromregion(rdata, rdclass, type, &region);
698
	}
699
	if (result != ISC_R_SUCCESS) {
700
701
702
703
704
		*target = st;
	}
	return (result);
}

705
static isc_result_t
Bob Halley's avatar
Bob Halley committed
706
707
rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
	     isc_buffer_t *target)
708
{
709
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
Mark Andrews's avatar
Mark Andrews committed
710
	isc_boolean_t use_default = ISC_FALSE;
Mark Andrews's avatar
Mark Andrews committed
711
712
	char buf[sizeof "65536"];
	isc_region_t sr;
713

714
	REQUIRE(rdata != NULL);
715
716
	REQUIRE(tctx->origin == NULL ||
		dns_name_isabsolute(tctx->origin) == ISC_TRUE);
717

718
719
720
	/*
	 * Some DynDNS meta-RRs have empty rdata.
	 */
721
722
	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
		INSIST(rdata->length == 0);
723
		return (ISC_R_SUCCESS);
724
	}
725

726
727
	TOTEXTSWITCH

Mark Andrews's avatar
Mark Andrews committed
728
	if (use_default) {
729
730
		sprintf(buf, "\\# ");
		result = str_totext(buf, target);
Mark Andrews's avatar
Mark Andrews committed
731
732
733
734
735
736
737
738
739
740
		dns_rdata_toregion(rdata, &sr);
		INSIST(sr.length < 65536);
		sprintf(buf, "%u", sr.length);
		result = str_totext(buf, target);
		if (sr.length != 0 && result == ISC_R_SUCCESS) {
			if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
				result = str_totext(" ( ", target);
			else
				result = str_totext(" ", target);
			if (result == ISC_R_SUCCESS)
741
742
743
				result = isc_hex_totext(&sr, tctx->width - 2,
							tctx->linebreak,
							target);
Mark Andrews's avatar
Mark Andrews committed
744
745
746
747
748
			if (result == ISC_R_SUCCESS &&
			    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
				result = str_totext(" )", target);
		}
	}
Mark Andrews's avatar
Mark Andrews committed
749

750
751
752
	return (result);
}

753
isc_result_t
754
dns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target)
755
{
756
757
758
759
	dns_rdata_textctx_t tctx;

	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));

760
761
762
	/*
	 * Set up formatting options for single-line output.
	 */
763
764
765
766
	tctx.origin = origin;
	tctx.flags = 0;
	tctx.width = 60;
	tctx.linebreak = " ";
Bob Halley's avatar
Bob Halley committed
767
	return (rdata_totext(rdata, &tctx, target));
768
769
}

770
isc_result_t
771
772
773
774
dns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin,
		    unsigned int flags, unsigned int width,
		    char *linebreak, isc_buffer_t *target)
{
775
776
777
778
	dns_rdata_textctx_t tctx;

	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));

779
780
781
	/*
	 * Set up formatting options for formatted output.
	 */
782
783
784
785
786
787
	tctx.origin = origin;
	tctx.flags = flags;
	if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
		tctx.width = width;
		tctx.linebreak = linebreak;
	} else {
788
		tctx.width = 60; /* Used for hex word length only. */
789
790
		tctx.linebreak = " ";
	}
Bob Halley's avatar
Bob Halley committed
791
	return (rdata_totext(rdata, &tctx, target));
792
793
}

794
isc_result_t
795
dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
Mark Andrews's avatar
Mark Andrews committed
796
797
798
		     dns_rdatatype_t type, void *source,
		     isc_buffer_t *target)
{
799
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
800
801
	isc_buffer_t st;
	isc_region_t region;
Mark Andrews's avatar
Mark Andrews committed
802
	isc_boolean_t use_default = ISC_FALSE;
803

804
	REQUIRE(source != NULL);
805
	if (rdata != NULL) {
806
		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
807
808
		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
	}
809

810
811
812
813
	st = *target;

	FROMSTRUCTSWITCH

Mark Andrews's avatar
Mark Andrews committed
814
815
	if (use_default)
		(void)NULL;
816

817
	if (rdata != NULL && result == ISC_R_SUCCESS) {
818
819
820
		region.base = isc_buffer_used(&st);
		region.length = isc_buffer_usedlength(target) -
				isc_buffer_usedlength(&st);
821
		dns_rdata_fromregion(rdata, rdclass, type, &region);
822
	}
823
	if (result != ISC_R_SUCCESS)
824
825
826
827
		*target = st;
	return (result);
}

828
isc_result_t
829
dns_rdata_tostruct(dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
830
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
Mark Andrews's avatar
Mark Andrews committed
831
	isc_boolean_t use_default = ISC_FALSE;
832

833
	REQUIRE(rdata != NULL);
834
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
835

836
837
	TOSTRUCTSWITCH

Mark Andrews's avatar
Mark Andrews committed
838
839
840
	if (use_default)
		(void)NULL;

841
842
843
	return (result);
}

844
845
846
847
848
849
850
851
void
dns_rdata_freestruct(void *source) {
	dns_rdatacommon_t *common = source;
	REQUIRE(source != NULL);

	FREESTRUCTSWITCH
}

852
isc_result_t
853
854
855
dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add,
			 void *arg)
{
856
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
857
858
859
860
861
862
863
864
865
	isc_boolean_t use_default = ISC_FALSE;

	/*
	 * Call 'add' for each name and type from 'rdata' which is subject to
	 * additional section processing.
	 */

	REQUIRE(rdata != NULL);
	REQUIRE(add != NULL);
866
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
867
868
869

	ADDITIONALDATASWITCH

Mark Andrews's avatar
Mark Andrews committed
870
	/* No additional processing for unknown types */
871
	if (use_default)
Mark Andrews's avatar
Mark Andrews committed
872
		result = ISC_R_SUCCESS;
873
874
875
876

	return (result);
}

877
isc_result_t
878
dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
879
	isc_result_t result = ISC_R_NOTIMPLEMENTED;
880
	isc_boolean_t use_default = ISC_FALSE;
Mark Andrews's avatar
Mark Andrews committed
881
	isc_region_t r;
882
883
884
885
886
887
888

	/*
	 * Send 'rdata' in DNSSEC canonical form to 'digest'.
	 */

	REQUIRE(rdata != NULL);
	REQUIRE(digest != NULL);
889
	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
890
891
892

	DIGESTSWITCH

Mark Andrews's avatar
Mark Andrews committed
893
894
895
896
	if (use_default) {
		dns_rdata_toregion(rdata, &r);
		result = (digest)(arg, &r);
	}
897
898
899
900

	return (result);
}

901
902
903
904
905
906
907
908
909
unsigned int
dns_rdatatype_attributes(dns_rdatatype_t type)
{
	if (type > 255)
		return (DNS_RDATATYPEATTR_UNKNOWN);

	return (typeattr[type].flags);
}

910
#define NUMBERSIZE sizeof("037777777777") /* 2^32-1 octal + NUL */
911

912
static isc_result_t
913
914
915
916
917
dns_mnemonic_fromtext(unsigned int *valuep, isc_textregion_t *source,
		      struct tbl *table, unsigned int max)
{
	int i;

918
919
	if (isdigit(source->base[0] & 0xff) &&
            source->length <= NUMBERSIZE - 1) {
920
921
922
923
924
925
926
927
928
929
		unsigned int n;
		char *e;
		char buffer[NUMBERSIZE];
		/*
		 * We have a potential number.  Try to parse it with strtoul().
		 * strtoul() requires null termination, so we must make
		 * a copy.
		 */
		strncpy(buffer, source->base, NUMBERSIZE);
		INSIST(buffer[source->length] == '\0');
930

931
932
933
		n = strtoul(buffer, &e, 10);
		if (*e == 0) {
			if (n > max)
David Lawrence's avatar
David Lawrence committed
934
				return (ISC_R_RANGE);
935
			*valuep = n;
936
			return (ISC_R_SUCCESS);
937
		}
938
939
940
		/*
		 * It was not a number after all; fall through.
		 */
941
	}
942

943
	for (i = 0; table[i].name != NULL; i++) {
944
		unsigned int n;
945
946
947
948
		n = strlen(table[i].name);
		if (n == source->length &&
		    strncasecmp(source->base, table[i].name, n) == 0) {
			*valuep = table[i].value;
949
			return (ISC_R_SUCCESS);
950
951
952
953
954
		}
	}
	return (DNS_R_UNKNOWN);
}

955
static isc_result_t
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
dns_mnemonic_totext(unsigned int value, isc_buffer_t *target,
		    struct tbl *table)
{
	int i = 0;
	char buf[sizeof "4294967296"];
	while (table[i].name != NULL) {
		if (table[i].value == value) {
			return (str_totext(table[i].name, target));
		}
		i++;
	}
	sprintf(buf, "%u", value);
	return (str_totext(buf, target));
}

971
972
973
974
975

/*
 * This uses lots of hard coded values, but how often do we actually
 * add classes?
 */
976
isc_result_t
977
dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source) {
978
#define COMPARE(string, rdclass) \
979
980
	if (((sizeof(string) - 1) == source->length) \
	    && (strcasecmp(source->base, string) == 0)) { \
981
		*classp = rdclass; \
982
983
984
		return (ISC_R_SUCCESS); \
	}

985
	switch (tolower((unsigned char)source->base[0])) {
986
	case 'a':
987
		COMPARE("any", dns_rdataclass_any);
988
989
		break;
	case 'c':
990
991
992
993
994
		/*
		 * RFC1035 says the mnemonic for the CHAOS class is CH,
		 * but historical BIND practice is to call it CHAOS.
		 * We will accept both forms, but only generate CH.
		 */
995
996
997
998
999
1000
		COMPARE("ch", dns_rdataclass_chaos);
		COMPARE("chaos", dns_rdataclass_chaos);
		if (source->length > 5 &&
		    strncasecmp("class", source->base, 5) == 0)
		{
			char *endp;
For faster browsing, not all history is shown. View entire blame