1 /****************************************************************************
2 ** File: dns.c
3 **
4 ** Author: Mike Borella
5 **
6 ** Comments: Dump DNS header information
7 **
8 ** $Id: dns.c,v 1.21 2002/01/03 00:04:01 mborella Exp $
9 **
10 ** This program is free software; you can redistribute it and/or modify
11 ** it under the terms of the GNU General Public License as published by
12 ** the Free Software Foundation; either version 2 of the License, or
13 ** (at your option) any later version.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ** GNU Library General Public License for more details.
19 **
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 **
24 *****************************************************************************/
25 
26 #include "dns.h"
27 #include "ns_labels.h"
28 
29 #define HOLDER_SIZE 256
30 
31 /*
32  * QR flag map
33  */
34 
35 strmap_t dns_qrflag_map [] =
36 {
37   { DNS_QRFLAG_QUERY,     "query" },
38   { DNS_QRFLAG_RESPONSE,  "response" },
39   { 0, "" }
40 };
41 
42 /*
43  * Opcode flag map
44  */
45 
46 strmap_t dns_opcodeflag_map [] =
47 {
48   { DNS_OPCODEFLAG_STANDARD,    "standard" },
49   { DNS_OPCODEFLAG_INVERSE,     "inverse" },
50   { DNS_OPCODEFLAG_STATUS,      "status" },
51   { 0, "" }
52 };
53 
54 
55 /*
56  * Rcode (return code) flag map
57  */
58 
59 strmap_t dns_rcodeflag_map [] =
60 {
61   { DNS_RCODEFLAG_NOERROR,          "no error" },
62   { DNS_RCODEFLAG_FORMATERROR,      "format error" },
63   { DNS_RCODEFLAG_SERVERERROR,      "server error" },
64   { DNS_RCODEFLAG_NAMEERROR,        "name error" },
65   { DNS_RCODEFLAG_NOTIMPLEMENTED,   "not implemented" },
66   { DNS_RCODEFLAG_SERVICEREFUSED,   "service refused" },
67   { 0, "" }
68 };
69 
70 /*
71  * Query type map
72  */
73 
74 strmap_t dns_querytype_map [] =
75 {
76   { DNS_QUERYTYPE_A,           "A - IP address" },
77   { DNS_QUERYTYPE_NS,          "NS - name server" },
78   { DNS_QUERYTYPE_CNAME,       "CNAME - canonical name" },
79   { DNS_QUERYTYPE_SOA,         "SOA - start of auth record" },
80   { DNS_QUERYTYPE_PTR,         "PTR - pointer record" },
81   { DNS_QUERYTYPE_HINFO,       "HINFO - host info" },
82   { DNS_QUERYTYPE_MX,          "MX - mail exchange record" },
83   { DNS_QUERYTYPE_AAAA,        "AAAA - IPv6 address" },
84   { DNS_QUERYTYPE_AXFR,        "AXFR - zone transfer request" },
85   { DNS_QUERYTYPE_ANY,         "ANY - all records request" },
86   { 0, "" }
87 };
88 
89 /*
90  * Query class map
91  */
92 
93 strmap_t dns_queryclass_map [] =
94 {
95   { DNS_QUERYCLASS_IP,         "Internet" },
96   { 0, "" }
97 };
98 
99 extern struct arg_t *my_args;
100 
101 /*----------------------------------------------------------------------------
102 **
103 ** dump_dns_questions()
104 **
105 ** Parse DNS questions and display them
106 **
107 **----------------------------------------------------------------------------
108 */
109 
dump_dns_questions(packet_t * pkt,u_int8_t num)110 void dump_dns_questions(packet_t *pkt, u_int8_t num)
111 {
112   char holder[HOLDER_SIZE];
113   u_int16_t query_type, query_class;
114 
115   while(num > 0)
116     {
117       /*
118        * Parse the name
119        */
120 
121       parse_ns_labels(pkt, holder);
122 
123       /*
124        * Parse the query type and class
125        */
126 
127       if (get_packet_bytes((u_int8_t *) &query_type, pkt, 2) == 0)
128 	return;
129       if (get_packet_bytes((u_int8_t *) &query_class, pkt, 2) == 0)
130 	return;
131 
132       /*
133        * Conversions
134        */
135 
136       query_type = ntohs(query_type);
137       query_class = ntohs(query_class);
138 
139       /*
140        * Dump the info
141        */
142 
143       if (my_args->m)
144 	{
145 	  display_minimal_string(holder);
146 	  display_minimal_string(" ");
147 	}
148       else
149 	{
150 	  display_string("Query", holder);
151 	  snprintf(holder, HOLDER_SIZE, "%d (%s)", query_type,
152 		  map2str(dns_querytype_map, query_type));
153 	  display_string("  Query type", holder);
154 	  snprintf(holder, HOLDER_SIZE, "%d (%s)", query_class,
155 		  map2str(dns_queryclass_map, query_class));
156 	  display_string("  Query class", holder);
157 	}
158 
159       num --;
160     }
161 }
162 
163 /*----------------------------------------------------------------------------
164 **
165 ** dump_dns_answers()
166 **
167 ** Parse DNS answers and display them
168 **
169 **----------------------------------------------------------------------------
170 */
dump_dns_answers(packet_t * pkt,u_int8_t num,char * answer_type)171 void dump_dns_answers(packet_t *pkt, u_int8_t num, char *answer_type)
172 {
173   char holder[HOLDER_SIZE];
174   u_int16_t query_type, query_class;
175   u_int32_t ttl;
176   u_int16_t rdl;
177   u_int8_t resource_data[64];
178 
179   while(num > 0)
180     {
181       /*
182        * Parse the name
183        */
184 
185       parse_ns_labels(pkt, holder);
186 
187       /*
188        * Parse the query type and class
189        */
190 
191       if (get_packet_bytes((u_int8_t *) &query_type, pkt, 2) == 0)
192 	return;
193       if (get_packet_bytes((u_int8_t *) &query_class, pkt, 2) == 0)
194 	return;
195       if (get_packet_bytes((u_int8_t *) &ttl, pkt, 4) == 0)
196 	return;
197       if (get_packet_bytes((u_int8_t *) &rdl, pkt, 2) == 0)
198 	return;
199 
200       /*
201        * Conversions
202        */
203 
204       query_type = ntohs(query_type);
205       query_class = ntohs(query_class);
206       ttl = ntohl(ttl);
207       rdl = ntohs(rdl);
208 
209       /*
210        * Get the resource data
211        */
212 
213       switch (query_type)
214 	{
215 	case DNS_QUERYTYPE_NS:
216 	case DNS_QUERYTYPE_CNAME:
217 	case DNS_QUERYTYPE_SOA:
218 	case DNS_QUERYTYPE_PTR:
219 	  parse_ns_labels(pkt, resource_data);
220 	  break;
221 
222 	case DNS_QUERYTYPE_A:
223 	default:
224 	  if (get_packet_bytes((u_int8_t *) &resource_data, pkt,
225 			       rdl) == 0)
226 	    return;
227 	  break;
228 
229 	}
230 
231       /*
232        * Dump the info
233        */
234 
235       if (my_args->m)
236 	{
237 	  if (query_type == DNS_QUERYTYPE_A && !strcmp(answer_type, "Answers"))
238 	    {
239 	      display_minimal_ipv4((u_int8_t *) resource_data);
240 	      display_minimal_string(" ");
241 	    }
242 	  if (query_type == DNS_QUERYTYPE_AAAA &&
243 	      !strcmp(answer_type, "Answers") && rdl == 16 )
244 	    {
245 	      display_minimal_ipv6((u_int8_t *) resource_data);
246 	      display_minimal_string(" ");
247 	    }
248 	}
249       else
250 	{
251 	  display_string(answer_type, holder);
252 	  snprintf(holder, HOLDER_SIZE, "%d (%s)", query_type,
253 		  map2str(dns_querytype_map, query_type));
254 	  display_string("  Query type", holder);
255 	  snprintf(holder, HOLDER_SIZE, "%d (%s)", query_class,
256 		  map2str(dns_queryclass_map, query_class));
257 	  display_string("  Query class", holder);
258 	  display("  TTL", (u_int8_t *) &ttl, 4, DISP_DEC);
259 	  display("  Resource data length", (u_int8_t *) &rdl, 2,
260 		  DISP_DEC);
261 	  switch(query_type)
262 	    {
263 	    case DNS_QUERYTYPE_A:
264 	      display_ipv4("  Resource data", (u_int8_t *) resource_data);
265 	      break;
266 
267 	    case DNS_QUERYTYPE_AAAA:
268 	      display_ipv6("  Resource data", (u_int8_t *) resource_data);
269 	      break;
270 
271 	    case DNS_QUERYTYPE_NS:
272 	    case DNS_QUERYTYPE_CNAME:
273 	    case DNS_QUERYTYPE_SOA:
274 	    case DNS_QUERYTYPE_PTR:
275 	      display_string("  Resource data", resource_data);
276 	      break;
277 
278 	    default:
279 	      display("  Resource data", (u_int8_t *) resource_data, rdl,
280 		      DISP_HEX);
281 	    }
282 	}
283 
284       num --;
285     }
286 
287 }
288 
289 /*----------------------------------------------------------------------------
290 **
291 ** dump_dns()
292 **
293 ** Parse DNS packet and dump fields
294 **
295 **----------------------------------------------------------------------------
296 */
297 
dump_dns(packet_t * pkt)298 void dump_dns(packet_t *pkt)
299 {
300   dns_header_t dns;
301   u_int8_t f_qr, f_opcode, f_aa, f_tc, f_rd, f_ra, f_zero, f_rcode;
302   char holder[HOLDER_SIZE];
303 
304   /* Set the layer */
305   set_layer(LAYER_APPLICATION);
306 
307   /*
308    * Mark the beginning of the DNS portion so that labels can be stored
309    * properly
310    */
311 
312   set_packet_mark(pkt);
313 
314   /*
315    * Reset the DNS labels structures for a new DNS packet
316    */
317 
318   reset_nslabels();
319 
320   /*
321    * Get the header
322    */
323 
324   if (get_packet_bytes((u_int8_t *) &dns, pkt, 12) == 0)
325     return;
326 
327   /*
328    * Conversions
329    */
330 
331   dns.id = ntohs(dns.id);
332   dns.number_questions = ntohs(dns.number_questions);
333   dns.number_answers = ntohs(dns.number_answers);
334   dns.number_authority = ntohs(dns.number_authority);
335   dns.number_additional = ntohs(dns.number_additional);
336   f_qr = dns.flag_qr;
337   f_opcode = dns.flag_opcode;
338   f_aa = dns.flag_aa;
339   f_tc = dns.flag_tc;
340   f_rd = dns.flag_rd;
341   f_ra = dns.flag_ra;
342   f_zero = dns.flag_zero;
343   f_rcode = dns.flag_rcode;
344 
345   /*
346    * Print it
347    */
348 
349   if (my_args->m)
350     {
351       display_minimal_string("| DNS ");
352       display_minimal_string(map2str(dns_qrflag_map, f_qr));
353       display_minimal_string(" ");
354     }
355   else
356     {
357       /* announcement */
358       display_header_banner("DNS Header");
359 
360       /* identification */
361       display("Identification", (u_int8_t *) &dns.id, 2, DISP_DEC);
362 
363       /* flags */
364       snprintf(holder, HOLDER_SIZE, "%d (%s)", f_qr,
365 	       map2str(dns_qrflag_map, f_qr));
366       display_string("Flag query/response", holder);
367       snprintf(holder, HOLDER_SIZE, "%d (%s)", f_opcode,
368 	      map2str(dns_opcodeflag_map, f_opcode));
369       display_string("Flag opcode", holder);
370       display("Flag auth answer", (u_int8_t *) &f_aa, 1, DISP_BINNLZ);
371       display("Flag trunctated", (u_int8_t *) &f_tc, 1, DISP_BINNLZ);
372       display("Flag recursion desired", (u_int8_t *) &f_ra, 1, DISP_BINNLZ);
373       display("Flag recursion available", (u_int8_t *) &f_ra, 1, DISP_BINNLZ);
374       display("Flag zero", (u_int8_t *) &f_zero, 1, DISP_BINNLZ);
375       snprintf(holder, HOLDER_SIZE, "%d (%s)", f_rcode,
376 	      map2str(dns_rcodeflag_map, f_rcode));
377       display_string("Flag return code", holder);
378 
379       /* numbers of questions and answers */
380       display("# of questions", (u_int8_t *) &dns.number_questions, 2,
381 	      DISP_DEC);
382       display("# of answers", (u_int8_t *) &dns.number_answers, 2,
383 	      DISP_DEC);
384       display("# of authorization RRs", (u_int8_t *) &dns.number_authority, 2,
385 	      DISP_DEC);
386       display("# of additional RRs", (u_int8_t *) &dns.number_additional, 2,
387 	      DISP_DEC);
388     }
389 
390   /*
391    * Parse the question and answers
392    */
393 
394   dump_dns_questions(pkt, dns.number_questions);
395   dump_dns_answers(pkt, dns.number_answers, "Answers");
396   dump_dns_answers(pkt, dns.number_authority, "Auth answers");
397   dump_dns_answers(pkt, dns.number_additional, "Addtl answers");
398 
399   /* dump the hex buffer */
400   hexbuffer_flush();
401 
402 }
403 
404 
405 
406 
407 
408