rrset-dump.c 41.3 KB
Newer Older
1
/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
Daniel Salzman's avatar
Daniel Salzman committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

17 18 19 20 21 22 23 24 25
#include <arpa/inet.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <netinet/in.h>
#include <sys/socket.h>
Daniel Salzman's avatar
Daniel Salzman committed
26

27 28
#include "dnssec/binary.h"
#include "dnssec/keytag.h"
29
#include "libknot/attribute.h"
30
#include "libknot/rrset-dump.h"
31
#include "libknot/codes.h"
32
#include "libknot/consts.h"
33 34
#include "libknot/descriptor.h"
#include "libknot/errcode.h"
35
#include "libknot/lookup.h"
36 37
#include "contrib/base32hex.h"
#include "contrib/base64.h"
38
#include "contrib/ctype.h"
39
#include "contrib/wire.h"
40
#include "contrib/wire_ctx.h"
Daniel Salzman's avatar
Daniel Salzman committed
41

42 43
#define RRSET_DUMP_LIMIT (2 * 1024 * 1024)

44
#define TAB_WIDTH		8
Daniel Salzman's avatar
Daniel Salzman committed
45 46 47
#define BLOCK_WIDTH		40
#define BLOCK_INDENT		"\n\t\t\t\t"

48 49
#define LOC_ZERO		2147483648	// 2^31

50 51 52 53 54 55 56 57
/*! \brief macros with repetitive (mostly error-checking) code of methods from first section of this file */
#define CHECK_PRET if (p->ret < 0) return;
#define CHECK_INMAX(mininmax) if (p->in_max < (mininmax)) { p->ret = -1; return; }
#define CHECK_RET_OUTMAX_SNPRINTF if (ret <= 0 || (size_t)ret >= p->out_max) { p->ret = -1; return; }
#define STRING_TERMINATION if (p->out_max > 0) { *p->out = '\0'; } else { p->ret = -1; return; }
#define FILL_IN_INPUT(pdata) if (memcpy(&(pdata), p->in, in_len) == NULL) { p->ret = -1; return; }
#define CHECK_RET_POSITIVE if (ret <= 0) { p->ret = -1; return; }

Daniel Salzman's avatar
Daniel Salzman committed
58
typedef struct {
59
	const knot_dump_style_t *style;
60 61 62 63 64 65
	const uint8_t *in;
	size_t        in_max;
	char          *out;
	size_t        out_max;
	size_t        total;
	int           ret;
Daniel Salzman's avatar
Daniel Salzman committed
66 67
} rrset_dump_params_t;

68
_public_
69 70
const knot_dump_style_t KNOT_DUMP_STYLE_DEFAULT = {
	.wrap = false,
71
	.show_class = false,
72 73
	.show_ttl = true,
	.verbose = false,
74
	.empty_ttl = false,
75
	.human_ttl = false,
Daniel Salzman's avatar
Daniel Salzman committed
76
	.human_tmstamp = true,
77
	.hide_crypto = false,
78
	.ascii_to_idn = NULL
79 80
};

Daniel Salzman's avatar
Daniel Salzman committed
81 82
static void dump_string(rrset_dump_params_t *p, const char *str)
{
83
	CHECK_PRET
84

Daniel Salzman's avatar
Daniel Salzman committed
85 86
	size_t in_len = strlen(str);

87 88
	// Check input size (+ 1 termination).
	if (in_len >= p->out_max) {
89
		p->ret = -1;
Daniel Salzman's avatar
Daniel Salzman committed
90 91 92 93 94
		return;
	}

	// Copy string including termination '\0'!
	if (memcpy(p->out, str, in_len + 1) == NULL) {
95
		p->ret = -1;
Daniel Salzman's avatar
Daniel Salzman committed
96 97 98 99 100 101 102
		return;
	}

	// Fill in output.
	p->out += in_len;
	p->out_max -= in_len;
	p->total += in_len;
Daniel Salzman's avatar
Daniel Salzman committed
103 104
}

Daniel Salzman's avatar
Daniel Salzman committed
105
static void wire_num8_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
106
{
107
	CHECK_PRET
108

Daniel Salzman's avatar
Daniel Salzman committed
109 110 111
	uint8_t data = *(p->in);
	size_t  in_len = sizeof(data);
	size_t  out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
112

113
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
114

Daniel Salzman's avatar
Daniel Salzman committed
115 116
	// Write number.
	int ret = snprintf(p->out, p->out_max, "%u", data);
117
	CHECK_RET_OUTMAX_SNPRINTF
Daniel Salzman's avatar
Daniel Salzman committed
118 119 120 121 122 123 124 125
	out_len = ret;

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
126 127
}

Daniel Salzman's avatar
Daniel Salzman committed
128
static void wire_num16_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
129
{
130
	CHECK_PRET
131

Daniel Salzman's avatar
Daniel Salzman committed
132
	uint16_t data;
Daniel Salzman's avatar
Daniel Salzman committed
133 134
	size_t   in_len = sizeof(data);
	size_t   out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
135

136
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
137

Daniel Salzman's avatar
Daniel Salzman committed
138
	// Fill in input data.
139
	data = wire_read_u16(p->in);
Daniel Salzman's avatar
Daniel Salzman committed
140

Daniel Salzman's avatar
Daniel Salzman committed
141
	// Write number.
142
	int ret = snprintf(p->out, p->out_max, "%u", data);
143
	CHECK_RET_OUTMAX_SNPRINTF
Daniel Salzman's avatar
Daniel Salzman committed
144 145 146 147 148 149 150 151
	out_len = ret;

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
152 153
}

Daniel Salzman's avatar
Daniel Salzman committed
154
static void wire_num32_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
155
{
156
	CHECK_PRET
157

Daniel Salzman's avatar
Daniel Salzman committed
158
	uint32_t data;
Daniel Salzman's avatar
Daniel Salzman committed
159 160
	size_t   in_len = sizeof(data);
	size_t   out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
161

162
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
163

Daniel Salzman's avatar
Daniel Salzman committed
164
	// Fill in input data.
165
	data = wire_read_u32(p->in);
166 167 168

	// Write number.
	int ret = snprintf(p->out, p->out_max, "%u", data);
169
	CHECK_RET_OUTMAX_SNPRINTF
170 171 172 173 174 175 176 177 178 179 180 181
	out_len = ret;

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
}

static void wire_num48_to_str(rrset_dump_params_t *p)
{
182
	CHECK_PRET
183

184 185 186 187
	uint64_t data;
	size_t   in_len = 6;
	size_t   out_len = 0;

188
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
189

190
	// Fill in input data.
191
	data = wire_read_u48(p->in);
192

Daniel Salzman's avatar
Daniel Salzman committed
193
	// Write number.
194
	int ret = snprintf(p->out, p->out_max, "%"PRIu64"", data);
195
	CHECK_RET_OUTMAX_SNPRINTF
Daniel Salzman's avatar
Daniel Salzman committed
196 197 198 199 200 201 202 203
	out_len = ret;

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
204 205
}

Daniel Salzman's avatar
Daniel Salzman committed
206
static void wire_ipv4_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
207
{
208
	CHECK_PRET
209

Daniel Salzman's avatar
Daniel Salzman committed
210
	struct in_addr addr4;
Daniel Salzman's avatar
Daniel Salzman committed
211 212
	size_t in_len = sizeof(addr4.s_addr);
	size_t out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
213

214
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
215

216
	FILL_IN_INPUT(addr4.s_addr)
Daniel Salzman's avatar
Daniel Salzman committed
217

Daniel Salzman's avatar
Daniel Salzman committed
218 219
	// Write address.
	if (inet_ntop(AF_INET, &addr4, p->out, p->out_max) == NULL) {
220
		p->ret = -1;
Daniel Salzman's avatar
Daniel Salzman committed
221 222 223 224 225 226 227 228 229 230
		return;
	}
	out_len = strlen(p->out);

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
231 232
}

Daniel Salzman's avatar
Daniel Salzman committed
233
static void wire_ipv6_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
234
{
235
	CHECK_PRET
236

Daniel Salzman's avatar
Daniel Salzman committed
237
	struct in6_addr addr6;
Daniel Salzman's avatar
Daniel Salzman committed
238 239
	size_t in_len = sizeof(addr6.s6_addr);
	size_t out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
240

241
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
242

243
	FILL_IN_INPUT(addr6.s6_addr)
Daniel Salzman's avatar
Daniel Salzman committed
244

Daniel Salzman's avatar
Daniel Salzman committed
245 246
	// Write address.
	if (inet_ntop(AF_INET6, &addr6, p->out, p->out_max) == NULL) {
247
		p->ret = -1;
Daniel Salzman's avatar
Daniel Salzman committed
248 249 250 251 252 253 254 255 256 257
		return;
	}
	out_len = strlen(p->out);

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
258 259
}

Daniel Salzman's avatar
Daniel Salzman committed
260
static void wire_type_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
261
{
262
	CHECK_PRET
263

Daniel Salzman's avatar
Daniel Salzman committed
264
	char     type[32];
Daniel Salzman's avatar
Daniel Salzman committed
265 266 267
	uint16_t data;
	size_t   in_len = sizeof(data);
	size_t   out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
268

269
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
270

271
	FILL_IN_INPUT(data)
Daniel Salzman's avatar
Daniel Salzman committed
272 273

	// Get record type name string.
274 275
	int ret = knot_rrtype_to_string(ntohs(data), type, sizeof(type));
	CHECK_RET_POSITIVE
Daniel Salzman's avatar
Daniel Salzman committed
276

Daniel Salzman's avatar
Daniel Salzman committed
277
	// Write string.
278 279
	ret = snprintf(p->out, p->out_max, "%s", type);
	CHECK_RET_OUTMAX_SNPRINTF
Daniel Salzman's avatar
Daniel Salzman committed
280
	out_len = ret;
Daniel Salzman's avatar
Daniel Salzman committed
281

Daniel Salzman's avatar
Daniel Salzman committed
282 283 284 285 286 287
	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
288 289
}

Daniel Salzman's avatar
Daniel Salzman committed
290 291 292 293 294 295
static int hex_encode(const uint8_t  *in,
                      const uint32_t in_len,
                      uint8_t        *out,
                      const uint32_t out_len)
{
	static const char hex[] = "0123456789ABCDEF";
Daniel Salzman's avatar
Daniel Salzman committed
296

Daniel Salzman's avatar
Daniel Salzman committed
297 298 299
	if (out_len < 2 * in_len) {
		return -1;
	}
Daniel Salzman's avatar
Daniel Salzman committed
300

Daniel Salzman's avatar
Daniel Salzman committed
301 302 303 304
	for (uint32_t i = 0; i < in_len; i++) {
		out[2 * i]     = hex[in[i] / 16];
		out[2 * i + 1] = hex[in[i] % 16];
	}
Daniel Salzman's avatar
Daniel Salzman committed
305

Daniel Salzman's avatar
Daniel Salzman committed
306 307
	return 2 * in_len;
}
Daniel Salzman's avatar
Daniel Salzman committed
308

Daniel Salzman's avatar
Daniel Salzman committed
309 310 311 312 313
static int hex_encode_alloc(const uint8_t  *in,
                            const uint32_t in_len,
                            uint8_t        **out)
{
	uint32_t out_len = 2 * in_len;
Daniel Salzman's avatar
Daniel Salzman committed
314

Daniel Salzman's avatar
Daniel Salzman committed
315 316
	// Allocating output buffer.
	*out = malloc(out_len);
Daniel Salzman's avatar
Daniel Salzman committed
317

Daniel Salzman's avatar
Daniel Salzman committed
318
	if (*out == NULL) {
Daniel Salzman's avatar
Daniel Salzman committed
319 320 321
		return -1;
	}

Daniel Salzman's avatar
Daniel Salzman committed
322 323
	// Encoding data.
	return hex_encode(in, in_len, *out, out_len);
Daniel Salzman's avatar
Daniel Salzman committed
324 325
}

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
static int num48_encode(const uint8_t  *in,
                        const uint32_t in_len,
                        uint8_t        *out,
                        const uint32_t out_len)
{
	if (in_len != 6) {
		return -1;
	}

	uint64_t data = wire_read_u48(in);

	int ret = snprintf((char *)out, out_len, "%"PRIu64"", data);
	if (ret <= 0 || (size_t)ret >= out_len) {
		return -1;
	}

	return ret;
}

Daniel Salzman's avatar
Daniel Salzman committed
345 346 347 348 349 350 351 352
typedef int (*encode_t)(const uint8_t *in, const uint32_t in_len,
                        uint8_t *out, const uint32_t out_len);

typedef int (*encode_alloc_t)(const uint8_t *in, const uint32_t in_len,
                              uint8_t **out);

static void wire_data_encode_to_str(rrset_dump_params_t *p,
                                    encode_t enc, encode_alloc_t enc_alloc)
Daniel Salzman's avatar
Daniel Salzman committed
353
{
354
	CHECK_PRET
355

356
	int    ret;
Daniel Salzman's avatar
Daniel Salzman committed
357 358
	size_t in_len = p->in_max;

Daniel Salzman's avatar
Daniel Salzman committed
359
	// One-line vs multi-line mode.
360
	if (p->style->wrap == false) {
Daniel Salzman's avatar
Daniel Salzman committed
361
		// Encode data directly to the output.
Daniel Salzman's avatar
Daniel Salzman committed
362
		ret = enc(p->in, in_len, (uint8_t *)(p->out), p->out_max);
363
		CHECK_RET_POSITIVE
Daniel Salzman's avatar
Daniel Salzman committed
364
		size_t out_len = ret;
Daniel Salzman's avatar
Daniel Salzman committed
365

Daniel Salzman's avatar
Daniel Salzman committed
366 367 368
		p->out += out_len;
		p->out_max -= out_len;
		p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
369
	} else {
370
		int     src_begin;
371
		uint8_t *buf;
Daniel Salzman's avatar
Daniel Salzman committed
372 373

		// Encode data to the temporary buffer.
374
		ret = enc_alloc(p->in, in_len, &buf);
375
		CHECK_RET_POSITIVE
Daniel Salzman's avatar
Daniel Salzman committed
376

Daniel Salzman's avatar
Daniel Salzman committed
377
		// Loop which wraps base64 block in more lines.
Daniel Salzman's avatar
Daniel Salzman committed
378
		for (src_begin = 0; src_begin < ret; src_begin += BLOCK_WIDTH) {
379 380 381
			if (src_begin > 0) {
				// Write indent block.
				dump_string(p, BLOCK_INDENT);
382
				if (p->ret < 0) {
383 384 385
					free(buf);
					return;
				}
Daniel Salzman's avatar
Daniel Salzman committed
386
			}
Daniel Salzman's avatar
Daniel Salzman committed
387 388

			// Compute block length (the last one can be shorter).
389 390
			int src_len = (ret - src_begin) < BLOCK_WIDTH ?
			              (ret - src_begin) : BLOCK_WIDTH;
Daniel Salzman's avatar
Daniel Salzman committed
391

392
			if ((size_t)src_len > p->out_max) {
Daniel Salzman's avatar
Daniel Salzman committed
393
				free(buf);
394
				p->ret = -1;
Daniel Salzman's avatar
Daniel Salzman committed
395 396 397
				return;
			}

Daniel Salzman's avatar
Daniel Salzman committed
398
			// Write data block.
Daniel Salzman's avatar
Daniel Salzman committed
399
			memcpy(p->out, buf + src_begin, src_len);
Daniel Salzman's avatar
Daniel Salzman committed
400

Daniel Salzman's avatar
Daniel Salzman committed
401 402 403 404
			p->out += src_len;
			p->out_max -= src_len;
			p->total += src_len;
		}
Daniel Salzman's avatar
Daniel Salzman committed
405 406 407 408 409

		// Destroy temporary buffer.
		free(buf);
	}

410
	STRING_TERMINATION
411 412 413 414 415 416

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
}

417 418 419 420 421
static void wire_len_data_encode_to_str(rrset_dump_params_t *p,
                                        encode_t            enc,
                                        const size_t        len_len,
                                        const bool          print_len,
                                        const char          *empty_str)
422
{
423
	CHECK_PRET
424

425 426 427
	size_t in_len;

	// First len_len bytes are data length.
428
	CHECK_INMAX(len_len)
429 430 431 432 433 434 435

	// Read data length.
	switch (len_len) {
	case 1:
		in_len = *(p->in);
		break;
	case 2:
436
		in_len = wire_read_u16(p->in);
437 438
		break;
	case 4:
439
		in_len = wire_read_u32(p->in);
440 441
		break;
	default:
442
		p->ret = -1;
443 444 445
		return;
	}

446
	// If required print data length.
447 448 449 450 451 452 453 454 455 456 457 458 459
	if (print_len == true) {
		switch (len_len) {
		case 1:
			wire_num8_to_str(p);
			break;
		case 2:
			wire_num16_to_str(p);
			break;
		case 4:
			wire_num32_to_str(p);
			break;
		}

460
		CHECK_PRET
461

462 463 464
		// If something follows, print one space character.
		if (in_len > 0 || *empty_str != '\0') {
			dump_string(p, " ");
465
			CHECK_PRET
466
		}
467 468 469
	} else {
		p->in += len_len;
		p->in_max -= len_len;
470
	}
471

472 473 474
	if (in_len > 0) {
		// Encode data directly to the output.
		int ret = enc(p->in, in_len, (uint8_t *)(p->out), p->out_max);
475
		CHECK_RET_POSITIVE
476 477 478
		p->out += ret;
		p->out_max -= ret;
		p->total += ret;
Jan Včelák's avatar
Jan Včelák committed
479

480
		STRING_TERMINATION
481

482 483 484
		// Fill in output.
		p->in += in_len;
		p->in_max -= in_len;
485
	} else if (*empty_str != '\0') {
486
		dump_string(p, empty_str);
487
		CHECK_PRET
Daniel Salzman's avatar
Daniel Salzman committed
488 489 490
	}
}

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
static void wire_data_omit(rrset_dump_params_t *p)
{
	CHECK_PRET

	const char *omit_message = "[omitted]";
	const size_t omlen = strlen(omit_message);

	if (p->out_max < omlen) {
		p->ret = -1;
		return;
	}

	memcpy(p->out, omit_message, omlen);
	p->out += omlen;
	p->out_max -= omlen;
	p->total += omlen;

	STRING_TERMINATION

	p->in += p->in_max;
	p->in_max = 0;
}

static void wire_dnskey_to_tag(rrset_dump_params_t *p)
{
	CHECK_PRET

	int key_pos = -4; // we expect that key flags, 3 and algorithm
	                  // have been already dumped

	uint16_t key_tag = 0;
	const dnssec_binary_t rdata_bin = {
		.data = (uint8_t *)(p->in + key_pos),
		.size = p->in_max - key_pos
	};
	dnssec_keytag(&rdata_bin, &key_tag);

	int ret = snprintf(p->out, p->out_max, "[id = %hu]", key_tag);
	CHECK_RET_OUTMAX_SNPRINTF

	p->in += p->in_max;
	p->in_max = 0;
	p->out += ret;
	p->out_max -= ret;
	p->total += ret;
}

538 539
static void wire_unknown_to_str(rrset_dump_params_t *p)
{
540
	CHECK_PRET
541

542 543 544 545 546 547 548 549 550 551
	int    ret;
	size_t in_len = p->in_max;
	size_t out_len = 0;

	// Write unknown length header.
	if (in_len > 0) {
		ret = snprintf(p->out, p->out_max, "\\# %zu ", in_len);
	} else {
		ret = snprintf(p->out, p->out_max, "\\# 0");
	}
552
	CHECK_RET_OUTMAX_SNPRINTF
553 554 555 556 557 558 559 560 561 562 563 564
	out_len = ret;

	// Fill in output.
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;

	// Write hex data if any.
	if (in_len > 0) {
		// If wrap mode wrap line.
		if (p->style->wrap) {
			dump_string(p, BLOCK_INDENT);
565
			CHECK_PRET
566 567 568
		}

		wire_data_encode_to_str(p, &hex_encode, &hex_encode_alloc);
569
		CHECK_PRET
570 571 572
	}
}

573
static void wire_text_to_str(rrset_dump_params_t *p, bool quote, bool with_header)
Daniel Salzman's avatar
Daniel Salzman committed
574
{
575
	CHECK_PRET
576

577 578 579 580
	size_t in_len = 0;

	if (with_header) {
		// First byte is string length.
581
		CHECK_INMAX(1)
582 583 584 585 586
		in_len = *(p->in);
		p->in++;
		p->in_max--;

		// Check if the given length makes sense.
587
		CHECK_INMAX(in_len)
588 589
	} else {
		in_len = p->in_max;
Daniel Salzman's avatar
Daniel Salzman committed
590
	}
Daniel Salzman's avatar
Daniel Salzman committed
591

592 593 594 595 596 597 598 599
	// Check if quotation can ever be disabled (parser protection fallback).
	if (!quote) {
		for (size_t i = 0; i < in_len; i++) {
			if (p->in[i] == ' ') { // Other WS characters are encoded.
				quote = true;
				break;
			}
		}
600
	}
Daniel Salzman's avatar
Daniel Salzman committed
601

602 603 604
	// Opening quotation.
	if (quote) {
		dump_string(p, "\"");
605
		CHECK_PRET
Daniel Salzman's avatar
Daniel Salzman committed
606 607 608
	}

	// Loop over all characters.
609
	for (size_t i = 0; i < in_len; i++) {
610
		uint8_t ch = p->in[i];
Daniel Salzman's avatar
Daniel Salzman committed
611

612
		if (is_print(ch)) {
Daniel Salzman's avatar
Daniel Salzman committed
613
			// For special character print leading slash.
Daniel Salzman's avatar
Daniel Salzman committed
614
			if (ch == '\\' || ch == '"') {
615
				dump_string(p, "\\");
616
				CHECK_PRET
Daniel Salzman's avatar
Daniel Salzman committed
617 618
			}

Daniel Salzman's avatar
Daniel Salzman committed
619 620
			// Print text character.
			if (p->out_max == 0) {
621
				p->ret = -1;
Daniel Salzman's avatar
Daniel Salzman committed
622
				return;
623
			}
Daniel Salzman's avatar
Daniel Salzman committed
624 625 626 627 628

			*p->out = ch;
			p->out++;
			p->out_max--;
			p->total++;
Daniel Salzman's avatar
Daniel Salzman committed
629
		} else {
Daniel Salzman's avatar
Daniel Salzman committed
630 631
			// Unprintable character encode via \ddd notation.
			int ret = snprintf(p->out, p->out_max,"\\%03u", ch);
632
			CHECK_RET_OUTMAX_SNPRINTF
Daniel Salzman's avatar
Daniel Salzman committed
633

Daniel Salzman's avatar
Daniel Salzman committed
634 635 636
			p->out += ret;
			p->out_max -= ret;
			p->total += ret;
Daniel Salzman's avatar
Daniel Salzman committed
637 638 639
		}
	}

640 641 642
	// Closing quotation.
	if (quote) {
		dump_string(p, "\"");
643
		CHECK_PRET
644
	}
Daniel Salzman's avatar
Daniel Salzman committed
645

646
	STRING_TERMINATION
Daniel Salzman's avatar
Daniel Salzman committed
647 648 649 650

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
Daniel Salzman's avatar
Daniel Salzman committed
651 652
}

653
static void wire_timestamp_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
654
{
655
	CHECK_PRET
656

657 658 659 660
	uint32_t data;
	size_t   in_len = sizeof(data);
	size_t   out_len = 0;
	int      ret;
Daniel Salzman's avatar
Daniel Salzman committed
661

662
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
663

664
	FILL_IN_INPUT(data)
Daniel Salzman's avatar
Daniel Salzman committed
665

666 667
	time_t timestamp = ntohl(data);

668
	if (p->style->human_tmstamp) {
669
		struct tm result;
670 671
		// Write timestamp in YYYYMMDDhhmmss format.
		ret = strftime(p->out, p->out_max, "%Y%m%d%H%M%S",
672
		               gmtime_r(&timestamp, &result));
673
		CHECK_RET_POSITIVE
674 675 676
	} else {
		// Write timestamp only.
		ret = snprintf(p->out, p->out_max, "%u", ntohl(data));
677
		CHECK_RET_OUTMAX_SNPRINTF
Daniel Salzman's avatar
Daniel Salzman committed
678
	}
679
	out_len = ret;
Daniel Salzman's avatar
Daniel Salzman committed
680

681 682 683 684 685 686
	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
687 688
}

689 690 691
static int time_to_human_str(char         *out,
                             const size_t out_len,
                             uint32_t     data)
Daniel Salzman's avatar
Daniel Salzman committed
692
{
693 694 695
	size_t   total_len = 0;
	uint32_t num;
	int      ret;
Daniel Salzman's avatar
Daniel Salzman committed
696

697 698 699 700 701 702 703 704 705 706
#define tths_process(unit_name, unit_size) \
	num = data / (unit_size); \
	if (num > 0) { \
		ret = snprintf(out + total_len, out_len - total_len, \
		               "%u%s", num, (unit_name)); \
		if (ret <= 0 || (size_t)ret >= out_len - total_len) { \
			return -1; \
		} \
		total_len += ret; \
		data -= num * (unit_size); \
Daniel Salzman's avatar
Daniel Salzman committed
707 708
	}

709 710 711 712
	tths_process("d", 86400);
	tths_process("h", 3600);
	tths_process("m", 60);
	tths_process("s", 1);
Daniel Salzman's avatar
Daniel Salzman committed
713

714
#undef tths_process
Daniel Salzman's avatar
Daniel Salzman committed
715

716
	return total_len > 0 ? total_len : -1;
Daniel Salzman's avatar
Daniel Salzman committed
717 718
}

719
static void wire_ttl_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
720
{
721
	CHECK_PRET
722

723 724 725 726
	uint32_t data;
	size_t   in_len = sizeof(data);
	size_t   out_len = 0;
	int      ret;
Daniel Salzman's avatar
Daniel Salzman committed
727

728
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
729

730
	FILL_IN_INPUT(data)
Daniel Salzman's avatar
Daniel Salzman committed
731

732
	if (p->style->human_ttl) {
733 734
		// Write time in human readable format.
		ret = time_to_human_str(p->out, p->out_max, ntohl(data));
735
		CHECK_RET_POSITIVE
736 737 738
	} else {
		// Write timestamp only.
		ret = snprintf(p->out, p->out_max, "%u", ntohl(data));
739
		CHECK_RET_OUTMAX_SNPRINTF
740 741 742 743 744 745 746 747 748
	}
	out_len = ret;

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
749 750
}

751
static void wire_bitmap_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
752
{
753
	CHECK_PRET
754

755 756 757 758 759 760
	int    ret;
	char   type[32];
	size_t i = 0;
	size_t in_len = p->in_max;
	size_t out_len = 0;

Daniel Salzman's avatar
Daniel Salzman committed
761 762 763
	// Loop over bitmap window array (can be empty).
	while (i < in_len) {
		// First byte is window number.
764
		uint8_t win = p->in[i++];
Daniel Salzman's avatar
Daniel Salzman committed
765

766
		// Check window length (length must follow).
Daniel Salzman's avatar
Daniel Salzman committed
767
		if (i >= in_len) {
768
			p->ret = -1;
769
			return;
Daniel Salzman's avatar
Daniel Salzman committed
770 771 772
		}

		// Second byte is window length.
773
		uint8_t bitmap_len = p->in[i++];
Daniel Salzman's avatar
Daniel Salzman committed
774 775 776

		// Check window length (len bytes must follow).
		if (i + bitmap_len > in_len) {
777
			p->ret = -1;
778
			return;
Daniel Salzman's avatar
Daniel Salzman committed
779 780 781
		}

		// Bitmap processing.
782 783 784
		for (size_t j = 0; j < (bitmap_len * 8); j++) {
			if ((p->in[i + j / 8] & (128 >> (j % 8))) != 0) {
				uint16_t type_num = win * 256 + j;
Daniel Salzman's avatar
Daniel Salzman committed
785

786 787
				ret = knot_rrtype_to_string(type_num, type, sizeof(type));
				CHECK_RET_POSITIVE
Daniel Salzman's avatar
Daniel Salzman committed
788

789 790 791 792 793 794 795 796
				// Print type name to type list.
				if (out_len > 0) {
					ret = snprintf(p->out, p->out_max,
					               " %s", type);
				} else {
					ret = snprintf(p->out, p->out_max,
					               "%s", type);
				}
797
				CHECK_RET_OUTMAX_SNPRINTF
798
				out_len += ret;
Daniel Salzman's avatar
Daniel Salzman committed
799 800
				p->out += ret;
				p->out_max -= ret;
Daniel Salzman's avatar
Daniel Salzman committed
801 802 803 804 805 806
			}
		}

		i += bitmap_len;
	}

807 808 809 810
	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->total += out_len;
Daniel Salzman's avatar
Daniel Salzman committed
811 812
}

Daniel Salzman's avatar
Daniel Salzman committed
813
static void wire_dname_to_str(rrset_dump_params_t *p)
Daniel Salzman's avatar
Daniel Salzman committed
814
{
815
	CHECK_PRET
816

817 818
	int in_len = knot_dname_size(p->in);
	if (in_len < 0) {
819
		p->ret = -1;
820 821 822
		return;
	}

Daniel Salzman's avatar
Daniel Salzman committed
823
	size_t out_len = 0;
Daniel Salzman's avatar
Daniel Salzman committed
824

825
	CHECK_INMAX(in_len)
Daniel Salzman's avatar
Daniel Salzman committed
826

Daniel Salzman's avatar
Daniel Salzman committed
827
	// Write dname string.
828 829 830
	if (p->style->ascii_to_idn == NULL) {
		char *dname_str = knot_dname_to_str(p->out, p->in, p->out_max);
		if (dname_str == NULL) {
831
			p->ret = -1;
832 833 834 835 836
			return;
		}
		out_len = strlen(dname_str);
	} else {
		char *dname_str = knot_dname_to_str_alloc(p->in);
837
		p->style->ascii_to_idn(&dname_str);
838 839 840

		int ret = snprintf(p->out, p->out_max, "%s", dname_str);
		free(dname_str);
841
		CHECK_RET_OUTMAX_SNPRINTF
842
		out_len = ret;
Daniel Salzman's avatar
Daniel Salzman committed
843
	}
Daniel Salzman's avatar
Daniel Salzman committed
844 845 846 847 848 849 850 851 852

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;
}

853 854
static void wire_apl_to_str(rrset_dump_params_t *p)
{
855
	CHECK_PRET
856

857 858 859 860 861 862
	struct in_addr addr4;
	struct in6_addr addr6;
	int    ret;
	size_t out_len = 0;

	// Input check: family(2B) + prefix(1B) + afdlen(1B).
863
	CHECK_INMAX(4)
864 865

	// Read fixed size values.
866
	uint16_t family   = wire_read_u16(p->in);
867 868 869 870 871 872 873 874 875
	uint8_t  prefix   = *(p->in + 2);
	uint8_t  negation = *(p->in + 3) >> 7;
	uint8_t  afdlen   = *(p->in + 3) & 0x7F;
	p->in += 4;
	p->in_max -= 4;

	// Write negation mark.
	if (negation != 0) {
		dump_string(p, "!");
876
		CHECK_PRET
877 878 879 880
	}

	// Write address family with colon.
	ret = snprintf(p->out, p->out_max, "%u:", family);
881
	CHECK_RET_OUTMAX_SNPRINTF
882 883 884 885 886 887 888 889 890 891
	p->out += ret;
	p->out_max -= ret;
	p->total += ret;

	// Write address.
	switch (family) {
	case 1:
		memset(&addr4, 0, sizeof(addr4));

		if (afdlen > sizeof(addr4.s_addr) || afdlen > p->in_max) {
892
			p->ret = -1;
893 894 895 896
			return;
		}

		if (memcpy(&(addr4.s_addr), p->in, afdlen) == NULL) {
897
			p->ret = -1;
898 899 900 901 902
			return;
		}

		// Write address.
		if (inet_ntop(AF_INET, &addr4, p->out, p->out_max) == NULL) {
903
			p->ret = -1;
904 905 906 907 908 909 910 911 912
			return;
		}
		out_len = strlen(p->out);

		break;
	case 2:
		memset(&addr6, 0, sizeof(addr6));

		if (afdlen > sizeof(addr6.s6_addr) || afdlen > p->in_max) {
913
			p->ret = -1;
914 915 916 917
			return;
		}

		if (memcpy(&(addr6.s6_addr), p->in, afdlen) == NULL) {
918
			p->ret = -1;
919 920 921 922 923
			return;
		}

		// Write address.
		if (inet_ntop(AF_INET6, &addr6, p->out, p->out_max) == NULL) {
924
			p->ret = -1;
925 926 927 928 929 930
			return;
		}
		out_len = strlen(p->out);

		break;
	default:
931
		p->ret = -1;
932 933 934 935 936 937 938 939 940 941
		return;
	}
	p->in += afdlen;
	p->in_max -= afdlen;
	p->out += out_len;
	p->out_max -= out_len;
	p->total += out_len;

	// Write prefix length with forward slash.
	ret = snprintf(p->out, p->out_max, "/%u", prefix);
942
	CHECK_RET_OUTMAX_SNPRINTF
943 944 945 946 947
	p->out += ret;
	p->out_max -= ret;
	p->total += ret;
}

948 949
static void wire_loc_to_str(rrset_dump_params_t *p)
{
950
	CHECK_PRET
951

952 953 954
	// Read values.
	wire_ctx_t wire = wire_ctx_init_const(p->in, p->in_max);
	uint8_t version = wire_ctx_read_u8(&wire);
955 956 957 958

	// Version check.
	if (version != 0) {
		wire_unknown_to_str(p);
959
		p->ret = -1;
960 961 962 963
		return;
	}

	// Continue to read values.
964 965 966 967 968 969 970 971 972
	uint8_t size_w = wire_ctx_read_u8(&wire);
	uint8_t hpre_w = wire_ctx_read_u8(&wire);
	uint8_t vpre_w = wire_ctx_read_u8(&wire);
	uint32_t lat_w = wire_ctx_read_u32(&wire);
	uint32_t lon_w = wire_ctx_read_u32(&wire);
	uint32_t alt_w = wire_ctx_read_u32(&wire);

	// Check if all reads are correct.
	if (wire.error != KNOT_EOK) {
973
		p->ret = -1;
974 975 976
		return;
	}

977 978
	p->in += wire_ctx_offset(&wire);
	p->in_max = wire_ctx_available(&wire);
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002

	// Latitude calculation.
	char lat_mark;
	uint32_t lat;
	if (lat_w >= LOC_ZERO) {
		lat_mark = 'N';
		lat = lat_w - LOC_ZERO;
	} else {
		lat_mark = 'S';
		lat = LOC_ZERO - lat_w;
	}

	uint32_t d1 = lat / 3600000;
	uint32_t m1 = (lat - 3600000 * d1) / 60000;
	double s1 = 0.001 * (lat - 3600000 * d1 - 60000 * m1);

	// Longitude calculation.
	char lon_mark;
	uint32_t lon;
	if (lon_w >= LOC_ZERO) {
		lon_mark = 'E';
		lon = lon_w - LOC_ZERO;
	} else {
		lon_mark = 'W';
Jan Včelák's avatar
Jan Včelák committed
1003
		lon = LOC_ZERO - lon_w;
1004 1005 1006 1007 1008 1009
	}

	uint32_t d2 = lon / 3600000;
	uint32_t m2 = (lon - 3600000 * d2) / 60000;
	double s2 = 0.001 * (lon - 3600000 * d2 - 60000 * m2);

Jan Včelák's avatar
Jan Včelák committed
1010
	// Write latitude and longitude.
1011 1012 1013
	int ret = snprintf(p->out, p->out_max, "%u %u %.*f %c  %u %u %.*f %c",
	                   d1, m1, (uint32_t)s1 != s1 ? 3 : 0, s1, lat_mark,
	                   d2, m2, (uint32_t)s2 != s2 ? 3 : 0, s2, lon_mark);
1014
	CHECK_RET_OUTMAX_SNPRINTF
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
	p->out += ret;
	p->out_max -= ret;
	p->total += ret;

	// Altitude calculation.
	double alt = 0.01 * alt_w - 100000.0;

	// Compute mantisa and exponent for each size.
	uint8_t size_m = size_w >> 4;
	uint8_t size_e = size_w & 0xF;
	uint8_t hpre_m = hpre_w >> 4;
	uint8_t hpre_e = hpre_w & 0xF;
	uint8_t vpre_m = vpre_w >> 4;
	uint8_t vpre_e = vpre_w & 0xF;

	// Sizes check.
	if (size_m > 9 || size_e > 9 || hpre_m > 9 || hpre_e > 9 ||
	    vpre_m > 9 || vpre_e > 9) {
1033
		p->ret = -1;
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
		return;
	}

	// Size and precisions calculation.
	double size = 0.01 * size_m * pow(10, size_e);
	double hpre = 0.01 * hpre_m * pow(10, hpre_e);
	double vpre = 0.01 * vpre_m * pow(10, vpre_e);

	// Write altitude and precisions.
	ret = snprintf(p->out, p->out_max, "  %.*fm  %.*fm %.*fm %.*fm",
	               (int32_t)alt != alt ? 2 : 0, alt,
	               (uint32_t)size != size ? 2 : 0, size,
	               (uint32_t)hpre != hpre ? 2 : 0, hpre,
	               (uint32_t)vpre != vpre ? 2 : 0, vpre);
1048
	CHECK_RET_OUTMAX_SNPRINTF
1049 1050 1051 1052 1053
	p->out += ret;
	p->out_max -= ret;
	p->total += ret;
}

1054 1055
static void wire_gateway_to_str(rrset_dump_params_t *p)
{
1056
	CHECK_PRET
1057

1058
	// Input check: type(1B) + algo(1B).
1059
	CHECK_INMAX(2)
1060 1061 1062 1063 1064 1065

	uint8_t type = *p->in;
	uint8_t alg = *(p->in + 1);

	// Write gateway type.
	wire_num8_to_str(p);
1066
	CHECK_PRET
1067 1068 1069

	// Write space.
	dump_string(p, " ");
1070
	CHECK_PRET
1071 1072 1073

	// Write algorithm number.
	wire_num8_to_str(p);
1074
	CHECK_PRET
1075 1076 1077

	// Write space.
	dump_string(p, " ");
1078
	CHECK_PRET
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094

	// Write appropriate gateway.
	switch (type) {
	case 0:
		dump_string(p, ".");
		break;
	case 1:
		wire_ipv4_to_str(p);
		break;
	case 2:
		wire_ipv6_to_str(p);
		break;
	case 3:
		wire_dname_to_str(p);
		break;
	default:
1095
		p->ret = -1;
1096
	}
1097
	CHECK_PRET
1098 1099

	if (alg > 0) {
1100 1101 1102 1103 1104 1105
		// If wrap mode wrap line.
		if (p->style->wrap) {
			dump_string(p, BLOCK_INDENT);
		} else {
			dump_string(p, " ");
		}
1106
		CHECK_PRET
1107 1108 1109

		// Write ipsec key.
		wire_data_encode_to_str(p, &base64_encode, &base64_encode_alloc);
1110
		CHECK_PRET
1111 1112 1113
	}
}

1114 1115
static void wire_l64_to_str(rrset_dump_params_t *p)
{
1116
	CHECK_PRET
1117

1118 1119
	// Check input size (64-bit identifier).
	if (p->in_max != 8) {
1120
		p->ret = -1;
1121 1122 1123 1124 1125 1126
		return;
	}

	// Write identifier (2-byte) labels separated with a colon.
	while (p->in_max > 0) {
		int ret = hex_encode(p->in, 2, (uint8_t *)(p->out), p->out_max);
1127
		CHECK_RET_POSITIVE
1128 1129 1130 1131 1132 1133 1134 1135 1136
		p->in += 2;
		p->in_max -= 2;
		p->out += ret;
		p->out_max -= ret;
		p->total += ret;

		// Write separation character.
		if (p->in_max > 0) {
			dump_string(p, ":");
1137
			CHECK_PRET
1138 1139 1140 1141
		}
	}
}

1142 1143
static void wire_eui_to_str(rrset_dump_params_t *p)
{
1144
	CHECK_PRET
1145

1146
	CHECK_INMAX(2)
1147 1148 1149 1150

	// Write EUI hexadecimal pairs.
	while (p->in_max > 0) {
		int ret = hex_encode(p->in, 1, (uint8_t *)(p->out), p->out_max);
1151
		CHECK_RET_POSITIVE
1152 1153 1154 1155 1156 1157 1158 1159 1160
		p->in++;
		p->in_max--;
		p->out += ret;
		p->out_max -= ret;
		p->total += ret;

		// Write separation character.
		if (p->in_max > 0) {
			dump_string(p, "-");
1161
			CHECK_PRET
1162 1163 1164 1165
		}
	}
}

1166
static void wire_tsig_rcode_to_str(rrset_dump_params_t *p)
1167
{
1168
	CHECK_PRET
1169

1170 1171
	uint16_t data;
	size_t   in_len = sizeof(data);
1172
	const char *rcode_str = "Unknown";
1173

1174
	CHECK_INMAX(in_len)
1175 1176

	// Fill in input data.
1177
	data = wire_read_u16(p->in);
1178 1179

	// Find RCODE name.
1180
	const knot_lookup_t *rcode = NULL;
1181 1182 1183 1184
	rcode = knot_lookup_by_id(knot_tsig_rcode_names, data);
	if (rcode == NULL) {
		rcode = knot_lookup_by_id(knot_rcode_names, data);
	}
1185 1186 1187 1188 1189 1190
	if (rcode != NULL) {
		rcode_str = rcode->name;
	}

	// Dump RCODE name.
	dump_string(p, rcode_str);
1191
	CHECK_PRET
1192 1193 1194 1195 1196 1197

	// Fill in output.
	p->in += in_len;
	p->in_max -= in_len;
}

1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
static size_t dnskey_len(const uint8_t *rdata,
                         const size_t  rdata_len)
{
	// Check for empty rdata and empty key.
	if (rdata_len <= 4) {
		return 0;
	}

	const uint8_t *key = rdata + 4;
	const size_t  len = rdata_len - 4;

	switch (rdata[3]) {
	case KNOT_DNSSEC_ALG_DSA:
	case KNOT_DNSSEC_ALG_DSA_NSEC3_SHA1:
1212
		// RFC 2536, key size ~ bit-length of 'modulus' P.
1213 1214 1215 1216 1217 1218
		return (64 + 8 * key[0]) * 8;
	case KNOT_DNSSEC_ALG_RSAMD5:
	case KNOT_DNSSEC_ALG_RSASHA1:
	case KNOT_DNSSEC_ALG_RSASHA1_NSEC3_SHA1:
	case KNOT_DNSSEC_ALG_RSASHA256:
	case KNOT_DNSSEC_ALG_RSASHA512:
1219
		// RFC 3110, key size ~ bit-length of 'modulus'.
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
		if (key[0] == 0) {
			if (len < 3) {
				return 0;
			}
			uint16_t exp;
			memcpy(&exp, key + 1, sizeof(uint16_t));
			return (len - 3 - ntohs(exp)) * 8;
		} else {
			return (len - 1 - key[0]) * 8;
		}
	case KNOT_DNSSEC_ALG_ECC_GOST:
1231
		// RFC 5933, key size of GOST public keys MUST be 512 bits.
1232 1233
		return 512;
	case KNOT_DNSSEC_ALG_ECDSAP256SHA256:
1234
		// RFC 6605.
1235 1236
		return 256;
	case KNOT_DNSSEC_ALG_ECDSAP384SHA384:
1237
		// RFC 6605.
1238
		return 384;
1239
	case KNOT_DNSSEC_ALG_ED25519:
1240
		// RFC 8080.
1241 1242
		return 256;
	case KNOT_DNSSEC_ALG_ED448:
1243
		// RFC 8080.
1244
		return 456;
1245 1246 1247 1248 1249
	default:
		return 0;
	}
}

1250 1251 1252 1253 1254
static void dnskey_info(const uint8_t *rdata,
                        const size_t  rdata_len,
                        char          *out,
                        const size_t  out_len)
{
1255 1256 1257 1258 1259 1260
	// TODO: migrate key info to libdnssec

	const uint8_t sep = *(rdata + 1) & 0x01;
	uint16_t      key_tag = 0;
	const size_t  key_len = dnskey_len(rdata, rdata_len);
	const uint8_t alg_id = rdata[3];
1261 1262 1263 1264

	const dnssec_binary_t rdata_bin = { .data = (uint8_t *)rdata,
	                                    .size = rdata_len };
	dnssec_keytag(&rdata_bin, &key_tag);
1265

1266 1267
	const knot_lookup_t *alg = NULL;
	alg = knot_lookup_by_id(knot_dnssec_alg_names, alg_id);
1268

1269
	int ret = snprintf(out, out_len, "%s, %s (%zub), id = %u",
1270 1271
	                   sep ? "KSK" : "ZSK",
	                   alg ? alg->name : "UNKNOWN",
1272
	                   key_len, key_tag );
1273 1274

	if (ret <= 0) {	// Truncated return is acceptable. Just check for errors.
1275
		out[0] = '\0';
1276 1277 1278
	}
}

1279 1280
#define DUMP_PARAMS	rrset_dump_params_t *const p
#define	DUMP_END	return (p->in_max == 0 ? (int)p->total : KNOT_EPARSEFAIL);
Daniel Salzman's avatar
Daniel Salzman committed
1281

1282
#define CHECK_RET(p)	if (p->ret < 0) return p->ret;
Daniel Salzman's avatar
Daniel Salzman committed
1283

1284 1285 1286
#define WRAP_INIT	dump_string(p, "(" BLOCK_INDENT); CHECK_RET(p);
#define WRAP_END	dump_string(p, BLOCK_INDENT ")"); CHECK_RET(p);
#define WRAP_LINE	dump_string(p, BLOCK_INDENT); CHECK_RET(p);
1287

1288 1289 1290
#define COMMENT(s)	if (p->style->verbose) { \
			    dump_string(p, " ; "); CHECK_RET(p); \
			    dump_string(p, s); CHECK_RET(p); \
1291
			}
1292

1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
#define DUMP_SPACE	dump_string(p, " "); CHECK_RET(p);
#define DUMP_NUM8	wire_num8_to_str(p); CHECK_RET(p);
#define DUMP_NUM16	wire_num16_to_str(p); CHECK_RET(p);
#define DUMP_NUM32	wire_num32_to_str(p); CHECK_RET(p);
#define DUMP_NUM48	wire_num48_to_str(p); CHECK_RET(p);
#define DUMP_DNAME	wire_dname_to_str(p); CHECK_RET(p);
#define DUMP_TIME	wire_ttl_to_str(p); CHECK_RET(p);
#define DUMP_TIMESTAMP	wire_timestamp_to_str(p); CHECK_RET(p);
#define DUMP_IPV4	wire_ipv4_to_str(p); CHECK_RET(p);
#define DUMP_IPV6	wire_ipv6_to_str(p); CHECK_RET(p);
#define DUMP_TYPE	wire_type_to_str(p); CHECK_RET(p);
#define DUMP_HEX	wire_data_encode_to_str(p, &hex_encode, \
1305
				&hex_encode_alloc); CHECK_RET(p);
1306
#define DUMP_BASE64	wire_data_encode_to_str(p, &base64_encode, \
1307
				&base64_encode_alloc); CHECK_RET(p);
1308
#define DUMP_HASH	wire_len_data_encode_to_str(p, &base32hex_encode, \
1309
				1, false, ""); CHECK_RET(p);
1310
#define DUMP_SALT	wire_len_data_encode_to_str(p, &hex_encode, \
1311
				1, false, "-"); CHECK_RET(p);
1312
#define DUMP_TSIG_DGST	wire_len_data_encode_to_str(p, &base64_encode, \