diff options
-rw-r--r-- | wiretap/nettrace_3gpp_32_423.c | 1638 |
1 files changed, 692 insertions, 946 deletions
diff --git a/wiretap/nettrace_3gpp_32_423.c b/wiretap/nettrace_3gpp_32_423.c index 8d3e499a42..825b7c1805 100644 --- a/wiretap/nettrace_3gpp_32_423.c +++ b/wiretap/nettrace_3gpp_32_423.c @@ -25,6 +25,7 @@ #include "file_wrappers.h" #include "pcap-encap.h" +#include <epan/exported_pdu.h> #include <wsutil/buffer.h> #include "wsutil/tempfile.h" #include "wsutil/os_version_info.h" @@ -35,607 +36,584 @@ #include "pcapng.h" #include "nettrace_3gpp_32_423.h" -/* -* Impose a not-too-large limit on the maximum file size, to avoid eating -* up 99% of the (address space, swap partition, disk space for swap/page -* files); if we were to return smaller chunks and let the dissector do -* reassembly, it would *still* have to allocate a buffer the size of -* the file, so it's not as if we'd never try to allocate a buffer the -* size of the file. Laeve space for the exported PDU tag 12 bytes. -*/ -#define MAX_FILE_SIZE (G_MAXINT-12) +/* String constants sought in the XML data. + * Written as strings instead of lists of chars for readability. + * Use the CLEN() macro to get the length of the constant without counting + * the null byte at the end. + */ +#define CLEN(x) (sizeof(x)-1) +static const guchar c_xml_magic[] = "<?xml"; +static const guchar c_file_header[] = "<fileHeader"; +static const guchar c_file_format_version[] = "fileFormatVersion=\""; +static const guchar c_threegpp_doc_no[] = "32.423"; +static const guchar c_begin_time[] = "<traceCollec beginTime=\""; +static const guchar c_s_msg[] = "<msg"; +static const guchar c_e_msg[] = "</msg>"; +static const guchar c_s_rawmsg[] = "<rawMsg"; +static const guchar c_change_time[] = "changeTime=\""; +static const guchar c_proto_name[] = "name=\""; +static const guchar c_address[] = "ddress"; /* omit the 'a' to cater for "Address" */ +static const guchar c_s_initiator[] = "<initiator"; +static const guchar c_e_initiator[] = "</initiator>"; +static const guchar c_s_target[] = "<target"; +static const guchar c_e_target[] = "</target>"; +static const guchar c_protocol[] = "protocol=\""; + +/* These are protocol names we may put in the exported-pdu data based on + * what's in the XML. They're defined here as constants so we can use + * sizeof()/CLEN() on them and slightly reduce our use of magic constants + * for their size. (Modern compilers should make this no slower than that.) + */ +static const guchar c_sai_req[] = "gsm_map.v3.arg.opcode"; +static const guchar c_sai_rsp[] = "gsm_map.v3.res.opcode"; +static const guchar c_nas_eps[] = "nas-eps_plain"; + +#define RINGBUFFER_START_SIZE G_MAXINT +#define RINGBUFFER_CHUNK_SIZE 1024 -static const guint8 xml_magic[] = { '<', '?', 'x', 'm', 'l' }; -static const guint8 Threegpp_doc_no[] = { '3', '2', '.', '4', '2', '3' }; +#define MAX_NAME_LEN 64 +#define MAX_PROTO_LEN 16 +#define MAX_DTBL_LEN 32 + +/* We expect to find all the info we need to tell if this file is ours + * within this many bytes. Must include the beginTime attribute. + */ +#define MAGIC_BUF_SIZE 1024 typedef struct nettrace_3gpp_32_423_file_info { - char *tmpname; - wtap *wth_tmp_file; + GByteArray *buffer; // holds current chunk of file + gint64 start_offset; // where in the file the start of the buffer points + nstime_t start_time; // from <traceCollec beginTime=""> attribute } nettrace_3gpp_32_423_file_info_t; -/* From epan/exported_pdu.h - Port types are no longer used for conversation/endpoints so - many of the enumerated values have been eliminated - Since export PDU functionality is serializing them, - keep the old values around for conversion */ -#define OLD_PT_NONE 0 -#define OLD_PT_SCTP 1 -#define OLD_PT_TCP 2 -#define OLD_PT_UDP 3 -#define OLD_PT_DCCP 4 -#define OLD_PT_IPX 5 -#define OLD_PT_NCP 6 -#define OLD_PT_EXCHG 7 -#define OLD_PT_DDP 8 -#define OLD_PT_SBCCS 9 -#define OLD_PT_IDP 10 -#define OLD_PT_TIPC 11 -#define OLD_PT_USB 12 -#define OLD_PT_I2C 13 -#define OLD_PT_IBQP 14 -#define OLD_PT_BLUETOOTH 15 -#define OLD_PT_TDMOP 16 - typedef struct exported_pdu_info { - guint32 precense_flags; - /*const char* proto_name;*/ + guint32 presence_flags; guint8 src_ip[16]; guint32 ptype; /* Based on epan/address.h port_type valid for both src and dst*/ guint32 src_port; guint8 dst_ip[16]; guint32 dst_port; char* proto_col_str; -}exported_pdu_info_t ; - -/* From epan/epxported_pdu.h*/ -#define EXP_PDU_TAG_END_OF_OPT 0 /**< End-of-options Tag. */ -/* 1 - 9 reserved */ -#define EXP_PDU_TAG_OPTIONS_LENGTH 10 /**< Total length of the options excluding this TLV */ -#define EXP_PDU_TAG_PROTO_NAME 12 /**< The value part should be an ASCII non NULL terminated string -* of the registered dissector used by Wireshark e.g "sip" -* Will be used to call the next dissector. -*/ -#define EXP_PDU_TAG_DISSECTOR_TABLE_NAME 14 /**< The value part should be an ASCII non NULL terminated string -* containing the dissector table name given -* during registration, e.g "gsm_map.v3.arg.opcode" -* Will be used to call the next dissector. -*/ - -#define EXP_PDU_TAG_IPV4_SRC 20 -#define EXP_PDU_TAG_IPV4_DST 21 -#define EXP_PDU_TAG_IPV6_SRC 22 -#define EXP_PDU_TAG_IPV6_DST 23 -#define EXP_PDU_TAG_SRC_PORT 25 -#define EXP_PDU_TAG_PORT_TYPE 24 /**< value part is port_type enum from epan/address.h */ -#define EXP_PDU_TAG_DST_PORT 26 -#define EXP_PDU_TAG_SS7_OPC 28 -#define EXP_PDU_TAG_SS7_DPC 29 - -#define EXP_PDU_TAG_ORIG_FNO 30 - -#define EXP_PDU_TAG_DVBCI_EVT 31 - -#define EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL 32 /**< value part is the numeric value to be used calling the dissector table -* given with tag EXP_PDU_TAG_DISSECTOR_TABLE_NAME, must follow emediatly after the table tag. -*/ - -#define EXP_PDU_TAG_COL_PROT_TEXT 33 /**< Text string to put in COL_PROTOCOL, one use case is in conjunction with dissector tables where -* COL_PROTOCOL might not be filled in. -*/ +} exported_pdu_info_t; + +/* flags for exported_pdu_info.presence_flags */ +#define EXP_PDU_TAG_IP_SRC_BIT 0x001 +#define EXP_PDU_TAG_IP_DST_BIT 0x002 +#define EXP_PDU_TAG_SRC_PORT_BIT 0x004 +#define EXP_PDU_TAG_DST_PORT_BIT 0x008 +#define EXP_PDU_TAG_ORIG_FNO_BIT 0x010 +#define EXP_PDU_TAG_SS7_OPC_BIT 0x020 +#define EXP_PDU_TAG_SS7_DPC_BIT 0x040 +#define EXP_PDU_TAG_IP6_SRC_BIT 0x080 +#define EXP_PDU_TAG_IP6_DST_BIT 0x100 +#define EXP_PDU_TAG_DVBCI_EVT_BIT 0x0100 +#define EXP_PDU_TAG_COL_PROT_BIT 0x0200 + + +/* Parse a string IPv4 or IPv6 address into bytes for exported_pdu_info. + * Also parses the port pairs and transport layer type. + */ +static char* +nettrace_parse_address(char* curr_pos, char* next_pos, gboolean is_src_addr, exported_pdu_info_t *exported_pdu_info) +{ + guint port; + char transp_str[5]; + int scan_found; + char str[3]; + char* end_pos, *skip_pos; + char ip_addr_str[WS_INET6_ADDRSTRLEN]; + int str_len; + ws_in6_addr ip6_addr; + guint32 ip4_addr; + gchar tempchar; -#define EXP_PDU_TAG_IP_SRC_BIT 0x001 -#define EXP_PDU_TAG_IP_DST_BIT 0x002 -#define EXP_PDU_TAG_SRC_PORT_BIT 0x004 -#define EXP_PDU_TAG_DST_PORT_BIT 0x008 -#define EXP_PDU_TAG_ORIG_FNO_BIT 0x010 -#define EXP_PDU_TAG_SS7_OPC_BIT 0x020 -#define EXP_PDU_TAG_SS7_DPC_BIT 0x040 -#define EXP_PDU_TAG_IP6_SRC_BIT 0x080 -#define EXP_PDU_TAG_IP6_DST_BIT 0x100 + /* curr_pos pointing to first char after address */ -/* 2nd byte of optional tags bitmap */ -#define EXP_PDU_TAG_DVBCI_EVT_BIT 0x0100 -#define EXP_PDU_TAG_COL_PROT_BIT 0x0200 + /* Excample from one trace, unsure if it's generic... + * {address == 192.168.73.1, port == 5062, transport == Udp} + * {address == [2001:1b70:8294:210a::78], port... + * {address == 2001:1B70:8294:210A::90, port... + * Address=198.142.204.199,Port=2123 + */ + /* Skip whitespace and equalsigns) */ + for (skip_pos = curr_pos; skip_pos < next_pos && + ((tempchar = *skip_pos) == ' ' || + tempchar == '\t' || tempchar == '\r' || tempchar == '\n' || tempchar == '='); + skip_pos++); -#define EXP_PDU_TAG_IPV4_SRC_LEN 4 -#define EXP_PDU_TAG_IPV4_DST_LEN 4 -#define EXP_PDU_TAG_PORT_TYPE_LEN 4 -#define EXP_PDU_TAG_SRC_PORT_LEN 4 -#define EXP_PDU_TAG_DST_PORT_LEN 4 + curr_pos = skip_pos; -#define EXP_PDU_TAG_IPV4_LEN 4 -#define EXP_PDU_TAG_IPV6_LEN 16 + g_strlcpy(str, curr_pos, 3); + /* If we find "" here we have no IP address */ + if (strcmp(str, "\"\"") == 0) { + return next_pos; + } + str[1] = 0; + if (strcmp(str, "[") == 0) { + /* Should we check for a digit here?*/ + end_pos = strstr(curr_pos, "]"); + }else { + /* Should we check for a digit here?*/ + end_pos = strstr(curr_pos, ","); + } + if (!end_pos) { + return next_pos; + } -static gboolean -nettrace_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info, gint64 *data_offset) -{ - nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; + str_len = (int)(end_pos - curr_pos)+1; + if (str_len > WS_INET6_ADDRSTRLEN) { + return next_pos; + } + g_strlcpy(ip_addr_str, curr_pos, str_len); + curr_pos = end_pos; + if (ws_inet_pton6(ip_addr_str, &ip6_addr)) { + if (is_src_addr) { + exported_pdu_info->presence_flags |= EXP_PDU_TAG_IP6_SRC_BIT; + memcpy(exported_pdu_info->src_ip, ip6_addr.bytes, EXP_PDU_TAG_IPV6_LEN); + } + else { + exported_pdu_info->presence_flags |= EXP_PDU_TAG_IP6_DST_BIT; + memcpy(exported_pdu_info->dst_ip, ip6_addr.bytes, EXP_PDU_TAG_IPV6_LEN); + } + } + else if (ws_inet_pton4(ip_addr_str, &ip4_addr)) { + if (is_src_addr) { + exported_pdu_info->presence_flags |= EXP_PDU_TAG_IP_SRC_BIT; + memcpy(exported_pdu_info->src_ip, &ip4_addr, EXP_PDU_TAG_IPV4_LEN); + } + else { + exported_pdu_info->presence_flags |= EXP_PDU_TAG_IP_DST_BIT; + memcpy(exported_pdu_info->dst_ip, &ip4_addr, EXP_PDU_TAG_IPV4_LEN); + } + } - /* we read the created pcapng file instead */ - return wtap_read(file_info->wth_tmp_file, rec, buf, err, err_info, data_offset); + curr_pos++; + scan_found = sscanf(curr_pos, ", %*s %*s %5u, %*s %*s %4s", &port, transp_str); + if (scan_found == 2) { + /* Only add port_type once */ + if (exported_pdu_info->ptype == OLD_PT_NONE) { + if (g_ascii_strncasecmp(transp_str, "udp", 3) == 0) { + exported_pdu_info->ptype = OLD_PT_UDP; + } + else if (g_ascii_strncasecmp(transp_str, "tcp", 3) == 0) { + exported_pdu_info->ptype = OLD_PT_TCP; + } + else if (g_ascii_strncasecmp(transp_str, "sctp", 4) == 0) { + exported_pdu_info->ptype = OLD_PT_SCTP; + } + } + if (is_src_addr) { + exported_pdu_info->presence_flags |= EXP_PDU_TAG_SRC_PORT_BIT; + exported_pdu_info->src_port = port; + } + else { + exported_pdu_info->presence_flags |= EXP_PDU_TAG_DST_PORT_BIT; + exported_pdu_info->dst_port = port; + } + } + return next_pos; } -static gboolean -nettrace_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) -{ - nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; - - /* we read the created pcapng file instead */ - return wtap_seek_read(file_info->wth_tmp_file, seek_off, rec, buf, err, err_info); -} -/* classic wtap: close capture file */ -static void -nettrace_close(wtap *wth) +/* Parse a <msg ...><rawMsg ...>XXXX</rawMsg></msg> into packet data. */ +static gboolean +nettrace_msg_to_packet(nettrace_3gpp_32_423_file_info_t *file_info, wtap_rec *rec, Buffer *buf, guint8 *input, gsize len, int *err, gchar **err_info) { - nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; +/* Convenience macro. haystack must be >= input! */ +#define STRNSTR(haystack, needle) g_strstr_len(haystack, (len - ((guint8*)(haystack) - (guint8*)input)), needle) - wtap_close(file_info->wth_tmp_file); + gboolean status = TRUE; + char *curr_pos, *next_msg_pos, *next_pos, *prev_pos; + exported_pdu_info_t exported_pdu_info = {0}; - /* delete the temp file */ - ws_unlink(file_info->tmpname); - g_free(file_info->tmpname); -} + char* raw_msg_pos; + char* start_msg_tag_cont; + char name_str[MAX_NAME_LEN+1]; + char proto_name_str[MAX_PROTO_LEN+1]; + char dissector_table_str[MAX_DTBL_LEN+1]; + int dissector_table_val = 0; -/* This attribute specification contains a timestamp that refers to the start of the -* first trace data that is stored in this file. -* -* It is a complete timestamp including day, time and delta UTC hour. E.g. -* "2001-09-11T09:30:47-05:00". -*/ + int name_str_len = 0; + int tag_str_len = 0; + int proto_str_len, dissector_table_str_len, raw_data_len, pkt_data_len, exp_pdu_tags_len, i, j; + guint8 *packet_buf; + gint val1, val2; + gboolean port_type_defined = FALSE; + gboolean use_proto_table = FALSE; -#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + /* We should always and only be called with a <msg....</msg> payload */ + if (0 != strncmp(input, c_s_msg, CLEN(c_s_msg))) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("Did not start with \"%s\"", c_s_msg); + return FALSE; + } + prev_pos = curr_pos = input + CLEN(c_s_msg); -static char* -nettrace_parse_begin_time(char *curr_pos, wtap_rec *rec) -{ - /* Time vars*/ - guint year, month, day, hour, minute, second, frac; - int UTCdiffh, UTCdiffm = 0; - int time_length = 0; - int scan_found; - static const guint days_in_month[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - struct tm tm; - char *prev_pos, *next_pos; - int length; + rec->rec_type = REC_TYPE_PACKET; + rec->presence_flags = 0; /* start out assuming no special features */ + rec->ts.secs = 0; + rec->ts.nsecs = 0; - prev_pos = curr_pos; - next_pos = strstr(curr_pos, "\"/>"); - length = (int)(next_pos - prev_pos); + /* Clear for each iteration */ + exported_pdu_info.presence_flags = 0; + exported_pdu_info.ptype = OLD_PT_NONE; - if (length < 2) { - return next_pos + 3; + prev_pos = curr_pos = curr_pos + 4; + /* Look for the end of the tag first */ + next_msg_pos = STRNSTR(curr_pos, ">"); + if (!next_msg_pos) { + /* Something's wrong, bail out */ + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup("Did not find end of tag \">\""); + status = FALSE; + goto end; + } + /* Check if its a tag close "/>" */ + if (*(next_msg_pos - 1) == '/') { + /* There is no rawmsg here. Should have been caught before we got called */ + *err = WTAP_ERR_INTERNAL; + *err_info = g_strdup("Had \"<msg />\" with no \"<rawMsg>\""); + status = FALSE; + goto end; } + start_msg_tag_cont = curr_pos = prev_pos; + next_msg_pos = STRNSTR(curr_pos, c_e_msg); + if (!next_msg_pos) { + /* Something's wrong, bail out */ + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("Did not find \"%s\"", c_e_msg); + status = FALSE; + goto end; + } + next_msg_pos += CLEN(c_e_msg); - rec->presence_flags = 0; /* mark time as invalid, until successful converted */ - rec->ts.secs = 0; - rec->ts.nsecs = 0; + /* Check if we have a time stamp "changeTime" + * expressed in number of seconds and milliseconds (nbsec.ms). + * Only needed if we have a "beginTime" for this file. + */ + if (!nstime_is_unset(&(file_info->start_time))) { + int scan_found; + guint second = 0, ms = 0; - /* Scan for this format: 2001-09-11T09:30:47 Then we will parse any fractions and UTC offset */ - scan_found = sscanf(curr_pos, "%4u-%2u-%2uT%2u:%2u:%2u%n", - &year, &month, &day, &hour, &minute, &second, &time_length); - if (scan_found == 6 && time_length == 19) { - /* Fill in the fields and return it in a time_t */ - tm.tm_year = year - 1900; - if (month < 1 || month > 12) { - /* g_warning("Failed to parse time, month is %u", month); */ - return curr_pos; - } - tm.tm_mon = month - 1; /* Zero count*/ - if (day > ((month == 2 && isleap(year)) ? 29 : days_in_month[month - 1])) { - /* g_warning("Failed to parse time, %u-%02u-%2u is not a valid day", year, month, day); */ - return curr_pos; - } - tm.tm_mday = day; - if (hour > 23) { - /* g_warning("Failed to parse time, hour is %u", hour); */ - return curr_pos; - } - tm.tm_hour = hour; - if (minute > 59) { - /* g_warning("Failed to parse time, minute is %u", minute); */ - return curr_pos; - } - tm.tm_min = minute; - if (second > 60) { - /* - * Yes, 60, for leap seconds - POSIX's and Windows' - * refusal to believe in them nonwithstanding. - */ - /* g_warning("Failed to parse time, second is %u", second); */ - return curr_pos; - } - tm.tm_sec = second; - tm.tm_isdst = -1; /* daylight saving time info not known */ + curr_pos = STRNSTR(start_msg_tag_cont, c_change_time); + /* Check if we have the tag or if we passed the end of the current message */ + if (curr_pos != NULL) { + curr_pos += CLEN(c_change_time); + scan_found = sscanf(curr_pos, "%u.%u", &second, &ms); - /* Move curr_pos to end of parsed object and get that character 2019-01-10T10:14:56 */ - curr_pos += time_length; - if (*curr_pos == '.' || *curr_pos == ',') { - /* We have fractions */ - curr_pos++; - if (1 == sscanf(curr_pos, "%u%n", &frac, &time_length)) { - if ((frac >= 1000000000) || (frac == 0)) { - rec->ts.nsecs = 0; - } else { - switch (time_length) { /* including leading zeros */ - case 1: rec->ts.nsecs = frac * 100000000; break; - case 2: rec->ts.nsecs = frac * 10000000; break; - case 3: rec->ts.nsecs = frac * 1000000; break; - case 4: rec->ts.nsecs = frac * 100000; break; - case 5: rec->ts.nsecs = frac * 10000; break; - case 6: rec->ts.nsecs = frac * 1000; break; - case 7: rec->ts.nsecs = frac * 100; break; - case 8: rec->ts.nsecs = frac * 10; break; - default: rec->ts.nsecs = frac; - } + if (scan_found == 2) { + guint start_ms = file_info->start_time.nsecs / 1000000; + guint elapsed_ms = start_ms + ms; + if (elapsed_ms > 1000) { + elapsed_ms -= 1000; + second++; } - curr_pos += time_length; + rec->presence_flags |= WTAP_HAS_TS; + rec->ts.secs = file_info->start_time.secs + second; + rec->ts.nsecs = file_info->start_time.nsecs + (elapsed_ms * 1000000); } } + } - if (*curr_pos == '-' || *curr_pos == '+' || *curr_pos == 'Z') { - /* We have UTC offset */ - if (1 <= sscanf(curr_pos, "%3d:%2d", &UTCdiffh, &UTCdiffm)) { - /* adjust for timezone */ - tm.tm_hour -= UTCdiffh; - tm.tm_min -= UTCdiffh < 0 ? -UTCdiffm: UTCdiffm; - } /* else 'Z' for Zero time */ - /* convert to UTC time */ -#ifdef _WIN32 - rec->ts.secs = _mkgmtime(&tm); -#else - rec->ts.secs = timegm(&tm); -#endif - } else { - /* no UTC offset means localtime in ISO 8601 */ - rec->ts.secs = mktime(&tm); + /* See if we have a "name" */ + curr_pos = STRNSTR(start_msg_tag_cont, c_proto_name); + if (curr_pos != NULL) { + /* extract the name */ + curr_pos += CLEN(c_proto_name); + next_pos = STRNSTR(curr_pos, "\""); + name_str_len = (int)(next_pos - curr_pos); + if (name_str_len > MAX_NAME_LEN) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("name_str_len > %d", MAX_NAME_LEN); + goto end; } - /* Mark time parsed successfully */ - rec->presence_flags = WTAP_HAS_TS; - /* } else { - g_warning("Failed to parse time, only %u fields", scan_found); */ + g_strlcpy(name_str, curr_pos, (gsize)name_str_len + 1); + ascii_strdown_inplace(name_str); + + } + /* Check if we have "<initiator>" + * It might contain an address + */ + curr_pos = STRNSTR(start_msg_tag_cont, c_s_initiator); + /* Check if we have the tag or if we passed the end of the current message */ + if (curr_pos != NULL) { + curr_pos += CLEN(c_s_initiator); + next_pos = STRNSTR(curr_pos, c_e_initiator); + /* Find address */ + curr_pos = STRNSTR(curr_pos, c_address); + if (curr_pos != NULL) { + curr_pos += CLEN(c_address); + nettrace_parse_address(curr_pos, next_pos, TRUE/* SRC */, &exported_pdu_info); + } } - return curr_pos; -} -/* Parsing something like - * <rawMsg - * protocol="Diameter" - * version="1"> - * [truncated]010001244000012C01000... - * </rawMsg> - */ -static wtap_open_return_val -write_packet_data(wtap_dumper *wdh, wtap_rec *rec, int *err, gchar **err_info, char *file_buf, nstime_t packet_time, exported_pdu_info_t *exported_pdu_info, char name_str[64]) -{ - char *curr_pos, *next_pos; - char proto_name_str[16]; - char dissector_table_str[32]; - int dissector_table_val=0; - int tag_str_len = 0; - int proto_str_len, dissector_table_str_len, raw_data_len, pkt_data_len, exp_pdu_tags_len, i, j; - guint8 *packet_buf; - gint val1, val2; - gboolean port_type_defined = FALSE; - gboolean use_proto_table = FALSE; + /* Check if we have "<target>" + * It might contain an address + */ + curr_pos = STRNSTR(start_msg_tag_cont, c_s_target); + /* Check if we have the tag or if we passed the end of the current message */ + if (curr_pos != NULL) { + curr_pos += CLEN(c_s_target); + curr_pos = curr_pos + 7; + next_pos = STRNSTR(curr_pos, c_e_target); + /* Find address */ + curr_pos = STRNSTR(curr_pos, c_address); + if (curr_pos != NULL) { + curr_pos += CLEN(c_address); + /* curr_pos set below */ + nettrace_parse_address(curr_pos, next_pos, FALSE/* DST */, &exported_pdu_info); + } + } - memset(proto_name_str, 0, sizeof(proto_name_str)); - /* Extract the protocol name */ - curr_pos = strstr(file_buf, "protocol=\""); - if (!curr_pos){ - return WTAP_OPEN_ERROR; + /* Do we have a raw message in the <msg> </msg> section? */ + raw_msg_pos = STRNSTR(start_msg_tag_cont, c_s_rawmsg); + if (raw_msg_pos == NULL) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("Did not find \"%s\"", c_s_rawmsg); + status = FALSE; + goto end; } - curr_pos = curr_pos + 10; - next_pos = strstr(curr_pos, "\""); + curr_pos = STRNSTR(raw_msg_pos, c_protocol); + if (curr_pos == NULL) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("Did not find \"%s\"", c_protocol); + status = FALSE; + goto end; + } + curr_pos += CLEN(c_protocol); + next_pos = STRNSTR(curr_pos, "\""); proto_str_len = (int)(next_pos - curr_pos); - if (proto_str_len > 15){ - return WTAP_OPEN_ERROR; + if (proto_str_len > MAX_PROTO_LEN){ + status = FALSE; + goto end; } - g_strlcpy(proto_name_str, curr_pos, (gsize)proto_str_len+1); ascii_strdown_inplace(proto_name_str); /* Do string matching and replace with Wiresharks protocol name */ - if (strcmp(proto_name_str, "gtpv2-c") == 0){ + if (strcmp(proto_name_str, "gtpv2-c") == 0) { /* Change to gtpv2 */ proto_name_str[5] = '\0'; proto_str_len = 5; } - /* XXX Do we need to check for function="S1" */ - if (strcmp(proto_name_str, "nas") == 0){ + /* XXX Do we need to check for function="S1"? */ + if (strcmp(proto_name_str, "nas") == 0) { /* Change to nas-eps_plain */ - g_strlcpy(proto_name_str, "nas-eps_plain", 14); - proto_str_len = 13; + g_strlcpy(proto_name_str, c_nas_eps, sizeof(c_nas_eps)); + proto_str_len = CLEN(c_nas_eps); } if (strcmp(proto_name_str, "map") == 0) { - /* For /GSM) map, it looks like the message data is stored like SendAuthenticationInfoArg + /* For GSM map, it looks like the message data is stored like SendAuthenticationInfoArg * use the GSM MAP dissector table to dissect the content. */ - exported_pdu_info->proto_col_str = g_strdup("GSM MAP"); + exported_pdu_info.proto_col_str = g_strdup("GSM MAP"); if (strcmp(name_str, "sai_request") == 0) { use_proto_table = TRUE; - g_strlcpy(dissector_table_str, "gsm_map.v3.arg.opcode", 22); - dissector_table_str_len = 21; + g_strlcpy(dissector_table_str, c_sai_req, sizeof(c_sai_req)); + dissector_table_str_len = CLEN(c_sai_req); dissector_table_val = 56; - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT; + exported_pdu_info.presence_flags |= EXP_PDU_TAG_COL_PROT_BIT; } else if (strcmp(name_str, "sai_response") == 0) { use_proto_table = TRUE; - g_strlcpy(dissector_table_str, "gsm_map.v3.res.opcode", 22); - dissector_table_str_len = 21; + g_strlcpy(dissector_table_str, c_sai_rsp, sizeof(c_sai_rsp)); + dissector_table_str_len = CLEN(c_sai_rsp); dissector_table_val = 56; - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT; + exported_pdu_info.presence_flags |= EXP_PDU_TAG_COL_PROT_BIT; } else { - g_free(exported_pdu_info->proto_col_str); - exported_pdu_info->proto_col_str = NULL; + g_free(exported_pdu_info.proto_col_str); + exported_pdu_info.proto_col_str = NULL; } } - /* Find the start of the raw data*/ - curr_pos = strstr(next_pos, ">") + 1; - next_pos = strstr(curr_pos, "<"); - + /* Find the start of the raw data */ + curr_pos = STRNSTR(next_pos, ">") + 1; + next_pos = STRNSTR(curr_pos, "<"); raw_data_len = (int)(next_pos - curr_pos); - /* Calculate the space needed for exp pdu tags*/ + /* Calculate the space needed for exp pdu tags */ if (use_proto_table == FALSE) { tag_str_len = (proto_str_len + 3) & 0xfffffffc; exp_pdu_tags_len = tag_str_len + 4; } else { tag_str_len = (dissector_table_str_len + 3) & 0xfffffffc; exp_pdu_tags_len = tag_str_len + 4; - /* Add EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL + length*/ - exp_pdu_tags_len = exp_pdu_tags_len + 4 + 4; + /* Add EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL + length */ + exp_pdu_tags_len += 4 + 4; } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) { + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_COL_PROT_BIT) { /* The assert prevents static code analyzers to raise warnings */ - g_assert(exported_pdu_info->proto_col_str); - exp_pdu_tags_len += 4 + (int)strlen(exported_pdu_info->proto_col_str); + g_assert(exported_pdu_info.proto_col_str); + exp_pdu_tags_len += 4 + (int)strlen(exported_pdu_info.proto_col_str); } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) { - exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_SRC_LEN; + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP_SRC_BIT) { + exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_LEN; } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_SRC_BIT) == EXP_PDU_TAG_IP6_SRC_BIT) { + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP6_SRC_BIT) { exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV6_LEN; } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) { + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_SRC_PORT_BIT) { if (!port_type_defined) { exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN; port_type_defined = TRUE; } - exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN; + exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_LEN; } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_DST_BIT) == EXP_PDU_TAG_IP_DST_BIT) { - exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_DST_LEN; + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP_DST_BIT) { + exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_LEN; } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_DST_BIT) == EXP_PDU_TAG_IP6_DST_BIT) { + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP6_DST_BIT) { exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV6_LEN; } - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) { + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_DST_PORT_BIT) { if (!port_type_defined) { exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN; + port_type_defined = TRUE; } - exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN; + exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_LEN; } - - port_type_defined = FALSE; + exp_pdu_tags_len += 4; /* account for opt_endofopt */ /* Allocate the packet buf */ pkt_data_len = raw_data_len / 2; - packet_buf = (guint8 *)g_malloc0((gsize)pkt_data_len + (gsize)exp_pdu_tags_len + (gsize)4); + ws_buffer_assure_space(buf, (gsize)pkt_data_len + (gsize)exp_pdu_tags_len); + ws_buffer_increase_length(buf, (gsize)pkt_data_len + (gsize)exp_pdu_tags_len); + packet_buf = ws_buffer_start_ptr(buf); /* Fill packet buff */ if (use_proto_table == FALSE) { - packet_buf[0] = 0; - packet_buf[1] = 12; /* EXP_PDU_TAG_PROTO_NAME */ - packet_buf[2] = 0; - packet_buf[3] = tag_str_len; - memcpy(&packet_buf[4], proto_name_str, proto_str_len); - i = 4 + tag_str_len; - }else{ - packet_buf[0] = 0; - packet_buf[1] = 14; /* EXP_PDU_TAG_DISSECTOR_TABLE_NAME */ - packet_buf[2] = 0; - packet_buf[3] = tag_str_len; - memcpy(&packet_buf[4], dissector_table_str, dissector_table_str_len); - i = 4 + tag_str_len; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = 4; /* tag length */; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = dissector_table_val; - i++; - } - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) { - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_COL_PROT_TEXT; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = (guint8)strlen(exported_pdu_info->proto_col_str); - i++; - for (j = 0; j < (int)strlen(exported_pdu_info->proto_col_str); i++, j++) { - packet_buf[i] = exported_pdu_info->proto_col_str[j]; - } - g_free(exported_pdu_info->proto_col_str); - } - - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) { - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV4_SRC; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV4_SRC_LEN; /* tag length */; - i++; - memcpy(packet_buf+i, exported_pdu_info->src_ip, EXP_PDU_TAG_IPV4_SRC_LEN); - i += EXP_PDU_TAG_IPV4_SRC_LEN; - } - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_SRC_BIT) == EXP_PDU_TAG_IP6_SRC_BIT) { - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV6_SRC; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV6_LEN; /* tag length */; - i++; - memcpy(packet_buf+i, exported_pdu_info->src_ip, EXP_PDU_TAG_IPV6_LEN); - i += EXP_PDU_TAG_IPV6_LEN; - } - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) { - if (!port_type_defined) { - port_type_defined = TRUE; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_PORT_TYPE; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_PORT_TYPE_LEN; /* tag length */; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0xff000000) >> 24; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0x00ff0000) >> 16; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0x0000ff00) >> 8; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0x000000ff); - i++; - } - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_SRC_PORT; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_SRC_PORT_LEN; /* tag length */; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0xff000000) >> 24; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0x00ff0000) >> 16; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0x0000ff00) >> 8; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0x000000ff); - i++; - } - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_DST_BIT) == EXP_PDU_TAG_IP_DST_BIT) { - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV4_DST; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV4_DST_LEN; /* tag length */; - i++; - memcpy(packet_buf + i, exported_pdu_info->dst_ip, EXP_PDU_TAG_IPV4_DST_LEN); - i += EXP_PDU_TAG_IPV4_DST_LEN; - } - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_DST_BIT) == EXP_PDU_TAG_IP6_DST_BIT) { - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV6_DST; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_IPV6_LEN; /* tag length */; - i++; - memcpy(packet_buf + i, exported_pdu_info->dst_ip, EXP_PDU_TAG_IPV6_LEN); - i += EXP_PDU_TAG_IPV6_LEN; - } - - if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) { - if (!port_type_defined) { - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_PORT_TYPE; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_PORT_TYPE_LEN; /* tag length */; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0xff000000) >> 24; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0x00ff0000) >> 16; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0x0000ff00) >> 8; - i++; - packet_buf[i] = (exported_pdu_info->ptype & 0x000000ff); - i++; - } - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_DST_PORT; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = EXP_PDU_TAG_DST_PORT_LEN; /* tag length */; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0xff000000) >> 24; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0x00ff0000) >> 16; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0x0000ff00) >> 8; - i++; - packet_buf[i] = (exported_pdu_info->src_port & 0x000000ff); - i++; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_PROTO_NAME; + *packet_buf++ = 0; + *packet_buf++ = tag_str_len; + memset(packet_buf, 0, tag_str_len); + memcpy(packet_buf, proto_name_str, proto_str_len); + packet_buf += tag_str_len; + } + else { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_DISSECTOR_TABLE_NAME; + *packet_buf++ = 0; + *packet_buf++ = tag_str_len; + memset(packet_buf, 0, tag_str_len); + memcpy(packet_buf, dissector_table_str, dissector_table_str_len); + packet_buf += tag_str_len; + + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL; + *packet_buf++ = 0; + *packet_buf++ = 4; /* option length */ + *packet_buf++ = 0; + *packet_buf++ = 0; + *packet_buf++ = 0; + *packet_buf++ = dissector_table_val; + } + + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_COL_PROT_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_COL_PROT_TEXT; + *packet_buf++ = 0; + *packet_buf++ = (guint8)strlen(exported_pdu_info.proto_col_str); + for (j = 0; j < (int)strlen(exported_pdu_info.proto_col_str); j++) { + *packet_buf++ = exported_pdu_info.proto_col_str[j]; + } + g_free(exported_pdu_info.proto_col_str); + exported_pdu_info.proto_col_str = NULL; + } + + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP_SRC_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV4_SRC; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV4_LEN; + memcpy(packet_buf, exported_pdu_info.src_ip, EXP_PDU_TAG_IPV4_LEN); + packet_buf += EXP_PDU_TAG_IPV4_LEN; + } + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP_DST_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV4_DST; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV4_LEN; + memcpy(packet_buf, exported_pdu_info.dst_ip, EXP_PDU_TAG_IPV4_LEN); + packet_buf += EXP_PDU_TAG_IPV4_LEN; + } + + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP6_SRC_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV6_SRC; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV6_LEN; + memcpy(packet_buf, exported_pdu_info.src_ip, EXP_PDU_TAG_IPV6_LEN); + packet_buf += EXP_PDU_TAG_IPV6_LEN; + } + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_IP6_DST_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV6_DST; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_IPV6_LEN; + memcpy(packet_buf, exported_pdu_info.dst_ip, EXP_PDU_TAG_IPV6_LEN); + packet_buf += EXP_PDU_TAG_IPV6_LEN; + } + + if (exported_pdu_info.presence_flags & (EXP_PDU_TAG_SRC_PORT_BIT | EXP_PDU_TAG_DST_PORT_BIT)) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_PORT_TYPE; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_PORT_TYPE_LEN; + *packet_buf++ = (exported_pdu_info.ptype & 0xff000000) >> 24; + *packet_buf++ = (exported_pdu_info.ptype & 0x00ff0000) >> 16; + *packet_buf++ = (exported_pdu_info.ptype & 0x0000ff00) >> 8; + *packet_buf++ = (exported_pdu_info.ptype & 0x000000ff); + } + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_SRC_PORT_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_SRC_PORT; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_PORT_LEN; + *packet_buf++ = (exported_pdu_info.src_port & 0xff000000) >> 24; + *packet_buf++ = (exported_pdu_info.src_port & 0x00ff0000) >> 16; + *packet_buf++ = (exported_pdu_info.src_port & 0x0000ff00) >> 8; + *packet_buf++ = (exported_pdu_info.src_port & 0x000000ff); + } + if (exported_pdu_info.presence_flags & EXP_PDU_TAG_DST_PORT_BIT) { + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_DST_PORT; + *packet_buf++ = 0; + *packet_buf++ = EXP_PDU_TAG_PORT_LEN; + *packet_buf++ = (exported_pdu_info.dst_port & 0xff000000) >> 24; + *packet_buf++ = (exported_pdu_info.dst_port & 0x00ff0000) >> 16; + *packet_buf++ = (exported_pdu_info.dst_port & 0x0000ff00) >> 8; + *packet_buf++ = (exported_pdu_info.dst_port & 0x000000ff); } /* Add end of options */ - packet_buf[i] = 0; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = 0; - i++; - packet_buf[i] = 0; - i++; - exp_pdu_tags_len = exp_pdu_tags_len + 4; + *packet_buf++ = 0; + *packet_buf++ = 0; + *packet_buf++ = 0; + *packet_buf++ = 0; /* Convert the hex raw msg data to binary and write to the packet buf*/ - for (; i < (pkt_data_len + exp_pdu_tags_len); i++){ + for (i = 0; i < pkt_data_len; i++) { gchar chr1, chr2; - chr1 = *curr_pos; + chr1 = *curr_pos++; + chr2 = *curr_pos++; val1 = g_ascii_xdigit_value(chr1); - curr_pos++; - chr2 = *curr_pos; val2 = g_ascii_xdigit_value(chr2); - if ((val1 != -1) && (val2 != -1)){ - packet_buf[i] = ((guint8)val1 * 16) + val2; + if ((val1 != -1) && (val2 != -1)) { + *packet_buf++ = ((guint8)val1 * 16) + val2; } - else{ + else { /* Something wrong, bail out */ *err_info = g_strdup_printf("Could not parse hex data,bufzize %u index %u %c%c", (pkt_data_len + exp_pdu_tags_len), @@ -643,505 +621,280 @@ write_packet_data(wtap_dumper *wdh, wtap_rec *rec, int *err, gchar **err_info, c chr1, chr2); *err = WTAP_ERR_BAD_FILE; - g_free(packet_buf); - return WTAP_OPEN_ERROR; + status = FALSE; + goto end; } - curr_pos++; - } - /* Construct the phdr */ - memset(rec, 0, sizeof *rec); - rec->rec_type = REC_TYPE_PACKET; - if (packet_time.secs == 0) { - rec->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ - rec->ts.secs = 0; - rec->ts.nsecs = 0; - } else { - rec->presence_flags = WTAP_HAS_TS; - rec->ts.secs = packet_time.secs; - rec->ts.nsecs = packet_time.nsecs; } rec->rec_header.packet_header.caplen = pkt_data_len + exp_pdu_tags_len; rec->rec_header.packet_header.len = pkt_data_len + exp_pdu_tags_len; - if (!wtap_dump(wdh, rec, packet_buf, err, err_info)) { - switch (*err) { +end: + return status; +#undef STRNSTR +} - case WTAP_ERR_UNWRITABLE_REC_DATA: +/* Read from fh and store into buffer, until buffer contains needle. + * Returns location of needle once found, or NULL if it's never found + * (due to either EOF or read error). + */ +static guint8 * +read_until(GByteArray *buffer, const guchar *needle, FILE_T fh, int *err, gchar **err_info) +{ + guint8 read_buffer[RINGBUFFER_CHUNK_SIZE]; + guint8 *found_it; + gint bytes_read = 0; + + while (NULL == (found_it = g_strstr_len(buffer->data, buffer->len, needle))) { + bytes_read = file_read(read_buffer, RINGBUFFER_CHUNK_SIZE, fh); + if (bytes_read < 0) { + *err = file_error(fh, err_info); break; - - default: + } + if (bytes_read == 0) { break; } - g_free(packet_buf); - return WTAP_OPEN_ERROR; + g_byte_array_append(buffer, read_buffer, bytes_read); } - - g_free(packet_buf); - return WTAP_OPEN_MINE; + return found_it; } -static char* -nettrace_parse_address(char* curr_pos, char* next_pos, gboolean is_src_addr/*SRC */, exported_pdu_info_t *exported_pdu_info) +/* Find a complete packet, parse and return it to wiretap. + * Set as the subtype_read function in the file_open function below. + */ +static gboolean +nettrace_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info, gint64 *data_offset) { - guint port; - char transp_str[5]; - int scan_found; - char str[3]; - char* end_pos, *skip_pos; - char ip_addr_str[WS_INET6_ADDRSTRLEN]; - int str_len; - ws_in6_addr ip6_addr; - guint32 ip4_addr; - gchar tempchar; - - /* curr_pos pointing to first char after address */ + nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; + guint8 *buf_start; + guint8 *msg_start, *msg_end; + guint msg_offset = 0; + gsize msg_len = 0; + gboolean status = FALSE; + + /* Make sure we have a start and end of message in our buffer -- end first */ + msg_end = read_until(file_info->buffer, c_e_msg, wth->fh, err, err_info); + if (msg_end == NULL) { + goto end; + } - /* Excample from one trace, unsure if it's generic... - * {address == 192.168.73.1, port == 5062, transport == Udp} - * {address == [2001:1b70:8294:210a::78], port... - * {address == 2001:1B70:8294:210A::90, port... - * Address=198.142.204.199,Port=2123 + buf_start = file_info->buffer->data; + /* Now search backwards for the message start + * (doing it this way should skip over any empty "<msg ... />" tags we have) */ - /* Skip whitespace and equalsigns)*/ - for (skip_pos = curr_pos; skip_pos < next_pos && - ((tempchar = *skip_pos) == ' ' || - tempchar == '\t' || tempchar == '\r' || tempchar == '\n' || tempchar == '='); - skip_pos++); + msg_start = g_strrstr_len(buf_start, (guint)(msg_end - buf_start), c_s_msg); + if (msg_start == NULL || msg_start > msg_end) { + *err_info = g_strdup_printf("Found \"%s\" without matching \"%s\"", c_e_msg, c_s_msg); + *err = WTAP_ERR_BAD_FILE; + goto end; + } - curr_pos = skip_pos; + /* We know we have a message, what's its offset from the buffer start? */ + msg_offset = (guint)(msg_start - buf_start); + msg_end += CLEN(c_e_msg); + msg_len = (guint)(msg_end - msg_start); - g_strlcpy(str, curr_pos, 3); - /* If we find "" here we have no IP address*/ - if (strcmp(str, "\"\"") == 0) { - return next_pos; - } - str[1] = 0; - if (strcmp(str, "[") == 0) { - /* Should we check for a digit here?*/ - end_pos = strstr(curr_pos, "]"); + /* Tell Wireshark to put us at the start of the "<msg" for seek_read later */ + *data_offset = file_info->start_offset + msg_offset; - }else { - /* Should we check for a digit here?*/ - end_pos = strstr(curr_pos, ","); - } - if (!end_pos) { - return next_pos; - } + /* pass all of <msg....</msg> to nettrace_msg_to_packet() */ + status = nettrace_msg_to_packet(file_info, rec, buf, msg_start, msg_len, err, err_info); - str_len = (int)(end_pos - curr_pos)+1; - if (str_len > WS_INET6_ADDRSTRLEN) { - return next_pos; - } - g_strlcpy(ip_addr_str, curr_pos, str_len); - curr_pos = end_pos; - if (ws_inet_pton6(ip_addr_str, &ip6_addr)) { - if (is_src_addr) { - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_IP6_SRC_BIT; - memcpy(exported_pdu_info->src_ip, ip6_addr.bytes, EXP_PDU_TAG_IPV6_LEN); - } - else { - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_IP6_DST_BIT; - memcpy(exported_pdu_info->dst_ip, ip6_addr.bytes, EXP_PDU_TAG_IPV6_LEN); - } - } - else if (ws_inet_pton4(ip_addr_str, &ip4_addr)) { - if (is_src_addr) { - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_IP_SRC_BIT; - memcpy(exported_pdu_info->src_ip, &ip4_addr, EXP_PDU_TAG_IPV4_LEN); - } - else { - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_IP_DST_BIT; - memcpy(exported_pdu_info->dst_ip, &ip4_addr, EXP_PDU_TAG_IPV4_LEN); - } + /* Finally, shift our buffer to the end of this message to get ready for the next one. + * Re-use msg_len to get the length of the data we're done with. + */ + msg_len = msg_end - file_info->buffer->data; + while (G_UNLIKELY(msg_len > G_MAXUINT)) { + g_byte_array_remove_range(file_info->buffer, 0, G_MAXUINT); + msg_len -= G_MAXUINT; } + g_byte_array_remove_range(file_info->buffer, 0, (guint)msg_len); + file_info->start_offset += msg_len; - curr_pos++; - scan_found = sscanf(curr_pos, ", %*s %*s %5u, %*s %*s %4s", &port, transp_str); - if (scan_found == 2) { - /* Only add port_type once */ - if (exported_pdu_info->ptype == OLD_PT_NONE) { - if (g_ascii_strncasecmp(transp_str, "udp", 3) == 0) exported_pdu_info->ptype = OLD_PT_UDP; - else if (g_ascii_strncasecmp(transp_str, "tcp", 3) == 0) exported_pdu_info->ptype = OLD_PT_TCP; - else if (g_ascii_strncasecmp(transp_str, "sctp", 4) == 0) exported_pdu_info->ptype = OLD_PT_SCTP; - } - if (is_src_addr) { - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_SRC_PORT_BIT; - exported_pdu_info->src_port = port; - } - else { - exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_DST_PORT_BIT; - exported_pdu_info->dst_port = port; - } +end: + if (status == FALSE) { + /* There's no more to read. Empty out the buffer */ + g_byte_array_set_size(file_info->buffer, 0); } - return next_pos; + + return status; } -/* - * Opens an .xml file with Trace data formatted according to 3GPP TS 32.423 and converts it to - * an "Exported PDU type file with the entire xml file as the first "packet" appending the - * raw messages as subsequent packages to be dissected by wireshark. +/* Seek to the complete packet at the offset, parse and return it to wiretap. + * Set as the subtype_seek_read function in the file_open function below. */ -static wtap_open_return_val -create_temp_pcapng_file(wtap *wth, int *err, gchar **err_info, nettrace_3gpp_32_423_file_info_t *file_info) +static gboolean +nettrace_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf, int *err, gchar **err_info) { - int import_file_fd; - wtap_dumper* wdh_exp_pdu; - wtap_open_return_val result = WTAP_OPEN_MINE; - - /* pcapng defs */ - GArray *shb_hdrs; - wtap_block_t shb_hdr; - wtapng_iface_descriptions_t *idb_inf = NULL; - wtap_block_t int_data; - wtapng_if_descr_mandatory_t *int_data_mand; - GString *os_info_str; - gint64 file_size; - int packet_size; - char *packet_buf = NULL; - wtap_rec rec; - nstime_t start_time, packet_time; - int scan_found; - unsigned int second, ms; - gboolean do_random = FALSE; - char *curr_pos, *next_msg_pos, *next_pos, *prev_pos; - int name_str_len; - char name_str[64]; - gsize opt_len; - gchar *opt_str; - /* Info to build exported_pdu tags*/ - exported_pdu_info_t exported_pdu_info = {0}; - - import_file_fd = create_tempfile(&(file_info->tmpname), "Wireshark_PDU_", NULL, NULL); - if (import_file_fd < 0) - return WTAP_OPEN_ERROR; - - /* Now open a file and dump to it */ - /* Create data for SHB */ - shb_hdrs = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); - os_info_str = g_string_new(""); - get_os_version_info(os_info_str); - - shb_hdr = wtap_block_create(WTAP_BLOCK_NG_SECTION); - /* options */ - wtap_block_add_string_option(shb_hdr, OPT_COMMENT, "File converted to Exported PDU format during opening", - strlen("File converted to Exported PDU format during opening")); - /* - * UTF-8 string containing the name of the operating system used to create - * this section. - */ - opt_len = os_info_str->len; - opt_str = g_string_free(os_info_str, FALSE); - if (opt_str) { - wtap_block_add_string_option(shb_hdr, OPT_SHB_OS, opt_str, opt_len); - g_free(opt_str); - } - - /* - * UTF-8 string containing the name of the application used to create - * this section. Avoid the precise version (get_appname_and_version) to - * avoid wiretap rebuilds when only the version changes. - */ - wtap_block_add_string_option_format(shb_hdr, OPT_SHB_USERAPPL, "Wireshark %s", VERSION); - - /* Add header to the array */ - g_array_append_val(shb_hdrs, shb_hdr); - - - /* Create fake IDB info */ - idb_inf = g_new(wtapng_iface_descriptions_t, 1); - idb_inf->interface_data = g_array_new(FALSE, FALSE, sizeof(wtap_block_t)); - - /* create the fake interface data */ - int_data = wtap_block_create(WTAP_BLOCK_IF_DESCR); - int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_block_get_mandatory_data(int_data); - int_data_mand->wtap_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU; - int_data_mand->time_units_per_second = 1000000; /* default microsecond resolution */ - int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; - wtap_block_add_string_option(int_data, OPT_IDB_NAME, "Fake IF", strlen("Fake IF")); - int_data_mand->num_stat_entries = 0; /* Number of ISB:s */ - int_data_mand->interface_statistics = NULL; - - g_array_append_val(idb_inf->interface_data, int_data); - - const wtap_dump_params params = { - .encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU, - .snaplen = WTAP_MAX_PACKET_SIZE_STANDARD, - .shb_hdrs = shb_hdrs, - .idb_inf = idb_inf, - }; - wdh_exp_pdu = wtap_dump_fdopen(import_file_fd, WTAP_FILE_TYPE_SUBTYPE_PCAPNG, - WTAP_UNCOMPRESSED, ¶ms, - err, err_info); - if (wdh_exp_pdu == NULL) { - result = WTAP_OPEN_ERROR; - goto end; - } - - /* OK we've opend a new pcapng file and written the headers, time to do the packets, strt by finding the file size */ + nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; + gboolean status = FALSE; + guint8 *msg_end; + guint msg_len = 0; - if ((file_size = wtap_file_size(wth, err)) == -1) { - result = WTAP_OPEN_ERROR; - goto end; - } + /* We stored the offset of the "<msg" for this packet */ + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + return FALSE; - if (file_size > MAX_FILE_SIZE) { - /* - * Don't blow up trying to allocate space for an - * immensely-large file. - */ - *err = WTAP_ERR_BAD_FILE; - *err_info = g_strdup_printf("mime_file: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u", - file_size, MAX_FILE_SIZE); - result = WTAP_OPEN_ERROR; - goto end; - } - packet_size = (int)file_size; - /* Allocate the packet buffer - * (the whole file + Exported PDU tag "protocol" and - * the string "xml" + 1 filler to end on 4 byte boundary for the tag - * + End of options 4 bytes - */ - /* XXX add the length of exported bdu tag(s) here */ - packet_buf = (char *)g_malloc((gsize)packet_size + (gsize)12 + (gsize)1); - - packet_buf[0] = 0; - packet_buf[1] = EXP_PDU_TAG_PROTO_NAME; - packet_buf[2] = 0; - packet_buf[3] = 4; - packet_buf[4] = 'x'; - packet_buf[5] = 'm'; - packet_buf[6] = 'l'; - packet_buf[7] = 0; - /* End of options */ - packet_buf[8] = 0; - packet_buf[9] = 0; - packet_buf[10] = 0; - packet_buf[11] = 0; - - if (!wtap_read_bytes(wth->fh, packet_buf + 12, packet_size, err, err_info)){ - result = WTAP_OPEN_ERROR; - goto end; + msg_end = read_until(file_info->buffer, c_e_msg, wth->random_fh, err, err_info); + if (msg_end == NULL) { + return FALSE; } + msg_end += CLEN(c_e_msg); + msg_len = (guint)(msg_end - file_info->buffer->data); - /* Null-terminate buffer; we'll be processing it as a string. */ - packet_buf[packet_size + 12] = '\0'; - - /* Create the record header */ - memset(&rec, 0, sizeof rec); + status = nettrace_msg_to_packet(file_info, rec, buf, file_info->buffer->data, msg_len, err, err_info); + g_byte_array_set_size(file_info->buffer, 0); + return status; +} - /* Read the file header of the input file, currently we only need the beginTime*/ +/* Clean up any memory we allocated for dealing with this file. + * Set as the subtype_close function in the file_open function below. + * (wiretap frees wth->priv itself) + */ +static void +nettrace_close(wtap *wth) +{ + nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; - /* Advance *packet_buf to point at the raw file data */ - curr_pos = packet_buf + 12; - /* Find the file header */ - curr_pos = strstr(curr_pos, "<fileHeader"); - if (!curr_pos) { - *err = WTAP_ERR_BAD_FILE; - *err_info = g_strdup("Could not parse \"<fileHeader\""); - result = WTAP_OPEN_ERROR; - goto end; + if (file_info != NULL && file_info->buffer != NULL) { + g_byte_array_free(file_info->buffer, TRUE); + file_info->buffer = NULL; } - curr_pos = curr_pos + 11; +} - /* Find start time */ - curr_pos = strstr(curr_pos, "<traceCollec beginTime=\""); - if (!curr_pos) { - *err = WTAP_ERR_BAD_FILE; - *err_info = g_strdup("Could not parse \"<traceCollec beginTime=\""); - result = WTAP_OPEN_ERROR; - goto end; - } - curr_pos = curr_pos + 24; +/* This attribute specification contains a timestamp that refers to the start of the +* first trace data that is stored in this file. +* +* It is a complete timestamp including day, time and delta UTC hour. E.g. +* "2001-09-11T09:30:47-05:00". +*/ - curr_pos = nettrace_parse_begin_time(curr_pos, &rec); +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) - start_time.secs = packet_time.secs = rec.ts.secs; - start_time.nsecs = packet_time.nsecs = rec.ts.nsecs; +static char* +nettrace_parse_begin_time(char *curr_pos, size_t n, nstime_t *ts) +{ + /* Time vars */ + guint year, month, day, hour, minute, second, frac; + int UTCdiffh, UTCdiffm = 0; + int time_length = 0; + int scan_found; + static const guint days_in_month[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + struct tm tm; + char *end_pos; + int length; - /* set rest of the record hdr data */ - rec.rec_type = REC_TYPE_PACKET; + nstime_set_unset(ts); /* mark time as invalid, until successful converted */ - rec.rec_header.packet_header.caplen = packet_size + 12; - rec.rec_header.packet_header.len = packet_size + 12; + end_pos = g_strstr_len(curr_pos, n, "\"/>"); + length = (int)(end_pos - curr_pos); - /* XXX: report errors! */ - if (!wtap_dump(wdh_exp_pdu, &rec, packet_buf, err, err_info)) { - result = WTAP_OPEN_ERROR; - goto end; + if (length < 2) { + return end_pos + 3; } - /* Lets add the raw messages as packets after the main "packet" with the whole file */ - while ((curr_pos = strstr(curr_pos, "<msg")) != NULL){ - wtap_open_return_val temp_val; - char str[3]; - char *raw_msg_pos; - char* start_msg_tag_cont; - - /* Clear for each iteration */ - exported_pdu_info.precense_flags = 0; - exported_pdu_info.ptype = OLD_PT_NONE; - - prev_pos = curr_pos = curr_pos + 4; - /* Look for the end of the tag first */ - next_msg_pos = strstr(curr_pos, ">"); - if (!next_msg_pos) { - /* Somethings wrong, bail out */ - *err = WTAP_ERR_BAD_FILE; - *err_info = g_strdup("Did not find end of tag \">\""); - result = WTAP_OPEN_ERROR; - goto end; - } - /* Check if its a tag close "/>" */ - g_strlcpy(str, next_msg_pos - 1 , 3); - next_msg_pos = next_msg_pos - 1; - if (strcmp(str, "/>") == 0) { - /* There is no rawmsg here skip to nex msg */ - curr_pos = next_msg_pos + 2; - continue; - } - start_msg_tag_cont = curr_pos = prev_pos; - next_msg_pos = strstr(curr_pos, "</msg>"); - if (!next_msg_pos){ - /* Somethings wrong, bail out */ - *err = WTAP_ERR_BAD_FILE; - *err_info = g_strdup("Did not find \"</msg>\""); - result = WTAP_OPEN_ERROR; - goto end; + /* Scan for this format: 2001-09-11T09:30:47 Then we will parse any fractions and UTC offset */ + scan_found = sscanf(curr_pos, "%4u-%2u-%2uT%2u:%2u:%2u%n", + &year, &month, &day, &hour, &minute, &second, &time_length); + if (scan_found == 6 && time_length == 19) { + /* Fill in the fields and return it in a time_t */ + tm.tm_year = year - 1900; + if (month < 1 || month > 12) { + /* g_warning("Failed to parse time, month is %u", month); */ + return curr_pos; } - next_msg_pos = next_msg_pos + 6; - - /* Do we have a raw message in the <msg> <\msg> section?*/ - raw_msg_pos = strstr(start_msg_tag_cont, "<rawMsg"); - if ((!raw_msg_pos) || (raw_msg_pos > next_msg_pos)) { - curr_pos = next_msg_pos; - continue; + tm.tm_mon = month - 1; /* Zero count*/ + if (day > ((month == 2 && isleap(year)) ? 29 : days_in_month[month - 1])) { + /* g_warning("Failed to parse time, %u-%02u-%2u is not a valid day", year, month, day); */ + return curr_pos; } - - - /* Check if we have a time stamp "changeTime" - * expressed in number of seconds and milliseconds (nbsec.ms). - */ - ms = 0; - curr_pos = strstr(start_msg_tag_cont, "changeTime"); - /* Check if we have the tag or if we passed the end of the current message */ - if ((curr_pos) && (curr_pos < next_msg_pos)) { - curr_pos = curr_pos + 12; - scan_found = sscanf(curr_pos, "%u.%u", &second, &ms); - - if ((scan_found == 2) && (start_time.secs != 0)) { - guint start_ms = start_time.nsecs / 1000000; - guint elapsed_ms = start_ms + ms; - if (elapsed_ms > 1000) { - elapsed_ms -= 1000; - second++; - } - packet_time.secs = start_time.secs + second; - packet_time.nsecs = start_time.nsecs + (elapsed_ms * 1000000); - } + tm.tm_mday = day; + if (hour > 23) { + /* g_warning("Failed to parse time, hour is %u", hour); */ + return curr_pos; } - - /* See if we have a "name" */ - curr_pos = strstr(start_msg_tag_cont, "name="); - if ((curr_pos) && (curr_pos < next_msg_pos)) { - /* extract the name */ - curr_pos = curr_pos + 6; - next_pos = strstr(curr_pos, "\""); - name_str_len = (int)(next_pos - curr_pos); - if (name_str_len > 63) { - *err = WTAP_ERR_BAD_FILE; - *err_info = g_strdup("name_str_len > 63"); - return WTAP_OPEN_ERROR; - } - - g_strlcpy(name_str, curr_pos, (gsize)name_str_len + 1); - ascii_strdown_inplace(name_str); - + tm.tm_hour = hour; + if (minute > 59) { + /* g_warning("Failed to parse time, minute is %u", minute); */ + return curr_pos; } - /* Check if we have "<initiator>" - * It might contain an address - */ - curr_pos = strstr(start_msg_tag_cont, "<initiator"); - /* Check if we have the tag or if we passed the end of the current message */ - if ((curr_pos) && (curr_pos < next_msg_pos)) { - curr_pos = curr_pos + 10; - next_pos = strstr(curr_pos, "</initiator>"); - /* Find address (omit the a to cater for A */ - curr_pos = strstr(curr_pos, "ddress"); - if ((curr_pos) && (curr_pos < next_pos)) { - curr_pos += 6; - nettrace_parse_address(curr_pos, next_pos, TRUE/*SRC */, &exported_pdu_info); - } + tm.tm_min = minute; + if (second > 60) { + /* + * Yes, 60, for leap seconds - POSIX's and Windows' + * refusal to believe in them nonwithstanding. + */ + /* g_warning("Failed to parse time, second is %u", second); */ + return curr_pos; } + tm.tm_sec = second; + tm.tm_isdst = -1; /* daylight saving time info not known */ - /* Check if we have "<target>" - * It might contain an address - */ - curr_pos = strstr(start_msg_tag_cont, "<target"); - /* Check if we have the tag or if we passed the end of the current message */ - if ((curr_pos) && (curr_pos < next_msg_pos)) { - curr_pos = curr_pos + 7; - next_pos = strstr(curr_pos, "</target>"); - /* Find address(omit the a to cater for A */ - curr_pos = strstr(curr_pos, "ddress"); - if ((curr_pos) && (curr_pos < next_pos)) { - curr_pos += 7; - /* curr_pos set below */ - nettrace_parse_address(curr_pos, next_pos, FALSE/*DST */, &exported_pdu_info); + /* Move curr_pos to end of parsed object and get that character 2019-01-10T10:14:56 */ + curr_pos += time_length; + if (*curr_pos == '.' || *curr_pos == ',') { + /* We have fractions */ + curr_pos++; + if (1 == sscanf(curr_pos, "%u%n", &frac, &time_length)) { + if ((frac >= 1000000000) || (frac == 0)) { + ts->nsecs = 0; + } else { + switch (time_length) { /* including leading zeros */ + case 1: ts->nsecs = frac * 100000000; break; + case 2: ts->nsecs = frac * 10000000; break; + case 3: ts->nsecs = frac * 1000000; break; + case 4: ts->nsecs = frac * 100000; break; + case 5: ts->nsecs = frac * 10000; break; + case 6: ts->nsecs = frac * 1000; break; + case 7: ts->nsecs = frac * 100; break; + case 8: ts->nsecs = frac * 10; break; + default: ts->nsecs = frac; + } + } + curr_pos += time_length; } } - /* Do we have a raw msg?) */ - curr_pos = raw_msg_pos; - curr_pos = curr_pos + 7; - /* Add the raw msg*/ - temp_val = write_packet_data(wdh_exp_pdu, &rec, err, err_info, curr_pos, packet_time, &exported_pdu_info, name_str); - if (temp_val != WTAP_OPEN_MINE){ - result = temp_val; - goto end; + if (*curr_pos == '-' || *curr_pos == '+' || *curr_pos == 'Z') { + /* We have UTC offset */ + if (1 <= sscanf(curr_pos, "%3d:%2d", &UTCdiffh, &UTCdiffm)) { + /* adjust for timezone */ + tm.tm_hour -= UTCdiffh; + tm.tm_min -= UTCdiffh < 0 ? -UTCdiffm: UTCdiffm; + } /* else 'Z' for Zero time */ + /* convert to UTC time */ +#ifdef _WIN32 + ts->secs = _mkgmtime(&tm); +#else + ts->secs = timegm(&tm); +#endif + } else { + /* no UTC offset means localtime in ISO 8601 */ + ts->secs = mktime(&tm); } - curr_pos = next_msg_pos; - } - - /* Close the written file*/ - if (!wtap_dump_close(wdh_exp_pdu, err, err_info)){ - result = WTAP_OPEN_ERROR; - goto end; - } - - /* Now open the file for reading */ - - /* Find out if random read was requested */ - if (wth->random_fh){ - do_random = TRUE; - } - file_info->wth_tmp_file = - wtap_open_offline(file_info->tmpname, WTAP_TYPE_AUTO, err, err_info, do_random); - - if (!file_info->wth_tmp_file){ - result = WTAP_OPEN_ERROR; - goto end; + /* } else { + g_warning("Failed to parse time, only %u fields", scan_found); */ } -end: - g_free(packet_buf); - wtap_block_array_free(shb_hdrs); - wtap_free_idb_info(idb_inf); - - return result; + return curr_pos; } +/* Test the current file to see if it's one we can read. + * Set in file_access.c as the function to be called for this file type. + */ wtap_open_return_val nettrace_3gpp_32_423_file_open(wtap *wth, int *err, gchar **err_info) { - char magic_buf[512+1]; /* increase buffer size when needed */ + char magic_buf[MAGIC_BUF_SIZE+1]; int bytes_read; char *curr_pos; nettrace_3gpp_32_423_file_info_t *file_info; - wtap_open_return_val temp_val; + gint64 start_offset; - - bytes_read = file_read(magic_buf, 512, wth->fh); + start_offset = file_tell(wth->fh); // Most likely 0 but doesn't hurt to check + bytes_read = file_read(magic_buf, MAGIC_BUF_SIZE, wth->fh); if (bytes_read < 0) { *err = file_error(wth->fh, err_info); @@ -1151,53 +904,46 @@ nettrace_3gpp_32_423_file_open(wtap *wth, int *err, gchar **err_info) return WTAP_OPEN_NOT_MINE; } - if (memcmp(magic_buf, xml_magic, sizeof(xml_magic)) != 0){ + if (memcmp(magic_buf, c_xml_magic, CLEN(c_xml_magic)) != 0){ return WTAP_OPEN_NOT_MINE; } - /* Null-terminate buffer; we'll be processing it as a string. */ - magic_buf[512] = '\0'; - - /* File header should contain something like fileFormatVersion="32.423 V8.1.0" */ - curr_pos = strstr(magic_buf, "fileFormatVersion"); - - if (!curr_pos){ + curr_pos = g_strstr_len(magic_buf, bytes_read, c_file_header); + if (!curr_pos) { return WTAP_OPEN_NOT_MINE; } - curr_pos += 19; - if (memcmp(curr_pos, Threegpp_doc_no, sizeof(Threegpp_doc_no)) != 0){ + curr_pos = g_strstr_len(curr_pos, bytes_read-(curr_pos-magic_buf), c_file_format_version); + if (!curr_pos) { return WTAP_OPEN_NOT_MINE; } - - if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) - return WTAP_OPEN_ERROR; - - /* Ok it's our file, open a temp file and do the conversion */ - file_info = g_new0(nettrace_3gpp_32_423_file_info_t, 1); - temp_val = create_temp_pcapng_file(wth, err, err_info, file_info); - - if (temp_val != WTAP_OPEN_MINE){ - return temp_val; + curr_pos += CLEN(c_file_format_version); + if (memcmp(curr_pos, c_threegpp_doc_no, CLEN(c_threegpp_doc_no)) != 0){ + return WTAP_OPEN_NOT_MINE; } + /* Next we expect something like <traceCollec beginTime="..."/> */ + curr_pos = g_strstr_len(curr_pos, bytes_read-(curr_pos-magic_buf), c_begin_time); + if (!curr_pos) { + return WTAP_OPEN_NOT_MINE; + } + curr_pos += CLEN(c_begin_time); - if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) - return WTAP_OPEN_ERROR; - - /* Copy data from the temp file wth */ - wtap_block_copy(g_array_index(wth->shb_hdrs, wtap_block_t, 0), g_array_index(file_info->wth_tmp_file->shb_hdrs, wtap_block_t, 0)); + /* Ok it's our file. From here we'll need to free memory */ + file_info = g_new0(nettrace_3gpp_32_423_file_info_t, 1); + curr_pos = nettrace_parse_begin_time(curr_pos, (guint)(bytes_read - (curr_pos - magic_buf)), &file_info->start_time); + file_info->start_offset = start_offset + (curr_pos - magic_buf); + file_info->buffer = g_byte_array_sized_new(RINGBUFFER_START_SIZE); + g_byte_array_append(file_info->buffer, curr_pos, (guint)(bytes_read - (curr_pos - magic_buf))); wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_NETTRACE_3GPP_32_423; - wth->file_encap = file_info->wth_tmp_file->file_encap; - wth->file_tsprec = file_info->wth_tmp_file->file_tsprec; + wth->file_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU; + wth->file_tsprec = WTAP_TSPREC_MSEC; wth->subtype_read = nettrace_read; wth->subtype_seek_read = nettrace_seek_read; wth->subtype_close = nettrace_close; wth->snapshot_length = 0; - wth->priv = (void*)file_info; return WTAP_OPEN_MINE; - } /* |