/* tvbparse.c * * Copyright 2005, Luis E. Garcia Ontanon * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #define TVBPARSE_DEBUG_ALL 0xffffffff #if 0 #define TVBPARSE_DEBUG_ 0x80000000 #define TVBPARSE_DEBUG_ 0x40000000 #define TVBPARSE_DEBUG_ 0x20000000 #define TVBPARSE_DEBUG_ 0x10000000 #endif #define TVBPARSE_DEBUG_CHAR 0x08000000 #define TVBPARSE_DEBUG_CHARS 0x04000000 #define TVBPARSE_DEBUG_NOT_CHAR 0x02000000 #define TVBPARSE_DEBUG_NOT_CHARS 0x01000000 #define TVBPARSE_DEBUG_STRING 0x00800000 #define TVBPARSE_DEBUG_CASESTRING 0x00400000 #define TVBPARSE_DEBUG_ONEOF 0x00200000 #define TVBPARSE_DEBUG_HASH 0x00100000 #define TVBPARSE_DEBUG_SEQ 0x00080000 #define TVBPARSE_DEBUG_SOME 0x00040000 #define TVBPARSE_DEBUG_UNTIL 0x00020000 #if 0 #define TVBPARSE_DEBUG_ 0x00010000 #define TVBPARSE_DEBUG_ 0x00008000 #define TVBPARSE_DEBUG_ 0x00004000 #define TVBPARSE_DEBUG_ 0x00002000 #define TVBPARSE_DEBUG_ 0x00001000 #endif #define TVBPARSE_DEBUG_TT 0x00000800 #define TVBPARSE_DEBUG_CB 0x00000400 #define TVBPARSE_DEBUG_GET 0x00000200 #define TVBPARSE_DEBUG_FIND 0x00000100 #define TVBPARSE_DEBUG_NEWTOK 0x00000080 #define TVBPARSE_DEBUG_IGNORE 0x00000040 #define TVBPARSE_DEBUG_PEEK 0x00000020 #if 0 #define TVBPARSE_DEBUG_ 0x00000010 #define TVBPARSE_DEBUG_ 0x00000008 #define TVBPARSE_DEBUG_ 0x00000004 #define TVBPARSE_DEBUG_ 0x00000002 #define TVBPARSE_DEBUG_ 0x00000001 #endif /* #define TVBPARSE_DEBUG (TVBPARSE_DEBUG_SOME) */ static tvbparse_elem_t* new_tok(tvbparse_t* tt, int id, int offset, int len, const tvbparse_wanted_t* wanted) { tvbparse_elem_t* tok; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NEWTOK) g_warning("new_tok: id=%i offset=%u len=%u",id,offset,len); #endif tok = (tvbparse_elem_t *)wmem_new(wmem_packet_scope(), tvbparse_elem_t); tok->tvb = tt->tvb; tok->id = id; tok->offset = offset; tok->len = len; tok->data = NULL; tok->sub = NULL; tok->next = NULL; tok->wanted = wanted; tok->last = tok; return tok; } static int ignore_fcn(tvbparse_t* tt, int offset) { int len = 0; int consumed; tvbparse_elem_t* ignored = NULL; if (!tt->ignore) return 0; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: enter"); #endif while ((consumed = tt->ignore->condition(tt,offset,tt->ignore,&ignored)) > 0) { len += consumed; offset += consumed; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: consumed=%i",consumed); #endif } #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_IGNORE) g_warning("ignore: len=%i",len); #endif return len; } static int cond_char (tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { gchar c,t; guint i; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) g_warning("cond_char: control='%s'",wanted->control.str); #endif if ( offset + 1 > tt->end_offset ) return -1; t = (gchar) tvb_get_guint8(tt->tvb,offset); for(i = 0; (c = wanted->control.str[i]) && offset <= tt->end_offset; i++) { if ( c == t ) { *tok = new_tok(tt,wanted->id,offset,1,wanted); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHAR) g_warning("cond_char: GOT: '%c'",c); #endif return 1; } } return -1; } tvbparse_wanted_t* tvbparse_char(const int id, const gchar* chr, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->condition = cond_char; w->id = id; w->control.str = chr; w->len = 1; w->data = data; w->before = before_cb; w->after = after_cb; return w; } static int cond_chars_common(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { guint length = 0; int start = offset; int left = tt->end_offset - offset; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) g_warning("cond_chars_common: control='%s'",wanted->control.str); #endif if ( offset + (int)wanted->min > tt->end_offset ) return -1; left = left < (int) wanted->max ? left : (int) wanted->max; while( left > 0 ) { guint8 t = tvb_get_guint8(tt->tvb,offset++); if (!wanted->control.str[t]) break; length++; left--; }; if (length < wanted->min) { return -1; } else { *tok = new_tok(tt,wanted->id,start,length,wanted); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CHARS) g_warning("cond_chars_common: GOT len=%i",length); #endif return length; } } tvbparse_wanted_t* tvbparse_chars(const int id, const guint min_len, const guint max_len, const gchar* chr, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); char *accept_str; gsize i; accept_str = (char *)g_malloc(256); memset(accept_str, 0x00, 256); for (i = 0; chr[i]; i++) accept_str[(unsigned)chr[i]] = (char)0xFF; w->condition = cond_chars_common; w->id = id; w->control.str = accept_str; w->min = min_len ? min_len : 1; w->max = max_len ? max_len : G_MAXINT/2; w->data = data; w->before = before_cb; w->after = after_cb; return w; } static int cond_not_char(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { gchar c, t; guint i; gboolean not_matched = FALSE; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) g_warning("cond_not_char: control='%s'",wanted->control.str); #endif if ( offset >= tt->end_offset ) { return -1; } t = (gchar) tvb_get_guint8(tt->tvb,offset); for(i = 0; (c = wanted->control.str[i]); i++) { if ( c == t ) { not_matched = TRUE; } } if (not_matched) { return -1; } else { *tok = new_tok(tt,wanted->id,offset,1,wanted); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_NOT_CHAR) g_warning("cond_not_char: GOT='%c'",t); #endif return 1; } } tvbparse_wanted_t* tvbparse_not_char(const int id, const gchar* chr, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->condition = cond_not_char; w->id = id; w->control.str = chr; w->data = data; w->before = before_cb; w->after = after_cb; return w; } tvbparse_wanted_t* tvbparse_not_chars(const int id, const guint min_len, const guint max_len, const gchar* chr, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); char *accept_str; gsize i; /* cond_chars_common() use accept string, so mark all elements with, and later unset from reject */ accept_str = (char *)g_malloc(256); memset(accept_str, 0xFF, 256); for (i = 0; chr[i]; i++) accept_str[(unsigned) chr[i]] = '\0'; w->condition = cond_chars_common; w->id = id; w->control.str = accept_str; w->len = 0; w->min = min_len ? min_len : 1; w->max = max_len ? max_len : G_MAXINT/2; w->data = data; w->before = before_cb; w->after = after_cb; return w; } static int cond_string(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { int len = wanted->len; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_warning("cond_string: control='%s'",wanted->control.str); #endif if ( offset + wanted->len > tt->end_offset ) return -1; if ( tvb_strneql(tt->tvb, offset, wanted->control.str, len) == 0 ) { *tok = new_tok(tt,wanted->id,offset,len,wanted); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_STRING) g_warning("cond_string: GOT len=%i",len); #endif return len; } else { return -1; } } tvbparse_wanted_t* tvbparse_string(const int id, const gchar* str, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->condition = cond_string; w->id = id; w->control.str = str; w->len = (int) strlen(str); w->data = data; w->before = before_cb; w->after = after_cb; return w; } static int cond_casestring(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { int len = wanted->len; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) g_warning("cond_casestring: control='%s'",wanted->control.str); #endif if ( offset + len > tt->end_offset ) return -1; if ( tvb_strncaseeql(tt->tvb, offset, wanted->control.str, len) == 0 ) { *tok = new_tok(tt,wanted->id,offset,len,wanted); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CASESTRING) g_warning("cond_casestring: GOT len=%i",len); #endif return len; } else { *tok = NULL; return -1; } } tvbparse_wanted_t* tvbparse_casestring(const int id, const gchar* str, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->condition = cond_casestring; w->id = id; w->control.str = str; w->len = (int) strlen(str); w->data = data; w->before = before_cb; w->after = after_cb; return w; } static int cond_one_of(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { guint i; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) g_warning("cond_one_of: START"); #endif if ( offset > tt->end_offset ) return -1; for(i=0; i < wanted->control.elems->len; i++) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i); tvbparse_elem_t* new_elem = NULL; int curr_len; if ( offset + w->len > tt->end_offset ) continue; curr_len = w->condition(tt, offset, w, &new_elem); if (curr_len >= 0) { *tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted); (*tok)->sub = new_elem; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_ONEOF) g_warning("cond_one_of: GOT len=%i",curr_len); #endif return curr_len; } } return -1; } tvbparse_wanted_t* tvbparse_set_oneof(const int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, ...) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); tvbparse_t* el; va_list ap; w->condition = cond_one_of; w->id = id; w->data = data; w->before = before_cb; w->after = after_cb; w->control.elems = g_ptr_array_new(); va_start(ap,after_cb); while(( el = va_arg(ap,tvbparse_t*) )) { g_ptr_array_add(w->control.elems,el); }; va_end(ap); return w; } static int cond_hash(tvbparse_t* tt, const int offset, const tvbparse_wanted_t* wanted, tvbparse_elem_t** tok) { int key_len; gchar* key = NULL; tvbparse_elem_t* key_elem = NULL; tvbparse_wanted_t* value_wanted = NULL; int value_len; tvbparse_elem_t* value_elem = NULL; int tot_len; tvbparse_elem_t* ret_tok; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: START"); #endif if ( offset > tt->end_offset ) return -1; key_len = wanted->control.hash.key->condition(tt, offset, wanted->control.hash.key, &key_elem); if (key_len < 0) return -1; key = tvb_get_string_enc(wmem_packet_scope(),key_elem->tvb,key_elem->offset,key_elem->len, ENC_ASCII); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: got key='%s'",key); #endif if ((value_wanted = (tvbparse_wanted_t *)g_hash_table_lookup(wanted->control.hash.table,key))) { value_len = value_wanted->condition(tt, offset + key_len, value_wanted, &value_elem); } else if (wanted->control.hash.other) { value_len = wanted->control.hash.other->condition(tt, offset+key_len, wanted->control.hash.other, &value_elem); if (value_len < 0) return -1; } else { return -1; } tot_len = key_len + value_len; ret_tok = new_tok(tt, value_elem->id, offset, tot_len, wanted); ret_tok->sub = key_elem; ret_tok->sub->last->next = value_elem; *tok = ret_tok; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_HASH) g_warning("cond_hash: GOT len=%i",tot_len); #endif return tot_len; } tvbparse_wanted_t* tvbparse_hashed(const int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, tvbparse_wanted_t* key, tvbparse_wanted_t* other, ...) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); gchar* name; tvbparse_wanted_t* el; va_list ap; w->condition = cond_hash; w->id = id; w->data = data; w->before = before_cb; w->after = after_cb; w->control.hash.table = g_hash_table_new(g_str_hash,g_str_equal); w->control.hash.key = key; w->control.hash.other = other; va_start(ap,other); while(( name = va_arg(ap,gchar*) )) { el = va_arg(ap,tvbparse_wanted_t*); g_hash_table_insert(w->control.hash.table,name,el); } va_end(ap); return w; } void tvbparse_hashed_add(tvbparse_wanted_t* w, ...) { tvbparse_wanted_t* el; va_list ap; gchar* name; va_start(ap,w); while (( name = va_arg(ap,gchar*) )) { el = va_arg(ap,tvbparse_wanted_t*); g_hash_table_insert(w->control.hash.table,name,el); } va_end(ap); } static int cond_seq(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { guint i; int len = 0; int start = offset; tvbparse_elem_t* ret_tok = NULL; if ( offset > tt->end_offset ) return -1; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) g_warning("cond_seq: START"); #endif for(i=0; i < wanted->control.elems->len; i++) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_ptr_array_index(wanted->control.elems,i); tvbparse_elem_t* new_elem = NULL; if ( offset + w->len > tt->end_offset ) return -1; len = w->condition(tt, offset, w, &new_elem); if (len >= 0) { if (ret_tok) { if (new_elem->len) ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len; ret_tok->sub->last->next = new_elem; ret_tok->sub->last = new_elem; } else { ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted); ret_tok->sub = new_elem; new_elem->last = new_elem; } } else { return -1; } offset += len; offset += ignore_fcn(tt,offset); } *tok = ret_tok; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SEQ) g_warning("cond_seq: GOT len=%i",offset - start); #endif return offset - start; } tvbparse_wanted_t* tvbparse_set_seq(const int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, ...) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); tvbparse_wanted_t* el = NULL; va_list ap; w->condition = cond_seq; w->id = id; w->data = data; w->before = before_cb; w->after = after_cb; w->control.elems = g_ptr_array_new(); va_start(ap,after_cb); while(( el = va_arg(ap,tvbparse_wanted_t*) )) { g_ptr_array_add(w->control.elems,el); }; va_end(ap); return w; } static int cond_some(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { guint got_so_far = 0; int start = offset; tvbparse_elem_t* ret_tok = NULL; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_warning("cond_some: START"); #endif if ( offset > tt->end_offset ) return -1; if ( wanted->min == 0 ) { ret_tok = new_tok(tt,wanted->id,offset,0,wanted); } while (got_so_far < wanted->max) { tvbparse_elem_t* new_elem = NULL; int consumed; if ( offset > tt->end_offset ) return -1; consumed = wanted->control.subelem->condition(tt, offset, wanted->control.subelem, &new_elem); if(consumed >= 0) { if (ret_tok) { if (new_elem->len) ret_tok->len = (new_elem->offset - ret_tok->offset) + new_elem->len; if (ret_tok->sub) { ret_tok->sub->last->next = new_elem; ret_tok->sub->last = new_elem; } else { ret_tok->sub = new_elem; } } else { ret_tok = new_tok(tt, wanted->id, new_elem->offset, new_elem->len, wanted); ret_tok->sub = new_elem; } } else { break; } offset += consumed; got_so_far++; } #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_warning("cond_some: got num=%u",got_so_far); #endif if(got_so_far < wanted->min) { return -1; } *tok = ret_tok; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_SOME) g_warning("cond_some: GOT len=%i",offset - start); #endif return offset - start; } tvbparse_wanted_t* tvbparse_some(const int id, const guint from, const guint to, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, const tvbparse_wanted_t* el) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); g_assert(from <= to); w->condition = cond_some; w->id = id; w->min = from; w->max = to; w->data = data; w->before = before_cb; w->after = after_cb; w->control.subelem = el; return w; } static int cond_until(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { tvbparse_elem_t* new_elem = NULL; int len = 0; int target_offset = offset; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: START"); #endif if ( offset + wanted->control.until.subelem->len > tt->end_offset ) return -1; do { len = wanted->control.until.subelem->condition(tt, target_offset++, wanted->control.until.subelem, &new_elem); } while(len < 0 && target_offset+1 < tt->end_offset); if (len >= 0) { new_elem->id = wanted->id; new_elem->next = NULL; new_elem->last = NULL; new_elem->wanted = wanted; new_elem->offset = offset; (*tok) = new_elem; switch (wanted->control.until.mode) { case TP_UNTIL_INCLUDE: new_elem->len = target_offset - offset - 1 + len; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1 + len); #endif return target_offset - offset -1 + len; case TP_UNTIL_SPEND: new_elem->len = target_offset - offset - 1; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1 + len); #endif return target_offset - offset - 1 + len; case TP_UNTIL_LEAVE: new_elem->len = target_offset - offset - 1; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_UNTIL) g_warning("cond_until: GOT len=%i",target_offset - offset -1); #endif return target_offset - offset -1; default: DISSECTOR_ASSERT_NOT_REACHED(); return -1; } } else { return -1; } } tvbparse_wanted_t* tvbparse_until(const int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, const tvbparse_wanted_t* el, until_mode_t until_mode) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->condition = cond_until; w->control.until.mode = until_mode; w->control.until.subelem = el; w->id = id; w->data = data; w->before = before_cb; w->after = after_cb; return w; } #if 0 static int cond_handle(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { tvbparse_wanted_t* w = *(wanted->control.handle); int len = w->condition(tt, offset, w, tok); if (len >= 0) { return len; } else { return -1; } } tvbparse_wanted_t* tvbparse_handle(tvbparse_wanted_t** handle) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->condition = cond_handle; w->control.handle = handle; return w; } static int cond_end(tvbparse_t* tt, const int offset, const tvbparse_wanted_t * wanted _U_, tvbparse_elem_t** tok) { if (offset == tt->end_offset) { *tok = new_tok(tt,wanted->id,offset,0,wanted); return 0; } else { return -1; } } tvbparse_wanted_t* tvbparse_end_of_buffer(const int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb) { tvbparse_wanted_t* w = (tvbparse_wanted_t *)g_malloc0(sizeof(tvbparse_wanted_t)); w->id = id; w->condition = cond_end; w->after = after_cb; w->before = before_cb; w->data = data; return w; } /* these extract binary values */ static int cond_ft(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted, tvbparse_elem_t** tok) { guint len = 0; if ( offset + wanted->len > tt->end_offset ) return -1; if (wanted->len) { return wanted->len; } else if (wanted->control.ftenum == FT_STRINGZ) { if (( len = tvb_find_guint8(tt->tvb,offset,tt->end_offset - offset,'\0') >= 0 )) { *tok = new_tok(tt,wanted->id,offset,len,wanted); return len; } else { return -1; } } else { return -2; } } gint ft_lens[] = {-1,-1,-1, 1, 2, 3, 4, 8, 1, 2, 3, 4, 8, 4, 8,-1,-1,-1, 0, -1, 6, -1, -1, 4, sizeof(struct e_in6_addr), -1, -1, -1, -1 }; tvbparse_wanted_t* tvbparse_ft(int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, enum ftenum ftenum) { gint len = ft_lens[ftenum]; if (len >= 0) { tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t)); w->id = id; w->condition = cond_ft; w->len = len; w->control.ftenum = ftenum; w->after = after_cb; w->before = before_cb; w->data = data; return w; } else { g_assert(! "unsupported ftenum" ); return NULL; } } static int cond_ft_comp(tvbparse_t* tt, int offset, const tvbparse_wanted_t * wanted _U_, tvbparse_elem_t** tok) { void* l = wanted->control.number.extract(tt->tvb,offset); const void* r = &(wanted->control.number.value); if ( offset + wanted->len > tt->end_offset ) return -1; if ( wanted->control.number.comp(&l,&r) ) { *tok = new_tok(tt,wanted->id,offset,wanted->len,wanted); return wanted->len; } else { return -1; } } static gboolean comp_gt_i(void* lp, const void* rp) { return ( *((gint64*)lp) > *((gint64*)rp) ); } static gboolean comp_ge_i(void* lp, const void* rp) { return ( *((gint64*)lp) >= *((gint64*)rp) ); } static gboolean comp_eq_i(void* lp, const void* rp) { return ( *((gint64*)lp) == *((gint64*)rp) ); } static gboolean comp_ne_i(void* lp, const void* rp) { return ( *((gint64*)lp) != *((gint64*)rp) ); } static gboolean comp_le_i(void* lp, const void* rp) { return ( *((gint64*)lp) <= *((gint64*)rp) ); } static gboolean comp_lt_i(void* lp, const void* rp) { return ( *((gint64*)lp) < *((gint64*)rp) ); } static gboolean comp_gt_u(void* lp, const void* rp) { return ( *((guint64*)lp) > *((guint64*)rp) ); } static gboolean comp_ge_u(void* lp, const void* rp) { return ( *((guint64*)lp) >= *((guint64*)rp) ); } static gboolean comp_eq_u(void* lp, const void* rp) { return ( *((guint64*)lp) == *((guint64*)rp) ); } static gboolean comp_ne_u(void* lp, const void* rp) { return ( *((guint64*)lp) != *((guint64*)rp) ); } static gboolean comp_le_u(void* lp, const void* rp) { return ( *((guint64*)lp) <= *((guint64*)rp) ); } static gboolean comp_lt_u(void* lp, const void* rp) { return ( *((guint64*)lp) < *((guint64*)rp) ); } static gboolean comp_gt_f(void* lp, const void* rp) { return ( *((gdouble*)lp) > *((gdouble*)rp) ); } static gboolean comp_ge_f(void* lp, const void* rp) { return ( *((gdouble*)lp) >= *((gdouble*)rp) ); } static gboolean comp_eq_f(void* lp, const void* rp) { return ( *((gdouble*)lp) == *((gdouble*)rp) ); } static gboolean comp_ne_f(void* lp, const void* rp) { return ( *((gdouble*)lp) != *((gdouble*)rp) ); } static gboolean comp_le_f(void* lp, const void* rp) { return ( *((gdouble*)lp) <= *((gdouble*)rp) ); } static gboolean comp_lt_f(void* lp, const void* rp) { return ( *((gdouble*)lp) < *((gdouble*)rp) ); } static void* extract_u8(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_guint8(tvb,offset); return p; } static void* extract_uns(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntohs(tvb,offset); return p; } static void* extract_un24(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntoh24(tvb,offset); return p; } static void* extract_unl(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntohl(tvb,offset); return p; } static void* extract_un64(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntoh64(tvb,offset); return p; } static void* extract_ules(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letohs(tvb,offset); return p; } static void* extract_ule24(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letoh24(tvb,offset); return p; } static void* extract_ulel(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letohl(tvb,offset); return p; } static void* extract_ule64(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letoh64(tvb,offset); return p; } static void* extract_ins(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntohs(tvb,offset); return p; } static void* extract_in24(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntoh24(tvb,offset); return p; } static void* extract_inl(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntohl(tvb,offset); return p; } static void* extract_in64(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_ntoh64(tvb,offset); return p; } static void* extract_iles(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letohs(tvb,offset); return p; } static void* extract_ile24(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letoh24(tvb,offset); return p; } static void* extract_ilel(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letohl(tvb,offset); return p; } static void* extract_ile64(tvbuff_t* tvb, guint offset) { guint64* p = wmem_new(wmem_packet_scope(), guint64); *p = tvb_get_letoh64(tvb,offset); return p; } static void* extract_inf(tvbuff_t* tvb, guint offset) { gdouble* p = wmem_new(wmem_packet_scope(), gdouble); *p = tvb_get_ntohieee_float(tvb,offset); return p; } static void* extract_ind(tvbuff_t* tvb, guint offset) { gdouble* p = wmem_new(wmem_packet_scope(), gdouble); *p = tvb_get_ntohieee_double(tvb,offset); return p; } static void* extract_ilef(tvbuff_t* tvb, guint offset) { gdouble* p = wmem_new(wmem_packet_scope(), gdouble); *p = tvb_get_letohieee_float(tvb,offset); return p; } static void* extract_iled(tvbuff_t* tvb, guint offset) { gdouble* p = wmem_new(wmem_packet_scope(), gdouble); *p = tvb_get_letohieee_double(tvb,offset); return p; } static gboolean (*comps_u[])(void*, const void*) = {comp_gt_u,comp_ge_u,comp_eq_u,comp_ne_u,comp_le_u,comp_lt_u}; static gboolean (*comps_i[])(void*, const void*) = {comp_gt_i,comp_ge_i,comp_eq_i,comp_ne_i,comp_le_i,comp_lt_i}; static gboolean (*comps_f[])(void*, const void*) = {comp_gt_f,comp_ge_f,comp_eq_f,comp_ne_f,comp_le_f,comp_lt_f}; static gboolean (**comps[])(void*, const void*) = {comps_u,comps_i,comps_f}; static void* (*extract_n[])(tvbuff_t* tvb, guint offset) = { NULL, NULL, NULL, extract_u8, extract_uns, extract_un24, extract_unl, extract_un64, extract_u8, extract_ins, extract_in24, extract_inl, extract_in64, extract_inf, extract_ind, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL }; static void* (*extract_le[])(tvbuff_t* tvb, guint offset) = { NULL, NULL, NULL, extract_u8, extract_ules, extract_ule24, extract_ulel, extract_ule64, extract_u8, extract_iles, extract_ile24, extract_ilel, extract_ile64, extract_ilef, extract_iled, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL, NULL }; static void* (**extracts[])(tvbuff_t* tvb, guint offset) = { extract_n, extract_le}; tvbparse_wanted_t* tvbparse_ft_numcmp(int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, enum ftenum ftenum, int little_endian, enum ft_cmp_op ft_cmp_op, ... ) { tvbparse_wanted_t* w = g_malloc0(sizeof(tvbparse_wanted_t)); va_list ap; va_start(ap,ft_cmp_op); switch (ftenum) { case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: w->control.number.comp = comps[0][ft_cmp_op]; w->control.number.value.u = va_arg(ap,guint32); break; case FT_UINT64: w->control.number.comp = comps[0][ft_cmp_op]; w->control.number.value.u = va_arg(ap,guint64); break; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: w->control.number.comp = comps[1][ft_cmp_op]; w->control.number.value.i = va_arg(ap,gint32); break; case FT_INT64: w->control.number.comp = comps[1][ft_cmp_op]; w->control.number.value.i = va_arg(ap,gint64); break; case FT_FLOAT: case FT_DOUBLE: w->control.number.comp = comps[1][ft_cmp_op]; w->control.number.value.i = va_arg(ap,gdouble); break; default: g_assert(! "comparison unsupported"); } w->control.number.extract = extracts[little_endian][ftenum]; g_assert(w->control.number.extract && "extraction unsupported"); w->id = id; w->condition = cond_ft_comp; w->after = after_cb; w->before = before_cb; w->data = data; return w; } #endif tvbparse_wanted_t* tvbparse_quoted(const int id, const void* data, tvbparse_action_t before_cb, tvbparse_action_t after_cb, const char quote, const char esc) { gchar* esc_quot = g_strdup_printf("%c%c",esc,quote); gchar* quot = g_strdup_printf("%c",quote); tvbparse_wanted_t* want_quot = tvbparse_char(-1,quot,NULL,NULL,NULL); return tvbparse_set_oneof(id, data, before_cb, after_cb, tvbparse_set_seq(-1, NULL, NULL, NULL, want_quot, tvbparse_set_seq(-1,NULL,NULL,NULL, tvbparse_set_oneof(-1, NULL, NULL, NULL, tvbparse_string(-1,esc_quot,NULL,NULL,NULL), tvbparse_not_chars(-1,0,0,quot,NULL,NULL,NULL), NULL), NULL), want_quot, NULL), tvbparse_set_seq(-1, NULL, NULL, NULL, want_quot, want_quot, NULL), NULL); } void tvbparse_shrink_token_cb(void* tvbparse_data _U_, const void* wanted_data _U_, tvbparse_elem_t* tok) { tok->offset += 1; tok->len -= 2; } tvbparse_t* tvbparse_init(tvbuff_t* tvb, const int offset, int len, void* data, const tvbparse_wanted_t* ignore) { tvbparse_t* tt = (tvbparse_t *)wmem_new(wmem_packet_scope(), tvbparse_t); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) g_warning("tvbparse_init: offset=%i len=%i",offset,len); #endif tt->tvb = tvb; tt->offset = offset; len = (len == -1) ? (int) tvb_captured_length(tvb) : len; tt->end_offset = offset + len; tt->data = data; tt->ignore = ignore; return tt; } gboolean tvbparse_reset(tvbparse_t* tt, const int offset, int len) { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_TT) g_warning("tvbparse_init: offset=%i len=%i",offset,len); #endif len = (len == -1) ? (int) tvb_captured_length(tt->tvb) : len; if( tvb_captured_length_remaining(tt->tvb, offset) >= len) { tt->offset = offset; tt->end_offset = offset + len; return TRUE; } else { return FALSE; } } guint tvbparse_curr_offset(tvbparse_t* tt) { return tt->offset; } static void execute_callbacks(tvbparse_t* tt, tvbparse_elem_t* curr) { wmem_stack_t *stack = wmem_stack_new(wmem_packet_scope()); while (curr) { if(curr->wanted->before) { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_warning("execute_callbacks: BEFORE: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len); #endif curr->wanted->before(tt->data, curr->wanted->data, curr); } if(curr->sub) { wmem_stack_push(stack, curr); curr = curr->sub; continue; } else { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len); #endif if(curr->wanted->after) curr->wanted->after(tt->data, curr->wanted->data, curr); } curr = curr->next; while( !curr && wmem_stack_count(stack) > 0 ) { curr = (tvbparse_elem_t *)wmem_stack_pop(stack); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_CB) g_warning("execute_callbacks: AFTER: id=%i offset=%i len=%i",curr->id,curr->offset,curr->len); #endif if( curr->wanted->after ) curr->wanted->after(tt->data, curr->wanted->data, curr); curr = curr->next; } } } gboolean tvbparse_peek(tvbparse_t* tt, const tvbparse_wanted_t* wanted) { tvbparse_elem_t* tok = NULL; int consumed; int offset = tt->offset; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: ENTER offset=%i",offset); #endif offset += ignore_fcn(tt,offset); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: after ignore offset=%i",offset); #endif consumed = wanted->condition(tt,offset,wanted,&tok); if (consumed >= 0) { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: GOT len=%i",consumed); #endif return TRUE; } else { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_PEEK) g_warning("tvbparse_peek: NOT GOT"); #endif return FALSE; } } tvbparse_elem_t* tvbparse_get(tvbparse_t* tt, const tvbparse_wanted_t* wanted) { tvbparse_elem_t* tok = NULL; int consumed; int offset = tt->offset; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: ENTER offset=%i",offset); #endif offset += ignore_fcn(tt,offset); #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: after ignore offset=%i",offset); #endif consumed = wanted->condition(tt,offset,wanted,&tok); if (consumed >= 0) { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: GOT len=%i",consumed); #endif execute_callbacks(tt,tok); tt->offset = offset + consumed; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_GET) g_warning("tvbparse_get: DONE offset=%i", tt->offset); #endif return tok; } else { return NULL; } } tvbparse_elem_t* tvbparse_find(tvbparse_t* tt, const tvbparse_wanted_t* wanted) { tvbparse_elem_t* tok = NULL; int len = 0; int offset = tt->offset; int target_offset = offset -1; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: ENTER offset=%i", tt->offset); #endif do { len = wanted->condition(tt, target_offset+1, wanted, &tok); } while(len < 0 && ++target_offset < tt->end_offset); if (len >= 0) { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: FOUND offset=%i len=%i", target_offset,len); #endif execute_callbacks(tt,tok); tt->offset = target_offset + len; #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: DONE offset=%i", tt->offset); #endif return tok; } else { #ifdef TVBPARSE_DEBUG if (TVBPARSE_DEBUG & TVBPARSE_DEBUG_FIND) g_warning("tvbparse_get: NOT FOUND"); #endif return NULL; } } struct _elem_tree_stack_frame { proto_tree* tree; tvbparse_elem_t* elem; }; void tvbparse_tree_add_elem(proto_tree* tree, tvbparse_elem_t* curr) { wmem_stack_t *stack = wmem_stack_new(wmem_packet_scope()); struct _elem_tree_stack_frame* frame = wmem_new(wmem_packet_scope(), struct _elem_tree_stack_frame); proto_item* pi; frame->tree = tree; frame->elem = curr; while (curr) { pi = proto_tree_add_format_text(frame->tree,curr->tvb,curr->offset,curr->len); if(curr->sub) { frame->elem = curr; wmem_stack_push(stack, frame); frame = wmem_new(wmem_packet_scope(), struct _elem_tree_stack_frame); frame->tree = proto_item_add_subtree(pi,0); curr = curr->sub; continue; } curr = curr->next; while( !curr && wmem_stack_count(stack) > 0 ) { frame = (struct _elem_tree_stack_frame *)wmem_stack_pop(stack); curr = frame->elem->next; } } } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */