/****************************************************************************
** File: netbios_ns.c
**
** Author: Mike Borella
**
** Dump netbios name service data
**
** $Id: netbios_ns.c,v 1.8 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 "global.h"
#include "netbios_ns.h"
#include "ns_labels.h"
#define HOLDER_SIZE 256
extern struct arg_t *my_args;
/*
* R flag map
*/
strmap_t netbios_ns_r_map [] =
{
{ NETBIOS_NS_R_QUERY, "query" },
{ NETBIOS_NS_R_RESPONSE, "response" },
{ 0, "" }
};
/*
* Opcode map
*/
strmap_t netbios_ns_opcode_map [] =
{
{ NETBIOS_NS_OPCODE_QUERY, "query" },
{ NETBIOS_NS_OPCODE_REGISTRATION, "registration" },
{ NETBIOS_NS_OPCODE_RELEASE, "release" },
{ NETBIOS_NS_OPCODE_WACK, "WACK" },
{ NETBIOS_NS_OPCODE_REFRESH, "refresh" },
{ 0, "" }
};
/*
* Rcode map
*/
strmap_t netbios_ns_rcode_map [] =
{
{ NETBIOS_NS_RCODE_NOERROR, "no error" },
{ 0, "" }
};
/*
* Query type map
*/
strmap_t netbios_ns_querytype_map [] =
{
{ NETBIOS_NS_QUERYTYPE_IPADDR, "A - IP address" },
{ NETBIOS_NS_QUERYTYPE_NAMESERVER, "NS - name server" },
{ NETBIOS_NS_QUERYTYPE_NULL, "NULL" },
{ NETBIOS_NS_QUERYTYPE_GENERAL, "NB - general" },
{ NETBIOS_NS_QUERYTYPE_NODESTATUS, "NBSTAT - node status" },
{ 0, "" }
};
/*
* Query class map
*/
strmap_t netbios_ns_queryclass_map [] =
{
{ NETBIOS_NS_QUERYCLASS_IP, "Internet" },
{ 0, "" }
};
/*----------------------------------------------------------------------------
**
** translate_netbios_ns_format()
**
** Translate the NETBIOS name format to something that makes sense to humans
**
** We do the reverse of this:
**
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|a b c d|w x y z| ORIGINAL BYTE
+-+-+-+-+-+-+-+-+
| |
+--------+ +--------+
| | SPLIT THE NIBBLES
v v
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|0 0 0 0 a b c d| |0 0 0 0 w x y z|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
| |
+ + ADD 'A'
| |
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|0 1 0 0 0 0 0 1| |0 1 0 0 0 0 0 1|
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
**----------------------------------------------------------------------------
*/
void translate_netbios_name(char *s)
{
char output[32];
int output_ptr = 0;
int input_ptr = 0;
int input_length = strlen(s);
char *ptr;
while(input_ptr < input_length)
{
char high_char, low_char;
/* get next two chars */
high_char = s[input_ptr];
input_ptr ++;
low_char = s[input_ptr];
input_ptr ++;
/* subtract A from each */
high_char = high_char - 'A';
low_char = low_char - 'A';
/* shift the high char left by 4 */
high_char = high_char << 4;
/* combine them into the output */
output[output_ptr] = high_char | low_char;
output_ptr++;
}
/* null terminate, eliminate spaces, and copy back to the input string */
output[output_ptr] = '\0';
strcat(output, " ");
ptr = strchr(output, ' ');
*ptr = '\0';
strcpy(s, output);
}
/*----------------------------------------------------------------------------
**
** dump_netbios_ns_questions()
**
** Parse NETBIOS name service questions and display them
**
**----------------------------------------------------------------------------
*/
void dump_netbios_ns_questions(packet_t *pkt, u_int16_t num)
{
char holder[HOLDER_SIZE];
u_int16_t query_type, query_class;
while(num > 0)
{
/*
* Parse the name
*/
parse_ns_labels(pkt, holder);
/*
* The name is stored in wacky NETBIOS format, with each
* character spread across 2 bytes. Let's fix that.
*
*/
/*
* 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);
/*
* The name may be stored in wacky NETBIOS format, with each
* character spread across 2 bytes. Let's fix that.
*/
if (query_type == NETBIOS_NS_QUERYTYPE_GENERAL)
translate_netbios_name(holder);
/*
* 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(netbios_ns_querytype_map, query_type));
display_string(" Type", holder);
snprintf(holder, HOLDER_SIZE, "%d (%s)", query_class,
map2str(netbios_ns_queryclass_map, query_class));
display_string(" Query class", holder);
}
num --;
}
}
/*----------------------------------------------------------------------------
**
** dump_netbios_ns_answers()
**
** Parse NETBIOS NS answers and display them
**
**----------------------------------------------------------------------------
*/
void dump_netbios_ns_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];
u_int16_t nb_flags;
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);
/*
* The name may be stored in wacky NETBIOS format, with each
* character spread across 2 bytes. Let's fix that.
*/
if (query_type == NETBIOS_NS_QUERYTYPE_GENERAL)
translate_netbios_name(holder);
/*
* Get the resource data
*/
switch (query_type)
{
case NETBIOS_NS_QUERYTYPE_NAMESERVER:
parse_ns_labels(pkt, resource_data);
break;
case NETBIOS_NS_QUERYTYPE_IPADDR:
case NETBIOS_NS_QUERYTYPE_GENERAL:
default:
if (get_packet_bytes((u_int8_t *) &nb_flags, pkt, 2) == 0)
return;
if (get_packet_bytes((u_int8_t *) &resource_data, pkt, 4) == 0)
return;
break;
}
/*
* Dump the info
*/
if (my_args->m)
{
if (query_type == NETBIOS_NS_QUERYTYPE_GENERAL &&
query_class == NETBIOS_NS_QUERYCLASS_IP)
{
display_minimal_ipv4((u_int8_t *) resource_data);
display_minimal_string(" ");
}
}
else
{
display_string(answer_type, holder);
snprintf(holder, HOLDER_SIZE, "%d (%s)", query_type,
map2str(netbios_ns_querytype_map, query_type));
display_string(" Query type", holder);
snprintf(holder, HOLDER_SIZE, "%d (%s)", query_class,
map2str(netbios_ns_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 NETBIOS_NS_QUERYTYPE_IPADDR:
case NETBIOS_NS_QUERYTYPE_GENERAL:
display(" NB flags", (u_int8_t *) &nb_flags, 2, DISP_HEX);
display_ipv4(" Resource data", (u_int8_t *) resource_data);
break;
case NETBIOS_NS_QUERYTYPE_NAMESERVER:
display_string(" Resource data", resource_data);
break;
default:
display(" Resource data", (u_int8_t *) resource_data, rdl,
DISP_HEX);
}
}
num --;
}
}
/*----------------------------------------------------------------------------
**
** dump_netbios_ns()
**
** Parse netbios name service header and dump fields
**
**----------------------------------------------------------------------------
*/
void dump_netbios_ns(packet_t *pkt)
{
netbios_ns_t nb_ns;
u_int8_t holder[64];
u_int8_t r, opcode, flags, rcode;
u_int8_t flag_aa, flag_tc, flag_rd, flag_ra, flag_zeros, flag_b;
/* Set the layer */
set_layer(LAYER_APPLICATION);
/*
* Mark the beginning of the NS portion so that labels can be stored
* properly
*/
set_packet_mark(pkt);
/*
* Reset the NS label module
*/
reset_nslabels();
/*
* Read the header
*/
if (get_packet_bytes((u_int8_t *) &nb_ns, pkt, sizeof(netbios_ns_t)) == 0)
return;
/*
* Conversions
*/
nb_ns.transaction_id = ntohs(nb_ns.transaction_id);
r = nb_ns.r;
opcode = nb_ns.opcode;
flags = (nb_ns.flags_high << 4) || nb_ns.flags_low;
flag_aa = (flags & 0x40) >> 7;
flag_tc = (flags & 0x20) >> 6;
flag_rd = (flags & 0x10) >> 5;
flag_ra = (flags & 0x08) >> 4;
flag_zeros = (flags & 0x06) >> 1;
flag_b = (flags & 0x01);
rcode = nb_ns.rcode;
nb_ns.questions = ntohs(nb_ns.questions);
nb_ns.answers = ntohs(nb_ns.answers);
nb_ns.auth_answers = ntohs(nb_ns.auth_answers);
nb_ns.add_answers = ntohs(nb_ns.add_answers);
/*
* Dump header
*/
if (my_args->m)
{
display_minimal_string("| NETBIOS NS ");
display_minimal_string(map2str(netbios_ns_r_map, r));
display_minimal_string(" ");
}
else
{
/* announcement */
display_header_banner("NETBIOS Name Service");
/* fields */
display("Transaction ID", (u_int8_t *) &nb_ns.transaction_id, 2,
DISP_DEC);
snprintf(holder, HOLDER_SIZE, "%d (%s)", r,
map2str(netbios_ns_r_map, r));
display_string("R", holder);
snprintf(holder, HOLDER_SIZE, "%d (%s)", opcode,
map2str(netbios_ns_opcode_map, opcode));
display_string("Opcode", holder);
snprintf(holder, HOLDER_SIZE, "%d (%s)", rcode,
map2str(netbios_ns_rcode_map, rcode));
display_string("Rcode", holder);
/* number of questions and answers */
display("Questions", (u_int8_t *) &nb_ns.questions, 2, DISP_DEC);
display("Answers", (u_int8_t *) &nb_ns.answers, 2, DISP_DEC);
display("Auth answers", (u_int8_t *) &nb_ns.auth_answers, 2, DISP_DEC);
display("Add answers", (u_int8_t *) &nb_ns.add_answers, 2, DISP_DEC);
}
/*
* Parse the question and answers
*/
dump_netbios_ns_questions(pkt, nb_ns.questions);
dump_netbios_ns_answers(pkt, nb_ns.answers, "Answers");
dump_netbios_ns_answers(pkt, nb_ns.auth_answers, "Auth answers");
dump_netbios_ns_answers(pkt, nb_ns.add_answers, "Addtl answers");
/* dump the hex buffer */
hexbuffer_flush();
}
syntax highlighted by Code2HTML, v. 0.9.1