/****************************************************************************
** 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();
}
syntax highlighted by Code2HTML, v. 0.9.1