aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/k12.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2013-11-20 20:17:33 +0000
committerGuy Harris <guy@alum.mit.edu>2013-11-20 20:17:33 +0000
commit7d2ae283572d76aa78ab9386b80bf6a3cd8f2c62 (patch)
treee447b7e13c4bb4fadda8e7bdb30370044dcd037f /wiretap/k12.c
parent564b444eb33dc844f7ef2d8034230ef130e49fe7 (diff)
Add code to dump part of a record as ASCII, and use it to dump strings
in a source description record, including the stack. Dump some other fields in those records as well. Attach separate sequential and random read buffers to the private data structure, rather than allocating them in various routines (and not always freeing them) and, in at least one case, allocating a single *common* buffer for all wth's to use. Fix some comments (the DS0 mask is 32 bytes long, but gets turned into a bitmask). Put in a description of what a "stack file"'s contents look like. Much of it may be useless to us (for example, we have the notion that TCP has protocol number 6 built-in...), but the RELATION entries that map from "BASE" to a protocol could obviate the need to have the user specify a map from stack file names to starting protocols, and we might be able to use, for example, entries that map TCP/UDP/SCTP port numbers to protocols to obviate the need for the user to explicitly use Decode As or otherwise configure port-to-protocol mappings themselves. Add a bunch of record length checks before we fetch data from records. svn path=/trunk/; revision=53450
Diffstat (limited to 'wiretap/k12.c')
-rw-r--r--wiretap/k12.c263
1 files changed, 236 insertions, 27 deletions
diff --git a/wiretap/k12.c b/wiretap/k12.c
index 8824831e41..d8218b1dad 100644
--- a/wiretap/k12.c
+++ b/wiretap/k12.c
@@ -124,9 +124,25 @@ void k12_hex_ascii_dump(guint level, gint64 offset, const char* label, const uns
#define K12_HEX_ASCII_DUMP(x,a,b,c,d) k12_hex_ascii_dump(x,a,b,c,d)
+void k12_ascii_dump(guint level, guint8 *buf, guint32 len, guint32 buf_offset) {
+ guint32 i;
+
+ if (debug_level < level) return;
+
+ for (i = buf_offset; i < len; i++) {
+ if (isprint(buf[i]) || buf[i] == '\n' || buf[i] == '\t')
+ putc(buf[i], dbg_out);
+ else if (buf[i] == '\0')
+ fprintf(dbg_out, "(NUL)\n");
+ }
+}
+
+#define K12_ASCII_DUMP(x,a,b,c) k12_ascii_dump(x,a,b,c)
+
#else
#define K12_DBG(level,args) (void)0
#define K12_HEX_ASCII_DUMP(x,a,b,c,d)
+#define K12_ASCII_DUMP(x,a,b,c)
#endif
@@ -147,12 +163,17 @@ static const guint8 k12_file_magic[] = { 0x00, 0x00, 0x02, 0x00 ,0x12, 0x05, 0x0
typedef struct {
guint32 file_len;
- guint32 num_of_records; /* XXX: not sure about this */
+ guint32 num_of_records; /* XXX: not sure about this */
- GHashTable* src_by_id; /* k12_srcdsc_recs by input */
- GHashTable* src_by_name; /* k12_srcdsc_recs by stack_name */
+ GHashTable* src_by_id; /* k12_srcdsc_recs by input */
+ GHashTable* src_by_name; /* k12_srcdsc_recs by stack_name */
- Buffer extra_info; /* Buffer to hold per packet extra information */
+ guint8 *seq_read_buff; /* read buffer for sequential reading */
+ guint seq_read_buff_len; /* length of that buffer */
+ guint8 *rand_read_buff; /* read buffer for random reading */
+ guint rand_read_buff_len; /* length of that buffer */
+
+ Buffer extra_info; /* Buffer to hold per packet extra information */
} k12_t;
typedef struct _k12_src_desc_t {
@@ -249,12 +270,87 @@ typedef struct _k12_src_desc_t {
#define K12_SRCDESC_STACKLEN 0x22 /* uint16, big endian */
#define K12_SRCDESC_EXTRATYPE 0x24 /* uint32, big endian */
+
#define K12_SRCDESC_ATM_VPI 0x38 /* uint16, big endian */
#define K12_SRCDESC_ATM_VCI 0x3a /* uint16, big endian */
+#define K12_SRCDESC_ATM_AAL 0x3c /* 1 byte */
-#define K12_SRCDESC_ATM_AAL 0x3c /* 1 byte */
-#define K12_SRCDESC_DS0_MASK 0x3c /* 1 byte */
+#define K12_SRCDESC_DS0_MASK 0x3c /* 32 bytes */
+/*
+ * A "stack file", as appears in a K12_REC_STK_FILE record, is a text
+ * file (with CR-LF line endings) with a sequence of lines, each of
+ * which begins with a keyword, and has white-space-separated tokens
+ * after that.
+ *
+ * They appear to be:
+ *
+ * STKVER, which is followed by a number (presumably a version number
+ * for the stack file format)
+ *
+ * STACK, which is followed by a quoted string ("ProtocolStack" in one
+ * file) and two numbers
+ *
+ * PATH, which is followed by a non-quoted string giving the pathname
+ * of the directory containing the stack file
+ *
+ * HLAYER, which is followed by a quoted string, a path for something
+ * (protocol module?), a keyword ("LOADED", in one file), and a
+ * quoted string giving a description - this is probably a protocol
+ * layer of some sort
+ *
+ * LAYER, which has a similar syntax to HLAYER - the first quoted
+ * string is a protocol name
+ *
+ * RELATION, which has a quoted string giving a protocol name,
+ * another quoted string giving a protocol name, and a condition
+ * specifier of some sort, which probably says the second protocol
+ * is layered atop the first protocol if the condition is true.
+ * The first protocol can also be "BASE", which means that the
+ * second protocol is the lowest-level protocol.
+ * The conditions are:
+ *
+ * CPLX, which may mean "complex" - it has parenthesized expressions
+ * including "&", presumably a boolean AND, with the individual
+ * tests being L:expr, where L is a letter such as "L", "D", or "P",
+ * and expr is:
+ *
+ * 0x........ for L, where each . is a hex digit or a ?, presumably
+ * meaning "don't care"
+ *
+ * 0;0{=,!=}0b........ for D, where . is presumably a bit or a ?
+ *
+ * param=value for P, where param is something such as "src_port"
+ * and value is a value, presumably to test, for example, TCP or
+ * UDP ports
+ *
+ * UNCOND, presumably meaning "always"
+ *
+ * PARAM, followed by a parameter name (as with P:) and a value,
+ * possibly followed by LAYPARAM and a hex value
+ *
+ * DECKRNL, followed by a quoted string protocol name, un-quoted
+ * "LSBF" or "MSBF" (Least/Most Significant Byte First?), and
+ * an un-quoted string ending with _DK
+ *
+ * LAYPARAM, followed by a quoted protocol name and a number (-2147221504
+ * in one file, which is 0x80040000)
+ *
+ * SPC_CONF, folloed by a number, a quoted string with numbers separated
+ * by hyphens, and another number
+ *
+ * CIC_CONF, with a similar syntax to SPC_CONF
+ *
+ * LAYPOS, followed by a protocol name or "BASE" and 3 numbers.
+ *
+ * Most of this is probably not useful, but the RELATION lines with
+ * "BASE" could be used to figure out how to start the dissection
+ * (if we knew what "L" and "D" did), and *some* of the others might
+ * be useful if they don't match what's already in various dissector
+ * tables (the ones for IP and a higher-level protocol, for example,
+ * aren't very useful, as those are standardized, but the ones for
+ * TCP, UDP, and SCTP ports, and SCTP PPIs, might be useful).
+ */
/*
* get_record: Get the next record into a buffer
@@ -270,10 +366,10 @@ typedef struct _k12_src_desc_t {
*
* XXX: works at most with 0x1FFF bytes per record
*/
-static gint get_record(guint8** bufferp, FILE_T fh, gint64 file_offset,
- int *err, gchar **err_info) {
- static guint8* buffer = NULL;
- static guint buffer_len = 0x2000 ;
+static gint get_record(k12_t *file_data, FILE_T fh, gint64 file_offset,
+ gboolean is_random, int *err, gchar **err_info) {
+ guint8 *buffer = is_random ? file_data->rand_read_buff : file_data->seq_read_buff;
+ guint buffer_len = is_random ? file_data->rand_read_buff_len : file_data->seq_read_buff_len;
guint bytes_read;
guint last_read;
guint left;
@@ -292,11 +388,17 @@ static gint get_record(guint8** bufferp, FILE_T fh, gint64 file_offset,
if (buffer == NULL) {
buffer = (guint8*)g_malloc(0x2000);
buffer_len = 0x2000;
+ if (is_random) {
+ file_data->rand_read_buff = buffer;
+ file_data->rand_read_buff_len = buffer_len;
+ } else {
+ file_data->seq_read_buff = buffer;
+ file_data->seq_read_buff_len = buffer_len;
+ }
}
- *bufferp = buffer;
-
- if ( junky_offset == 0x2000 ) {
+ /* Get the record length. */
+ if ( junky_offset == 0x2000 ) {
/* the length of the record is 0x10 bytes ahead from we are reading */
bytes_read = file_read(junk,0x14,fh);
@@ -330,7 +432,7 @@ static gint get_record(guint8** bufferp, FILE_T fh, gint64 file_offset,
}
}
- left = pntohl(buffer);
+ left = pntohl(buffer + K12_RECORD_LEN);
#ifdef DEBUG_K12
actual_len = left;
#endif
@@ -338,7 +440,13 @@ static gint get_record(guint8** bufferp, FILE_T fh, gint64 file_offset,
K12_DBG(5,("get_record: GET length=%u",left));
- /* XXX - Is WTAP_MAX_PACKET_SIZE */
+ /*
+ * Record length must be at least large enough for the length,
+ * hence 4 bytes.
+ *
+ * XXX - Is WTAP_MAX_PACKET_SIZE the right check for a maximum
+ * record size? Should we report this error differently?
+ */
if (left < 4 || left > WTAP_MAX_PACKET_SIZE) {
K12_DBG(1,("get_record: Invalid GET length=%u",left));
*err = WTAP_ERR_BAD_FILE;
@@ -346,11 +454,25 @@ static gint get_record(guint8** bufferp, FILE_T fh, gint64 file_offset,
return -1;
}
- while (left > buffer_len) *bufferp = buffer = (guint8*)g_realloc(buffer,buffer_len*=2);
+ /*
+ * XXX - calculate the lowest power of 2 >= left, rather than just
+ * looping.
+ */
+ while (left > buffer_len) {
+ buffer = (guint8*)g_realloc(buffer,buffer_len*=2);
+ if (is_random) {
+ file_data->rand_read_buff = buffer;
+ file_data->rand_read_buff_len = buffer_len;
+ } else {
+ file_data->seq_read_buff = buffer;
+ file_data->seq_read_buff_len = buffer_len;
+ }
+ }
writep = buffer + 4;
left -= 4;
+ /* Read the rest of the record. */
do {
K12_DBG(6,("get_record: looping left=%d junky_offset=%" G_GINT64_MODIFIER "d",left,junky_offset));
@@ -483,7 +605,7 @@ process_packet_data(struct wtap_pkthdr *phdr, Buffer *target, guint8 *buffer,
static gboolean k12_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) {
k12_t *k12 = (k12_t *)wth->priv;
k12_src_desc_t* src_desc;
- guint8* buffer = NULL;
+ guint8* buffer;
gint64 offset;
gint len;
guint32 type;
@@ -497,15 +619,24 @@ static gboolean k12_read(wtap *wth, int *err, gchar **err_info, gint64 *data_off
*data_offset = offset;
- len = get_record(&buffer, wth->fh, offset, err, err_info);
+ len = get_record(k12, wth->fh, offset, FALSE, err, err_info);
if (len < 0) {
+ /* read error */
return FALSE;
} else if (len == 0) {
+ /* EOF */
*err = 0;
return FALSE;
+ } else if (len < K12_RECORD_SRC_ID + 4) {
+ /* Record not large enough to contain a src ID */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("data record length %d too short", len);
+ return FALSE;
}
+ buffer = k12->seq_read_buff;
+
type = pntohl(buffer + K12_RECORD_TYPE);
src_id = pntohl(buffer + K12_RECORD_SRC_ID);
@@ -545,17 +676,19 @@ static gboolean k12_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *ph
return FALSE;
}
- len = get_record(&buffer, wth->random_fh, seek_off, err, err_info);
+ len = get_record(k12, wth->random_fh, seek_off, TRUE, err, err_info);
if (len < 0) {
K12_DBG(5,("k12_seek_read: READ ERROR"));
return FALSE;
- }
- if (len < 1) {
+ } else if (len < K12_RECORD_SRC_ID + 4) {
+ /* Record not large enough to contain a src ID */
K12_DBG(5,("k12_seek_read: SHORT READ"));
*err = WTAP_ERR_SHORT_READ;
return FALSE;
}
+ buffer = k12->rand_read_buff;
+
process_packet_data(phdr, buf, buffer, len, k12);
K12_DBG(5,("k12_seek_read: DONE OK"));
@@ -571,6 +704,10 @@ static k12_t* new_k12_file_data(void) {
fd->num_of_records = 0;
fd->src_by_name = g_hash_table_new(g_str_hash,g_str_equal);
fd->src_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
+ fd->seq_read_buff = NULL;
+ fd->seq_read_buff_len = 0;
+ fd->rand_read_buff = NULL;
+ fd->rand_read_buff_len = 0;
buffer_init(&(fd->extra_info), 100);
@@ -592,6 +729,8 @@ static void destroy_k12_file_data(k12_t* fd) {
g_hash_table_foreach_remove(fd->src_by_name,destroy_srcdsc,NULL);
g_hash_table_destroy(fd->src_by_name);
buffer_free(&(fd->extra_info));
+ g_free(fd->seq_read_buff);
+ g_free(fd->rand_read_buff);
g_free(fd);
}
@@ -665,7 +804,7 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
do {
- len = get_record(&read_buffer, wth->fh, offset, err, err_info);
+ len = get_record(file_data, wth->fh, offset, FALSE, err, err_info);
if ( len < 0 ) {
K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
@@ -679,7 +818,23 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
return -1;
}
+ if (len == 0) {
+ K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
+ *err = WTAP_ERR_SHORT_READ;
+ destroy_k12_file_data(file_data);
+ return -1;
+ }
+ read_buffer = file_data->seq_read_buff;
+
+ rec_len = pntohl( read_buffer + K12_RECORD_LEN );
+ if (rec_len < K12_RECORD_TYPE + 4) {
+ /* Record isn't long enough to have a type field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: record length %u < %u",
+ rec_len, K12_RECORD_TYPE + 4);
+ return -1;
+ }
type = pntohl( read_buffer + K12_RECORD_TYPE );
if ( (type & K12_MASK_PACKET) == K12_REC_PACKET) {
@@ -695,7 +850,13 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
} else if (type == K12_REC_SRCDSC || type == K12_REC_SRCDSC2 ) {
rec = g_new0(k12_src_desc_t,1);
- rec_len = pntohl( read_buffer + K12_RECORD_LEN );
+ if (rec_len < K12_SRCDESC_STACKLEN + 2) {
+ /* Record isn't long enough to have a stack length field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
+ rec_len, K12_SRCDESC_STACKLEN + 2);
+ return -1;
+ }
extra_len = pntohs( read_buffer + K12_SRCDESC_EXTRALEN );
name_len = pntohs( read_buffer + K12_SRCDESC_NAMELEN );
stack_len = pntohs( read_buffer + K12_SRCDESC_STACKLEN );
@@ -713,9 +874,24 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
return 0;
}
- if (extra_len)
+ if (extra_len) {
+ if (rec_len < K12_SRCDESC_EXTRATYPE + 4) {
+ /* Record isn't long enough to have a source descriptor extra type field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
+ rec_len, K12_SRCDESC_EXTRATYPE + 4);
+ return -1;
+ }
switch(( rec->input_type = pntohl( read_buffer + K12_SRCDESC_EXTRATYPE ) )) {
case K12_PORT_DS0S:
+ if (rec_len < K12_SRCDESC_DS0_MASK + 32) {
+ /* Record isn't long enough to have a source descriptor extra type field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
+ rec_len, K12_SRCDESC_DS0_MASK + 12);
+ return -1;
+ }
+
rec->input_info.ds0mask = 0x00000000;
for (i = 0; i < 32; i++) {
@@ -724,19 +900,37 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
break;
case K12_PORT_ATMPVC:
+ if (rec_len < K12_SRCDESC_ATM_VCI + 2) {
+ /* Record isn't long enough to have a source descriptor extra type field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
+ rec_len, K12_SRCDESC_DS0_MASK + 12);
+ return -1;
+ }
+
rec->input_info.atm.vp = pntohs( read_buffer + K12_SRCDESC_ATM_VPI );
rec->input_info.atm.vc = pntohs( read_buffer + K12_SRCDESC_ATM_VCI );
break;
default:
break;
}
- else { /* Record viewer generated files
- don't have this information */
+ } else {
+ /* Record viewer generated files don't have this information */
+ if (rec_len < K12_SRCDESC_PORT_TYPE + 1) {
+ /* Record isn't long enough to have a source descriptor extra type field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
+ rec_len, K12_SRCDESC_DS0_MASK + 12);
+ return -1;
+ }
if (read_buffer[K12_SRCDESC_PORT_TYPE] >= 0x14
- && read_buffer[K12_SRCDESC_PORT_TYPE] <= 0x17)
+ && read_buffer[K12_SRCDESC_PORT_TYPE] <= 0x17) {
/* For ATM2_E1DS1, ATM2_E3DS3,
ATM2_STM1EL and ATM2_STM1OP */
rec->input_type = K12_PORT_ATMPVC;
+ rec->input_info.atm.vp = 0;
+ rec->input_info.atm.vc = 0;
+ }
}
/* XXX - this is assumed, in a number of places (not just in the
@@ -745,6 +939,13 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
Obviously not, as a corrupt file could contain anything
here; the Tektronix document says the strings "must end
with \0", but a bad file could fail to add the \0. */
+ if (rec_len < K12_SRCDESC_EXTRATYPE + extra_len + name_len + stack_len) {
+ /* Record isn't long enough to have a source descriptor extra type field */
+ *err = WTAP_ERR_BAD_FILE;
+ *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
+ rec_len, K12_SRCDESC_EXTRATYPE + extra_len + name_len + stack_len);
+ return -1;
+ }
rec->input_name = (gchar *)g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len, name_len);
rec->stack_file = (gchar *)g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len + name_len, stack_len);
@@ -755,6 +956,14 @@ int k12_open(wtap *wth, int *err, gchar **err_info) {
offset += len;
continue;
+ } else if (type == K12_REC_STK_FILE) {
+ K12_DBG(1,("k12_open: K12_REC_STK_FILE"));
+ K12_DBG(1,("Field 1: 0x%08x",pntohl( read_buffer + 0x08 )));
+ K12_DBG(1,("Field 2: 0x%08x",pntohl( read_buffer + 0x0c )));
+ K12_ASCII_DUMP(1, read_buffer, rec_len, 0x10);
+
+ offset += len;
+ continue;
} else {
K12_DBG(1,("k12_open: RECORD TYPE 0x%08x",type));
offset += len;