xref: /openbsd/usr.sbin/unbound/testcode/pktview.c (revision 712b2f30)
1*712b2f30Ssthen /*
2*712b2f30Ssthen  * testcode/pktview.c - debug program to disassemble a DNS packet.
3*712b2f30Ssthen  *
4*712b2f30Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5*712b2f30Ssthen  *
6*712b2f30Ssthen  * This software is open source.
7*712b2f30Ssthen  *
8*712b2f30Ssthen  * Redistribution and use in source and binary forms, with or without
9*712b2f30Ssthen  * modification, are permitted provided that the following conditions
10*712b2f30Ssthen  * are met:
11*712b2f30Ssthen  *
12*712b2f30Ssthen  * Redistributions of source code must retain the above copyright notice,
13*712b2f30Ssthen  * this list of conditions and the following disclaimer.
14*712b2f30Ssthen  *
15*712b2f30Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16*712b2f30Ssthen  * this list of conditions and the following disclaimer in the documentation
17*712b2f30Ssthen  * and/or other materials provided with the distribution.
18*712b2f30Ssthen  *
19*712b2f30Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20*712b2f30Ssthen  * be used to endorse or promote products derived from this software without
21*712b2f30Ssthen  * specific prior written permission.
22*712b2f30Ssthen  *
23*712b2f30Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*712b2f30Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*712b2f30Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*712b2f30Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*712b2f30Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*712b2f30Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*712b2f30Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*712b2f30Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*712b2f30Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*712b2f30Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*712b2f30Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*712b2f30Ssthen  */
35*712b2f30Ssthen 
36*712b2f30Ssthen /**
37*712b2f30Ssthen  * \file
38*712b2f30Ssthen  *
39*712b2f30Ssthen  * This program shows a dns packet wire format.
40*712b2f30Ssthen  */
41*712b2f30Ssthen 
42*712b2f30Ssthen #include "config.h"
43*712b2f30Ssthen #include "util/log.h"
44*712b2f30Ssthen #include "util/data/dname.h"
45*712b2f30Ssthen #include "util/data/msgparse.h"
46*712b2f30Ssthen #include "testcode/unitmain.h"
47*712b2f30Ssthen #include "testcode/readhex.h"
48*712b2f30Ssthen #include "sldns/sbuffer.h"
49*712b2f30Ssthen #include "sldns/parseutil.h"
50*712b2f30Ssthen 
51*712b2f30Ssthen /** usage information for pktview */
usage(char * argv[])52*712b2f30Ssthen static void usage(char* argv[])
53*712b2f30Ssthen {
54*712b2f30Ssthen 	printf("usage: %s\n", argv[0]);
55*712b2f30Ssthen 	printf("present hex packet on stdin.\n");
56*712b2f30Ssthen 	exit(1);
57*712b2f30Ssthen }
58*712b2f30Ssthen 
59*712b2f30Ssthen /** read hex input */
read_input(sldns_buffer * pkt,FILE * in)60*712b2f30Ssthen static void read_input(sldns_buffer* pkt, FILE* in)
61*712b2f30Ssthen {
62*712b2f30Ssthen 	char buf[102400];
63*712b2f30Ssthen 	char* np = buf;
64*712b2f30Ssthen 	while(fgets(np, (int)sizeof(buf) - (np-buf), in)) {
65*712b2f30Ssthen 		if(buf[0] == ';') /* comment */
66*712b2f30Ssthen 			continue;
67*712b2f30Ssthen 		np = &np[strlen(np)];
68*712b2f30Ssthen 	}
69*712b2f30Ssthen 	hex_to_buf(pkt, buf);
70*712b2f30Ssthen }
71*712b2f30Ssthen 
72*712b2f30Ssthen /** analyze domain name in packet, possibly compressed */
analyze_dname(sldns_buffer * pkt)73*712b2f30Ssthen static void analyze_dname(sldns_buffer* pkt)
74*712b2f30Ssthen {
75*712b2f30Ssthen 	size_t oldpos = sldns_buffer_position(pkt);
76*712b2f30Ssthen 	size_t len;
77*712b2f30Ssthen 	printf("[pos %d] dname: ", (int)oldpos);
78*712b2f30Ssthen 	dname_print(stdout, pkt, sldns_buffer_current(pkt));
79*712b2f30Ssthen 	len = pkt_dname_len(pkt);
80*712b2f30Ssthen 	printf(" len=%d", (int)len);
81*712b2f30Ssthen 	if(sldns_buffer_position(pkt)-oldpos != len)
82*712b2f30Ssthen 		printf(" comprlen=%d\n",
83*712b2f30Ssthen 			(int)(sldns_buffer_position(pkt)-oldpos));
84*712b2f30Ssthen 	else	printf("\n");
85*712b2f30Ssthen }
86*712b2f30Ssthen 
87*712b2f30Ssthen /** analyze rdata in packet */
analyze_rdata(sldns_buffer * pkt,const sldns_rr_descriptor * desc,uint16_t rdlen)88*712b2f30Ssthen static void analyze_rdata(sldns_buffer*pkt, const sldns_rr_descriptor* desc,
89*712b2f30Ssthen 	uint16_t rdlen)
90*712b2f30Ssthen {
91*712b2f30Ssthen 	int rdf = 0;
92*712b2f30Ssthen 	int count = (int)desc->_dname_count;
93*712b2f30Ssthen 	size_t len, oldpos;
94*712b2f30Ssthen 	while(rdlen > 0 && count) {
95*712b2f30Ssthen 		switch(desc->_wireformat[rdf]) {
96*712b2f30Ssthen 		case LDNS_RDF_TYPE_DNAME:
97*712b2f30Ssthen 			oldpos = sldns_buffer_position(pkt);
98*712b2f30Ssthen 			analyze_dname(pkt);
99*712b2f30Ssthen 			rdlen -= sldns_buffer_position(pkt)-oldpos;
100*712b2f30Ssthen 			count --;
101*712b2f30Ssthen 			len = 0;
102*712b2f30Ssthen 			break;
103*712b2f30Ssthen 		case LDNS_RDF_TYPE_STR:
104*712b2f30Ssthen 			len = sldns_buffer_current(pkt)[0] + 1;
105*712b2f30Ssthen 			break;
106*712b2f30Ssthen 		default:
107*712b2f30Ssthen 			len = get_rdf_size(desc->_wireformat[rdf]);
108*712b2f30Ssthen 		}
109*712b2f30Ssthen 		if(len) {
110*712b2f30Ssthen 			printf(" wf[%d]", (int)len);
111*712b2f30Ssthen 			sldns_buffer_skip(pkt, (ssize_t)len);
112*712b2f30Ssthen 			rdlen -= len;
113*712b2f30Ssthen 		}
114*712b2f30Ssthen 		rdf++;
115*712b2f30Ssthen 	}
116*712b2f30Ssthen 	if(rdlen) {
117*712b2f30Ssthen 		size_t i;
118*712b2f30Ssthen 		printf(" remain[%d]\n", (int)rdlen);
119*712b2f30Ssthen 		for(i=0; i<rdlen; i++)
120*712b2f30Ssthen 			printf(" %2.2X", (unsigned)sldns_buffer_current(pkt)[i]);
121*712b2f30Ssthen 		printf("\n");
122*712b2f30Ssthen 	}
123*712b2f30Ssthen 	else	printf("\n");
124*712b2f30Ssthen 	sldns_buffer_skip(pkt, (ssize_t)rdlen);
125*712b2f30Ssthen }
126*712b2f30Ssthen 
127*712b2f30Ssthen /** analyze rr in packet */
analyze_rr(sldns_buffer * pkt,int q)128*712b2f30Ssthen static void analyze_rr(sldns_buffer* pkt, int q)
129*712b2f30Ssthen {
130*712b2f30Ssthen 	uint16_t type, dclass, len;
131*712b2f30Ssthen 	uint32_t ttl;
132*712b2f30Ssthen 	analyze_dname(pkt);
133*712b2f30Ssthen 	type = sldns_buffer_read_u16(pkt);
134*712b2f30Ssthen 	dclass = sldns_buffer_read_u16(pkt);
135*712b2f30Ssthen 	printf("type %s(%d)", sldns_rr_descript(type)?
136*712b2f30Ssthen 		sldns_rr_descript(type)->_name: "??" , (int)type);
137*712b2f30Ssthen 	printf(" class %s(%d) ", sldns_lookup_by_id(sldns_rr_classes,
138*712b2f30Ssthen 		(int)dclass)?sldns_lookup_by_id(sldns_rr_classes,
139*712b2f30Ssthen 		(int)dclass)->name:"??", (int)dclass);
140*712b2f30Ssthen 	if(q) {
141*712b2f30Ssthen 		printf("\n");
142*712b2f30Ssthen 	} else {
143*712b2f30Ssthen 		ttl = sldns_buffer_read_u32(pkt);
144*712b2f30Ssthen 		printf(" ttl %d (0x%x)", (int)ttl, (unsigned)ttl);
145*712b2f30Ssthen 		len = sldns_buffer_read_u16(pkt);
146*712b2f30Ssthen 		printf(" rdata len %d:\n", (int)len);
147*712b2f30Ssthen 		if(sldns_rr_descript(type))
148*712b2f30Ssthen 			analyze_rdata(pkt, sldns_rr_descript(type), len);
149*712b2f30Ssthen 		else sldns_buffer_skip(pkt, (ssize_t)len);
150*712b2f30Ssthen 	}
151*712b2f30Ssthen }
152*712b2f30Ssthen 
153*712b2f30Ssthen /** analyse pkt */
analyze(sldns_buffer * pkt)154*712b2f30Ssthen static void analyze(sldns_buffer* pkt)
155*712b2f30Ssthen {
156*712b2f30Ssthen 	uint16_t i, f, qd, an, ns, ar;
157*712b2f30Ssthen 	int rrnum = 0;
158*712b2f30Ssthen 	printf("packet length %d\n", (int)sldns_buffer_limit(pkt));
159*712b2f30Ssthen 	if(sldns_buffer_limit(pkt) < 12) return;
160*712b2f30Ssthen 
161*712b2f30Ssthen 	i = sldns_buffer_read_u16(pkt);
162*712b2f30Ssthen 	printf("id (hostorder): %d (0x%x)\n", (int)i, (unsigned)i);
163*712b2f30Ssthen 	f = sldns_buffer_read_u16(pkt);
164*712b2f30Ssthen 	printf("flags: 0x%x\n", (unsigned)f);
165*712b2f30Ssthen 	qd = sldns_buffer_read_u16(pkt);
166*712b2f30Ssthen 	printf("qdcount: %d\n", (int)qd);
167*712b2f30Ssthen 	an = sldns_buffer_read_u16(pkt);
168*712b2f30Ssthen 	printf("ancount: %d\n", (int)an);
169*712b2f30Ssthen 	ns = sldns_buffer_read_u16(pkt);
170*712b2f30Ssthen 	printf("nscount: %d\n", (int)ns);
171*712b2f30Ssthen 	ar = sldns_buffer_read_u16(pkt);
172*712b2f30Ssthen 	printf("arcount: %d\n", (int)ar);
173*712b2f30Ssthen 
174*712b2f30Ssthen 	printf(";-- query section\n");
175*712b2f30Ssthen 	while(sldns_buffer_remaining(pkt) > 0) {
176*712b2f30Ssthen 		if(rrnum == (int)qd)
177*712b2f30Ssthen 			printf(";-- answer section\n");
178*712b2f30Ssthen 		if(rrnum == (int)qd+(int)an)
179*712b2f30Ssthen 			printf(";-- authority section\n");
180*712b2f30Ssthen 		if(rrnum == (int)qd+(int)an+(int)ns)
181*712b2f30Ssthen 			printf(";-- additional section\n");
182*712b2f30Ssthen 		printf("rr %d ", rrnum);
183*712b2f30Ssthen 		analyze_rr(pkt, rrnum < (int)qd);
184*712b2f30Ssthen 		rrnum++;
185*712b2f30Ssthen 	}
186*712b2f30Ssthen }
187*712b2f30Ssthen 
188*712b2f30Ssthen /** main program for pktview */
main(int argc,char * argv[])189*712b2f30Ssthen int main(int argc, char* argv[])
190*712b2f30Ssthen {
191*712b2f30Ssthen 	sldns_buffer* pkt = sldns_buffer_new(65553);
192*712b2f30Ssthen 	if(argc != 1) {
193*712b2f30Ssthen 		usage(argv);
194*712b2f30Ssthen 	}
195*712b2f30Ssthen 	if(!pkt) fatal_exit("out of memory");
196*712b2f30Ssthen 
197*712b2f30Ssthen 	read_input(pkt, stdin);
198*712b2f30Ssthen 	analyze(pkt);
199*712b2f30Ssthen 
200*712b2f30Ssthen 	sldns_buffer_free(pkt);
201*712b2f30Ssthen 	return 0;
202*712b2f30Ssthen }
203