/**************************************************************************** ** File: dns.c ** ** Author: Mike Borella ** ** Comments: Dump DNS header information ** ** $Id: dns.c,v 1.21 2002/01/03 00:04:01 mborella Exp $ ** ** 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 2 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 Library General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** *****************************************************************************/ #include "dns.h" #include "ns_labels.h" #define HOLDER_SIZE 256 /* * QR flag map */ strmap_t dns_qrflag_map [] = { { DNS_QRFLAG_QUERY, "query" }, { DNS_QRFLAG_RESPONSE, "response" }, { 0, "" } }; /* * Opcode flag map */ strmap_t dns_opcodeflag_map [] = { { DNS_OPCODEFLAG_STANDARD, "standard" }, { DNS_OPCODEFLAG_INVERSE, "inverse" }, { DNS_OPCODEFLAG_STATUS, "status" }, { 0, "" } }; /* * Rcode (return code) flag map */ strmap_t dns_rcodeflag_map [] = { { DNS_RCODEFLAG_NOERROR, "no error" }, { DNS_RCODEFLAG_FORMATERROR, "format error" }, { DNS_RCODEFLAG_SERVERERROR, "server error" }, { DNS_RCODEFLAG_NAMEERROR, "name error" }, { DNS_RCODEFLAG_NOTIMPLEMENTED, "not implemented" }, { DNS_RCODEFLAG_SERVICEREFUSED, "service refused" }, { 0, "" } }; /* * Query type map */ strmap_t dns_querytype_map [] = { { DNS_QUERYTYPE_A, "A - IP address" }, { DNS_QUERYTYPE_NS, "NS - name server" }, { DNS_QUERYTYPE_CNAME, "CNAME - canonical name" }, { DNS_QUERYTYPE_SOA, "SOA - start of auth record" }, { DNS_QUERYTYPE_PTR, "PTR - pointer record" }, { DNS_QUERYTYPE_HINFO, "HINFO - host info" }, { DNS_QUERYTYPE_MX, "MX - mail exchange record" }, { DNS_QUERYTYPE_AAAA, "AAAA - IPv6 address" }, { DNS_QUERYTYPE_AXFR, "AXFR - zone transfer request" }, { DNS_QUERYTYPE_ANY, "ANY - all records request" }, { 0, "" } }; /* * Query class map */ strmap_t dns_queryclass_map [] = { { DNS_QUERYCLASS_IP, "Internet" }, { 0, "" } }; extern struct arg_t *my_args; /*---------------------------------------------------------------------------- ** ** dump_dns_questions() ** ** Parse DNS questions and display them ** **---------------------------------------------------------------------------- */ void dump_dns_questions(packet_t *pkt, u_int8_t num) { char holder[HOLDER_SIZE]; u_int16_t query_type, query_class; while(num > 0) { /* * Parse the name */ parse_ns_labels(pkt, holder); /* * Parse the query type and class */ if (get_packet_bytes((u_int8_t *) &query_type, pkt, 2) == 0) return; if (get_packet_bytes((u_int8_t *) &query_class, pkt, 2) == 0) return; /* * Conversions */ query_type = ntohs(query_type); query_class = ntohs(query_class); /* * Dump the info */ if (my_args->m) { display_minimal_string(holder); display_minimal_string(" "); } else { display_string("Query", holder); snprintf(holder, HOLDER_SIZE, "%d (%s)", query_type, map2str(dns_querytype_map, query_type)); display_string(" Query type", holder); snprintf(holder, HOLDER_SIZE, "%d (%s)", query_class, map2str(dns_queryclass_map, query_class)); display_string(" Query class", holder); } num --; } } /*---------------------------------------------------------------------------- ** ** dump_dns_answers() ** ** Parse DNS answers and display them ** **---------------------------------------------------------------------------- */ void dump_dns_answers(packet_t *pkt, u_int8_t num, char *answer_type) { char holder[HOLDER_SIZE]; u_int16_t query_type, query_class; u_int32_t ttl; u_int16_t rdl; u_int8_t resource_data[64]; while(num > 0) { /* * Parse the name */ parse_ns_labels(pkt, holder); /* * Parse the query type and class */ if (get_packet_bytes((u_int8_t *) &query_type, pkt, 2) == 0) return; if (get_packet_bytes((u_int8_t *) &query_class, pkt, 2) == 0) return; if (get_packet_bytes((u_int8_t *) &ttl, pkt, 4) == 0) return; if (get_packet_bytes((u_int8_t *) &rdl, pkt, 2) == 0) return; /* * Conversions */ query_type = ntohs(query_type); query_class = ntohs(query_class); ttl = ntohl(ttl); rdl = ntohs(rdl); /* * Get the resource data */ switch (query_type) { case DNS_QUERYTYPE_NS: case DNS_QUERYTYPE_CNAME: case DNS_QUERYTYPE_SOA: case DNS_QUERYTYPE_PTR: parse_ns_labels(pkt, resource_data); break; case DNS_QUERYTYPE_A: default: if (get_packet_bytes((u_int8_t *) &resource_data, pkt, rdl) == 0) return; break; } /* * Dump the info */ if (my_args->m) { if (query_type == DNS_QUERYTYPE_A && !strcmp(answer_type, "Answers")) { display_minimal_ipv4((u_int8_t *) resource_data); display_minimal_string(" "); } if (query_type == DNS_QUERYTYPE_AAAA && !strcmp(answer_type, "Answers") && rdl == 16 ) { display_minimal_ipv6((u_int8_t *) resource_data); display_minimal_string(" "); } } else { display_string(answer_type, holder); snprintf(holder, HOLDER_SIZE, "%d (%s)", query_type, map2str(dns_querytype_map, query_type)); display_string(" Query type", holder); snprintf(holder, HOLDER_SIZE, "%d (%s)", query_class, map2str(dns_queryclass_map, query_class)); display_string(" Query class", holder); display(" TTL", (u_int8_t *) &ttl, 4, DISP_DEC); display(" Resource data length", (u_int8_t *) &rdl, 2, DISP_DEC); switch(query_type) { case DNS_QUERYTYPE_A: display_ipv4(" Resource data", (u_int8_t *) resource_data); break; case DNS_QUERYTYPE_AAAA: display_ipv6(" Resource data", (u_int8_t *) resource_data); break; case DNS_QUERYTYPE_NS: case DNS_QUERYTYPE_CNAME: case DNS_QUERYTYPE_SOA: case DNS_QUERYTYPE_PTR: display_string(" Resource data", resource_data); break; default: display(" Resource data", (u_int8_t *) resource_data, rdl, DISP_HEX); } } num --; } } /*---------------------------------------------------------------------------- ** ** dump_dns() ** ** Parse DNS packet and dump fields ** **---------------------------------------------------------------------------- */ void dump_dns(packet_t *pkt) { dns_header_t dns; u_int8_t f_qr, f_opcode, f_aa, f_tc, f_rd, f_ra, f_zero, f_rcode; char holder[HOLDER_SIZE]; /* Set the layer */ set_layer(LAYER_APPLICATION); /* * Mark the beginning of the DNS portion so that labels can be stored * properly */ set_packet_mark(pkt); /* * Reset the DNS labels structures for a new DNS packet */ reset_nslabels(); /* * Get the header */ if (get_packet_bytes((u_int8_t *) &dns, pkt, 12) == 0) return; /* * Conversions */ dns.id = ntohs(dns.id); dns.number_questions = ntohs(dns.number_questions); dns.number_answers = ntohs(dns.number_answers); dns.number_authority = ntohs(dns.number_authority); dns.number_additional = ntohs(dns.number_additional); f_qr = dns.flag_qr; f_opcode = dns.flag_opcode; f_aa = dns.flag_aa; f_tc = dns.flag_tc; f_rd = dns.flag_rd; f_ra = dns.flag_ra; f_zero = dns.flag_zero; f_rcode = dns.flag_rcode; /* * Print it */ if (my_args->m) { display_minimal_string("| DNS "); display_minimal_string(map2str(dns_qrflag_map, f_qr)); display_minimal_string(" "); } else { /* announcement */ display_header_banner("DNS Header"); /* identification */ display("Identification", (u_int8_t *) &dns.id, 2, DISP_DEC); /* flags */ snprintf(holder, HOLDER_SIZE, "%d (%s)", f_qr, map2str(dns_qrflag_map, f_qr)); display_string("Flag query/response", holder); snprintf(holder, HOLDER_SIZE, "%d (%s)", f_opcode, map2str(dns_opcodeflag_map, f_opcode)); display_string("Flag opcode", holder); display("Flag auth answer", (u_int8_t *) &f_aa, 1, DISP_BINNLZ); display("Flag trunctated", (u_int8_t *) &f_tc, 1, DISP_BINNLZ); display("Flag recursion desired", (u_int8_t *) &f_ra, 1, DISP_BINNLZ); display("Flag recursion available", (u_int8_t *) &f_ra, 1, DISP_BINNLZ); display("Flag zero", (u_int8_t *) &f_zero, 1, DISP_BINNLZ); snprintf(holder, HOLDER_SIZE, "%d (%s)", f_rcode, map2str(dns_rcodeflag_map, f_rcode)); display_string("Flag return code", holder); /* numbers of questions and answers */ display("# of questions", (u_int8_t *) &dns.number_questions, 2, DISP_DEC); display("# of answers", (u_int8_t *) &dns.number_answers, 2, DISP_DEC); display("# of authorization RRs", (u_int8_t *) &dns.number_authority, 2, DISP_DEC); display("# of additional RRs", (u_int8_t *) &dns.number_additional, 2, DISP_DEC); } /* * Parse the question and answers */ dump_dns_questions(pkt, dns.number_questions); dump_dns_answers(pkt, dns.number_answers, "Answers"); dump_dns_answers(pkt, dns.number_authority, "Auth answers"); dump_dns_answers(pkt, dns.number_additional, "Addtl answers"); /* dump the hex buffer */ hexbuffer_flush(); }