xref: /netbsd/external/mpl/bind/dist/bin/tests/wire_test.c (revision e2b1b9c0)
1*e2b1b9c0Schristos /*	$NetBSD: wire_test.c,v 1.1.1.1 2018/08/12 12:07:27 christos Exp $	*/
2*e2b1b9c0Schristos 
3*e2b1b9c0Schristos /*
4*e2b1b9c0Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*e2b1b9c0Schristos  *
6*e2b1b9c0Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
7*e2b1b9c0Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
8*e2b1b9c0Schristos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9*e2b1b9c0Schristos  *
10*e2b1b9c0Schristos  * See the COPYRIGHT file distributed with this work for additional
11*e2b1b9c0Schristos  * information regarding copyright ownership.
12*e2b1b9c0Schristos  */
13*e2b1b9c0Schristos 
14*e2b1b9c0Schristos #include <config.h>
15*e2b1b9c0Schristos 
16*e2b1b9c0Schristos #include <stdlib.h>
17*e2b1b9c0Schristos 
18*e2b1b9c0Schristos #include <isc/buffer.h>
19*e2b1b9c0Schristos #include <isc/commandline.h>
20*e2b1b9c0Schristos #include <isc/file.h>
21*e2b1b9c0Schristos #include <isc/mem.h>
22*e2b1b9c0Schristos #include <isc/print.h>
23*e2b1b9c0Schristos #include <isc/string.h>
24*e2b1b9c0Schristos #include <isc/util.h>
25*e2b1b9c0Schristos 
26*e2b1b9c0Schristos #include <dns/message.h>
27*e2b1b9c0Schristos #include <dns/result.h>
28*e2b1b9c0Schristos 
29*e2b1b9c0Schristos int parseflags = 0;
30*e2b1b9c0Schristos isc_mem_t *mctx = NULL;
31*e2b1b9c0Schristos isc_boolean_t printmemstats = ISC_FALSE;
32*e2b1b9c0Schristos isc_boolean_t dorender = ISC_FALSE;
33*e2b1b9c0Schristos 
34*e2b1b9c0Schristos static void
35*e2b1b9c0Schristos process_message(isc_buffer_t *source);
36*e2b1b9c0Schristos 
37*e2b1b9c0Schristos static isc_result_t
38*e2b1b9c0Schristos printmessage(dns_message_t *msg);
39*e2b1b9c0Schristos 
40*e2b1b9c0Schristos static inline void
41*e2b1b9c0Schristos CHECKRESULT(isc_result_t result, const char *msg) {
42*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS) {
43*e2b1b9c0Schristos 		printf("%s: %s\n", msg, dns_result_totext(result));
44*e2b1b9c0Schristos 
45*e2b1b9c0Schristos 		exit(1);
46*e2b1b9c0Schristos 	}
47*e2b1b9c0Schristos }
48*e2b1b9c0Schristos 
49*e2b1b9c0Schristos static int
50*e2b1b9c0Schristos fromhex(char c) {
51*e2b1b9c0Schristos 	if (c >= '0' && c <= '9')
52*e2b1b9c0Schristos 		return (c - '0');
53*e2b1b9c0Schristos 	else if (c >= 'a' && c <= 'f')
54*e2b1b9c0Schristos 		return (c - 'a' + 10);
55*e2b1b9c0Schristos 	else if (c >= 'A' && c <= 'F')
56*e2b1b9c0Schristos 		return (c - 'A' + 10);
57*e2b1b9c0Schristos 
58*e2b1b9c0Schristos 	fprintf(stderr, "bad input format: %02x\n", c);
59*e2b1b9c0Schristos 	exit(3);
60*e2b1b9c0Schristos 	/* NOTREACHED */
61*e2b1b9c0Schristos }
62*e2b1b9c0Schristos 
63*e2b1b9c0Schristos static void
64*e2b1b9c0Schristos usage(void) {
65*e2b1b9c0Schristos 	fprintf(stderr, "wire_test [-b] [-d] [-p] [-r] [-s]\n");
66*e2b1b9c0Schristos 	fprintf(stderr, "          [-m {usage|trace|record|size|mctx}]\n");
67*e2b1b9c0Schristos 	fprintf(stderr, "          [filename]\n\n");
68*e2b1b9c0Schristos 	fprintf(stderr, "\t-b\tBest-effort parsing (ignore some errors)\n");
69*e2b1b9c0Schristos 	fprintf(stderr, "\t-d\tRead input as raw binary data\n");
70*e2b1b9c0Schristos 	fprintf(stderr, "\t-p\tPreserve order of the records in messages\n");
71*e2b1b9c0Schristos 	fprintf(stderr, "\t-r\tAfter parsing, re-render the message\n");
72*e2b1b9c0Schristos 	fprintf(stderr, "\t-s\tPrint memory statistics\n");
73*e2b1b9c0Schristos 	fprintf(stderr, "\t-t\tTCP mode - ignore the first 2 bytes\n");
74*e2b1b9c0Schristos }
75*e2b1b9c0Schristos 
76*e2b1b9c0Schristos static isc_result_t
77*e2b1b9c0Schristos printmessage(dns_message_t *msg) {
78*e2b1b9c0Schristos 	isc_buffer_t b;
79*e2b1b9c0Schristos 	char *buf = NULL;
80*e2b1b9c0Schristos 	int len = 1024;
81*e2b1b9c0Schristos 	isc_result_t result = ISC_R_SUCCESS;
82*e2b1b9c0Schristos 
83*e2b1b9c0Schristos 	do {
84*e2b1b9c0Schristos 		buf = isc_mem_get(mctx, len);
85*e2b1b9c0Schristos 		if (buf == NULL) {
86*e2b1b9c0Schristos 			result = ISC_R_NOMEMORY;
87*e2b1b9c0Schristos 			break;
88*e2b1b9c0Schristos 		}
89*e2b1b9c0Schristos 
90*e2b1b9c0Schristos 		isc_buffer_init(&b, buf, len);
91*e2b1b9c0Schristos 		result = dns_message_totext(msg, &dns_master_style_debug,
92*e2b1b9c0Schristos 					    0, &b);
93*e2b1b9c0Schristos 		if (result == ISC_R_NOSPACE) {
94*e2b1b9c0Schristos 			isc_mem_put(mctx, buf, len);
95*e2b1b9c0Schristos 			len *= 2;
96*e2b1b9c0Schristos 		} else if (result == ISC_R_SUCCESS)
97*e2b1b9c0Schristos 			printf("%.*s\n", (int) isc_buffer_usedlength(&b), buf);
98*e2b1b9c0Schristos 	} while (result == ISC_R_NOSPACE);
99*e2b1b9c0Schristos 
100*e2b1b9c0Schristos 	if (buf != NULL)
101*e2b1b9c0Schristos 		isc_mem_put(mctx, buf, len);
102*e2b1b9c0Schristos 
103*e2b1b9c0Schristos 	return (result);
104*e2b1b9c0Schristos }
105*e2b1b9c0Schristos 
106*e2b1b9c0Schristos int
107*e2b1b9c0Schristos main(int argc, char *argv[]) {
108*e2b1b9c0Schristos 	isc_buffer_t *input = NULL;
109*e2b1b9c0Schristos 	isc_boolean_t need_close = ISC_FALSE;
110*e2b1b9c0Schristos 	isc_boolean_t tcp = ISC_FALSE;
111*e2b1b9c0Schristos 	isc_boolean_t rawdata = ISC_FALSE;
112*e2b1b9c0Schristos 	isc_result_t result;
113*e2b1b9c0Schristos 	isc_uint8_t c;
114*e2b1b9c0Schristos 	FILE *f;
115*e2b1b9c0Schristos 	int ch;
116*e2b1b9c0Schristos 
117*e2b1b9c0Schristos #define CMDLINE_FLAGS "bdm:prst"
118*e2b1b9c0Schristos 	/*
119*e2b1b9c0Schristos 	 * Process memory debugging argument first.
120*e2b1b9c0Schristos 	 */
121*e2b1b9c0Schristos 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
122*e2b1b9c0Schristos 		switch (ch) {
123*e2b1b9c0Schristos 		case 'm':
124*e2b1b9c0Schristos 			if (strcasecmp(isc_commandline_argument, "record") == 0)
125*e2b1b9c0Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
126*e2b1b9c0Schristos 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
127*e2b1b9c0Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
128*e2b1b9c0Schristos 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
129*e2b1b9c0Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
130*e2b1b9c0Schristos 			if (strcasecmp(isc_commandline_argument, "size") == 0)
131*e2b1b9c0Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
132*e2b1b9c0Schristos 			if (strcasecmp(isc_commandline_argument, "mctx") == 0)
133*e2b1b9c0Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGCTX;
134*e2b1b9c0Schristos 			break;
135*e2b1b9c0Schristos 		default:
136*e2b1b9c0Schristos 			break;
137*e2b1b9c0Schristos 		}
138*e2b1b9c0Schristos 	}
139*e2b1b9c0Schristos 	isc_commandline_reset = ISC_TRUE;
140*e2b1b9c0Schristos 
141*e2b1b9c0Schristos 	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
142*e2b1b9c0Schristos 
143*e2b1b9c0Schristos 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
144*e2b1b9c0Schristos 		switch (ch) {
145*e2b1b9c0Schristos 			case 'b':
146*e2b1b9c0Schristos 				parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
147*e2b1b9c0Schristos 				break;
148*e2b1b9c0Schristos 			case 'd':
149*e2b1b9c0Schristos 				rawdata = ISC_TRUE;
150*e2b1b9c0Schristos 				break;
151*e2b1b9c0Schristos 			case 'm':
152*e2b1b9c0Schristos 				break;
153*e2b1b9c0Schristos 			case 'p':
154*e2b1b9c0Schristos 				parseflags |= DNS_MESSAGEPARSE_PRESERVEORDER;
155*e2b1b9c0Schristos 				break;
156*e2b1b9c0Schristos 			case 'r':
157*e2b1b9c0Schristos 				dorender = ISC_TRUE;
158*e2b1b9c0Schristos 				break;
159*e2b1b9c0Schristos 			case 's':
160*e2b1b9c0Schristos 				printmemstats = ISC_TRUE;
161*e2b1b9c0Schristos 				break;
162*e2b1b9c0Schristos 			case 't':
163*e2b1b9c0Schristos 				tcp = ISC_TRUE;
164*e2b1b9c0Schristos 				break;
165*e2b1b9c0Schristos 			default:
166*e2b1b9c0Schristos 				usage();
167*e2b1b9c0Schristos 				exit(1);
168*e2b1b9c0Schristos 		}
169*e2b1b9c0Schristos 	}
170*e2b1b9c0Schristos 
171*e2b1b9c0Schristos 	argc -= isc_commandline_index;
172*e2b1b9c0Schristos 	argv += isc_commandline_index;
173*e2b1b9c0Schristos 
174*e2b1b9c0Schristos 	if (argc >= 1) {
175*e2b1b9c0Schristos 		f = fopen(argv[0], "r");
176*e2b1b9c0Schristos 		if (f == NULL) {
177*e2b1b9c0Schristos 			fprintf(stderr, "%s: fopen failed\n", argv[0]);
178*e2b1b9c0Schristos 			exit(1);
179*e2b1b9c0Schristos 		}
180*e2b1b9c0Schristos 		need_close = ISC_TRUE;
181*e2b1b9c0Schristos 	} else
182*e2b1b9c0Schristos 		f = stdin;
183*e2b1b9c0Schristos 
184*e2b1b9c0Schristos 	result = isc_buffer_allocate(mctx, &input, 64 * 1024);
185*e2b1b9c0Schristos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
186*e2b1b9c0Schristos 
187*e2b1b9c0Schristos 	if (rawdata) {
188*e2b1b9c0Schristos 		while (fread(&c, 1, 1, f) != 0) {
189*e2b1b9c0Schristos 			result = isc_buffer_reserve(&input, 1);
190*e2b1b9c0Schristos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
191*e2b1b9c0Schristos 			isc_buffer_putuint8(input, (isc_uint8_t) c);
192*e2b1b9c0Schristos 		}
193*e2b1b9c0Schristos 	} else {
194*e2b1b9c0Schristos 		char s[BUFSIZ];
195*e2b1b9c0Schristos 
196*e2b1b9c0Schristos 		while (fgets(s, sizeof(s), f) != NULL) {
197*e2b1b9c0Schristos 			char *rp = s, *wp = s;
198*e2b1b9c0Schristos 			size_t i, len = 0;
199*e2b1b9c0Schristos 
200*e2b1b9c0Schristos 			while (*rp != '\0') {
201*e2b1b9c0Schristos 				if (*rp == '#')
202*e2b1b9c0Schristos 					break;
203*e2b1b9c0Schristos 				if (*rp != ' ' && *rp != '\t' &&
204*e2b1b9c0Schristos 				    *rp != '\r' && *rp != '\n') {
205*e2b1b9c0Schristos 					*wp++ = *rp;
206*e2b1b9c0Schristos 					len++;
207*e2b1b9c0Schristos 				}
208*e2b1b9c0Schristos 				rp++;
209*e2b1b9c0Schristos 			}
210*e2b1b9c0Schristos 			if (len == 0U)
211*e2b1b9c0Schristos 				continue;
212*e2b1b9c0Schristos 			if (len % 2 != 0U) {
213*e2b1b9c0Schristos 				fprintf(stderr, "bad input format: %lu\n",
214*e2b1b9c0Schristos 				       (unsigned long)len);
215*e2b1b9c0Schristos 				exit(1);
216*e2b1b9c0Schristos 			}
217*e2b1b9c0Schristos 
218*e2b1b9c0Schristos 			rp = s;
219*e2b1b9c0Schristos 			for (i = 0; i < len; i += 2) {
220*e2b1b9c0Schristos 				c = fromhex(*rp++);
221*e2b1b9c0Schristos 				c *= 16;
222*e2b1b9c0Schristos 				c += fromhex(*rp++);
223*e2b1b9c0Schristos 				result = isc_buffer_reserve(&input, 1);
224*e2b1b9c0Schristos 				RUNTIME_CHECK(result == ISC_R_SUCCESS);
225*e2b1b9c0Schristos 				isc_buffer_putuint8(input, (isc_uint8_t) c);
226*e2b1b9c0Schristos 			}
227*e2b1b9c0Schristos 		}
228*e2b1b9c0Schristos 	}
229*e2b1b9c0Schristos 
230*e2b1b9c0Schristos 	if (need_close)
231*e2b1b9c0Schristos 		fclose(f);
232*e2b1b9c0Schristos 
233*e2b1b9c0Schristos 	if (tcp) {
234*e2b1b9c0Schristos 		while (isc_buffer_remaininglength(input) != 0) {
235*e2b1b9c0Schristos 			unsigned int tcplen;
236*e2b1b9c0Schristos 
237*e2b1b9c0Schristos 			if (isc_buffer_remaininglength(input) < 2) {
238*e2b1b9c0Schristos 				fprintf(stderr, "premature end of packet\n");
239*e2b1b9c0Schristos 				exit(1);
240*e2b1b9c0Schristos 			}
241*e2b1b9c0Schristos 			tcplen = isc_buffer_getuint16(input);
242*e2b1b9c0Schristos 
243*e2b1b9c0Schristos 			if (isc_buffer_remaininglength(input) < tcplen) {
244*e2b1b9c0Schristos 				fprintf(stderr, "premature end of packet\n");
245*e2b1b9c0Schristos 				exit(1);
246*e2b1b9c0Schristos 			}
247*e2b1b9c0Schristos 			process_message(input);
248*e2b1b9c0Schristos 		}
249*e2b1b9c0Schristos 	} else
250*e2b1b9c0Schristos 		process_message(input);
251*e2b1b9c0Schristos 
252*e2b1b9c0Schristos 	if (input != NULL)
253*e2b1b9c0Schristos 		isc_buffer_free(&input);
254*e2b1b9c0Schristos 
255*e2b1b9c0Schristos 	if (printmemstats)
256*e2b1b9c0Schristos 		isc_mem_stats(mctx, stdout);
257*e2b1b9c0Schristos 	isc_mem_destroy(&mctx);
258*e2b1b9c0Schristos 
259*e2b1b9c0Schristos 	return (0);
260*e2b1b9c0Schristos }
261*e2b1b9c0Schristos 
262*e2b1b9c0Schristos static void
263*e2b1b9c0Schristos process_message(isc_buffer_t *source) {
264*e2b1b9c0Schristos 	dns_message_t *message;
265*e2b1b9c0Schristos 	isc_result_t result;
266*e2b1b9c0Schristos 	int i;
267*e2b1b9c0Schristos 
268*e2b1b9c0Schristos 	message = NULL;
269*e2b1b9c0Schristos 	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &message);
270*e2b1b9c0Schristos 	CHECKRESULT(result, "dns_message_create failed");
271*e2b1b9c0Schristos 
272*e2b1b9c0Schristos 	result = dns_message_parse(message, source, parseflags);
273*e2b1b9c0Schristos 	if (result == DNS_R_RECOVERABLE)
274*e2b1b9c0Schristos 		result = ISC_R_SUCCESS;
275*e2b1b9c0Schristos 	CHECKRESULT(result, "dns_message_parse failed");
276*e2b1b9c0Schristos 
277*e2b1b9c0Schristos 	result = printmessage(message);
278*e2b1b9c0Schristos 	CHECKRESULT(result, "printmessage() failed");
279*e2b1b9c0Schristos 
280*e2b1b9c0Schristos 	if (printmemstats)
281*e2b1b9c0Schristos 		isc_mem_stats(mctx, stdout);
282*e2b1b9c0Schristos 
283*e2b1b9c0Schristos 	if (dorender) {
284*e2b1b9c0Schristos 		unsigned char b2[64 * 1024];
285*e2b1b9c0Schristos 		isc_buffer_t buffer;
286*e2b1b9c0Schristos 		dns_compress_t cctx;
287*e2b1b9c0Schristos 
288*e2b1b9c0Schristos 		isc_buffer_init(&buffer, b2, sizeof(b2));
289*e2b1b9c0Schristos 
290*e2b1b9c0Schristos 		/*
291*e2b1b9c0Schristos 		 * XXXMLG
292*e2b1b9c0Schristos 		 * Changing this here is a hack, and should not be done in
293*e2b1b9c0Schristos 		 * reasonable application code, ever.
294*e2b1b9c0Schristos 		*/
295*e2b1b9c0Schristos 		message->from_to_wire = DNS_MESSAGE_INTENTRENDER;
296*e2b1b9c0Schristos 
297*e2b1b9c0Schristos 		for (i = 0; i < DNS_SECTION_MAX; i++)
298*e2b1b9c0Schristos 			message->counts[i] = 0;  /* Another hack XXX */
299*e2b1b9c0Schristos 
300*e2b1b9c0Schristos 		result = dns_compress_init(&cctx, -1, mctx);
301*e2b1b9c0Schristos 		CHECKRESULT(result, "dns_compress_init() failed");
302*e2b1b9c0Schristos 
303*e2b1b9c0Schristos 		result = dns_message_renderbegin(message, &cctx, &buffer);
304*e2b1b9c0Schristos 		CHECKRESULT(result, "dns_message_renderbegin() failed");
305*e2b1b9c0Schristos 
306*e2b1b9c0Schristos 		result = dns_message_rendersection(message,
307*e2b1b9c0Schristos 						   DNS_SECTION_QUESTION, 0);
308*e2b1b9c0Schristos 		CHECKRESULT(result,
309*e2b1b9c0Schristos 			    "dns_message_rendersection(QUESTION) failed");
310*e2b1b9c0Schristos 
311*e2b1b9c0Schristos 		result = dns_message_rendersection(message,
312*e2b1b9c0Schristos 						   DNS_SECTION_ANSWER, 0);
313*e2b1b9c0Schristos 		CHECKRESULT(result,
314*e2b1b9c0Schristos 			    "dns_message_rendersection(ANSWER) failed");
315*e2b1b9c0Schristos 
316*e2b1b9c0Schristos 		result = dns_message_rendersection(message,
317*e2b1b9c0Schristos 						   DNS_SECTION_AUTHORITY, 0);
318*e2b1b9c0Schristos 		CHECKRESULT(result,
319*e2b1b9c0Schristos 			    "dns_message_rendersection(AUTHORITY) failed");
320*e2b1b9c0Schristos 
321*e2b1b9c0Schristos 		result = dns_message_rendersection(message,
322*e2b1b9c0Schristos 						   DNS_SECTION_ADDITIONAL, 0);
323*e2b1b9c0Schristos 		CHECKRESULT(result,
324*e2b1b9c0Schristos 			    "dns_message_rendersection(ADDITIONAL) failed");
325*e2b1b9c0Schristos 
326*e2b1b9c0Schristos 		dns_message_renderend(message);
327*e2b1b9c0Schristos 
328*e2b1b9c0Schristos 		dns_compress_invalidate(&cctx);
329*e2b1b9c0Schristos 
330*e2b1b9c0Schristos 		message->from_to_wire = DNS_MESSAGE_INTENTPARSE;
331*e2b1b9c0Schristos 		dns_message_destroy(&message);
332*e2b1b9c0Schristos 
333*e2b1b9c0Schristos 		printf("Message rendered.\n");
334*e2b1b9c0Schristos 		if (printmemstats)
335*e2b1b9c0Schristos 			isc_mem_stats(mctx, stdout);
336*e2b1b9c0Schristos 
337*e2b1b9c0Schristos 		result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
338*e2b1b9c0Schristos 					    &message);
339*e2b1b9c0Schristos 		CHECKRESULT(result, "dns_message_create failed");
340*e2b1b9c0Schristos 
341*e2b1b9c0Schristos 		result = dns_message_parse(message, &buffer, parseflags);
342*e2b1b9c0Schristos 		CHECKRESULT(result, "dns_message_parse failed");
343*e2b1b9c0Schristos 
344*e2b1b9c0Schristos 		result = printmessage(message);
345*e2b1b9c0Schristos 		CHECKRESULT(result, "printmessage() failed");
346*e2b1b9c0Schristos 	}
347*e2b1b9c0Schristos 	dns_message_destroy(&message);
348*e2b1b9c0Schristos }
349