/* * Compare two conversation keys, except for the port 2 value. * We don't check both directions of the conversation - the routine * doing the hash lookup has to do two searches, as the hash key * will be different for the two directions. */ static gint conversation_match_no_port2(gconstpointer v, gconstpointer w) { const conversation_key *v1 = (const conversation_key *)v; const conversation_key *v2 = (const conversation_key *)w; if (v1->ptype != v2->ptype) return 0; /* different types of port */ /* * Are the first and second port 1 values the same, the first and * second address 1 values the same, and the first and second * address 2 values the same? */ if (v1->port1 == v2->port1 && ADDRESSES_EQUAL(&v1->addr1, &v2->addr1) && ADDRESSES_EQUAL(&v1->addr2, &v2->addr2)) { /* * Yes. It's the same conversation, and the two * address/port pairs are going in the same direction. */ return 1; } /* * The addresses or the ports don't match. */ return 0; }
/** Compare two conversation keys for an exact match. * (Parameter types are gconstpointer for GHashTable compatibility.) * * @param key1 First conversation. MUST point to a conv_key_t struct. * @param key2 Second conversation. MUST point to a conv_key_t struct. * @return TRUE if conversations are equal, FALSE otherwise. */ static gboolean conversation_equal(gconstpointer key1, gconstpointer key2) { const conv_key_t *ck1 = (const conv_key_t *)key1; const conv_key_t *ck2 = (const conv_key_t *)key2; if (ck1->conv_id == ck2->conv_id) { if (ck1->port1 == ck2->port1 && ck1->port2 == ck2->port2 && ADDRESSES_EQUAL(&ck1->addr1, &ck2->addr1) && ADDRESSES_EQUAL(&ck1->addr2, &ck2->addr2)) { return TRUE; } if (ck1->port2 == ck2->port1 && ck1->port1 == ck2->port2 && ADDRESSES_EQUAL(&ck1->addr2, &ck2->addr1) && ADDRESSES_EQUAL(&ck1->addr1, &ck2->addr2)) { return TRUE; } } /* * The addresses, ports, or conversation IDs don't match. */ return FALSE; }
/* compare the endpoints of two RTP streams */ gboolean rtp_stream_info_is_reverse(const rtp_stream_info_t *stream_a, rtp_stream_info_t *stream_b) { if (stream_a == NULL || stream_b == NULL) return FALSE; if ((ADDRESSES_EQUAL(&(stream_a->src_addr), &(stream_b->dest_addr))) && (stream_a->src_port == stream_b->dest_port) && (ADDRESSES_EQUAL(&(stream_a->dest_addr), &(stream_b->src_addr))) && (stream_a->dest_port == stream_b->src_port)) return TRUE; else return FALSE; }
static sctp_assoc_info_t * add_address(address * vadd, sctp_assoc_info_t *info, guint8 direction) { GList *list; address *v=NULL; if (direction == 1) list = g_list_first(info->addr1); else list = g_list_first(info->addr2); while (list) { v = (address *) (list->data); if (ADDRESSES_EQUAL(vadd, v)) { g_free(vadd); return info; } list = g_list_next(list); } if (direction == 1) info->addr1 = g_list_append(info->addr1, vadd); else if (direction==2) info->addr2 = g_list_append(info->addr2, vadd); return info; }
/* GCompareFunc style comparison function for _rtp_stream_info */ gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb) { const struct _rtp_stream_info* a = (const struct _rtp_stream_info*)aa; const struct _rtp_stream_info* b = (const struct _rtp_stream_info*)bb; if (a==b) return 0; if (a==NULL || b==NULL) return 1; if (ADDRESSES_EQUAL(&(a->src_addr), &(b->src_addr)) && (a->src_port == b->src_port) && ADDRESSES_EQUAL(&(a->dest_addr), &(b->dest_addr)) && (a->dest_port == b->dest_port) && (a->ssrc == b->ssrc)) return 0; else return 1; }
/* checks if a packet matches the source/destination manually-configured in preferences */ static gboolean manual_addr_match(packet_info *pinfo) { if (gPREF_MAN_EN) { /* If the manual settings are enabled see if this fits - in which case we can skip the following checks entirely and go straight to dissecting */ if ( (ADDRESSES_EQUAL(&pinfo->src, &manual_addr[0]) && ADDRESSES_EQUAL(&pinfo->dst, &manual_addr[1]) && (pinfo->srcport == 0xffffffff /* is unknown */ || pinfo->srcport == gPREF_QP[0]) && (pinfo->destport == 0xffffffff /* is unknown */ || pinfo->destport == gPREF_QP[1])) || (ADDRESSES_EQUAL(&pinfo->src, &manual_addr[1]) && ADDRESSES_EQUAL(&pinfo->dst, &manual_addr[0]) && (pinfo->srcport == 0xffffffff /* is unknown */ || pinfo->srcport == gPREF_QP[1]) && (pinfo->destport == 0xffffffff /* is unknown */ || pinfo->destport == gPREF_QP[0])) ) return TRUE; } return FALSE; }
/* GCompareFunc style comparison function for _mcast_stream_info */ static gint mcast_stream_info_cmp(gconstpointer aa, gconstpointer bb) { const struct _mcast_stream_info* a = aa; const struct _mcast_stream_info* b = bb; if (a==b) return 0; if (a==NULL || b==NULL) return 1; if (ADDRESSES_EQUAL(&(a->src_addr), &(b->src_addr)) && (a->src_port == b->src_port) && ADDRESSES_EQUAL(&(a->dest_addr), &(b->dest_addr)) && (a->dest_port == b->dest_port)) return 0; else return 1; }
static gboolean is_broadcast(address* addr) { static address broadcast_addr; static const guint8 broadcast_addr_bytes[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; SET_ADDRESS(&broadcast_addr, AT_ETHER, 6, broadcast_addr_bytes); return ADDRESSES_EQUAL(addr, &broadcast_addr); }
WSLUA_METAMETHOD Address__eq(lua_State* L) { /* Compares two Addresses */ Address addr1 = checkAddress(L,1); Address addr2 = checkAddress(L,2); gboolean result = FALSE; if (ADDRESSES_EQUAL(addr1, addr2)) result = TRUE; lua_pushboolean(L,result); return 1; }
static sctp_assoc_info_t * add_chunk_count(address *vadd, sctp_assoc_info_t *info, guint32 direction, guint32 type) { GList *list; address *v=NULL; sctp_addr_chunk *ch=NULL; guint8 * dat; int i; list = g_list_first(info->addr_chunk_count); while (list) { ch = (sctp_addr_chunk *)(list->data); if (ch->direction == direction) { v = (address *) (ch->addr); if (ADDRESSES_EQUAL(vadd, v)) { if (IS_SCTP_CHUNK_TYPE(type)) ch->addr_count[type]++; else ch->addr_count[OTHER_CHUNKS_INDEX]++; return info; } else { list = g_list_next(list); } } else list = g_list_next(list); } ch = (sctp_addr_chunk *)g_malloc(sizeof(sctp_addr_chunk)); ch->direction = direction; ch->addr = (address *)g_malloc(sizeof(address)); ch->addr->type = vadd->type; ch->addr->len = vadd->len; dat = (guint8 *)g_malloc(vadd->len); memcpy(dat, vadd->data, vadd->len); ch->addr->data = dat; for (i=0; i < NUM_CHUNKS; i++) ch->addr_count[i] = 0; if (IS_SCTP_CHUNK_TYPE(type)) ch->addr_count[type]++; else ch->addr_count[OTHER_CHUNKS_INDEX]++; info->addr_chunk_count = g_list_append(info->addr_chunk_count, ch); return info; }
/* * Compare two host keys for an exact match. */ static gint host_match(gconstpointer v, gconstpointer w) { const host_key_t *v1 = (const host_key_t *)v; const host_key_t *v2 = (const host_key_t *)w; if (v1->port == v2->port && ADDRESSES_EQUAL(&v1->myaddress, &v2->myaddress)) { return 1; } /* * The addresses or the ports don't match. */ return 0; }
/* compare two bindings (except the interface related things, e.g. uuid) */ static gint decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b) { const decode_dcerpc_bind_values_t *binding_a = a; const decode_dcerpc_bind_values_t *binding_b = b; /* don't compare uuid and ver! */ if( ADDRESSES_EQUAL(&binding_a->addr_a, &binding_b->addr_a) && ADDRESSES_EQUAL(&binding_a->addr_b, &binding_b->addr_b) && binding_a->ptype == binding_b->ptype && binding_a->port_a == binding_b->port_a && binding_a->port_b == binding_b->port_b && binding_a->ctx_id == binding_b->ctx_id && binding_a->smb_fid == binding_b->smb_fid) { /* equal */ return 0; } /* unequal */ return 1; }
void reassemble_tcp( guint32 tcp_stream, guint32 sequence, guint32 acknowledgement, guint32 length, const char* data, guint32 data_length, int synflag, address *net_src, address *net_dst, guint srcport, guint dstport) { guint8 srcx[MAX_IPADDR_LEN], dstx[MAX_IPADDR_LEN]; int src_index, j, first = 0, len; guint32 newseq; tcp_frag *tmp_frag; tcp_stream_chunk sc; src_index = -1; /* First, check if this packet should be processed. */ if (find_tcp_index) { if ((port[0] == srcport && port[1] == dstport && ADDRESSES_EQUAL(&tcp_addr[0], net_src) && ADDRESSES_EQUAL(&tcp_addr[1], net_dst)) || (port[1] == srcport && port[0] == dstport && ADDRESSES_EQUAL(&tcp_addr[1], net_src) && ADDRESSES_EQUAL(&tcp_addr[0], net_dst))) { find_tcp_index = FALSE; tcp_stream_to_follow = tcp_stream; } else { return; } } else if ( tcp_stream != tcp_stream_to_follow ) return; if ((net_src->type != AT_IPv4 && net_src->type != AT_IPv6) || (net_dst->type != AT_IPv4 && net_dst->type != AT_IPv6)) return; if (net_src->type == AT_IPv4) len = 4; else len = 16; memcpy(srcx, net_src->data, len); memcpy(dstx, net_dst->data, len); /* follow_tcp_index() needs to learn address/port pairs */ if (find_tcp_addr) { find_tcp_addr = FALSE; memcpy(ip_address[0], net_src->data, net_src->len); port[0] = srcport; memcpy(ip_address[1], net_dst->data, net_dst->len); port[1] = dstport; } /* Check to see if we have seen this source IP and port before. (Yes, we have to check both source IP and port; the connection might be between two different ports on the same machine.) */ for( j=0; j<2; j++ ) { if (memcmp(src_addr[j], srcx, len) == 0 && src_port[j] == srcport ) { src_index = j; } } /* we didn't find it if src_index == -1 */ if( src_index < 0 ) { /* assign it to a src_index and get going */ for( j=0; j<2; j++ ) { if( src_port[j] == 0 ) { memcpy(src_addr[j], srcx, len); src_port[j] = srcport; src_index = j; first = 1; break; } } } if( src_index < 0 ) { fprintf( stderr, "ERROR in reassemble_tcp: Too many addresses!\n"); return; } if( data_length < length ) { incomplete_tcp_stream = TRUE; } /* Before adding data for this flow to the data_out_file, check whether * this frame acks fragments that were already seen. This happens when * frames are not in the capture file, but were actually seen by the * receiving host (Fixes bug 592). */ if( frags[1-src_index] ) { memcpy(sc.src_addr, dstx, len); sc.src_port = dstport; sc.dlen = 0; /* Will be filled in in check_fragments */ while ( check_fragments( 1-src_index, &sc, acknowledgement ) ) ; } /* Initialize our stream chunk. This data gets written to disk. */ memcpy(sc.src_addr, srcx, len); sc.src_port = srcport; sc.dlen = data_length; /* now that we have filed away the srcs, lets get the sequence number stuff figured out */ if( first ) { /* this is the first time we have seen this src's sequence number */ seq[src_index] = sequence + length; if( synflag ) { seq[src_index]++; } /* write out the packet data */ write_packet_data( src_index, &sc, data ); return; } /* if we are here, we have already seen this src, let's try and figure out if this packet is in the right place */ if( sequence < seq[src_index] ) { /* this sequence number seems dated, but check the end to make sure it has no more info than we have already seen */ newseq = sequence + length; if( newseq > seq[src_index] ) { guint32 new_len; /* this one has more than we have seen. let's get the payload that we have not seen. */ new_len = seq[src_index] - sequence; if ( data_length <= new_len ) { data = NULL; data_length = 0; incomplete_tcp_stream = TRUE; } else { data += new_len; data_length -= new_len; } sc.dlen = data_length; sequence = seq[src_index]; length = newseq - seq[src_index]; /* this will now appear to be right on time :) */ } } if ( sequence == seq[src_index] ) { /* right on time */ seq[src_index] += length; if( synflag ) seq[src_index]++; if( data ) { write_packet_data( src_index, &sc, data ); } /* done with the packet, see if it caused a fragment to fit */ while( check_fragments( src_index, &sc, 0 ) ) ; } else { /* out of order packet */ if(data_length > 0 && ((glong)(sequence - seq[src_index]) > 0) ) { tmp_frag = (tcp_frag *)g_malloc( sizeof( tcp_frag ) ); tmp_frag->data = (gchar *)g_malloc( data_length ); tmp_frag->seq = sequence; tmp_frag->len = length; tmp_frag->data_len = data_length; memcpy( tmp_frag->data, data, data_length ); if( frags[src_index] ) { tmp_frag->next = frags[src_index]; } else { tmp_frag->next = NULL; } frags[src_index] = tmp_frag; } } } /* end reassemble_tcp */
static void dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *ftp_tree = NULL; proto_tree *reqresp_tree = NULL; proto_item *ti, *hidden_item; gint offset = 0; const guchar *line; guint32 code; gchar code_str[4]; gboolean is_port_request = FALSE; gboolean is_pasv_response = FALSE; gboolean is_epasv_response = FALSE; gint next_offset; int linelen; int tokenlen; const guchar *next_token; guint32 pasv_ip; guint32 ftp_ip; guint16 ftp_port; address ftp_ip_address; gboolean ftp_nat; conversation_t *conversation; ftp_ip_address = pinfo->src; if (pinfo->match_uint == pinfo->destport) is_request = TRUE; else is_request = FALSE; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FTP"); /* * Find the end of the first line. * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); /* * Put the first line from the buffer into the summary * (but leave out the line terminator). */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "Request" : "Response", format_text(line, linelen)); if (tree) { ti = proto_tree_add_item(tree, proto_ftp, tvb, offset, -1, ENC_NA); ftp_tree = proto_item_add_subtree(ti, ett_ftp); if (is_request) { hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); } else { hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); } /* * Put the line into the protocol tree. */ ti = proto_tree_add_text(ftp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); reqresp_tree = proto_item_add_subtree(ti, ett_ftp_reqresp); } if (is_request) { /* * Extract the first token, and, if there is a first * token, add it as the request. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { if (tree) { proto_tree_add_item(reqresp_tree, hf_ftp_request_command, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); } if (strncmp(line, "PORT", tokenlen) == 0) is_port_request = TRUE; } } else { /* * This is a response; the response code is 3 digits, * followed by a space or hyphen, possibly followed by * text. * * If the line doesn't start with 3 digits, it's part of * a continuation. * * XXX - keep track of state in the first pass, and * treat non-continuation lines not beginning with digits * as errors? */ if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2])) { /* * One-line reply, or first or last line * of a multi-line reply. */ tvb_get_nstringz0(tvb, offset, sizeof(code_str), code_str); code = strtoul(code_str, NULL, 10); if (tree) { proto_tree_add_uint(reqresp_tree, hf_ftp_response_code, tvb, offset, 3, code); } /* * See if it's a passive-mode response. * * XXX - does anybody do FOOBAR, as per RFC * 1639, or has that been supplanted by RFC 2428? */ if (code == 227) is_pasv_response = TRUE; /* * Responses to EPSV command, as per RFC 2428 * XXX - handle IPv6? */ if (code == 229) is_epasv_response = TRUE; /* * Skip the 3 digits and, if present, the * space or hyphen. */ if (linelen >= 4) next_token = line + 4; else next_token = line + linelen; } else { /* * Line doesn't start with 3 digits; assume it's * a line in the middle of a multi-line reply. */ next_token = line; } } offset += (gint) (next_token - line); linelen -= (int) (next_token - line); line = next_token; if (tree) { /* * Add the rest of the first line as request or * reply data. */ if (linelen != 0) { if (is_request) { proto_tree_add_item(reqresp_tree, hf_ftp_request_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } else { proto_tree_add_item(reqresp_tree, hf_ftp_response_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } } offset = next_offset; } /* * If this is a PORT request or a PASV response, handle it. */ if (is_port_request) { if (parse_port_pasv(line, linelen, &ftp_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip, tvb, 0, 0, ftp_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_active_port, tvb, 0, 0, ftp_port); } SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&ftp_ip); ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean( reqresp_tree, hf_ftp_active_nat, tvb, 0, 0, ftp_nat); } } } } if (is_pasv_response) { if (linelen != 0) { /* * This frame contains a PASV response; set up a * conversation for the data. */ if (parse_port_pasv(line, linelen, &pasv_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_pasv_ip, tvb, 0, 0, pasv_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, 0, 0, ftp_port); } SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&pasv_ip); ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean(reqresp_tree, hf_ftp_pasv_nat, tvb, 0, 0, ftp_nat); } } /* * We use "ftp_ip_address", so that if * we're NAT'd we look for the un-NAT'd * connection. * * XXX - should this call to * "find_conversation()" just use * "ftp_ip_address" and "server_port", and * wildcard everything else? */ conversation = find_conversation(pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { /* * XXX - should this call to "conversation_new()" * just use "ftp_ip_address" and "server_port", * and wildcard everything else? * * XXX - what if we did find a conversation? As * we create it only on the first pass through the * packets, if we find one, it's presumably an * unrelated conversation. Should we remove the * old one from the hash table and put this one in * its place? Can the conversation code handle * conversations not in the hash table? Or should * we make conversations support start and end * frames, as circuits do, and treat this as an * indication that one conversation was closed and * a new one was opened? */ conversation = conversation_new( pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (is_epasv_response) { if (linelen != 0) { /* * This frame contains an EPSV response; set up a * conversation for the data. */ if (parse_extended_pasv_response(line, linelen, &ftp_port)) { /* Add port number to tree */ if (tree) { proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, 0, 0, ftp_port); } /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (tree) { /* * Show the rest of the request or response as text, * a line at a time. * XXX - only if there's a continuation indicator? */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_text(ftp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
static int dissect_slimp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { const char *opcode_str; proto_tree *slimp3_tree = NULL; proto_item *ti = NULL, *hidden_item; gint i1; gint offset = 0; guint16 opcode; guchar lcd_char; char lcd_str[MAX_LCD_STR_LEN + 1]; int to_server = FALSE; int old_protocol = FALSE; address tmp_addr; gboolean in_str; int lcd_strlen; /* * If it doesn't begin with a known opcode, reject it, so that * traffic that happens to be do or from one of our ports * doesn't get misidentified as SliMP3 traffic. */ if (!tvb_bytes_exist(tvb, offset, 1)) return 0; /* not even an opcode */ opcode = tvb_get_guint8(tvb, offset); opcode_str = match_strval(opcode, slimp3_opcode_vals); if (opcode_str == NULL) return 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SliMP3"); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, opcode_str); } if (tree) { ti = proto_tree_add_item(tree, proto_slimp3, tvb, offset, -1, ENC_NA); slimp3_tree = proto_item_add_subtree(ti, ett_slimp3); proto_tree_add_uint(slimp3_tree, hf_slimp3_opcode, tvb, offset, 1, opcode); } /* The new protocol (v1.3 and later) uses an IANA-assigned port number. * It usually uses the same number for both sizes of the conversation, so * the port numbers can't always be used to determine client and server. * The new protocol places the clients MAC address in the packet, so that * is used to identify packets originating at the client. */ if ((pinfo->destport == UDP_PORT_SLIMP3_V2) && (pinfo->srcport == UDP_PORT_SLIMP3_V2)) { SET_ADDRESS(&tmp_addr, AT_ETHER, 6, tvb_get_ptr(tvb, offset+12, 6)); to_server = ADDRESSES_EQUAL(&tmp_addr, &pinfo->dl_src); } else if (pinfo->destport == UDP_PORT_SLIMP3_V2) { to_server = TRUE; } else if (pinfo->srcport == UDP_PORT_SLIMP3_V2) { to_server = FALSE; } if (pinfo->destport == UDP_PORT_SLIMP3_V1) { to_server = TRUE; old_protocol = TRUE; } else if (pinfo->srcport == UDP_PORT_SLIMP3_V1) { to_server = FALSE; old_protocol = TRUE; } switch (opcode) { case SLIMP3_IR: /* IR code * * [0] 'i' as in "IR" * [1] 0x00 * [2..5] player's time since startup in ticks @625 KHz * [6] IR code id, ff=JVC, 02=SLIMP3 * [7] number of meaningful bits - 16 for JVC, 32 for SLIMP3 * [8..11] the 32-bit IR code * [12..17] reserved */ if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_ir, tvb, offset+8, 4, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); i1 = tvb_get_ntohl(tvb, offset+2); proto_tree_add_text(slimp3_tree, tvb, offset+2, 4, "Uptime: %u sec (%u ticks)", i1/625000, i1); i1 = tvb_get_guint8(tvb, offset+6); proto_tree_add_text(slimp3_tree, tvb, offset+6, 1, "Code identifier: 0x%0x: %s", i1, val_to_str(i1, slimp3_ir_types, "Unknown")); proto_tree_add_text(slimp3_tree, tvb, offset+7, 1, "Code bits: %d", tvb_get_guint8(tvb, offset+7)); i1 = tvb_get_ntohl(tvb, offset+8); /* Check the code to figure out which remote is being used. */ if (tvb_get_guint8(tvb, offset+6) == 0x02 && tvb_get_guint8(tvb, offset+7) == 32) { /* This is the custom SLIMP3 remote. */ proto_tree_add_text(slimp3_tree, tvb, offset+8, 4, "Infrared Code: %s: 0x%0x", val_to_str(i1, slimp3_ir_codes_slimp3, "Unknown"), i1); } else if (tvb_get_guint8(tvb, offset+6) == 0xff && tvb_get_guint8(tvb, offset+7) == 16) { /* This is a JVC DVD player remote */ proto_tree_add_text(slimp3_tree, tvb, offset+8, 4, "Infrared Code: %s: 0x%0x", val_to_str(i1, slimp3_ir_codes_jvc, "Unknown"), i1); } else { /* Unknown code; just write it */ proto_tree_add_text(slimp3_tree, tvb, offset+8, 4, "Infrared Code: 0x%0x", i1); } } if (check_col(pinfo->cinfo, COL_INFO)) { i1 = tvb_get_ntohl(tvb, offset+8); if (tvb_get_guint8(tvb, offset+6) == 0x02 && tvb_get_guint8(tvb, offset+7) == 32) { col_append_fstr(pinfo->cinfo, COL_INFO, ", SLIMP3: %s", val_to_str(i1, slimp3_ir_codes_slimp3, "Unknown (0x%0x)")); } else if (tvb_get_guint8(tvb, offset+6) == 0xff && tvb_get_guint8(tvb, offset+7) == 16) { col_append_fstr(pinfo->cinfo, COL_INFO, ", JVC: %s", val_to_str(i1, slimp3_ir_codes_jvc, "Unknown (0x%0x)")); } else { /* Unknown code; just write it */ col_append_fstr(pinfo->cinfo, COL_INFO, ", 0x%0x", i1); } } break; case SLIMP3_DISPLAY: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_display, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); /* Loop through the commands */ i1 = 18; in_str = FALSE; lcd_strlen = 0; while (i1 < tvb_reported_length_remaining(tvb, offset)) { switch(tvb_get_guint8(tvb, offset + i1)) { case 0: in_str = FALSE; lcd_strlen = 0; proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "Delay (%d ms)", tvb_get_guint8(tvb, offset + i1 + 1)); i1 += 2; break; case 3: lcd_char = tvb_get_guint8(tvb, offset + i1 + 1); if (!isprint(lcd_char)) lcd_char = '.'; if (ti && in_str) { lcd_strlen += 2; proto_item_append_text(ti, "%c", lcd_char); proto_item_set_len(ti, lcd_strlen); } else { ti = proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "String: %c", lcd_char); in_str = TRUE; lcd_strlen = 2; } i1 += 2; break; case 2: in_str = FALSE; lcd_strlen = 0; ti = proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "Command: %s", val_to_str(tvb_get_guint8(tvb, offset + i1 + 1), slimp3_display_commands, "Unknown (0x%0x)")); if ((tvb_get_guint8(tvb, offset + i1 + 1) & 0xf0) == 0x30) { proto_item_append_text(ti, ": %s", val_to_str(tvb_get_guint8(tvb, offset + i1 + 2), slimp3_display_fset8, "Unknown (0x%0x)")); i1 += 2; } i1 += 2; break; default: proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "Unknown 0x%0x, 0x%0x", tvb_get_guint8(tvb, offset + i1), tvb_get_guint8(tvb, offset + i1 + 1)); i1 += 2; break; } } } if (check_col(pinfo->cinfo, COL_INFO)) { i1 = 18; lcd_strlen = 0; while (tvb_offset_exists(tvb, offset + i1) && lcd_strlen < MAX_LCD_STR_LEN) { switch (tvb_get_guint8(tvb, offset + i1)) { case 0: lcd_str[lcd_strlen++] = '.'; break; case 2: lcd_str[lcd_strlen++] = '|'; if (tvb_offset_exists(tvb, offset + i1 + 1) && (tvb_get_guint8(tvb, offset + i1 + 1) & 0xf0) == 0x30) i1 += 2; break; case 3: if (tvb_offset_exists(tvb, offset + i1 + 1)) { if (lcd_strlen < 1 || lcd_str[lcd_strlen-1] != ' ' || tvb_get_guint8(tvb, offset + i1 + 1) != ' ') { lcd_char = tvb_get_guint8(tvb, offset + i1 + 1); lcd_str[lcd_strlen++] = isprint(lcd_char) ? lcd_char : '.'; } } } i1 += 2; } lcd_str[lcd_strlen] = '\0'; if (lcd_strlen > 0) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", lcd_str); } break; case SLIMP3_CONTROL: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_control, tvb, offset+1, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Command: %s", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_stream_control, "Unknown (0x%0x)")); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_stream_control, "Unknown (0x%0x)")); } break; case SLIMP3_HELLO: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_hello, tvb, offset+1, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); if (to_server) { guint8 fw_ver = 0; /* Hello response; client->server */ proto_tree_add_text(slimp3_tree, tvb, offset, 1, "Hello Response (Client --> Server)"); proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Device ID: %d", tvb_get_guint8(tvb, offset+1)); fw_ver = tvb_get_guint8(tvb, offset+2); proto_tree_add_text(slimp3_tree, tvb, offset+2, 1, "Firmware Revision: %d.%d (0x%0x)", fw_ver>>4, fw_ver & 0xf, fw_ver); } else { /* Hello request; server->client */ proto_tree_add_text(slimp3_tree, tvb, offset, 1, "Hello Request (Server --> Client)"); } } break; case SLIMP3_I2C: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_i2c, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); if (to_server) { /* Hello response; client->server */ proto_tree_add_text(slimp3_tree, tvb, offset, -1, "I2C Response (Client --> Server)"); } else { /* Hello request; server->client */ proto_tree_add_text(slimp3_tree, tvb, offset, -1, "I2C Request (Server --> Client)"); } } if (check_col(pinfo->cinfo, COL_INFO)) { if (to_server) { col_append_str(pinfo->cinfo, COL_INFO, ", Response"); } else { col_append_str(pinfo->cinfo, COL_INFO, ", Request"); } } break; case SLIMP3_DATA_REQ: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_data_request, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_text(slimp3_tree, tvb, offset+2, 2, "Requested offset: %d bytes.", tvb_get_ntohs(tvb, offset+2)*2); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Offset: %d bytes", tvb_get_ntohs(tvb, offset+2)*2); } break; case SLIMP3_DATA: /* MPEG data (v1.3 and later) * * [0] 'm' * [1..5] reserved * [6..7] Write pointer (in words) * [8..9] reserved * [10..11] Sequence number * [12..17] reserved * [18..] MPEG data */ if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_data, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); if (old_protocol) { proto_tree_add_text(slimp3_tree, tvb, offset, -1, "Length: %d bytes", tvb_reported_length_remaining(tvb, offset+18)); proto_tree_add_text(slimp3_tree, tvb, offset+2, 2, "Buffer offset: %d bytes.", tvb_get_ntohs(tvb, offset+2) * 2); } else { proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Command: %s", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_mpg_control, "Unknown (0x%0x)")); proto_tree_add_text(slimp3_tree, tvb, offset, -1, "Length: %d bytes", tvb_reported_length_remaining(tvb, offset+18)); proto_tree_add_text(slimp3_tree, tvb, offset+6, 2, "Write Pointer: %d", tvb_get_ntohs(tvb, offset+6) * 2); proto_tree_add_text(slimp3_tree, tvb, offset+10, 2, "Sequence: %d", tvb_get_ntohs(tvb, offset+10)); } } if (check_col(pinfo->cinfo, COL_INFO)) { if (old_protocol) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Length: %d bytes, Offset: %d bytes.", tvb_reported_length_remaining(tvb, offset+18), tvb_get_ntohs(tvb, offset+2) * 2); } else { col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, %d bytes at %d, Sequence: %d", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_mpg_control, "Unknown (0x%0x)"), tvb_reported_length_remaining(tvb, offset+18), tvb_get_ntohs(tvb, offset+6) * 2, tvb_get_ntohs(tvb, offset+10)); } } break; case SLIMP3_DISC_REQ: if (tree) { guint8 fw_ver; hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_discover_request, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Device ID: %d.", tvb_get_guint8(tvb, offset+1)); fw_ver = tvb_get_guint8(tvb, offset+2); proto_tree_add_text(slimp3_tree, tvb, offset+2, 1, "Firmware Revision: %d.%d (0x%0x)", fw_ver>>4, fw_ver & 0xf, fw_ver); } if (check_col(pinfo->cinfo, COL_INFO)) { guint8 fw_ver = tvb_get_guint8(tvb, offset+2); col_append_fstr(pinfo->cinfo, COL_INFO, ", Device ID: %d. Firmware: %d.%d", tvb_get_guint8(tvb, offset+1), fw_ver>>4, fw_ver & 0xf); }
Iax2AnalysisDialog::Iax2AnalysisDialog(QWidget &parent, CaptureFile &cf) : WiresharkDialog(parent, cf), ui(new Ui::Iax2AnalysisDialog), port_src_fwd_(0), port_dst_fwd_(0), port_src_rev_(0), port_dst_rev_(0) { ui->setupUi(this); setWindowSubtitle(tr("IAX2 Stream Analysis")); // XXX Use recent settings instead resize(parent.width() * 4 / 5, parent.height() * 4 / 5); ui->progressFrame->hide(); stream_ctx_menu_.addAction(ui->actionGoToPacket); stream_ctx_menu_.addAction(ui->actionNextProblem); stream_ctx_menu_.addSeparator(); stream_ctx_menu_.addAction(ui->actionSaveAudio); stream_ctx_menu_.addAction(ui->actionSaveForwardAudio); stream_ctx_menu_.addAction(ui->actionSaveReverseAudio); stream_ctx_menu_.addSeparator(); stream_ctx_menu_.addAction(ui->actionSaveCsv); stream_ctx_menu_.addAction(ui->actionSaveForwardCsv); stream_ctx_menu_.addAction(ui->actionSaveReverseCsv); stream_ctx_menu_.addSeparator(); stream_ctx_menu_.addAction(ui->actionSaveGraph); ui->forwardTreeWidget->installEventFilter(this); ui->forwardTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->forwardTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showStreamMenu(QPoint))); ui->reverseTreeWidget->installEventFilter(this); ui->reverseTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->reverseTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showStreamMenu(QPoint))); connect(ui->streamGraph, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(graphClicked(QMouseEvent*))); graph_ctx_menu_.addAction(ui->actionSaveGraph); QStringList header_labels; for (int i = 0; i < ui->forwardTreeWidget->columnCount(); i++) { header_labels << ui->forwardTreeWidget->headerItem()->text(i); } ui->reverseTreeWidget->setHeaderLabels(header_labels); memset(&src_fwd_, 0, sizeof(address)); memset(&dst_fwd_, 0, sizeof(address)); memset(&src_rev_, 0, sizeof(address)); memset(&dst_rev_, 0, sizeof(address)); QList<QCheckBox *> graph_cbs = QList<QCheckBox *>() << ui->fJitterCheckBox << ui->fDiffCheckBox << ui->rJitterCheckBox << ui->rDiffCheckBox; for (int i = 0; i < num_graphs_; i++) { QCPGraph *graph = ui->streamGraph->addGraph(); graph->setPen(QPen(ColorUtils::graph_colors_[i])); graph->setName(graph_cbs[i]->text()); graphs_ << graph; graph_cbs[i]->setChecked(true); graph_cbs[i]->setIcon(StockIcon::colorIcon(ColorUtils::graph_colors_[i], QPalette::Text)); } ui->streamGraph->xAxis->setLabel("Arrival Time"); ui->streamGraph->yAxis->setLabel("Value (ms)"); // We keep our temp files open for the lifetime of the dialog. The GTK+ // UI opens and closes at various points. QString tempname = QString("%1/wireshark_iax2_f").arg(QDir::tempPath()); fwd_tempfile_ = new QTemporaryFile(tempname, this); fwd_tempfile_->open(); tempname = QString("%1/wireshark_iax2_r").arg(QDir::tempPath()); rev_tempfile_ = new QTemporaryFile(tempname, this); rev_tempfile_->open(); if (fwd_tempfile_->error() != QFile::NoError || rev_tempfile_->error() != QFile::NoError) { err_str_ = tr("Unable to save RTP data."); ui->actionSaveAudio->setEnabled(false); ui->actionSaveForwardAudio->setEnabled(false); ui->actionSaveReverseAudio->setEnabled(false); } QMenu *save_menu = new QMenu(); save_menu->addAction(ui->actionSaveAudio); save_menu->addAction(ui->actionSaveForwardAudio); save_menu->addAction(ui->actionSaveReverseAudio); save_menu->addSeparator(); save_menu->addAction(ui->actionSaveCsv); save_menu->addAction(ui->actionSaveForwardCsv); save_menu->addAction(ui->actionSaveReverseCsv); save_menu->addSeparator(); save_menu->addAction(ui->actionSaveGraph); ui->buttonBox->button(QDialogButtonBox::Save)->setMenu(save_menu); const gchar *filter_text = "iax2 && (ip || ipv6)"; dfilter_t *sfcode; gchar *err_msg; if (!dfilter_compile(filter_text, &sfcode, &err_msg)) { QMessageBox::warning(this, tr("No IAX2 packets found"), QString("%1").arg(err_msg)); g_free(err_msg); close(); } if (!cap_file_.capFile() || !cap_file_.capFile()->current_frame) close(); frame_data *fdata = cap_file_.capFile()->current_frame; if (!cf_read_record(cap_file_.capFile(), fdata)) close(); epan_dissect_t edt; epan_dissect_init(&edt, cap_file_.capFile()->epan, TRUE, FALSE); epan_dissect_prime_dfilter(&edt, sfcode); epan_dissect_run(&edt, cap_file_.capFile()->cd_t, &cap_file_.capFile()->phdr, frame_tvbuff_new_buffer(fdata, &cap_file_.capFile()->buf), fdata, NULL); // This shouldn't happen (the menu item should be disabled) but check anyway if (!dfilter_apply_edt(sfcode, &edt)) { epan_dissect_cleanup(&edt); dfilter_free(sfcode); err_str_ = tr("Please select an IAX2 packet"); updateWidgets(); return; } dfilter_free(sfcode); /* ok, it is a IAX2 frame, so let's get the ip and port values */ COPY_ADDRESS(&(src_fwd_), &(edt.pi.src)); COPY_ADDRESS(&(dst_fwd_), &(edt.pi.dst)); port_src_fwd_ = edt.pi.srcport; port_dst_fwd_ = edt.pi.destport; /* assume the inverse ip/port combination for the reverse direction */ COPY_ADDRESS(&(src_rev_), &(edt.pi.dst)); COPY_ADDRESS(&(dst_rev_), &(edt.pi.src)); port_src_rev_ = edt.pi.destport; port_dst_rev_ = edt.pi.srcport; #if 0 /* check if it is Voice or MiniPacket */ bool ok; getIntFromProtoTree(edt.tree, "iax2", "iax2.call", &ok); if (!ok) { err_str_ = tr("Please select an IAX2 packet."); updateWidgets(); return; } #endif #ifdef IAX2_RTP_STREAM_CHECK rtpstream_tapinfot tapinfo; /* Register the tap listener */ memset(&tapinfo, 0, sizeof(rtpstream_tapinfot)); tapinfo.tap_data = this; tapinfo.mode = TAP_ANALYSE; // register_tap_listener_rtp_stream(&tapinfo, NULL); /* Scan for RTP streams (redissect all packets) */ rtpstream_scan(&tapinfo, cap_file_.capFile(), NULL); int num_streams = 0; GList *filtered_list = NULL; for (GList *strinfo_list = g_list_first(tapinfo.strinfo_list); strinfo_list; strinfo_list = g_list_next(strinfo_list)) { rtp_stream_info_t * strinfo = (rtp_stream_info_t*)(strinfo_list->data); << address_to_qstring(&strinfo->dest_addr) << address_to_qstring(&src_rev_) << address_to_qstring(&dst_rev_); if (ADDRESSES_EQUAL(&(strinfo->src_addr), &(src_fwd_)) && (strinfo->src_port == port_src_fwd_) && (ADDRESSES_EQUAL(&(strinfo->dest_addr), &(dst_fwd_))) && (strinfo->dest_port == port_dst_fwd_)) { ++num_streams; filtered_list = g_list_prepend(filtered_list, strinfo); } if (ADDRESSES_EQUAL(&(strinfo->src_addr), &(src_rev_)) && (strinfo->src_port == port_src_rev_) && (ADDRESSES_EQUAL(&(strinfo->dest_addr), &(dst_rev_))) && (strinfo->dest_port == port_dst_rev_)) { ++num_streams; filtered_list = g_list_append(filtered_list, strinfo); } }
/* initialize the tap t38_info and the conversation */ static void init_t38_info_conv(packet_info *pinfo) { /* tap info */ t38_info_current++; if (t38_info_current==MAX_T38_MESSAGES_IN_PACKET) { t38_info_current=0; } t38_info = &t38_info_arr[t38_info_current]; t38_info->seq_num = 0; t38_info->type_msg = 0; t38_info->data_value = 0; t38_info->t30ind_value =0; t38_info->setup_frame_number = 0; t38_info->Data_Field_field_type_value = 0; t38_info->desc[0] = '\0'; t38_info->desc_comment[0] = '\0'; t38_info->time_first_t4_data = 0; t38_info->frame_num_first_t4_data = 0; /* p_t38_packet_conv hold the conversation info in each of the packets. p_t38_conv hold the conversation info used to reassemble the HDLC packets, and also the Setup info (e.g SDP) If we already have p_t38_packet_conv in the packet, it means we already reassembled the HDLC packets, so we don't need to use p_t38_conv */ p_t38_packet_conv = NULL; p_t38_conv = NULL; /* Use existing packet info if available */ p_t38_packet_conv = (t38_conv *)p_get_proto_data(wmem_file_scope(), pinfo, proto_t38, 0); /* find the conversation used for Reassemble and Setup Info */ p_conv = find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src, pinfo->ptype, pinfo->destport, pinfo->srcport, NO_ADDR_B | NO_PORT_B); /* create a conv if it doen't exist */ if (!p_conv) { p_conv = conversation_new(pinfo->fd->num, &pinfo->net_src, &pinfo->net_dst, pinfo->ptype, pinfo->srcport, pinfo->destport, NO_ADDR_B | NO_PORT_B); /* Set dissector */ conversation_set_dissector(p_conv, t38_udp_handle); } if (!p_t38_packet_conv) { p_t38_conv = (t38_conv *)conversation_get_proto_data(p_conv, proto_t38); /* create the conversation if it doen't exist */ if (!p_t38_conv) { p_t38_conv = wmem_new(wmem_file_scope(), t38_conv); p_t38_conv->setup_method[0] = '\0'; p_t38_conv->setup_frame_number = 0; p_t38_conv->src_t38_info.reass_ID = 0; p_t38_conv->src_t38_info.reass_start_seqnum = -1; p_t38_conv->src_t38_info.reass_data_type = 0; p_t38_conv->src_t38_info.last_seqnum = -1; p_t38_conv->src_t38_info.packet_lost = 0; p_t38_conv->src_t38_info.burst_lost = 0; p_t38_conv->src_t38_info.time_first_t4_data = 0; p_t38_conv->src_t38_info.additional_hdlc_data_field_counter = 0; p_t38_conv->src_t38_info.seqnum_prev_data_field = -1; p_t38_conv->dst_t38_info.reass_ID = 0; p_t38_conv->dst_t38_info.reass_start_seqnum = -1; p_t38_conv->dst_t38_info.reass_data_type = 0; p_t38_conv->dst_t38_info.last_seqnum = -1; p_t38_conv->dst_t38_info.packet_lost = 0; p_t38_conv->dst_t38_info.burst_lost = 0; p_t38_conv->dst_t38_info.time_first_t4_data = 0; p_t38_conv->dst_t38_info.additional_hdlc_data_field_counter = 0; p_t38_conv->dst_t38_info.seqnum_prev_data_field = -1; conversation_add_proto_data(p_conv, proto_t38, p_t38_conv); } /* copy the t38 conversation info to the packet t38 conversation */ p_t38_packet_conv = wmem_new(wmem_file_scope(), t38_conv); g_strlcpy(p_t38_packet_conv->setup_method, p_t38_conv->setup_method, MAX_T38_SETUP_METHOD_SIZE); p_t38_packet_conv->setup_frame_number = p_t38_conv->setup_frame_number; memcpy(&(p_t38_packet_conv->src_t38_info), &(p_t38_conv->src_t38_info), sizeof(t38_conv_info)); memcpy(&(p_t38_packet_conv->dst_t38_info), &(p_t38_conv->dst_t38_info), sizeof(t38_conv_info)); p_add_proto_data(wmem_file_scope(), pinfo, proto_t38, 0, p_t38_packet_conv); } if (ADDRESSES_EQUAL(&p_conv->key_ptr->addr1, &pinfo->net_src)) { p_t38_conv_info = &(p_t38_conv->src_t38_info); p_t38_packet_conv_info = &(p_t38_packet_conv->src_t38_info); } else { p_t38_conv_info = &(p_t38_conv->dst_t38_info); p_t38_packet_conv_info = &(p_t38_packet_conv->dst_t38_info); } /* update t38_info */ t38_info->setup_frame_number = p_t38_packet_conv->setup_frame_number; }
//Copy from ui/gtk/follow_ssl.c static int ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *ssl) { Q_UNUSED(edt); follow_info_t * follow_info = (follow_info_t*) tapdata; SslDecryptedRecord * rec = NULL; SslDataInfo * appl_data = NULL; int proto_ssl = GPOINTER_TO_INT(ssl); SslPacketInfo * pi = NULL; show_stream_t from = FROM_CLIENT; /* Skip packets without decrypted payload data. */ pi = (SslPacketInfo*) p_get_proto_data(wmem_file_scope(), pinfo, proto_ssl, 0); if (!pi || !pi->appl_data) return 0; /* Compute the packet's sender. */ if (follow_info->client_port == 0) { follow_info->client_port = pinfo->srcport; copy_address(&follow_info->client_ip, &pinfo->src); } if (ADDRESSES_EQUAL(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport) { from = FROM_CLIENT; } else { from = FROM_SERVER; } for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) { /* TCP segments that contain the end of two or more SSL PDUs will be queued to SSL taps for each of those PDUs. Therefore a single packet could be processed by this SSL tap listener multiple times. The following test handles that scenario by treating the follow_info->bytes_written[] values as the next expected appl_data->seq. Any appl_data instances that fall below that have already been processed and must be skipped. */ if (appl_data->seq < follow_info->bytes_written[from]) continue; /* Allocate a SslDecryptedRecord to hold the current appl_data instance's decrypted data. Even though it would be possible to consolidate multiple appl_data instances into a single rec, it is beneficial to use a one-to-one mapping. This affords the Follow Stream dialog view modes (ASCII, EBCDIC, Hex Dump, C Arrays, Raw) the opportunity to accurately reflect SSL PDU boundaries. Currently the Hex Dump view does by starting a new line, and the C Arrays view does by starting a new array declaration. */ rec = (SslDecryptedRecord*) g_malloc(sizeof(SslDecryptedRecord) + appl_data->plain_data.data_len); rec->is_from_server = from == FROM_SERVER; rec->packet_num = pinfo->fd->num; rec->data.data = (guchar*) (rec + 1); rec->data.data_len = appl_data->plain_data.data_len; memcpy(rec->data.data, appl_data->plain_data.data, appl_data->plain_data.data_len); /* Append the record to the follow_info structure. */ follow_info->payload = g_list_append(follow_info->payload, rec); follow_info->bytes_written[from] += rec->data.data_len; } return 0; }