Tag NetBIOS Name Service-over-UDP packets as "NBNS (UDP)".

Give a detailed display of the innards of NBNS-over-UDP packets.  Export
some stuff from the DNS decoder for the use of the NBNS decoder (NBNS is
DNS-like).

Give a more detailed display of the innards of DNS packets as well.

Fix a couple of minor NBNS bugs.

svn path=/trunk/; revision=55
This commit is contained in:
Guy Harris 1998-10-14 19:35:00 +00:00
parent b3da21d812
commit 022967513b
4 changed files with 804 additions and 149 deletions

View File

@ -1,6 +1,6 @@
/* ethereal.c
*
* $Id: ethereal.c,v 1.5 1998/10/12 01:40:47 gerald Exp $
* $Id: ethereal.c,v 1.6 1998/10/14 19:34:57 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -520,7 +520,7 @@ main(int argc, char *argv[])
col_width = gdk_string_width(pl_style->font, "00:00:00:00:00:00") + 2;
gtk_clist_set_column_width(GTK_CLIST(packet_list), COL_SOURCE, col_width);
gtk_clist_set_column_width(GTK_CLIST(packet_list), COL_DESTINATION, col_width);
col_width = gdk_string_width(pl_style->font, "AppleTalk") + 2;
col_width = gdk_string_width(pl_style->font, "NBNS (UDP)") + 2;
gtk_clist_set_column_width(GTK_CLIST(packet_list), COL_PROTOCOL, col_width);
gtk_widget_set_usize(packet_list, -1, pl_size);
gtk_paned_add1(GTK_PANED(u_pane), packet_list);

View File

@ -1,7 +1,7 @@
/* packet-dns.c
* Routines for DNS packet disassembly
*
* $Id: packet-dns.c,v 1.4 1998/09/27 22:12:28 gerald Exp $
* $Id: packet-dns.c,v 1.5 1998/10/14 19:34:58 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -43,6 +43,7 @@
#include "ethereal.h"
#include "packet.h"
#include "packet-dns.h"
/* DNS structs and definitions */
@ -56,8 +57,6 @@ typedef struct _e_dns {
guint16 dns_add;
} e_dns;
#define MAXDNAME 1025 /* maximum domain name */
/* type values */
#define T_A 1 /* host address */
#define T_NS 2 /* authoritative server */
@ -71,8 +70,6 @@ typedef struct _e_dns {
#define T_AAAA 28 /* IP6 Address */
static const u_char *dns_data_ptr;
static char *
dns_type_name (int type)
{
@ -116,7 +113,7 @@ dns_type_name (int type)
}
static char *
char *
dns_class_name(int class)
{
char *class_name;
@ -171,7 +168,8 @@ copy_one_name_component(const u_char *dataptr, char *nameptr)
static int
copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_len)
copy_name_component_rec(const u_char *dns_data_ptr, const u_char *dataptr,
char *nameptr, int *real_string_len)
{
int len = 0;
int str_len;
@ -182,7 +180,7 @@ copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_l
compress = 1;
offset = get_compressed_name_offset(dataptr);
dataptr = dns_data_ptr + offset;
copy_name_component_rec(dataptr, nameptr, &str_len);
copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
*real_string_len += str_len;
nameptr += str_len;
len = 2;
@ -202,7 +200,7 @@ copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_l
if (*dataptr > 0) {
*nameptr++ = '.';
len += copy_name_component_rec(dataptr, nameptr, &str_len);
len += copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
*real_string_len += str_len;
return len;
}
@ -211,24 +209,27 @@ copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_l
}
static int
get_dns_name(const u_char *pd, int offset, char *nameptr, int maxname)
int
get_dns_name(const u_char *dns_data_ptr, const u_char *pd, int offset,
char *nameptr, int maxname)
{
int len;
const u_char *dataptr = pd + offset;
int str_len = 0;
memset (nameptr, 0, maxname);
len = copy_name_component_rec(dataptr, nameptr, &str_len);
len = copy_name_component_rec(dns_data_ptr, dataptr, nameptr, &str_len);
return len;
}
static int
get_dns_name_type_class (const u_char *pd,
get_dns_name_type_class (const u_char *dns_data_ptr,
const u_char *pd,
int offset,
char *name_ret,
char *name_ret,
int *name_len_ret,
int *type_ret,
int *class_ret)
{
@ -239,19 +240,20 @@ get_dns_name_type_class (const u_char *pd,
char name[MAXDNAME];
const u_char *pd_save;
name_len = get_dns_name(pd, offset, name, sizeof(name));
name_len = get_dns_name(dns_data_ptr, pd, offset, name, sizeof(name));
pd += offset;
pd_save = pd;
pd += name_len;
type = (*pd << 8) | *(pd + 1);
type = pntohs(pd);
pd += 2;
class = (*pd << 8) | *(pd + 1);
class = pntohs(pd);
pd += 2;
strcpy (name_ret, name);
*type_ret = type;
*class_ret = class;
*name_len_ret = name_len;
len = pd - pd_save;
return len;
@ -259,114 +261,141 @@ get_dns_name_type_class (const u_char *pd,
static int
dissect_dns_query(const u_char *pd, int offset, GtkWidget *dns_tree)
{
int len;
char name[MAXDNAME];
int type;
int class;
char *class_name;
char *type_name;
len = get_dns_name_type_class (pd, offset, name, &type, &class);
type_name = dns_type_name(type);
class_name = dns_class_name(class);
add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s",
name, type_name, class_name );
return len;
}
static int
dissect_dns_answer(const u_char *pd, int offset, GtkWidget *dns_tree)
dissect_dns_query(const u_char *dns_data_ptr, const u_char *pd, int offset,
GtkWidget *dns_tree)
{
int len;
char name[MAXDNAME];
int name_len;
int type;
int class;
char *class_name;
char *type_name;
const u_char *dptr;
const u_char *data_start;
const u_char *res_ptr;
u_int ttl;
u_short data_len;
data_start = dptr = pd + offset;
len = get_dns_name_type_class (pd, offset, name, &type, &class);
len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
&type, &class);
dptr += len;
/* this works regardless of the alignment */
ttl = (*dptr << 24) | *(dptr + 1) << 16 | *(dptr + 2) << 8 | *(dptr + 3);
dptr += 4;
data_len = (*dptr << 8) | *(dptr + 1);
dptr += 2;
add_item_to_tree(dns_tree, offset, name_len, "Name: %s", name);
offset += name_len;
type_name = dns_type_name(type);
add_item_to_tree(dns_tree, offset, 2, "Type: %s", type_name);
offset += 2;
class_name = dns_class_name(class);
add_item_to_tree(dns_tree, offset, 2, "Class: %s", class_name);
offset += 2;
return dptr - data_start;
}
GtkWidget *
add_rr_to_tree(GtkWidget *trr, int rr_type, int offset, const char *name,
int namelen, const char *type_name, const char *class_name, u_int ttl,
u_short data_len)
{
GtkWidget *rr_tree;
rr_tree = gtk_tree_new();
add_subtree(trr, rr_tree, rr_type);
add_item_to_tree(rr_tree, offset, namelen, "Name: %s", name);
offset += namelen;
add_item_to_tree(rr_tree, offset, 2, "Type: %s", type_name);
offset += 2;
add_item_to_tree(rr_tree, offset, 2, "Class: %s", class_name);
offset += 2;
add_item_to_tree(rr_tree, offset, 4, "Time to live: %u", ttl);
offset += 4;
add_item_to_tree(rr_tree, offset, 2, "Data length: %u", data_len);
return rr_tree;
}
static int
dissect_dns_answer(const u_char *dns_data_ptr, const u_char *pd, int offset,
GtkWidget *dns_tree)
{
int len;
char name[MAXDNAME];
int name_len;
int type;
int class;
char *class_name;
char *type_name;
const u_char *dptr;
const u_char *data_start;
u_int ttl;
u_short data_len;
GtkWidget *rr_tree, *trr;
data_start = dptr = pd + offset;
len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
&type, &class);
dptr += len;
type_name = dns_type_name(type);
class_name = dns_class_name(class);
res_ptr = dptr;
/* skip the resource data */
dptr += data_len;
len = dptr - data_start;
ttl = pntohl(dptr);
dptr += 4;
data_len = pntohs(dptr);
dptr += 2;
switch (type) {
case T_A: /* "A" record */
add_item_to_tree(dns_tree, offset, len,
trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, addr %d.%d.%d.%d",
name, type_name, class_name,
*res_ptr, *(res_ptr+1), *(res_ptr+2), *(res_ptr+3));
*dptr, *(dptr+1), *(dptr+2), *(dptr+3));
rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
class_name, ttl, data_len);
offset += (dptr - data_start);
add_item_to_tree(rr_tree, offset, 4, "Addr: %d.%d.%d.%d",
*dptr, *(dptr+1), *(dptr+2), *(dptr+3));
break;
case T_NS: /* "NS" record */
{
char ns_name[MAXDNAME];
int ns_name_len;
get_dns_name(res_ptr, 0, ns_name, sizeof(ns_name));
add_item_to_tree(dns_tree, offset, len,
"%s: %s, type %s, class %s",
name, ns_name, type_name, class_name);
ns_name_len = get_dns_name(dns_data_ptr, dptr, 0, ns_name, sizeof(ns_name));
trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s, ns %s",
name, type_name, class_name, ns_name);
rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len,
type_name, class_name, ttl, data_len);
offset += (dptr - data_start);
add_item_to_tree(rr_tree, offset, ns_name_len, "Name server: %s", ns_name);
}
break;
/* TODO: parse more record types */
default:
add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s",
default:
trr = add_item_to_tree(dns_tree, offset, (dptr - data_start) + data_len,
"%s: type %s, class %s",
name, type_name, class_name);
rr_tree = add_rr_to_tree(trr, ETT_DNS_RR, offset, name, name_len, type_name,
class_name, ttl, data_len);
offset += (dptr - data_start);
add_item_to_tree(rr_tree, offset, data_len, "Data");
}
return len;
dptr += data_len;
return dptr - data_start;
}
static int
dissect_answer_records(int count, const u_char *pd, int cur_off,
GtkWidget *dns_tree, char *name)
{
int start_off;
GtkWidget *qatree, *ti;
qatree = gtk_tree_new();
start_off = cur_off;
while (count-- > 0)
cur_off += dissect_dns_answer(pd, cur_off, qatree);
ti = add_item_to_tree(GTK_WIDGET(dns_tree), start_off, cur_off - start_off, name);
add_subtree(ti, qatree, ETT_DNS_ANS);
return cur_off - start_off;
}
static int
dissect_query_records(int count, const u_char *pd,
dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd,
int cur_off, GtkWidget *dns_tree)
{
int start_off;
@ -376,7 +405,7 @@ dissect_query_records(int count, const u_char *pd,
start_off = cur_off;
while (count-- > 0)
cur_off += dissect_dns_query(pd, cur_off, qatree);
cur_off += dissect_dns_query(dns_data_ptr, pd, cur_off, qatree);
ti = add_item_to_tree(GTK_WIDGET(dns_tree),
start_off, cur_off - start_off, "Queries");
add_subtree(ti, qatree, ETT_DNS_QRY);
@ -386,8 +415,29 @@ dissect_query_records(int count, const u_char *pd,
static int
dissect_answer_records(const u_char *dns_data_ptr, int count,
const u_char *pd, int cur_off, GtkWidget *dns_tree,
char *name)
{
int start_off;
GtkWidget *qatree, *ti;
qatree = gtk_tree_new();
start_off = cur_off;
while (count-- > 0)
cur_off += dissect_dns_answer(dns_data_ptr, pd, cur_off, qatree);
ti = add_item_to_tree(GTK_WIDGET(dns_tree), start_off, cur_off - start_off, name);
add_subtree(ti, qatree, ETT_DNS_ANS);
return cur_off - start_off;
}
void
dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
const u_char *dns_data_ptr;
e_dns *dh;
GtkWidget *dns_tree, *ti;
guint16 id, flags, quest, ans, auth, add;
@ -430,17 +480,19 @@ dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
cur_off = offset + 12;
if (quest > 0)
cur_off += dissect_query_records(quest, pd, cur_off, dns_tree);
cur_off += dissect_query_records(dns_data_ptr, quest, pd, cur_off,
dns_tree);
if (ans > 0)
cur_off += dissect_answer_records(ans, pd, cur_off, dns_tree, "Answers");
cur_off += dissect_answer_records(dns_data_ptr, ans, pd, cur_off,
dns_tree, "Answers");
if (auth > 0)
cur_off += dissect_answer_records(auth, pd, cur_off, dns_tree,
"Authoritative nameservers");
cur_off += dissect_answer_records(dns_data_ptr, auth, pd, cur_off,
dns_tree, "Authoritative nameservers");
if (add > 0)
cur_off += dissect_answer_records(add, pd, cur_off, dns_tree,
"Additional records");
cur_off += dissect_answer_records(dns_data_ptr, add, pd, cur_off,
dns_tree, "Additional records");
}
}

View File

@ -1,8 +1,9 @@
/* packet-nbns.c
* Routines for NetBIOS Name Service packet disassembly
* Gilbert Ramirez <gram@verdict.uthscsa.edu>
* Much stuff added by Guy Harris <guy@netapp.com>
*
* $Id: packet-nbns.c,v 1.1 1998/10/14 04:09:11 gram Exp $
* $Id: packet-nbns.c,v 1.2 1998/10/14 19:34:59 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -44,6 +45,7 @@
#include "ethereal.h"
#include "packet.h"
#include "packet-dns.h"
/* Packet structure taken from RFC 1002. See also RFC 1001.
* The Samba source code, specifically nmblib.c, also helps a lot. */
@ -67,36 +69,638 @@ struct nbns_header {
guint16 arcount;
};
/* type values */
#define T_NB 32 /* NetBIOS name service RR */
#define T_NBSTAT 33 /* NetBIOS node status RR */
static char *
nbns_type_name (int type)
{
switch (type) {
case T_NB:
return "NB";
case T_NBSTAT:
return "NBSTAT";
}
return "unknown";
}
/* "Canonicalize" a 16-character NetBIOS name by:
*
* removing and saving the last byte;
*
* stripping trailing blanks;
*
* appending the trailing byte, as a hex number, in square brackets. */
static char *
canonicalize_netbios_name(char *nbname)
{
char *pnbname;
u_char lastchar;
/* Get the last character of the name, as it's a special number
* indicating the type of the name, rather than part of the name
* *per se*. */
pnbname = nbname + 15; /* point to the 16th character */
lastchar = *(unsigned char *)pnbname;
/* Now strip off any trailing blanks used to pad it to
* 16 bytes. */
while (pnbname > &nbname[0]) {
if (*(pnbname - 1) != ' ')
break; /* found non-blank character */
pnbname--; /* blank - skip over it */
}
/* Replace the last character with its hex value, in square
* brackets, to make it easier to tell what it is. */
sprintf(pnbname, "[%02X]", lastchar);
pnbname += 4;
return pnbname;
}
static int
get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
int offset, char *name_ret, int *name_len_ret, int *type_ret,
int *class_ret)
{
int len;
int name_len;
int type;
int class;
char name[MAXDNAME];
char nbname[MAXDNAME+4]; /* 4 for [<last char>] */
char *pname, *pnbname, cname, cnbname;
const u_char *pd_save;
name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
pd += offset;
pd_save = pd;
pd += name_len;
type = pntohs(pd);
pd += 2;
class = pntohs(pd);
pd += 2;
/* OK, now undo the first-level encoding. */
pname = &name[0];
pnbname = &nbname[0];
for (;;) {
/* Every two characters of the first level-encoded name
* turn into one character in the decoded name. */
cname = *pname;
if (cname == '\0')
break; /* no more characters */
if (cname == '.')
break; /* scope ID follows */
if (cname < 'A' || cname > 'Z') {
/* Not legal. */
strcpy(nbname,
"Illegal NetBIOS name (character not between A and Z in first-level encoding)");
goto bad;
}
cname -= 'A';
cnbname = cname << 4;
pname++;
cname = *pname;
if (cname == '\0' || cname == '.') {
/* No more characters in the name - but we're in
* the middle of a pair. Not legal. */
strcpy(nbname,
"Illegal NetBIOS name (odd number of bytes)");
goto bad;
}
if (cname < 'A' || cname > 'Z') {
/* Not legal. */
strcpy(nbname,
"Illegal NetBIOS name (character not between A and Z in first-level encoding)");
goto bad;
}
cname -= 'A';
cnbname |= cname;
pname++;
/* Store the character. */
*pnbname++ = cnbname;
}
/* NetBIOS names are supposed to be exactly 16 bytes long. */
if (pnbname - nbname == 16) {
/* This one is; canonicalize its name. */
pnbname = canonicalize_netbios_name(nbname);
} else {
sprintf(nbname, "Illegal NetBIOS name (%d bytes long)",
pnbname - nbname);
goto bad;
}
if (cname == '.') {
/* We have a scope ID, starting at "pname"; append that to
* the decoded host name. */
strcpy(pnbname, pname);
} else {
/* Terminate the decoded host name. */
*pnbname = '\0';
}
bad:
strcpy (name_ret, nbname);
*type_ret = type;
*class_ret = class;
*name_len_ret = name_len;
len = pd - pd_save;
return len;
}
static int
dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
GtkWidget *nbns_tree)
{
int len;
char name[MAXDNAME];
int name_len;
int type;
int class;
char *class_name;
char *type_name;
const u_char *dptr;
const u_char *data_start;
data_start = dptr = pd + offset;
len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
&name_len, &type, &class);
dptr += len;
add_item_to_tree(nbns_tree, offset, name_len, "Name: %s", name);
offset += name_len;
type_name = nbns_type_name(type);
add_item_to_tree(nbns_tree, offset, 2, "Type: %s", type_name);
offset += 2;
class_name = dns_class_name(class);
add_item_to_tree(nbns_tree, offset, 2, "Class: %s", class_name);
offset += 2;
return dptr - data_start;
}
static int
dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
GtkWidget *nbns_tree, int opcode)
{
int len;
char name[MAXDNAME];
int name_len;
int type;
int class;
char *class_name;
char *type_name;
const u_char *dptr;
const u_char *data_start;
u_int ttl;
u_short data_len;
u_short flags;
GtkWidget *rr_tree, *trr;
data_start = dptr = pd + offset;
len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
&name_len, &type, &class);
dptr += len;
type_name = nbns_type_name(type);
class_name = dns_class_name(class);
ttl = pntohl(dptr);
dptr += 4;
data_len = pntohs(dptr);
dptr += 2;
switch (type) {
case T_NB: /* "NB" record */
trr = add_item_to_tree(nbns_tree, offset,
(dptr - data_start) + data_len,
"%s: type %s, class %s",
name, type_name, class_name);
rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
name_len, type_name, class_name, ttl, data_len);
offset += (dptr - data_start);
while (data_len > 0) {
if (opcode == 0x7) {
/* WACK response. This doesn't contain the
* same type of RR data as other T_NB
* responses. */
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
flags = pntohs(dptr);
dptr += 2;
add_item_to_tree(rr_tree, offset, 2,
"Flags: 0x%x", flags);
offset += 2;
data_len -= 2;
} else {
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
flags = pntohs(dptr);
dptr += 2;
add_item_to_tree(rr_tree, offset, 2,
"Flags: 0x%x", flags);
offset += 2;
data_len -= 2;
if (data_len < 4) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 4,
"Addr: %d.%d.%d.%d",
*dptr, *(dptr+1), *(dptr+2), *(dptr+3));
dptr += 4;
offset += 4;
data_len -= 4;
}
}
break;
case T_NBSTAT: /* "NBSTAT" record */
{
u_int num_names;
char nbname[16+4+1]; /* 4 for [<last char>] */
u_short name_flags;
trr = add_item_to_tree(nbns_tree, offset,
(dptr - data_start) + data_len,
"%s: type %s, class %s",
name, type_name, class_name);
rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
name_len, type_name, class_name, ttl, data_len);
offset += (dptr - data_start);
if (data_len < 1) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
num_names = *dptr;
dptr += 1;
add_item_to_tree(rr_tree, offset, 2,
"Number of names: %u", num_names);
offset += 1;
while (num_names != 0) {
if (data_len < 16) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
goto out;
}
memcpy(nbname, dptr, 16);
dptr += 16;
canonicalize_netbios_name(nbname);
add_item_to_tree(rr_tree, offset, 16,
"Name: %s", nbname);
offset += 16;
data_len -= 16;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
goto out;
}
name_flags = pntohs(dptr);
dptr += 2;
add_item_to_tree(rr_tree, offset, 2,
"Name flags: 0x%x", name_flags);
offset += 2;
data_len -= 2;
num_names--;
}
if (data_len < 6) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 6,
"Unit ID: %02x:%02x:%02x:%02x:%02x:%02x",
*dptr, *(dptr + 1), *(dptr + 2),
*(dptr + 3), *(dptr + 4), *(dptr + 5));
dptr += 6;
offset += 6;
data_len -= 6;
if (data_len < 1) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 1,
"Jumpers: 0x%x", *dptr);
dptr += 1;
offset += 1;
data_len -= 1;
if (data_len < 1) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 1,
"Test result: 0x%x", *dptr);
dptr += 1;
offset += 1;
data_len -= 1;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Version number: 0x%x", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Period of statistics: 0x%x", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of CRCs: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of alignment errors: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of collisions: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of send aborts: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 4) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 4,
"Number of good sends: %u", pntohl(dptr));
dptr += 4;
offset += 4;
data_len -= 4;
if (data_len < 4) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 4,
"Number of good receives: %u", pntohl(dptr));
dptr += 4;
offset += 4;
data_len -= 4;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of retransmits: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of no resource conditions: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of command blocks: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Number of pending sessions: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Max number of pending sessions: %u", pntohs(dptr));
dptr += 2;
offset += 2;
add_item_to_tree(rr_tree, offset, 2,
"Max total sessions possible: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
if (data_len < 2) {
add_item_to_tree(rr_tree, offset,
data_len, "(incomplete entry)");
break;
}
add_item_to_tree(rr_tree, offset, 2,
"Session data packet size: %u", pntohs(dptr));
dptr += 2;
offset += 2;
data_len -= 2;
}
out:
break;
default:
trr = add_item_to_tree(nbns_tree, offset,
(dptr - data_start) + data_len,
"%s: type %s, class %s",
name, type_name, class_name);
rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
name_len, type_name, class_name, ttl, data_len);
offset += (dptr - data_start);
add_item_to_tree(rr_tree, offset, data_len, "Data");
break;
}
dptr += data_len;
return dptr - data_start;
}
static int
dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd,
int cur_off, GtkWidget *nbns_tree)
{
int start_off;
GtkWidget *qatree, *ti;
qatree = gtk_tree_new();
start_off = cur_off;
while (count-- > 0)
cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
ti = add_item_to_tree(GTK_WIDGET(nbns_tree),
start_off, cur_off - start_off, "Queries");
add_subtree(ti, qatree, ETT_NBNS_QRY);
return cur_off - start_off;
}
static int
dissect_answer_records(const u_char *nbns_data_ptr, int count,
const u_char *pd, int cur_off, GtkWidget *nbns_tree, int opcode, char *name)
{
int start_off;
GtkWidget *qatree, *ti;
qatree = gtk_tree_new();
start_off = cur_off;
while (count-- > 0)
cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
qatree, opcode);
ti = add_item_to_tree(GTK_WIDGET(nbns_tree), start_off, cur_off - start_off, name);
add_subtree(ti, qatree, ETT_NBNS_ANS);
return cur_off - start_off;
}
void
dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
{
GtkWidget *nbns_tree, *ti;
GtkWidget *nbns_tree, *ti;
struct nbns_header header;
int nm_flags;
int nm_flags;
const u_char *nbns_data_ptr;
int cur_off;
char *opcode[] = {
"Query",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown operation (1)",
"Unknown operation (2)",
"Unknown operation (3)",
"Unknown operation (4)",
"Registration",
"Release",
"Wait and Acknowledge",
"Refresh"
"Refresh(altcode)"
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Refresh",
"Refresh(altcode)",
"Unknown operation (10)",
"Unknown operation (11)",
"Unknown operation (12)",
"Unknown operation (13)",
"Unknown operation (14)",
"Multi-Homed Registration",
};
nbns_data_ptr = &pd[offset];
/* This is taken from samba/source/nmlib.c, parse_nmb() */
header.name_tran_id = pntohs(&pd[offset]);
header.opcode = (pd[offset+2] >> 3) & 0xf;
header.r = (pd[offset+2] >> 7) & 1;
nm_flags = ((pd[offset+2] & 0x7) << 4) + (pd[offset+3] >> 4);
header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
header.rcode = pd[offset+3] & 0xf;
header.qdcount = pntohs(&pd[offset+4]);
header.ancount = pntohs(&pd[offset+6]);
header.nscount = pntohs(&pd[offset+8]);
header.arcount = pntohs(&pd[offset+10]);
if (fd->win_info[COL_NUM]) {
/*strcpy(fd->win_info[COL_PROTOCOL], "NBNS (UDP)");*/
strcpy(fd->win_info[COL_PROTOCOL], "NBNS");
strcpy(fd->win_info[COL_INFO], "NetBIOS Name Service");
strcpy(fd->win_info[COL_PROTOCOL], "NBNS (UDP)");
if (header.opcode <= 15) {
sprintf(fd->win_info[COL_INFO], "%s %s",
opcode[header.opcode], header.r ? "reply" : "request");
} else {
sprintf(fd->win_info[COL_INFO], "Unknown operation (%d) %s",
header.opcode, header.r ? "reply" : "request");
}
}
if (tree) {
@ -105,27 +709,9 @@ dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
nbns_tree = gtk_tree_new();
add_subtree(ti, nbns_tree, ETT_NBNS);
/* This is taken from samba/source/nmlib.c, parse_nmb() */
header.name_tran_id = pntohs(&pd[offset]);
header.opcode = (pd[offset+2] >> 3) & 0xf;
header.r = (pd[offset+2] >> 7) & 1;
nm_flags = ((pd[offset+2] & 0x7) << 4) + (pd[offset+3] >> 4);
header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
header.rcode = pd[offset+3] & 0xf;
header.qdcount = pletohs(&pd[offset+4]);
header.ancount = pletohs(&pd[offset+6]);
header.nscount = pletohs(&pd[offset+8]);
header.arcount = pletohs(&pd[offset+10]);
add_item_to_tree(nbns_tree, offset, 2, "Transaction ID: 0x%04X",
add_item_to_tree(nbns_tree, offset, 2, "Transaction ID: 0x%04X",
header.name_tran_id);
add_item_to_tree(nbns_tree, offset + 2, 1, "Type: %s",
add_item_to_tree(nbns_tree, offset + 2, 1, "Type: %s",
header.r == 0 ? "Request" : "Response" );
if (header.opcode <= 15) {
@ -136,22 +722,35 @@ dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: Unknown (%d)",
header.opcode);
}
add_item_to_tree(nbns_tree, offset + 4, 2, "Questions: %d",
header.qdcount);
add_item_to_tree(nbns_tree, offset + 6, 2, "Answer RRs: %d",
header.ancount);
add_item_to_tree(nbns_tree, offset + 8, 2, "Authority RRs: %d",
header.nscount);
add_item_to_tree(nbns_tree, offset + 10, 2, "Additional RRs: %d",
header.arcount);
/* add_item_to_tree(nbns_tree, offset+2, 2, */
cur_off = offset + 12;
if (header.qdcount > 0)
cur_off += dissect_query_records(nbns_data_ptr,
header.qdcount, pd, cur_off, nbns_tree);
if (header.ancount > 0)
cur_off += dissect_answer_records(nbns_data_ptr,
header.ancount, pd, cur_off, nbns_tree,
header.opcode, "Answers");
if (header.nscount > 0)
cur_off += dissect_answer_records(nbns_data_ptr,
header.nscount, pd, cur_off, nbns_tree,
header.opcode,
"Authoritative nameservers");
if (header.arcount > 0)
cur_off += dissect_answer_records(nbns_data_ptr,
header.arcount, pd, cur_off, nbns_tree,
header.opcode, "Additional records");
}
}

View File

@ -1,7 +1,7 @@
/* packet.h
* Definitions for packet disassembly structures and routines
*
* $Id: packet.h,v 1.16 1998/10/14 05:18:32 gram Exp $
* $Id: packet.h,v 1.17 1998/10/14 19:35:00 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -405,6 +405,7 @@ enum {
ETT_DNS,
ETT_DNS_ANS,
ETT_DNS_QRY,
ETT_DNS_RR,
ETT_RIP,
ETT_RIP_VEC,
ETT_OSPF,
@ -427,6 +428,9 @@ enum {
ETT_IPXSAP,
ETT_IPXSAP_SERVER,
ETT_NBNS,
ETT_NBNS_ANS,
ETT_NBNS_QRY,
ETT_NBNS_RR,
ETT_NBIPX,
NUM_TREE_TYPES /* last item number plus one */
};