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