/* 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>
#include "ethereal.h"
#include "packet.h"
+#include "packet-dns.h"
/* DNS structs and definitions */
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 */
#define T_AAAA 28 /* IP6 Address */
-static const u_char *dns_data_ptr;
-
static char *
dns_type_name (int type)
{
}
-static char *
+char *
dns_class_name(int class)
{
char *class_name;
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;
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;
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;
}
}
-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)
{
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;
static int
-dissect_dns_query(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;
- len = get_dns_name_type_class (pd, offset, name, &type, &class);
+ data_start = dptr = pd + offset;
+
+ len = get_dns_name_type_class(dns_data_ptr, pd, offset, name, &name_len,
+ &type, &class);
+ dptr += len;
+
+ 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;
- add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s",
- name, type_name, class_name );
-
- return len;
+ 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 *pd, int offset, GtkWidget *dns_tree)
+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;
- const u_char *res_ptr;
u_int ttl;
u_short data_len;
+ GtkWidget *rr_tree, *trr;
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;
-
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)
+dissect_query_records(const u_char *dns_data_ptr, int count, const u_char *pd,
+ int cur_off, GtkWidget *dns_tree)
{
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);
+ 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);
return cur_off - start_off;
}
+
static int
-dissect_query_records(int count, const u_char *pd,
- int cur_off, GtkWidget *dns_tree)
+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_query(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);
+ 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;
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");
}
}
/* 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>
#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. */
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) {
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) {
add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: Unknown (%d)",
header.opcode);
}
-
-/* add_item_to_tree(nbns_tree, offset+2, 2, */
+ 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);
+
+ 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");
}
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-