diff options
-rw-r--r-- | wiretap/k12.c | 263 |
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; |