aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;