exec.c 18.7 KB
Newer Older
1
/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 4 5 6 7 8 9 10 11 12 13

    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
14
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
15 16
*/

17 18 19
#include <arpa/inet.h>
#include <stdlib.h>
#include <time.h>
20

21
#include "libdnssec/random.h"
22 23 24 25
#include "utils/common/exec.h"
#include "utils/common/msg.h"
#include "utils/common/netio.h"
#include "utils/common/params.h"
26
#include "libknot/libknot.h"
Mark Karpilovskij's avatar
Mark Karpilovskij committed
27
#include "contrib/ctype.h"
28
#include "contrib/sockaddr.h"
29
#include "contrib/openbsd/strlcat.h"
30
#include "contrib/ucw/lists.h"
31
#include "contrib/wire_ctx.h"
32

33
static knot_lookup_t rtypes[] = {
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
	{ KNOT_RRTYPE_A,      "has IPv4 address" },
	{ KNOT_RRTYPE_NS,     "nameserver is" },
	{ KNOT_RRTYPE_CNAME,  "is an alias for" },
	{ KNOT_RRTYPE_SOA,    "start of authority is" },
	{ KNOT_RRTYPE_PTR,    "points to" },
	{ KNOT_RRTYPE_MX,     "mail is handled by" },
	{ KNOT_RRTYPE_TXT,    "description is" },
	{ KNOT_RRTYPE_AAAA,   "has IPv6 address" },
	{ KNOT_RRTYPE_LOC,    "location is" },
	{ KNOT_RRTYPE_DS,     "delegation signature is" },
	{ KNOT_RRTYPE_SSHFP,  "SSH fingerprint is" },
	{ KNOT_RRTYPE_RRSIG,  "RR set signature is" },
	{ KNOT_RRTYPE_DNSKEY, "DNSSEC key is" },
	{ KNOT_RRTYPE_TLSA,   "has TLS certificate" },
	{ 0, NULL }
};

51
static void print_header(const knot_pkt_t *packet, const style_t *style)
52
{
53
	char flags[64] = "";
54 55 56 57 58
	char unknown_rcode[64] = "";
	char unknown_opcode[64] = "";

	const char *rcode_str = NULL;
	const char *opcode_str = NULL;
59

60 61 62 63
	// Get extended RCODE.
	const char *code_name = knot_pkt_ext_rcode_name(packet);
	if (code_name[0] != '\0') {
		rcode_str = code_name;
64 65 66 67
	} else {
		uint16_t code = knot_pkt_ext_rcode(packet);
		(void)snprintf(unknown_rcode, sizeof(unknown_rcode), "RCODE %d", code);
		rcode_str = unknown_rcode;
68 69
	}

Daniel Salzman's avatar
Daniel Salzman committed
70
	// Get OPCODE.
71 72
	uint8_t code = knot_wire_get_opcode(packet->wire);
	const knot_lookup_t *opcode = knot_lookup_by_id(knot_opcode_names, code);
73 74
	if (opcode != NULL) {
		opcode_str = opcode->name;
75 76 77
	} else {
		(void)snprintf(unknown_opcode, sizeof(unknown_opcode), "OPCODE %d", code);
		opcode_str = unknown_opcode;
78
	}
79

80
	// Get flags.
81
	size_t flags_rest = sizeof(flags);
82 83
	const size_t flag_len = 4;
	if (knot_wire_get_qr(packet->wire) != 0 && flags_rest > flag_len) {
84
		flags_rest -= strlcat(flags, " qr", flags_rest);
85
	}
86
	if (knot_wire_get_aa(packet->wire) != 0 && flags_rest > flag_len) {
87
		flags_rest -= strlcat(flags, " aa", flags_rest);
88
	}
89
	if (knot_wire_get_tc(packet->wire) != 0 && flags_rest > flag_len) {
90
		flags_rest -= strlcat(flags, " tc", flags_rest);
91
	}
92
	if (knot_wire_get_rd(packet->wire) != 0 && flags_rest > flag_len) {
93
		flags_rest -= strlcat(flags, " rd", flags_rest);
94
	}
95
	if (knot_wire_get_ra(packet->wire) != 0 && flags_rest > flag_len) {
96
		flags_rest -= strlcat(flags, " ra", flags_rest);
97
	}
98
	if (knot_wire_get_z(packet->wire) != 0 && flags_rest > flag_len) {
99
		flags_rest -= strlcat(flags, " z", flags_rest);
100
	}
101
	if (knot_wire_get_ad(packet->wire) != 0 && flags_rest > flag_len) {
102
		flags_rest -= strlcat(flags, " ad", flags_rest);
103
	}
104
	if (knot_wire_get_cd(packet->wire) != 0 && flags_rest > flag_len) {
Daniel Salzman's avatar
Daniel Salzman committed
105
		strlcat(flags, " cd", flags_rest);
106
	}
107

108 109 110 111 112 113
	uint16_t id = knot_wire_get_id(packet->wire);
	uint16_t qdcount = knot_wire_get_qdcount(packet->wire);
	uint16_t ancount = knot_wire_get_ancount(packet->wire);
	uint16_t nscount = knot_wire_get_nscount(packet->wire);
	uint16_t arcount = knot_wire_get_arcount(packet->wire);

Lubos Slovak's avatar
Lubos Slovak committed
114
	if (knot_pkt_has_tsig(packet)) {
115 116 117
		arcount++;
	}

118
	// Print formatted info.
119
	switch (style->format) {
120
	case FORMAT_NSUPDATE:
121
		printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n"
122 123
		       ";; Flags:%1s; "
		       "ZONE: %u; PREREQ: %u; UPDATE: %u; ADDITIONAL: %u\n",
124 125
		       opcode_str, rcode_str, id, flags, qdcount, ancount,
		       nscount, arcount);
126 127
		break;
	default:
128
		printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n"
129 130
		       ";; Flags:%1s; "
		       "QUERY: %u; ANSWER: %u; AUTHORITY: %u; ADDITIONAL: %u\n",
131 132
		       opcode_str, rcode_str, id, flags, qdcount, ancount,
		       nscount, arcount);
133 134
		break;
	}
135 136
}

137 138 139 140
static void print_footer(const size_t total_len,
                         const size_t msg_count,
                         const size_t rr_count,
                         const net_t  *net,
Daniel Salzman's avatar
Daniel Salzman committed
141
                         const float  elapsed,
142
                         time_t       exec_time,
143
                         const bool   incoming)
144
{
145
	struct tm tm;
146
	char date[64];
147

148
	// Get current timestamp.
149 150 151
	if (exec_time == 0) {
		exec_time = time(NULL);
	}
152

153
	// Create formatted date-time string.
154
	localtime_r(&exec_time, &tm);
155 156
	strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S %Z", &tm);

157 158
	// Print messages statistics.
	if (incoming) {
159
		printf(";; Received %zu B", total_len);
160
	} else {
161
		printf(";; Sent %zu B", total_len);
162 163 164 165 166 167 168 169
	}

	// If multimessage (XFR) print additional statistics.
	if (msg_count > 0) {
		printf(" (%zu messages, %zu records)\n", msg_count, rr_count);
	} else {
		printf("\n");
	}
170 171
	// Print date.
	printf(";; Time %s\n", date);
172 173 174 175

	// Print connection statistics.
	if (net != NULL) {
		if (incoming) {
176
			printf(";; From %s", net->remote_str);
177
		} else {
178
			printf(";; To %s", net->remote_str);
179 180 181 182 183 184 185 186
		}

		if (elapsed >= 0) {
			printf(" in %.1f ms\n", elapsed);
		} else {
			printf("\n");
		}
	}
187 188
}

Mark Karpilovskij's avatar
Mark Karpilovskij committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
static void print_hex(const uint8_t *data, uint16_t len)
{
	for (int i = 0; i < len; i++) {
		printf("%02X", data[i]);
	}
}

static void print_nsid(const uint8_t *data, uint16_t len)
{
	if (len == 0) {
		return;
	}

	print_hex(data, len);

	// Check if printable string.
	for (int i = 0; i < len; i++) {
		if (!is_print(data[i])) {
			return;
		}
	}
	printf(" \"%.*s\"", len, data);
}

static void print_edns_client_subnet(const uint8_t *data, uint16_t len)
214
{
215 216
	knot_edns_client_subnet_t ecs = { 0 };
	int ret = knot_edns_client_subnet_parse(&ecs, data, len);
217 218 219 220
	if (ret != KNOT_EOK) {
		return;
	}

221 222 223 224 225 226
	struct sockaddr_storage addr = { 0 };
	ret = knot_edns_client_subnet_get_addr(&addr, &ecs);
	assert(ret == KNOT_EOK);

	char addr_str[SOCKADDR_STRLEN] = { 0 };
	sockaddr_tostr(addr_str, sizeof(addr_str), (struct sockaddr *)&addr);
227

Mark Karpilovskij's avatar
Mark Karpilovskij committed
228
	printf("%s/%u/%u", addr_str, ecs.source_len, ecs.scope_len);
229 230
}

231
static void print_section_opt(const knot_pkt_t *packet)
232
{
233 234
	char unknown_ercode[64] = "";
	const char *ercode_str = NULL;
235

236
	uint16_t ercode = knot_edns_get_ext_rcode(packet->opt_rr);
237
	if (ercode > 0) {
238 239 240 241 242 243 244
		ercode = knot_edns_whole_rcode(ercode,
		                               knot_wire_get_rcode(packet->wire));
	}

	const knot_lookup_t *item = knot_lookup_by_id(knot_rcode_names, ercode);
	if (item != NULL) {
		ercode_str = item->name;
245 246 247
	} else {
		(void)snprintf(unknown_ercode, sizeof(unknown_ercode), "RCODE %d", ercode);
		ercode_str = unknown_ercode;
248 249
	}

Daniel Salzman's avatar
Daniel Salzman committed
250
	printf("Version: %u; flags: %s; UDP size: %u B; ext-rcode: %s\n",
251 252 253 254
	       knot_edns_get_version(packet->opt_rr),
	       (knot_edns_do(packet->opt_rr) != 0) ? "do" : "",
	       knot_edns_get_payload(packet->opt_rr),
	       ercode_str);
255

256 257
	assert(packet->opt_rr->rrs.count > 0);
	knot_rdata_t *rdata = packet->opt_rr->rrs.rdata;
258
	wire_ctx_t wire = wire_ctx_init_const(rdata->data, rdata->len);
259

260 261 262 263
	while (wire_ctx_available(&wire) >= KNOT_EDNS_OPTION_HDRLEN) {
		uint16_t opt_code = wire_ctx_read_u16(&wire);
		uint16_t opt_len = wire_ctx_read_u16(&wire);
		uint8_t *opt_data = wire.position;
264

265 266 267 268
		if (wire.error != KNOT_EOK) {
			WARN("invalid OPT record data\n");
			return;
		}
269

270 271
		switch (opt_code) {
		case KNOT_EDNS_OPTION_NSID:
272
			printf(";; NSID: ");
Mark Karpilovskij's avatar
Mark Karpilovskij committed
273
			print_nsid(opt_data, opt_len);
274 275 276 277 278
			break;
		case KNOT_EDNS_OPTION_CLIENT_SUBNET:
			printf(";; CLIENT-SUBNET: ");
			print_edns_client_subnet(opt_data, opt_len);
			break;
279
		case KNOT_EDNS_OPTION_PADDING:
Mark Karpilovskij's avatar
Mark Karpilovskij committed
280 281 282 283 284
			printf(";; PADDING: %u B", opt_len);
			break;
		case KNOT_EDNS_OPTION_COOKIE:
			printf(";; COOKIE: ");
			print_hex(opt_data, opt_len);
285
			break;
286
		default:
287
			printf(";; Option (%u): ", opt_code);
Mark Karpilovskij's avatar
Mark Karpilovskij committed
288
			print_hex(opt_data, opt_len);
289
		}
Mark Karpilovskij's avatar
Mark Karpilovskij committed
290
		printf("\n");
291

292 293 294 295 296
		wire_ctx_skip(&wire, opt_len);
	}

	if (wire_ctx_available(&wire) > 0) {
		WARN("invalid OPT record data\n");
297
	}
298 299
}

300
static void print_section_question(const knot_dname_t *owner,
301
                                   const uint16_t     qclass,
302 303
                                   const uint16_t     qtype,
                                   const style_t      *style)
304 305
{
	size_t buflen = 8192;
306
	char *buf = calloc(buflen, 1);
307 308 309 310 311

	// Don't print zero TTL.
	knot_dump_style_t qstyle = style->style;
	qstyle.empty_ttl = true;

312
	knot_rrset_t *question = knot_rrset_new(owner, qtype, qclass, 0, NULL);
313

314
	if (knot_rrset_txt_dump_header(question, 0, buf, buflen, &qstyle) < 0) {
315
		WARN("can't print whole question section\n");
316 317 318 319
	}

	printf("%s\n", buf);

320
	knot_rrset_free(question, NULL);
Daniel Salzman's avatar
Daniel Salzman committed
321
	free(buf);
322 323
}

324
static void print_section_full(const knot_rrset_t *rrsets,
325
                               const uint16_t     count,
326 327
                               const style_t      *style,
                               const bool         no_tsig)
Daniel Salzman's avatar
Daniel Salzman committed
328 329
{
	size_t buflen = 8192;
330
	char *buf = calloc(buflen, 1);
Daniel Salzman's avatar
Daniel Salzman committed
331

332
	for (size_t i = 0; i < count; i++) {
333
		// Ignore OPT records.
334
		if (rrsets[i].type == KNOT_RRTYPE_OPT) {
335 336 337
			continue;
		}

338 339 340 341 342
		// Exclude TSIG record.
		if (no_tsig && rrsets[i].type == KNOT_RRTYPE_TSIG) {
			continue;
		}

343 344
		if (knot_rrset_txt_dump(&rrsets[i], &buf, &buflen,
		                        &(style->style)) < 0) {
345 346
				WARN("can't print whole section\n");
				break;
Daniel Salzman's avatar
Daniel Salzman committed
347 348 349 350 351 352 353
		}
		printf("%s", buf);
	}

	free(buf);
}

354
static void print_section_dig(const knot_rrset_t *rrsets,
355 356
                              const uint16_t     count,
                              const style_t      *style)
357 358
{
	size_t buflen = 8192;
359
	char *buf = calloc(buflen, 1);
360

361
	for (size_t i = 0; i < count; i++) {
362
		const knot_rrset_t *rrset = &rrsets[i];
363
		uint16_t rrset_rdata_count = rrset->rrs.count;
364
		for (uint16_t j = 0; j < rrset_rdata_count; j++) {
365 366
			while (knot_rrset_txt_dump_data(rrset, j, buf, buflen,
			                                &(style->style)) < 0) {
367 368
				buflen += 4096;
				// Oversize protection.
369
				if (buflen > 100000) {
370 371 372
					WARN("can't print whole section\n");
					break;
				}
373 374 375 376 377 378 379

				char *newbuf = realloc(buf, buflen);
				if (newbuf == NULL) {
					WARN("can't print whole section\n");
					break;
				}
				buf = newbuf;
380 381
			}
			printf("%s\n", buf);
382
		}
383 384 385 386 387
	}

	free(buf);
}

388
static void print_section_host(const knot_rrset_t *rrsets,
389 390
                               const uint16_t     count,
                               const style_t      *style)
391 392
{
	size_t buflen = 8192;
393
	char *buf = calloc(buflen, 1);
394

395
	for (size_t i = 0; i < count; i++) {
Daniel Salzman's avatar
Daniel Salzman committed
396
		const knot_rrset_t *rrset = &rrsets[i];
397
		const knot_lookup_t *descr;
398 399
		char type[32] = "NULL";
		char *owner;
400

401
		owner = knot_dname_to_str_alloc(rrset->owner);
402 403
		if (style->style.ascii_to_idn != NULL) {
			style->style.ascii_to_idn(&owner);
Daniel Salzman's avatar
Daniel Salzman committed
404
		}
405
		descr = knot_lookup_by_id(rtypes, rrset->type);
406

407
		uint16_t rrset_rdata_count = rrset->rrs.count;
408
		for (uint16_t j = 0; j < rrset_rdata_count; j++) {
409 410 411 412 413
			if (rrset->type == KNOT_RRTYPE_CNAME &&
			    style->hide_cname) {
				continue;
			}

414 415
			while (knot_rrset_txt_dump_data(rrset, j, buf, buflen,
			                                &(style->style)) < 0) {
416 417
				buflen += 4096;
				// Oversize protection.
418
				if (buflen > 100000) {
419 420 421 422 423 424 425
					WARN("can't print whole section\n");
					break;
				}

				char *newbuf = realloc(buf, buflen);
				if (newbuf == NULL) {
					WARN("can't print whole section\n");
426 427
					break;
				}
428
				buf = newbuf;
429 430 431 432 433 434
			}

			if (descr != NULL) {
				printf("%s %s %s\n", owner, descr->name, buf);
			} else {
				knot_rrtype_to_string(rrset->type, type,
435
						      sizeof(type));
436 437 438
				printf("%s has %s record %s\n",
				       owner, type, buf);
			}
439
		}
440 441 442 443 444 445 446

		free(owner);
	}

	free(buf);
}

447
static void print_error_host(const knot_pkt_t *packet, const style_t *style)
448
{
449
	char type[32] = "Unknown";
450
	const char *rcode_str = "Unknown";
451

452 453 454 455 456 457
	knot_rrtype_to_string(knot_pkt_qtype(packet), type, sizeof(type));

	// Get extended RCODE.
	const char *code_name = knot_pkt_ext_rcode_name(packet);
	if (code_name[0] != '\0') {
		rcode_str = code_name;
Daniel Salzman's avatar
Daniel Salzman committed
458
	}
459

460 461 462 463
	// Get record owner.
	char *owner = knot_dname_to_str_alloc(knot_pkt_qname(packet));
	if (style->style.ascii_to_idn != NULL) {
		style->style.ascii_to_idn(&owner);
464
	}
465

466
	if (knot_pkt_ext_rcode(packet) == KNOT_RCODE_NOERROR) {
467
		printf("Host %s has no %s record\n", owner, type);
Jan Včelák's avatar
Jan Včelák committed
468
	} else {
469
		printf("Host %s type %s error: %s\n", owner, type, rcode_str);
470 471 472 473 474
	}

	free(owner);
}

475
knot_pkt_t *create_empty_packet(const uint16_t max_size)
476 477
{
	// Create packet skeleton.
478
	knot_pkt_t *packet = knot_pkt_new(NULL, max_size, NULL);
479 480 481 482 483
	if (packet == NULL) {
		DBG_NULL;
		return NULL;
	}

484
	// Set random sequence id.
485
	knot_wire_set_id(packet->wire, dnssec_random_uint16_t());
486

487 488 489
	return packet;
}

490
void print_header_xfr(const knot_pkt_t *packet, const style_t *style)
491
{
Daniel Salzman's avatar
Daniel Salzman committed
492
	if (style == NULL) {
493
		DBG_NULL;
Daniel Salzman's avatar
Daniel Salzman committed
494 495 496
		return;
	}

497
	char xfr[16] = "AXFR";
Daniel Salzman's avatar
Daniel Salzman committed
498

499
	switch (knot_pkt_qtype(packet)) {
Daniel Salzman's avatar
Daniel Salzman committed
500 501 502
	case KNOT_RRTYPE_AXFR:
		break;
	case KNOT_RRTYPE_IXFR:
503
		xfr[0] = 'I';
Daniel Salzman's avatar
Daniel Salzman committed
504 505 506 507 508
		break;
	default:
		return;
	}

509
	if (style->show_header) {
510
		char *owner = knot_dname_to_str_alloc(knot_pkt_qname(packet));
511 512
		if (style->style.ascii_to_idn != NULL) {
			style->style.ascii_to_idn(&owner);
Daniel Salzman's avatar
Daniel Salzman committed
513
		}
514
		if (owner != NULL) {
515
			printf(";; %s for %s\n", xfr, owner);
516 517
			free(owner);
		}
Daniel Salzman's avatar
Daniel Salzman committed
518
	}
519 520
}

521
void print_data_xfr(const knot_pkt_t *packet,
Jan Včelák's avatar
Jan Včelák committed
522
                    const style_t    *style)
523
{
524
	if (packet == NULL || style == NULL) {
525
		DBG_NULL;
526 527 528
		return;
	}

529
	const knot_pktsection_t *answers = knot_pkt_section(packet, KNOT_ANSWER);
530

531
	switch (style->format) {
532
	case FORMAT_DIG:
533
		print_section_dig(knot_pkt_rr(answers, 0), answers->count, style);
534 535
		break;
	case FORMAT_HOST:
536
		print_section_host(knot_pkt_rr(answers, 0), answers->count, style);
537
		break;
538
	case FORMAT_FULL:
539
		print_section_full(knot_pkt_rr(answers, 0), answers->count, style, true);
540

541
		// Print TSIG record.
Lubos Slovak's avatar
Lubos Slovak committed
542
		if (style->show_tsig && knot_pkt_has_tsig(packet)) {
543
			print_section_full(packet->tsig_rr, 1, style, false);
544
		}
Daniel Salzman's avatar
Daniel Salzman committed
545 546 547 548
		break;
	default:
		break;
	}
549 550
}

551 552 553 554 555
void print_footer_xfr(const size_t  total_len,
                      const size_t  msg_count,
                      const size_t  rr_count,
                      const net_t   *net,
                      const float   elapsed,
556
                      const time_t  exec_time,
557
                      const style_t *style)
Daniel Salzman's avatar
Daniel Salzman committed
558
{
559
	if (style == NULL) {
560
		DBG_NULL;
Daniel Salzman's avatar
Daniel Salzman committed
561 562 563
		return;
	}

564
	if (style->show_footer) {
565 566
		print_footer(total_len, msg_count, rr_count, net, elapsed,
		             exec_time, true);
Daniel Salzman's avatar
Daniel Salzman committed
567
	}
Daniel Salzman's avatar
Daniel Salzman committed
568 569
}

570
void print_packet(const knot_pkt_t *packet,
Jan Včelák's avatar
Jan Včelák committed
571
                  const net_t      *net,
572
                  const size_t     size,
Jan Včelák's avatar
Jan Včelák committed
573
                  const float      elapsed,
574
                  const time_t     exec_time,
Jan Včelák's avatar
Jan Včelák committed
575 576
                  const bool       incoming,
                  const style_t    *style)
577
{
578
	if (packet == NULL || style == NULL) {
579
		DBG_NULL;
580 581 582
		return;
	}

583 584 585 586 587 588
	const knot_pktsection_t *answers = knot_pkt_section(packet,
	                                                    KNOT_ANSWER);
	const knot_pktsection_t *authority = knot_pkt_section(packet,
	                                                      KNOT_AUTHORITY);
	const knot_pktsection_t *additional = knot_pkt_section(packet,
	                                                       KNOT_ADDITIONAL);
589 590

	uint16_t qdcount = knot_wire_get_qdcount(packet->wire);
591 592 593 594 595 596
	uint16_t ancount = knot_wire_get_ancount(packet->wire);
	uint16_t nscount = knot_wire_get_nscount(packet->wire);
	uint16_t arcount = knot_wire_get_arcount(packet->wire);

	// Disable additionals printing if there are no other records.
	// OPT record may be placed anywhere within additionals!
Lubos Slovak's avatar
Lubos Slovak committed
597
	if (knot_pkt_has_edns(packet) && arcount == 1) {
598 599
		arcount = 0;
	}
600

601 602
	// Print packet information header.
	if (style->show_header) {
603 604 605
		if (net != NULL) {
			print_tls(&net->tls);
		}
606
		print_header(packet, style);
607 608 609
	}

	// Print EDNS section.
Lubos Slovak's avatar
Lubos Slovak committed
610
	if (style->show_edns && knot_pkt_has_edns(packet)) {
611
		printf("%s", style->show_section ? "\n;; EDNS PSEUDOSECTION:\n;; " : ";;");
612
		print_section_opt(packet);
613 614 615
	}

	// Print DNS sections.
616
	switch (style->format) {
617
	case FORMAT_DIG:
618
		if (ancount > 0) {
619
			print_section_dig(knot_pkt_rr(answers, 0), ancount, style);
620
		}
621 622
		break;
	case FORMAT_HOST:
623
		if (ancount > 0) {
624
			print_section_host(knot_pkt_rr(answers, 0), ancount, style);
625
		} else {
626
			print_error_host(packet, style);
627
		}
628
		break;
629
	case FORMAT_NSUPDATE:
630
		if (style->show_question && qdcount > 0) {
631
			printf("%s", style->show_section ? "\n;; ZONE SECTION:\n;; " : ";;");
632 633 634
			print_section_question(knot_pkt_qname(packet),
			                       knot_pkt_qclass(packet),
			                       knot_pkt_qtype(packet),
635
			                       style);
636 637
		}

638
		if (style->show_answer && ancount > 0) {
639
			printf("%s", style->show_section ? "\n;; PREREQUISITE SECTION:\n" : "");
640
			print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
641 642
		}

643
		if (style->show_authority && nscount > 0) {
644
			printf("%s", style->show_section ? "\n;; UPDATE SECTION:\n" : "");
645
			print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
646 647
		}

648
		if (style->show_additional && arcount > 0) {
649
			printf("%s", style->show_section ? "\n;; ADDITIONAL DATA:\n" : "");
650
			print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
651 652
		}
		break;
653
	case FORMAT_FULL:
654
		if (style->show_question && qdcount > 0) {
655
			printf("%s", style->show_section ? "\n;; QUESTION SECTION:\n;; " : ";;");
656 657 658
			print_section_question(knot_pkt_qname(packet),
			                       knot_pkt_qclass(packet),
			                       knot_pkt_qtype(packet),
659
			                       style);
Daniel Salzman's avatar
Daniel Salzman committed
660
		}
661

662
		if (style->show_answer && ancount > 0) {
663
			printf("%s", style->show_section ? "\n;; ANSWER SECTION:\n" : "");
664
			print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
Daniel Salzman's avatar
Daniel Salzman committed
665
		}
666

667
		if (style->show_authority && nscount > 0) {
668
			printf("%s", style->show_section ? "\n;; AUTHORITY SECTION:\n" : "");
669
			print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
Daniel Salzman's avatar
Daniel Salzman committed
670 671
		}

672
		if (style->show_additional && arcount > 0) {
673
			printf("%s", style->show_section ? "\n;; ADDITIONAL SECTION:\n" : "");
674
			print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
Daniel Salzman's avatar
Daniel Salzman committed
675
		}
676 677 678 679
		break;
	default:
		break;
	}
Jan Včelák's avatar
Jan Včelák committed
680

681
	// Print TSIG section.
Lubos Slovak's avatar
Lubos Slovak committed
682
	if (style->show_tsig && knot_pkt_has_tsig(packet)) {
683
		printf("%s", style->show_section ? "\n;; TSIG PSEUDOSECTION:\n" : "");
684 685 686
		print_section_full(packet->tsig_rr, 1, style, false);
	}

687
	// Print packet statistics.
688
	if (style->show_footer) {
689
		printf("\n");
690
		print_footer(size, 0, 0, net, elapsed, exec_time, incoming);
691
	}
692
}