/* nettrace_3gpp_32_423.c * * Decoder for 3GPP TS 32.423 file format for the Wiretap library. * The main purpose is to have Wireshark decode raw message content ( tag). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Ref: http://www.3gpp.org/DynaReport/32423.htm */ #include "config.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include "wtap-int.h" #include "file_wrappers.h" #include "pcap-encap.h" #include #include "wsutil/tempfile.h" #include "wsutil/os_version_info.h" #include "ws_version_info.h" #include "wsutil/str_util.h" #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) static const guint8 xml_magic[] = { '<', '?', 'x', 'm', 'l' }; static const guint8 Threegpp_doc_no[] = { '3', '2', '.', '4', '2', '3' }; typedef struct nettrace_3gpp_32_423_file_info { char *tmpname; wtap *wth_tmp_file; } nettrace_3gpp_32_423_file_info_t; /* From epan/address.h Types of port numbers Wireshark knows about. */ typedef enum { PT_NONE, /* no port number */ PT_SCTP, /* SCTP */ PT_TCP, /* TCP */ PT_UDP, /* UDP */ PT_DCCP, /* DCCP */ PT_IPX, /* IPX sockets */ PT_NCP, /* NCP connection */ PT_EXCHG, /* Fibre Channel exchange */ PT_DDP, /* DDP AppleTalk connection */ PT_SBCCS, /* FICON */ PT_IDP, /* XNS IDP sockets */ PT_TIPC, /* TIPC PORT */ PT_USB, /* USB endpoint 0xffff means the host */ PT_I2C, PT_IBQP, /* Infiniband QP number */ PT_BLUETOOTH, PT_TDMOP } port_type; typedef struct exported_pdu_info { guint32 precense_flags; /*const char* proto_name;*/ guint8 src_ipv4_d1; guint8 src_ipv4_d2; guint8 src_ipv4_d3; guint8 src_ipv4_d4; port_type ptype; /* epan/address.h port_type valid for both src and dst*/ guint32 src_port; guint8 dst_ipv4_d1; guint8 dst_ipv4_d2; guint8 dst_ipv4_d3; guint8 dst_ipv4_d4; 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_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. */ #define EXP_PDU_TAG_IP_SRC_BIT 0x01 #define EXP_PDU_TAG_IP_DST_BIT 0x02 #define EXP_PDU_TAG_SRC_PORT_BIT 0x04 #define EXP_PDU_TAG_DST_PORT_BIT 0x08 #define EXP_PDU_TAG_SS7_OPC_BIT 0x20 #define EXP_PDU_TAG_SS7_DPC_BIT 0x40 #define EXP_PDU_TAG_ORIG_FNO_BIT 0x80 /* 2nd byte of optional tags bitmap */ #define EXP_PDU_TAG_DVBCI_EVT_BIT 0x0100 #define EXP_PDU_TAG_COL_PROT_BIT 0x0200 #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 static gboolean nettrace_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) { struct Buffer *frame_buffer_saved; gboolean result; nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; frame_buffer_saved = file_info->wth_tmp_file->frame_buffer; file_info->wth_tmp_file->frame_buffer = wth->frame_buffer; /* we read the created pcapng file instead */ result = wtap_read(file_info->wth_tmp_file, err, err_info, data_offset); file_info->wth_tmp_file->frame_buffer = frame_buffer_saved; if (!result) return result; wth->phdr.rec_type = file_info->wth_tmp_file->phdr.rec_type; wth->phdr.presence_flags = file_info->wth_tmp_file->phdr.presence_flags; wth->phdr.ts = file_info->wth_tmp_file->phdr.ts; wth->phdr.caplen = file_info->wth_tmp_file->phdr.caplen; wth->phdr.len = file_info->wth_tmp_file->phdr.len; wth->phdr.pkt_encap = file_info->wth_tmp_file->phdr.pkt_encap; wth->phdr.pkt_tsprec = file_info->wth_tmp_file->phdr.pkt_tsprec; wth->phdr.interface_id = file_info->wth_tmp_file->phdr.interface_id; wth->phdr.opt_comment = file_info->wth_tmp_file->phdr.opt_comment; wth->phdr.drop_count = file_info->wth_tmp_file->phdr.drop_count; wth->phdr.pack_flags = file_info->wth_tmp_file->phdr.pack_flags; wth->phdr.ft_specific_data = file_info->wth_tmp_file->phdr.ft_specific_data; return result; } static gboolean nettrace_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info) { struct Buffer *frame_buffer_saved; gboolean result; nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; frame_buffer_saved = file_info->wth_tmp_file->frame_buffer; file_info->wth_tmp_file->frame_buffer = wth->frame_buffer; result = wtap_seek_read(file_info->wth_tmp_file, seek_off, phdr, buf, err, err_info); file_info->wth_tmp_file->frame_buffer = frame_buffer_saved; return result; } /* classic wtap: close capture file */ static void nettrace_close(wtap *wth) { nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv; wtap_close(file_info->wth_tmp_file); /*Clear the shb info, it's been freed by wtap_close*/ wtap_optionblock_set_option_string(wth->shb_hdr, OPT_COMMENT, NULL); wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_HARDWARE, NULL); wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_OS, NULL); wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_USERAPPL, NULL); /* delete the temp file */ ws_unlink(file_info->tmpname); } /* 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". */ #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) static guint8* nettrace_parse_begin_time(guint8 *curr_pos, struct wtap_pkthdr *phdr) { /* Time vars*/ guint year, month, day, hour, minute, second, ms; int UTCdiffh; guint UTCdiffm; 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; guint8 *prev_pos, *next_pos; int length; prev_pos = curr_pos; next_pos = strstr(curr_pos, "\"/>"); length = (int)(next_pos - prev_pos); if (length < 2) { return next_pos + 3; } /* Scan for all fields */ scan_found = sscanf(curr_pos, "%4u-%2u-%2uT%2u:%2u:%2u%3d:%2u", &year, &month, &day, &hour, &minute, &second, &UTCdiffh, &UTCdiffm); phdr->ts.nsecs = 0; if (scan_found != 8) { /* Found this format in a file: * beginTime="2013-09-11T15:45:00,666+02:00"/> */ scan_found = sscanf(curr_pos, "%4u-%2u-%2uT%2u:%2u:%2u,%3u%3d:%2u", &year, &month, &day, &hour, &minute, &second, &ms, &UTCdiffh, &UTCdiffm); if (scan_found == 9) { phdr->ts.nsecs = ms * 1000; /* Use the code below to set the time stamp */ scan_found = 8; } else { phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; g_warning("Failed to parse second time format, scan_found %u", scan_found); return curr_pos; } } if (scan_found == 8) { guint UTCdiffsec; /* Only set time if we managed to parse it*/ /* Fill in remaining fields and return it in a time_t */ tm.tm_year = year - 1900; if (month < 1 || month > 12) { phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; 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])) { phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; 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) { phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; g_warning("Failed to parse time, hour is %u", hour); return curr_pos; } tm.tm_hour = hour; if (minute > 59) { phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; 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. */ phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; 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 */ /* Get seconds from this time */ phdr->presence_flags = WTAP_HAS_TS; phdr->ts.secs = mktime(&tm); UTCdiffsec = (abs(UTCdiffh) * 60 * 60) + (UTCdiffm * 60); if (UTCdiffh < 0) { phdr->ts.secs = phdr->ts.secs - UTCdiffsec; } else { phdr->ts.secs = phdr->ts.secs + UTCdiffsec; } } else { g_warning("Failed to parse time, only %u fields", scan_found); phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; } return curr_pos; } /* Parsing something like * * [truncated]010001244000012C01000... * */ static wtap_open_return_val write_packet_data(wtap_dumper *wdh, struct wtap_pkthdr *phdr, int *err, gchar **err_info, guint8 *file_buf, time_t start_time, int ms, 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; gchar chr; gint val1, val2; gboolean port_type_defined = FALSE; gboolean use_proto_table = FALSE; 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; } curr_pos = curr_pos + 10; next_pos = strstr(curr_pos, "\""); proto_str_len = (int)(next_pos - curr_pos); if (proto_str_len > 15){ return WTAP_OPEN_ERROR; } g_strlcpy(proto_name_str, curr_pos, 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){ /* Change to gtpv2 */ proto_name_str[5] = '\0'; proto_name_str[6] = '\0'; proto_str_len = 5; } /* 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_name_str[13] = '\0'; proto_str_len = 13; } if (strcmp(proto_name_str, "map") == 0) { /* 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"); 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[21] = '\0'; dissector_table_str_len = 21; dissector_table_val = 56; exported_pdu_info->precense_flags = exported_pdu_info->precense_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[21] = '\0'; dissector_table_str_len = 21; dissector_table_val = 56; exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT; } } /* Find the start of the raw data*/ curr_pos = strstr(next_pos, ">") + 1; next_pos = strstr(next_pos, "<"); raw_data_len = (int)(next_pos - curr_pos); /* 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; } if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) { 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->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == 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; } 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->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) { if (!port_type_defined) { exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN; } exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN; } port_type_defined = FALSE; /* Allocate the packet buf */ pkt_data_len = raw_data_len / 2; packet_buf = (guint8 *)g_malloc0(pkt_data_len + exp_pdu_tags_len +4); /* 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; for (i = 4, j = 0; j < tag_str_len; i++, j++) { packet_buf[i] = proto_name_str[j]; } }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; for (i = 4, j = 0; j < tag_str_len; i++, j++) { packet_buf[i] = dissector_table_str[j]; } 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++; packet_buf[i] = exported_pdu_info->src_ipv4_d1; i++; packet_buf[i] = exported_pdu_info->src_ipv4_d2; i++; packet_buf[i] = exported_pdu_info->src_ipv4_d3; i++; packet_buf[i] = exported_pdu_info->src_ipv4_d4; i++; } 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++; packet_buf[i] = exported_pdu_info->dst_ipv4_d1; i++; packet_buf[i] = exported_pdu_info->dst_ipv4_d2; i++; packet_buf[i] = exported_pdu_info->dst_ipv4_d3; i++; packet_buf[i] = exported_pdu_info->dst_ipv4_d4; i++; } 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++; } /* 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; /* Convert the hex raw msg data to binary and write to the packet buf*/ for (; i < (pkt_data_len + exp_pdu_tags_len); i++){ chr = *curr_pos; val1 = g_ascii_xdigit_value(chr); curr_pos++; chr = *curr_pos; val2 = g_ascii_xdigit_value(chr); if ((val1 != -1) && (val2 != -1)){ packet_buf[i] = ((guint8)val1 * 16) + val2; } else{ /* Something wrong, bail out */ g_free(packet_buf); return WTAP_OPEN_ERROR; } curr_pos++; } /* Construct the phdr */ memset(phdr, 0, sizeof(struct wtap_pkthdr)); phdr->rec_type = REC_TYPE_PACKET; if (start_time == 0) { phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ phdr->ts.secs = 0; phdr->ts.nsecs = 0; } else { phdr->presence_flags = WTAP_HAS_TS; phdr->ts.secs = start_time; phdr->ts.nsecs = ms * 1000000; } phdr->caplen = pkt_data_len + exp_pdu_tags_len; phdr->len = pkt_data_len + exp_pdu_tags_len; if (!wtap_dump(wdh, phdr, packet_buf, err, err_info)) { switch (*err) { case WTAP_ERR_UNWRITABLE_REC_DATA: g_free(err_info); break; default: break; } g_free(packet_buf); return WTAP_OPEN_ERROR; } g_free(packet_buf); return WTAP_OPEN_MINE; } /* * Opens an .xml file with Trace data formated 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. */ 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) { int import_file_fd; wtap_dumper* wdh_exp_pdu; int exp_pdu_file_err; wtap_open_return_val result = WTAP_OPEN_MINE; /* pcapng defs */ wtap_optionblock_t shb_hdr = NULL; wtapng_iface_descriptions_t *idb_inf = NULL; wtap_optionblock_t int_data; wtapng_if_descr_mandatory_t *int_data_mand; GString *os_info_str; gint64 file_size; int packet_size; guint8 *packet_buf = NULL; int wrt_err; gchar *wrt_err_info = NULL; struct wtap_pkthdr phdr; time_t start_time; int scan_found; unsigned second, ms; gboolean do_random = FALSE; gchar* wireshark_ver; char *curr_pos, *next_msg_pos, *next_pos, *prev_pos; int name_str_len; char name_str[64]; /* Info to build exported_pdu tags*/ exported_pdu_info_t exported_pdu_info; exported_pdu_info.precense_flags = 0; exported_pdu_info.src_ipv4_d1 = 0; exported_pdu_info.src_ipv4_d2 = 0; exported_pdu_info.src_ipv4_d3 = 0; exported_pdu_info.src_ipv4_d4 = 0; exported_pdu_info.ptype = PT_NONE; exported_pdu_info.src_port = 0; exported_pdu_info.dst_ipv4_d1 = 0; exported_pdu_info.dst_ipv4_d2 = 0; exported_pdu_info.dst_ipv4_d3 = 0; exported_pdu_info.dst_ipv4_d4 = 0; exported_pdu_info.dst_port = 0; exported_pdu_info.proto_col_str = NULL; import_file_fd = create_tempfile(&(file_info->tmpname), "Wireshark_PDU_"); /* Now open a file and dump to it */ /* Create data for SHB */ os_info_str = g_string_new(""); get_os_version_info(os_info_str); shb_hdr = wtap_optionblock_create(WTAP_OPTION_BLOCK_NG_SECTION); /* options */ wtap_optionblock_set_option_string(wth->shb_hdr, OPT_COMMENT, "File converted to Exported PDU format during opening"); /* * UTF-8 string containing the name of the operating system used to create * this section. */ wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_OS, g_string_free(os_info_str, TRUE)); /* * UTF-8 string containing the name of the application used to create * this section. */ wireshark_ver = g_strdup_printf("Wireshark %s", get_ws_vcs_version_info()); wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_USERAPPL, wireshark_ver); g_free(wireshark_ver); /* Create fake IDB info */ idb_inf = g_new(wtapng_iface_descriptions_t, 1); idb_inf->interface_data = g_array_new(FALSE, FALSE, sizeof(wtap_optionblock_t)); /* create the fake interface data */ int_data = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR); int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_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->link_type = wtap_wtap_encap_to_pcap_encap(WTAP_ENCAP_WIRESHARK_UPPER_PDU); int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE; wtap_optionblock_set_option_string(int_data, OPT_IDB_NAME, "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); wdh_exp_pdu = wtap_dump_fdopen_ng(import_file_fd, WTAP_FILE_TYPE_SUBTYPE_PCAPNG, WTAP_ENCAP_WIRESHARK_UPPER_PDU, WTAP_MAX_PACKET_SIZE, FALSE, shb_hdr, idb_inf, NULL, &exp_pdu_file_err); if (wdh_exp_pdu == NULL) { result = WTAP_OPEN_ERROR; goto end; } /* OK we've opend a new pcap-ng file and written the headers, time to do the packets, strt by finding the file size */ if ((file_size = wtap_file_size(wth, err)) == -1) { result = WTAP_OPEN_ERROR; goto end; } 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 = (guint8 *)g_malloc(packet_size + 12 + 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, &wrt_err, &wrt_err_info)){ result = WTAP_OPEN_ERROR; goto end; } /* Null-terminate buffer; we'll be processing it as a string. */ packet_buf[packet_size + 12] = '\0'; /* Create the packet header */ memset(&phdr, 0, sizeof(struct wtap_pkthdr)); /* Read the file header of the input file, currently we only need the beginTime*/ /* Advance *packet_buf to point at the raw file data */ curr_pos = packet_buf + 12; /* Find the file header */ curr_pos = strstr(curr_pos, ""); if (!next_msg_pos){ /* Somethings wrong, bail out */ break; } next_msg_pos = next_msg_pos + 6; /* Check if we have a time stamp "changeTime" * expressed in number of seconds and milliseconds (nbsec.ms). */ prev_pos = curr_pos; ms = 0; /* See if we have a "name" */ curr_pos = strstr(curr_pos, "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) { return WTAP_OPEN_ERROR; } g_strlcpy(name_str, curr_pos, name_str_len + 1); ascii_strdown_inplace(name_str); } else { curr_pos = prev_pos; } curr_pos = strstr(curr_pos, "changeTime"); /* Check if we have the tag or if we pased 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 != 0)) { start_time = start_time + second; } } else { curr_pos = prev_pos; } /* Check if we have "" * It might contain an address */ prev_pos = curr_pos; curr_pos = strstr(curr_pos, ""); /* Check if we have the tag or if we pased the end of the current message */ if ((curr_pos) && (curr_pos < next_msg_pos)) { curr_pos = curr_pos + 11; next_pos = strstr(curr_pos, ""); /* Find address*/ curr_pos = strstr(curr_pos, "address"); if ((curr_pos) && (curr_pos < next_pos)) { guint d1, d2, d3, d4, port; char transp_str[5]; curr_pos = curr_pos + 7; /* Excample from one trace, unsure if it's generic... * {address == 192.168.73.1, port == 5062, transport == Udp} */ scan_found = sscanf(curr_pos, "%*s %3u.%3u.%3u.%3u, %*s %*s %5u, %*s %*s %4s", &d1, &d2, &d3, &d4, &port, transp_str); if (scan_found == 6) { exported_pdu_info.precense_flags = exported_pdu_info.precense_flags + EXP_PDU_TAG_IP_SRC_BIT + EXP_PDU_TAG_SRC_PORT_BIT; exported_pdu_info.src_ipv4_d1 = d1; exported_pdu_info.src_ipv4_d2 = d2; exported_pdu_info.src_ipv4_d3 = d3; exported_pdu_info.src_ipv4_d4 = d4; /* Only add port_type once */ if(exported_pdu_info.ptype == PT_NONE){ if (g_ascii_strncasecmp(transp_str, "udp", 3) == 0) exported_pdu_info.ptype = PT_UDP; else if (g_ascii_strncasecmp(transp_str, "tcp", 3) == 0) exported_pdu_info.ptype = PT_TCP; else if (g_ascii_strncasecmp(transp_str, "sctp", 4) == 0) exported_pdu_info.ptype = PT_SCTP; } exported_pdu_info.src_port = port; } else { g_warning("scan_found:%u, %u.%u.%u.%u Port %u transport %s", scan_found, d1, d2, d3, d4, port, transp_str); } } else { /* address not found*/ curr_pos = next_pos; } } else { /*"" not found */ curr_pos = prev_pos; } /* Check if we have "" * It might contain an address */ prev_pos = curr_pos; curr_pos = strstr(curr_pos, ""); /* Check if we have the tag or if we pased the end of the current message */ if ((curr_pos) && (curr_pos < next_msg_pos)) { curr_pos = curr_pos + 8; next_pos = strstr(curr_pos, ""); /* Find address*/ curr_pos = strstr(curr_pos, "address"); if ((curr_pos) && (curr_pos < next_pos)) { guint d1, d2, d3, d4, port; char transp_str[5]; curr_pos = curr_pos + 7; /* Excample from one trace, unsure if it's generic... * {address == 192.168.73.1, port == 5062, transport == Udp} */ scan_found = sscanf(curr_pos, "%*s %3u.%3u.%3u.%3u, %*s %*s %5u, %*s %*s %4s", &d1, &d2, &d3, &d4, &port, transp_str); if (scan_found == 6) { exported_pdu_info.precense_flags = exported_pdu_info.precense_flags + EXP_PDU_TAG_IP_DST_BIT + EXP_PDU_TAG_DST_PORT_BIT; exported_pdu_info.dst_ipv4_d1 = d1; exported_pdu_info.dst_ipv4_d2 = d2; exported_pdu_info.dst_ipv4_d3 = d3; exported_pdu_info.dst_ipv4_d4 = d4; /* Only add port_type once */ if (exported_pdu_info.ptype == PT_NONE) { if (g_ascii_strncasecmp(transp_str, "udp", 3) == 0) exported_pdu_info.ptype = PT_UDP; else if (g_ascii_strncasecmp(transp_str, "tcp", 3) == 0) exported_pdu_info.ptype = PT_TCP; else if (g_ascii_strncasecmp(transp_str, "sctp", 4) == 0) exported_pdu_info.ptype = PT_SCTP; } exported_pdu_info.dst_port = port; } else { g_warning("scan_found:%u, %u.%u.%u.%u Port %u transport %s", scan_found, d1, d2, d3, d4, port, transp_str); } } else { /* address not found */ curr_pos = next_pos; } } else { /* "" not found */ curr_pos = prev_pos; } /* Do we have a raw msg?) */ curr_pos = strstr(curr_pos, "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; } end: g_free(wrt_err_info); g_free(packet_buf); wtap_optionblock_free(shb_hdr); wtap_free_idb_info(idb_inf); return result; } 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 */ int bytes_read; char *curr_pos; nettrace_3gpp_32_423_file_info_t *file_info; wtap_open_return_val temp_val; bytes_read = file_read(magic_buf, 512, wth->fh); if (bytes_read < 0) { *err = file_error(wth->fh, err_info); return WTAP_OPEN_ERROR; } if (bytes_read == 0){ return WTAP_OPEN_NOT_MINE; } if (memcmp(magic_buf, xml_magic, sizeof(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){ return WTAP_OPEN_NOT_MINE; } curr_pos += 19; if (memcmp(curr_pos, Threegpp_doc_no, sizeof(Threegpp_doc_no)) != 0){ 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; } if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) return WTAP_OPEN_ERROR; /* Copy data from the temp file wth */ wtap_optionblock_copy_options(wth->shb_hdr, file_info->wth_tmp_file->shb_hdr); 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->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; } /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: * * vi: set shiftwidth=8 tabstop=8 noexpandtab: * :indentSize=8:tabSize=8:noTabs=false: */