diff options
Diffstat (limited to 'tools/parse_xml2skinny_dissector.py')
-rwxr-xr-x | tools/parse_xml2skinny_dissector.py | 1073 |
1 files changed, 1073 insertions, 0 deletions
diff --git a/tools/parse_xml2skinny_dissector.py b/tools/parse_xml2skinny_dissector.py new file mode 100755 index 00000000..b13776e3 --- /dev/null +++ b/tools/parse_xml2skinny_dissector.py @@ -0,0 +1,1073 @@ +# +# Wireshark Dissector Generator for SkinnyProtocolOptimized.xml +# +# Author: Diederik de Groot <ddegroot@user.sf.net> +# Date: 2014-7-22 +# Skinny Protocol Versions: 0 through 22 +# +# Heritage: +# xml2obj based on https://code.activestate.com/recipes/149368-xml2obj/ +# +# Dependencies: +# python / xml / sax +# +# Called By: +# cog.py + packet-skinny.c.in for inplace code generation +# See: https://nedbatchelder.com/code/cog/ +# +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + +import re +import xml.sax.handler + +indentation = 0 +indent_str = '' +fieldsArray = {} +si_fields = { + "callReference" : "si->callId", + "lineInstance": "si->lineId", + "passThroughPartyId" : "si->passThroughPartyId", + "callState" : "si->callState", + "callingParty" : "si->callingParty", + "calledParty" : "si->calledParty", + "mediaReceptionStatus" : "si->mediaReceptionStatus", + "mediaTransmissionStatus" : "si->mediaTransmissionStatus", + "multimediaReceptionStatus" : "si->multimediaReceptionStatus", + "multimediaTransmissionStatus" : "si->multimediaTransmissionStatus", + "multicastReceptionStatus" : "si->multicastReceptionStatus", +} + +debug = 0 + +def xml2obj(src): + """ + A function to converts XML data into native Python objects. + + """ + non_id_char = re.compile('[^_0-9a-zA-Z]') + + def _name_mangle(name): + return non_id_char.sub('_', + name) + + class DataNode(object): + def __init__(self): + self._attrs = {} # XML attributes and child elements + self.data = None # child text data + self.parent = None + self.basemessage = None + self.intsize = 0 + self._children = [] + self.declared = [] + + def __len__(self): + # treat single element as a list of 1 + return 1 + def __getitem__(self, key): + if isinstance(key, str): + return self._attrs.get(key,None) + else: + return [self][key] + + def __contains__(self, name): + return name in self._attrs + + def __bool__(self): + return bool(self._attrs or self.data) + + def __getattr__(self, name): + if name.startswith('__'): + # need to do this for Python special methods??? + raise AttributeError(name) + return self._attrs.get(name,None) + + def _add_xml_attr(self, name, value): + if name in self._attrs: + # multiple attribute of the same name are represented by a list + children = self._attrs[name] + if not isinstance(children, list): + children = [children] + self._attrs[name] = children + children.append(value) + else: + self._attrs[name] = value + + def _add_child(self, name, value): + #print "adding : %s / %s to %s" %(name,value, self.__class__) + self._children.append(value) + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def keys(self): + return self._attrs.keys() + + def __repr__(self): + items = {} + if self.data: + items.append(('data', self.data)) + return '{%s}' % ', '.join(['%s:%s' % (k,repr(v)) for k,v in items]) + + def __setitem__(self, key, value): + self._attrs[key] = value + + def getfieldnames(self): + return '' + + def get_req_resp_keys(self, req_resp_keys): + return [] + + def get_req_resp_key(self): + if self.req_resp_key == "1": + return self.name + return None + + def declaration(self): + global fieldsArray + if self.name not in fieldsArray: + fieldsArray[self.name] = '/* UNKNOWN { &hf_skinny_%s,\n {\n"%s", "skinny.%s", FT_UINT32, BASE_DEC, NULL, 0x0,\n "%s", HFILL }}, */\n' %(self.name, self.name, self.name, self.comment) + return '' + + def dissect(self): + return self.name or '' + + def incr_indent(self): + global indentation + global indent_str + indentation += 1 + indent_str = '' + for x in range(0, indentation): + indent_str += ' ' + + def decr_indent(self): + global indentation + global indent_str + indentation -= 1 + indent_str = '' + for x in range(0, indentation): + indent_str += ' ' + + def indent_out(self, string): + return indent_str + string + + + class Message(DataNode): + ''' Message ''' + def __str__(self): + return self.name + + def gen_handler(self): + if self.fields is None: + # skip whole message and return NULL as handler + return 'NULL' + return 'handle_%s' %self.name + + def dissect(self): + ret = '' + declarations = 0 + fixed = 0 + + if (self.fields is not None): + ret += self.indent_out("/*\n") + ret += self.indent_out(" * Message: %s\n" %self.name) + ret += self.indent_out(" * Opcode: %s\n" %self.opcode) + ret += self.indent_out(" * Type: %s\n" %self.type) + ret += self.indent_out(" * Direction: %s\n" %self.direction) + ret += self.indent_out(" * VarLength: %s\n" %self.dynamic) + ret += self.indent_out(" * MsgType: %s\n" %self.msgtype) + if self.comment: + ret += self.indent_out(" * Comment: %s\n" %self.comment) + ret += self.indent_out(" */\n") + ret += self.indent_out("static void\n") + ret += self.indent_out("handle_%s(ptvcursor_t *cursor, packet_info * pinfo _U_, skinny_conv_info_t * skinny_conv _U_)\n" %self.name) + ret += self.indent_out("{\n") + self.incr_indent() + + for fields in self.fields: + if fields.size_lt or fields.size_gt: + if self.basemessage.declared is None or "hdr_data_length" not in self.basemessage.declared: + ret += self.indent_out("uint32_t hdr_data_length = tvb_get_letohl(ptvcursor_tvbuff(cursor), 0);\n") + self.basemessage.declared.append("hdr_data_length") + declarations += 1 + if fields.fixed == "yes": + fixed = 1 + + if not declarations or fixed == 1: + for fields in self.fields[1:]: + if self.basemessage.declared is None or "hdr_version" not in self.basemessage.declared: + ret += self.indent_out("uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n") + self.basemessage.declared.append("hdr_version") + declarations += 1 + + req_resp_keys = [] + for fields in self.fields: + fields.get_req_resp_keys(req_resp_keys) + ret += '%s' %fields.declaration() + declarations += 1 + + if declarations > 1: + ret += "\n" + + if self.fields is not None: + for fields in self.fields: + ret += '%s' %fields.dissect() + + # setup request/response + if self.msgtype == "request": + if req_resp_keys and req_resp_keys[0] != '': + ret += self.indent_out('skinny_reqrep_add_request(cursor, pinfo, skinny_conv, %s ^ %s);\n' %(self.opcode, req_resp_keys[0])) + else: + ret += self.indent_out('skinny_reqrep_add_request(cursor, pinfo, skinny_conv, %s);\n' %(self.opcode)) + + if self.msgtype == "response": + if req_resp_keys and req_resp_keys[0] != '': + ret += self.indent_out('skinny_reqrep_add_response(cursor, pinfo, skinny_conv, %s ^ %s);\n' %(self.request, req_resp_keys[0])) + else: + ret += self.indent_out('skinny_reqrep_add_response(cursor, pinfo, skinny_conv, %s);\n' %(self.request)) + + self.decr_indent() + + ret += "}\n\n" + return ret + + class Fields(DataNode): + ''' Fields ''' + size_fieldnames= [] + + def get_req_resp_keys(self, req_resp): + for field in self._children: + key = field.get_req_resp_key() + if not key is None and not key in req_resp: + req_resp.append(key) + + def declaration(self): + ret = '' + + for field in self._children: + ret += '%s' %(field.declaration()) + self.intsize += field.intsize + return ret + + def dissect(self, lookupguide=""): + ret = '' + ifstarted = 0 + #ret += "/* [PARENT: %s, BASEMESSAGE: %s] */\n" %(self.parent.name,self.basemessage.name) + + if ((self.beginversion or self.endversion) and (self.beginversion != "0" or self.endversion != "22")): + + ifstarted = 1 + ret += self.indent_out('if (') + if (self.beginversion and self.beginversion != "0"): + if (not self.endversion or self.endversion == "22"): + ret += 'hdr_version >= V%s_MSG_TYPE) {\n' %self.beginversion + else: + ret += 'hdr_version >= V%s_MSG_TYPE && ' %self.beginversion + if (self.endversion and self.endversion != "22"): + ret += 'hdr_version <= V%s_MSG_TYPE) {\n' %self.endversion + self.incr_indent() + + if self.size_lt: + ret += self.indent_out('if (hdr_data_length < %s) {\n' %self.size_lt) + self.incr_indent() + + if self.size_gt: + ret += self.indent_out('if (hdr_data_length > %s) {\n' %self.size_gt) + self.incr_indent() + + # generate dissection + for field in self._children: + ret += '%s' %(field.dissect()) + + if self.size_lt: + self.decr_indent() + ret += self.indent_out('}\n') + + if self.size_gt: + self.decr_indent() + ret += self.indent_out('}\n') + + if ifstarted: + self.decr_indent() + ret += self.indent_out('}\n') + + return ret; + + class Integer(DataNode): + def __init__(self): + DataNode.__init__(self) + self.intsize = 0 + self.endian = "ENC_LITTLE_ENDIAN" + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + ret = '' + + int_sizes = {'uint32':4,'uint16':2,'uint8':1,'int32':4,'int16':2,'int8':1,'ipport':4} + if self.endianness == "big": + self.endian = "ENC_BIG_ENDIAN" + if self.type in int_sizes: + self.intsize = int_sizes[self.type] + else: + print(("ERROR integer %s with type: %s, could not be found" %(self.name, self.type))) + + if self.declare == "yes" or self.make_additional_info == "yes": + if self.basemessage.declared is None or self.name not in self.basemessage.declared: + ret += self.indent_out(f'uint{self.intsize * 8}_t {self.name} = 0;\n') + self.basemessage.declared.append(self.name) + + global fieldsArray + if self.name not in fieldsArray: + fieldsArray[self.name] ='{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_UINT%d, BASE_DEC, NULL, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), self.intsize * 8, '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + return ret + + def dissect(self): + ret = '' + + size = 0 + if self.size_fieldname: + if self.basemessage.dynamic == "yes": + size = self.size_fieldname + else: + size = self.maxsize + elif self.size: + size = self.size + + if size: + if self.size_fieldname: + ret += self.indent_out('if (%s <= %s) {%s\n' %(self.size_fieldname, size, ' /* tvb integer size guard */' if debug else '')) + else: + ret += self.indent_out('{\n') + self.incr_indent() + variable = 'counter_%d' %indentation + ret += self.indent_out('uint32_t %s = 0;\n' %(variable)); + if self.size_fieldname: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [ref:%s = %%d, max:%s]", %s);\n' %(self.name, self.size_fieldname, size, self.size_fieldname)) + else: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [max:%s]");\n' %(self.name, size)) + ret += self.indent_out('for (%s = 0; %s < %s; %s++) {\n' %(variable, variable, size, variable)); + if self.basemessage.dynamic == "no" and self.size_fieldname: + self.incr_indent() + ret += self.indent_out('if (%s < %s) {\n' %(variable,self.size_fieldname)) + self.incr_indent() + + if self.declare == "yes" or self.make_additional_info == "yes": + if self.endianness == "big": + if (self.intsize == 4): + ret += self.indent_out('%s = tvb_get_ntohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + elif (self.intsize == 2): + ret += self.indent_out('%s = tvb_get_ntohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + else: + ret += self.indent_out('%s = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + else: + if (self.intsize == 4): + ret += self.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + elif (self.intsize == 2): + ret += self.indent_out('%s = tvb_get_letohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + else: + ret += self.indent_out('%s = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + + if self.name in si_fields.keys(): + if self.endianness == "big": + ret += self.indent_out('%s = tvb_get_ntohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(si_fields[self.name])) + else: + ret += self.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(si_fields[self.name])) + + ret += self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %d, %s);\n' %(self.name, self.intsize, self.endian)) + + if size: + if self.basemessage.dynamic == "no" and self.size_fieldname: + self.decr_indent() + ret += self.indent_out('} else {\n') + ret += self.indent_out(' ptvcursor_advance(cursor, %d);\n' %self.intsize) + ret += self.indent_out('}\n') + self.decr_indent() + ret += self.indent_out('}\n') + if debug: + ret += self.indent_out('ptvcursor_pop_subtree(cursor); /* end for loop tree: %s */\n' %(self.name)) + else: + ret += self.indent_out('ptvcursor_pop_subtree(cursor);\n') + self.decr_indent() + if self.size_fieldname: + ret += self.indent_out('} else {\n') + self.incr_indent() + ret += self.indent_out('ptvcursor_advance(cursor, (%s * %s));%s\n' %(size, self.intsize, ' /* guard kicked in -> skip the rest */;' if debug else '')) + self.decr_indent() + ret += self.indent_out('}\n') + + if self.make_additional_info == "yes": + ret += self.indent_out('srtp_add_address(pinfo, PT_UDP, &%s, %s, 0, "SKINNY", pinfo->num, false, NULL, NULL, NULL);\n' %(self.use_param, self.name)) + ret += self.indent_out('%s_str = address_to_display(NULL, &%s);\n' % (self.use_param, self.use_param)) + ret += self.indent_out('si->additionalInfo = ws_strdup_printf("%%s:%%d", %s_str, %s);\n' % (self.use_param, self.name)) + ret += self.indent_out('wmem_free(NULL, %s_str);\n' % (self.use_param)) + + return ret + + class Enum(DataNode): + def __init__(self): + DataNode.__init__(self) + self.intsize = 0 + self.sparse = 0 + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + ret = '' + prevvalue = 0 + enum_sizes = {'uint32':4,'uint16':2,'uint8':1} + if self.type in enum_sizes: + self.intsize = enum_sizes[self.type] + else: + print(("ERROR enum %s with type: %s, could not be found" %(self.name, self.type))) + + if self.declare == "yes": + if self.basemessage.declared is None or self.name not in self.basemessage.declared: + ret += self.indent_out('g%s %s = 0;\n' %(self.type, self.name)) + self.basemessage.declared.append(self.name) + + global fieldsArray + if self.name not in fieldsArray: + fieldsArray[self.name] ='{&hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_UINT%d, BASE_HEX | BASE_EXT_STRING, &%s_ext, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), self.intsize * 8, self.subtype[0].upper() + self.subtype[1:], '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + return ret + + def dissect(self): + ret = '' + endian = "ENC_LITTLE_ENDIAN" + size = 0 + if self.size_fieldname: + if self.basemessage.dynamic == "yes": + size = self.size_fieldname + else: + size = self.maxsize + elif self.size: + size = self.size + + if self.make_additional_info == "yes": + ret += self.indent_out('si->additionalInfo = ws_strdup_printf("\\"%s\\"",\n') + self.incr_indent() + ret += self.indent_out('try_val_to_str_ext(\n') + self.incr_indent() + ret += self.indent_out('tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)),\n') + ret += self.indent_out('&%s_ext\n' %(self.subtype[0].upper() + self.subtype[1:])) + self.decr_indent() + ret += self.indent_out(')\n') + self.decr_indent() + ret += self.indent_out(');\n') + + if self.make_additional_info_short == "yes": + ret += self.indent_out('si->additionalInfo = ws_strdup_printf("\\"%s\\"",\n') + self.incr_indent() + ret += self.indent_out('try_val_to_str_ext(\n') + self.incr_indent() + ret += self.indent_out('tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor)),\n') + ret += self.indent_out('&%s_short_ext\n' %(self.subtype[0].upper() + self.subtype[1:])) + self.decr_indent() + ret += self.indent_out(')\n') + self.decr_indent() + ret += self.indent_out(');\n') + + if size: + if self.size_fieldname: + ret += self.indent_out('if (%s <= %s) { /* tvb enum size guard */\n' %(self.size_fieldname, self.maxsize)) + else: + ret += self.indent_out('{\n') + self.incr_indent() + variable = 'counter_%d' %indentation + ret += self.indent_out('uint32_t %s = 0;\n' %(variable)); + if self.size_fieldname: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [ref: %s = %%d, max:%s]", %s);\n' %(self.name, self.size_fieldname, size, self.size_fieldname)) + else: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [max:%s]");\n' %(self.name, size)) + ret += self.indent_out('for (%s = 0; %s < %s; %s++) {\n' %(variable, variable, size, variable)); + if self.basemessage.dynamic == "no" and self.size_fieldname: + self.incr_indent() + ret += self.indent_out('if (%s < %s) {\n' %(variable,self.size_fieldname)) + self.incr_indent() + + if self.name in si_fields.keys(): + ret += self.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(si_fields[self.name])) + + if self.declare == "yes": + if (self.intsize == 4): + ret += self.indent_out('%s = tvb_get_letohl(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + elif (self.intsize == 2): + ret += self.indent_out('%s = tvb_get_letohs(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + else: + ret += self.indent_out('%s = tvb_get_guint8(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor));\n' %(self.name)) + + ret += self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %d, %s);\n' %(self.name, self.intsize, endian)) + + if size: + if self.basemessage.dynamic == "no" and self.size_fieldname: + self.decr_indent() + ret += self.indent_out('} else {\n') + ret += self.indent_out(' ptvcursor_advance(cursor, 4);\n') + ret += self.indent_out('}\n') + self.decr_indent() + ret += self.indent_out('}\n') + if debug: + ret += self.indent_out('ptvcursor_pop_subtree(cursor); /* end for loop tree: %s */\n' %(self.name)) + else: + ret += self.indent_out('ptvcursor_pop_subtree(cursor);\n') + self.decr_indent() + if self.size_fieldname: + ret += self.indent_out('} else {\n') + self.incr_indent() + ret += self.indent_out('ptvcursor_advance(cursor, (%s * %s)); /* guard kicked in -> skip the rest */;\n' %(size, self.intsize)) + self.decr_indent() + ret += self.indent_out('}\n') + + return ret + + class String(DataNode): + def __init__(self): + DataNode.__init__(self) + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def get_req_resp_key(self): + if self.req_resp_key == "1": + return 'wmem_str_hash(%s)' %self.name + return None + + def declaration(self): + ret = '' + self.intsize = 0 + if self.size: + if self.size=="VariableDirnumSize": + self.intsize = 24 + else: + self.intsize = int(self.size) + elif self.maxsize and self.basemessage.dynamic == "no": + self.intsize = int(self.maxsize) + + if self.declare == "yes": + if self.size=="VariableDirnumSize": + if self.basemessage.declared is None or "VariableDirnumSize" not in self.basemessage.declared: + if self.basemessage.declared is None or "hdr_version" not in self.basemessage.declared: + #if (self.basemessage.fields is not None and len(self.basemessage.fields) == 1): + ret += self.indent_out('uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n') + self.basemessage.declared.append("hdr_version") + ret += self.indent_out('uint32_t VariableDirnumSize = (hdr_version >= V18_MSG_TYPE) ? 25 : 24;\n') + self.basemessage.declared.append("VariableDirnumSize") + #else: + # if self.basemessage.declared is None or self.name not in self.basemessage.declared: + # ret += self.indent_out('char *%s = NULL;\n' %self.name) + # self.basemessage.declared.append(self.name) + + if self.basemessage.dynamic == "yes" and not self.subtype == "DisplayLabel": + if self.basemessage.declared is None or self.name + '_len' not in self.basemessage.declared: + ret += self.indent_out('uint32_t %s_len = 0;\n' %self.name) + self.basemessage.declared.append(self.name + '_len') + + global fieldsArray + if self.name not in fieldsArray: + fieldsArray[self.name] = '{&hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_STRING, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + return ret + + def dissect(self): + ret = '' + + if self.declare == "yes" and self.size != "VariableDirnumSize": + ret += self.indent_out('const char * %s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(self.name, self.size)) + + if self.subtype == "DisplayLabel": + if self.basemessage.dynamic == "yes": + ret += self.indent_out('dissect_skinny_displayLabel(cursor, pinfo, hf_skinny_%s, 0);\n' %(self.name)) + elif self.size_fieldname: + ret += self.indent_out('dissect_skinny_displayLabel(cursor, pinfo, hf_skinny_%s, %s);\n' %(self.name, self.size_fieldname)) + else: + ret += self.indent_out('dissect_skinny_displayLabel(cursor, pinfo, hf_skinny_%s, %s);\n' %(self.name, self.size)) + + elif self.basemessage.dynamic == "yes": + ret += self.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), -1)+1;\n' %self.name) + ret += self.indent_out('if (%s_len > 1) {\n' %self.name) + if self.name in si_fields.keys(): + ret += self.indent_out(' %s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s_len));\n' %(si_fields[self.name], self.name)) + ret += self.indent_out(' ptvcursor_add(cursor, hf_skinny_%s, %s_len, ENC_ASCII);\n' %(self.name, self.name)) + ret += self.indent_out('} else {\n') + ret += self.indent_out(' ptvcursor_advance(cursor, 1);\n') + ret += self.indent_out('}\n') + elif self.size_fieldname: + if self.name in si_fields.keys(): + ret += self.indent_out('%s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(si_fields[self.name], self.size_fieldname)) + ret += self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %s, ENC_ASCII);\n' %(self.name, self.size_fieldname)) + else: + if self.name in si_fields.keys(): + ret += self.indent_out('%s = g_strdup(tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s));\n' %(si_fields[self.name], self.size)) + if self.make_additional_info == "yes": + ret += self.indent_out('uint32_t %s_len;\n' %(self.name)) + if self.size=="VariableDirnumSize": + ret += self.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), VariableDirnumSize)+1;\n' %(self.name)) + else: + ret += self.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), 24)+1;\n' %(self.name)) + ret += self.indent_out('if (%s_len > 1) {\n' %(self.name)) + self.incr_indent() + ret += self.indent_out('si->additionalInfo = ws_strdup_printf("\\"%%s\\"", tvb_format_stringzpad(pinfo->pool, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), %s_len));\n' %(self.name)) + self.decr_indent() + ret += self.indent_out('}\n') + + ret += self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, %s, ENC_ASCII);\n' %(self.name, self.size)) + + return ret + + class Ether(DataNode): + def __init__(self): + DataNode.__init__(self) + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + ret = '' + self.intsize = 6 + if self.size: + self.intsize = int(self.size) + elif self.maxsize and self.basemessage.dynamic == "no": + self.intsize = int(self.maxsize) + + if self.declare == "yes": + if self.basemessage.declared is None or self.name not in self.basemessage.declared: + ret += self.indent_out('uint32_t %s = 0;\n' %self.name) + self.basemessage.declared.append(self.name) + + if self.basemessage.dynamic == "yes": + if self.basemessage.declared is None or self.name + '_len' not in self.basemessage.declared: + ret += self.indent_out('uint32_t %s_len = 0;\n' %self.name) + self.basemessage.declared.append(self.name + '_len') + + global fieldsArray + if self.name not in fieldsArray: + fieldsArray[self.name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_ETHER, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + return ret + + def dissect(self): + ret = '' + + if self.basemessage.dynamic == "yes": + ret += self.indent_out('%s_len = tvb_strnlen(ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), -1)+1;\n' %self.name) + ret += self.indent_out('if (%s_len > 1) {\n' %self.name) + ret += self.indent_out(' ptvcursor_add(cursor, hf_skinny_%s, 6, ENC_NA);\n' %(self.name)) + ret += self.indent_out(' ptvcursor_advance(cursor, %s_len - 6);\n' %(self.name)) + ret += self.indent_out('} else {\n') + ret += self.indent_out(' ptvcursor_advance(cursor, 1);\n') + ret += self.indent_out('}\n') + elif self.size_fieldname: + ret += self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 6, ENC_NA);\n' %(self.name)) + ret += self.indent_out('ptvcursor_advance(cursor, %s - 6);\n' %(self.size_fieldname)) + else: + ret += self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 6, ENC_NA);\n' %(self.name)) + ret += self.indent_out('ptvcursor_advance(cursor, %s - 6);\n' %(self.size)) + return ret + + class BitField(DataNode): + def __init__(self): + DataNode.__init__(self) + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + global fieldsArray + ret = '' + int_sizes = {'uint32':4,'uint16':2,'uint8':1,'int32':4,'int16':2,'int8':1} + self.intsize = 0 + if self.size in int_sizes: + self.intsize = int_sizes[self.size] + + for entries in self.entries: + for entry in entries.entry: + if entry.name not in fieldsArray: + fieldsArray[entry.name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_BOOLEAN, %d, TFS(&tfs_yes_no), %s,\n %s, HFILL }},\n' %(entry.name, entry.text, entry.name.replace("_","."), self.intsize * 8, entry.value, '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + + return ret + + def dissect(self): + ret = '' + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s");\n' %(self.name)) + for entries in self.entries: + for entry in entries.entry: + ret += self.indent_out('ptvcursor_add_no_advance(cursor, hf_skinny_%s, %d, ENC_LITTLE_ENDIAN);\n' %(entry.name, self.intsize)) + ret += self.indent_out('ptvcursor_advance(cursor, %d);\n' %(self.intsize)) + ret += self.indent_out('ptvcursor_pop_subtree(cursor); /* end bitfield: %s */\n' %(self.name)) + + + return ret + + class Ip(DataNode): + def __init__(self): + DataNode.__init__(self) + self.intsize = 4 + if self.type == "ipv6": + self.intsize = 16 + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + global fieldsArray + if self.name not in fieldsArray: + if self.type == "ipv4": + fieldsArray[self.name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv4, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + else: + fieldsArray[self.name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv6, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + return '' + + def dissect(self): + if self.type == "ipv4": + return self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 4, ENC_BIG_ENDIAN);\n' %self.name) + else: + return self.indent_out('ptvcursor_add(cursor, hf_skinny_%s, 16, ENC_NA);\n' %self.name) + + class Ipv4or6(DataNode): + def __init__(self): + DataNode.__init__(self) + self.intsize = 4 + if self.endianness is None: + self.intsize += 16 + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + global fieldsArray + + ret = '' + name = self.name + '_ipv4' + if name not in fieldsArray: + fieldsArray[name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv4, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(name, self.name + ' IPv4 Address', name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + name = self.name + '_ipv6' + if name not in fieldsArray: + fieldsArray[name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_IPv6, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(name, self.name + ' IPv6 Address', name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + if self.make_additional_info == "yes": + if self.basemessage.declared is None or self.name not in self.basemessage.declared: + ret += self.indent_out('address %s;\n' %(self.name)) + ret += self.indent_out('char *%s_str = NULL;\n' %(self.name)) + self.basemessage.declared.append(self.name) + + return ret + + def dissect(self): + ret = '' + if self.make_additional_info == "yes": + ret += self.indent_out('read_skinny_ipv4or6(cursor, &%s);\n' %(self.name)); + ret += self.indent_out('dissect_skinny_ipv4or6(cursor, hf_skinny_%s_ipv4, hf_skinny_%s_ipv6);\n' %(self.name, self.name)); + return ret; + + class XML(DataNode): + def __init__(self): + DataNode.__init__(self) + self.intsize = 0 + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + global fieldsArray + + if self.size: + self.intsize = int(self.size) + elif self.maxsize: + self.intsize = int(self.maxsize) + + if self.name not in fieldsArray: + fieldsArray[self.name] = '{ &hf_skinny_%s,\n {\n "%s", "skinny.%s", FT_STRING, BASE_NONE, NULL, 0x0,\n %s, HFILL }},\n' %(self.name, self.comment if (self.comment and self.longcomment) else self.name, self.name.replace("_","."), '"' + self.longcomment + '"' if self.longcomment else '"' + self.comment + '"' if self.comment else 'NULL') + return '' + + def dissect(self): + ret = '' + if self.size_fieldname: + ret += self.indent_out('dissect_skinny_xml(cursor, hf_skinny_%s, pinfo, %s, %d);\n' %(self.name, self.size_fieldname, self.intsize)) + else: + ret += self.indent_out('dissect_skinny_xml(cursor, hf_skinny_%s, pinfo, 0, %d);\n' %(self.name, self.intsize)) + return ret + + class Code(DataNode): + def __init__(self): + DataNode.__init__(self) + + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + return '' + + def dissect(self): + ret = '' + if self.type == "calling_and_called_party": + params = self.use_param.split(',') + ret += self.indent_out('if (si->%s && si->%s) {\n' %(params[0], params[1])) + self.incr_indent() + ret += self.indent_out('si->additionalInfo = ws_strdup_printf("\\"%%s -> %%s\\"", si->%s, si->%s);\n' %(params[0], params[1])) + self.decr_indent() + ret += self.indent_out('}\n') + return ret + + class Struct(DataNode): + def __str__(self): + return '// Struct : %s / %s / %s / %s\n' %(self.name, self.size, self.field_sizename, self.maxsize) + + def declaration(self): + ret = '' + + if (self.fields is not None and len(self.fields)): + if (len(self.fields) > 1): + if self.basemessage.declared is None or "hdr_version" not in self.basemessage.declared: + ret += self.indent_out("uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n") + self.basemessage.declared.append("hdr_version") + for fields in self.fields: + ret += '%s' %fields.declaration() + #self.intsize += fields.intsize + self.intsize = fields.intsize + return ret + + def dissect(self): + ret = '' + variable = 'counter_%d' %indentation + size = 0 + + if self.size_fieldname: + #if self.basemessage.dynamic == "yes": + # size = self.size_fieldname + #else: + # size = self.maxsize + size = self.maxsize + elif self.size: + size = self.size + + if size: + if self.size_fieldname: + ret += self.indent_out('if (%s <= %s) {%s\n' %(self.size_fieldname, size, ' /* tvb struct size guard */' if debug else '')) + else: + ret += self.indent_out('{\n') + self.incr_indent() + if debug: + ret += self.indent_out('/* start struct : %s / size: %d */\n' %(self.name, self.intsize)) + ret += self.indent_out('uint32_t %s = 0;\n' %(variable)); + if self.size_fieldname: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [ref:%s = %%d, max:%s]", %s);\n' %(self.name, self.size_fieldname, self.maxsize, self.size_fieldname)) + if self.maxsize: + ret += self.indent_out('if (%s && tvb_get_letohl(ptvcursor_tvbuff(cursor), 0) + 8 >= ptvcursor_current_offset(cursor) + (%s * %s) && %s <= %s) {%s\n' %(self.size_fieldname, self.size_fieldname, self.intsize, self.size_fieldname, self.maxsize, '/* tvb counter size guard */' if debug else '')) + else: + ret += self.indent_out('if (%s && tvb_get_letohl(ptvcursor_tvbuff(cursor), 0) + 8 >= ptvcursor_current_offset(cursor) + (%s * %s)) {%s\n' %(self.size_fieldname, self.size_fieldname, self.intsize, '/* tvb counter size guard */' if debug else '')) + self.incr_indent() + else: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [max:%s]");\n' %(self.name, size)) + + ret += self.indent_out('for (%s = 0; %s < %s; %s++) {\n' %(variable, variable, size, variable)); + if self.basemessage.dynamic == "no" and self.size_fieldname: + self.incr_indent() + ret += self.indent_out('if (%s < %s) {\n' %(variable,self.size_fieldname)) + self.incr_indent() + else: + if debug: + ret += self.indent_out('{ /* start struct : %s / size: %d */\n' %(self.name, self.intsize)) + else: + ret += self.indent_out('{\n') + self.incr_indent() + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s");\n' %(self.name)) + + if size: + if self.size_fieldname: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [%%d / %%d]", %s + 1, %s);\n' %(self.name, variable, self.size_fieldname)) + else: + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s [%%d / %%d]", %s + 1, %s);\n' %(self.name, variable, size)) + + if (self.fields is not None and len(self.fields)): + for fields in self.fields: + ret += '%s' %fields.dissect() + + if self.basemessage.dynamic == "no" and self.size_fieldname: + self.decr_indent() + ret += self.indent_out('} else {\n') + ret += self.indent_out(' ptvcursor_advance(cursor, %d);\n' %(self.intsize)) + ret += self.indent_out('}\n') + + if size: + ret += self.indent_out('ptvcursor_pop_subtree(cursor);\n') + self.decr_indent() + if debug: + ret += self.indent_out('} /* end for loop tree: %s */\n' %self.name) + else: + ret += self.indent_out('}\n') + if self.size_fieldname: + self.decr_indent() + ret += self.indent_out('} /* end counter tvb size guard */\n' if debug else '}\n') + + ret += self.indent_out('ptvcursor_pop_subtree(cursor);\n') + if debug: + ret += self.indent_out('/* end struct: %s */\n' %self.name) + self.decr_indent() + if self.size_fieldname: + ret += self.indent_out('} else {\n') + self.incr_indent() + ret += self.indent_out('ptvcursor_advance(cursor, (%s * %s));%s\n' %(self.size_fieldname, self.intsize, ' /* guard kicked in -> skip the rest */' if debug else '')); + self.decr_indent() + ret += self.indent_out('} /* end struct size guard */\n' if debug else '}\n') + + return ret + + class Union(DataNode): + def __str__(self): + return '%s:%s' %(self.__class__,self.name) + + def declaration(self): + ret = '' + self.maxsize = 0 + if (self.fields is not None and len(self.fields)): + if (len(self.fields) > 1): + if self.basemessage.declared is None or "hdr_version" not in self.basemessage.declared: + ret += self.indent_out("uint32_t hdr_version = tvb_get_letohl(ptvcursor_tvbuff(cursor), 4);\n") + self.basemessage.declared.append("hdr_version") + for fields in self.fields: + ret += '%s' %fields.declaration() + previous_lookup_eq = fields._children[0].lookup_eq + previous_lookup_le = fields._children[0].lookup_le + previous_lookup_ge = fields._children[0].lookup_ge + self.runningtotal = 0 + for field in fields._children: + if previous_lookup_eq != field.lookup_eq or previous_lookup_le != field.lookup_le or previous_lookup_ge == field.lookup_ge: + previous_lookup_eq = field.lookup_eq + previous_lookup_le = field.lookup_le + previous_lookup_ge = field.lookup_ge + self.runningtotal = 0 + + self.runningtotal += field.intsize + if self.runningtotal > self.maxsize: + self.maxsize = self.runningtotal + + self.intsize = self.maxsize + + return ret + + def dissect(self): + ret = '' + ifblock = self.indent_out('if') + skip = 0 + #ret += self.indent_out('/* Union : %s / maxsize: %s */\n' %(self.name, self.maxsize)) + + if (self.fields is not None and len(self.fields)): + for fields in self.fields: + for field in fields._children: + if self.lookup_guide and (field.lookup_ge or field.lookup_le or field.lookup_eq): + lookupguide = self.lookup_guide + # start block + subtree_text = '' + if field.lookup_ge and field.lookup_le: + ret += '%s (%s >= %s && %s <= %s)' %(ifblock, lookupguide, field.lookup_ge.upper(), lookupguide, field.lookup_le.upper()) + subtree_text = "%s <= %s <= %s" %(field.lookup_ge, lookupguide, field.lookup_le) + elif field.lookup_ge: + ret += '%s (%s >= %s)' %(ifblock, lookupguide, field.lookup_ge.upper()) + subtree_text = "%s >= %s" %(lookupguide, field.lookup_ge) + elif field.lookup_le: + ret += '%s (%s <= %s)' %(ifblock, lookupguide, field.lookup_le.upper()) + subtree_text = "%s <= %s" %(lookupguide, field.lookup_le) + elif field.lookup_eq: + if field.lookup_eq == "*": + ret += ' else' + subtree_text = "any %s" %(lookupguide) + elif field.lookup_eq == "skip": + continue + else: + ret += '%s (%s == %s)' %(ifblock, lookupguide, field.lookup_eq.upper()) + subtree_text = "%s is %s" %(lookupguide, field.lookup_eq) + + ret += self.indent_out(' {\n') + self.incr_indent() + if debug: + ret += self.indent_out('/* start union : %s / maxsize: %s */\n' %(self.name, self.maxsize)) + currsize = 0 + # dissect field + + ret += self.indent_out('ptvcursor_add_text_with_subtree(cursor, SUBTREE_UNDEFINED_LENGTH, ett_skinny_tree, "%s");\n' %subtree_text) + ret += '%s' %field.dissect() + ret += self.indent_out('ptvcursor_pop_subtree(cursor);\n') + + currsize += field.intsize + + # compensate length + if (self.maxsize - currsize) > 0: + ret += self.indent_out('ptvcursor_advance(cursor, %d);\n' %(self.maxsize - currsize)) + + self.decr_indent() + + # close block + ret += self.indent_out('}') + ifblock = ' else if' + else: + ret += '/* ERROR %s, missing lookup_guide */' %field.dissect() + ret += '\n' + + return ret + + class TreeBuilder(xml.sax.handler.ContentHandler): + def __init__(self): + self.stack = [] + self.root = DataNode() + self.previous = self.root + self.current = self.root + self.basemessage = None + self.text_parts = [] + def startElement(self, name, attrs): + objecttype = {"message": Message(), "fields": Fields(), "enum" : Enum(), "bitfield" : BitField(), "struct": Struct(), "union": Union(), "integer": Integer(), "string": String(), "ether": Ether(), "ip": Ip(), "ipv4or6": Ipv4or6(), "xml": XML(), "code": Code()} + self.previous = self.current + self.stack.append((self.current, self.text_parts)) + if name in objecttype.keys(): + self.current = objecttype[name] + else: + self.current = DataNode() + if name == "message": + self.basemessage = self.current + self.text_parts = [] + #self.children = [] + self.current.parent = self.previous + self.current.basemessage = self.basemessage + # xml attributes --> python attributes + for k, v in list(attrs.items()): + self.current._add_xml_attr(_name_mangle(k), v) + + def endElement(self, name): + text = ''.join(self.text_parts).strip() + if text: + self.current.data = text + if self.current._attrs: + obj = self.current + else: + # a text only node is simply represented by the string + obj = text or '' + self.current, self.text_parts = self.stack.pop() + self.current._add_xml_attr(_name_mangle(name), obj) + self.current._add_child(_name_mangle(name), obj) + def characters(self, content): + self.text_parts.append(content) + + builder = TreeBuilder() + xml.sax.parse(src, builder) + return list(builder.root._attrs.values())[0] + +# skinny = xml2obj('SkinnyProtocolOptimized.xml') +# for message in skinny.message: +# print '%s' %message.dissect() + +#if __name__ == '__main__': +# import timeit +# print(timeit.timeit("generateMessageDissectors()", setup="from __main__ import generateMessageDissectors")) + + +#skinny = xml2obj('SkinnyProtocolOptimized.xml') +#for message in skinny.message: +# print(message) +# message.dissect() + +#for key,value in fieldsArray.items(): +# print "%s : %s" %(key,value) +#print '%r\n' %fieldsArray + +#skinny = xml2obj('SkinnyProtocolOptimized.xml') +#for message in skinny.message: +# print message.declaration() |