//Copy from ui/gtk/follow_udp.c static gboolean udp_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *, const void *data) { follow_record_t *follow_record; follow_info_t *follow_info = (follow_info_t *)tapdata; tvbuff_t *next_tvb = (tvbuff_t *)data; follow_record = g_new(follow_record_t,1); follow_record->data = g_byte_array_sized_new(tvb_captured_length(next_tvb)); follow_record->data = g_byte_array_append(follow_record->data, tvb_get_ptr(next_tvb, 0, -1), tvb_captured_length(next_tvb)); follow_record->packet_num = pinfo->fd->num; 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) follow_record->is_server = FALSE; else follow_record->is_server = TRUE; /* update stream counter */ follow_info->bytes_written[follow_record->is_server] += follow_record->data->len; follow_info->payload = g_list_append(follow_info->payload, follow_record); return FALSE; }
/* * Compare the address 1 and port 1 in the two conversation keys. * 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_addr2_or_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 and the first * and second address 1 values the same? */ if (v1->port1 == v2->port1 && addresses_equal(&v1->addr1, &v2->addr1)) { /* * 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; }
static sctp_assoc_info_t * add_address(address *vadd, sctp_assoc_info_t *info, guint16 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; }
//Copy from ui/gtk/follow_ssl.c static gboolean ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *, const void *ssl) { 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 FALSE; }
/* 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 _rtp_stream_info */ static 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; }
/* compare two ids by flags */ gboolean rtpstream_id_equal(const rtpstream_id_t *id1, const rtpstream_id_t *id2, guint flags) { if (addresses_equal(&(id1->src_addr), &(id2->src_addr)) && id1->src_port == id2->src_port && addresses_equal(&(id1->dst_addr), &(id2->dst_addr)) && id1->dst_port == id2->dst_port) { gboolean equal = TRUE; if ((flags & RTPSTREAM_ID_EQUAL_SSRC) && id1->ssrc != id2->ssrc) { equal = FALSE; } return equal; } return FALSE; }
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); }
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; }
void update(wlan_hdr_t *wlan_hdr) { bool is_sender = addresses_equal(&addr_, &wlan_hdr->src); // XXX Should we count received probes and auths? This is what the // GTK+ UI does, but it seems odd. switch (wlan_hdr->type) { case MGT_PROBE_REQ: probe_req_++; break; case MGT_PROBE_RESP: probe_resp_++; break; case MGT_BEACON: // Skip break; case MGT_AUTHENTICATION: auth_++; break; case MGT_DEAUTHENTICATION: deauth_++; break; case DATA: case DATA_CF_ACK: case DATA_CF_POLL: case DATA_CF_ACK_POLL: case DATA_QOS_DATA: case DATA_QOS_DATA_CF_ACK: case DATA_QOS_DATA_CF_POLL: case DATA_QOS_DATA_CF_ACK_POLL: if (is_sender) { sent_++; } else { received_++; } break; default: other_++; break; } if (wlan_hdr->type != MGT_BEACON) packets_++; }
static void dissect_macctrl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti, *opcode_item; proto_tree *macctrl_tree = NULL; proto_tree *pause_times_tree = NULL; guint16 opcode; guint16 pause_time; int i; col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC CTRL"); col_clear(pinfo->cinfo, COL_INFO); opcode = tvb_get_ntohs(tvb, 0); ti = proto_tree_add_item(tree, proto_macctrl, tvb, 0, 46, ENC_NA); macctrl_tree = proto_item_add_subtree(ti, ett_macctrl); opcode_item = proto_tree_add_uint(macctrl_tree, hf_macctrl_opcode, tvb, 0, 2, opcode); proto_tree_add_item(macctrl_tree, hf_macctrl_timestamp, tvb, 2, 4, ENC_BIG_ENDIAN); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, opcode_vals, "Unknown")); switch (opcode) { case MACCTRL_PAUSE: if (!addresses_equal(&pinfo->dst, &macctrl_dst_address)) { expert_add_info(pinfo, opcode_item, &ei_macctrl_dst_address); } pause_time = tvb_get_ntohs(tvb, 6); col_append_fstr(pinfo->cinfo, COL_INFO, ": pause_time: %u quanta", pause_time); proto_tree_add_uint(macctrl_tree, hf_macctrl_pause_time, tvb, 6, 2, pause_time); break; case MACCTRL_GATE: break; case MACCTRL_REPORT: break; case MACCTRL_REGISTER_REQ: /* Flags */ proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb, 6, 1, ENC_NA); /* Pending Grants */ proto_tree_add_item(macctrl_tree, hf_reg_req_grants, tvb, 7, 1, ENC_NA); break; case MACCTRL_REGISTER: /* Assigned Port */ proto_tree_add_item(macctrl_tree, hf_reg_port, tvb, 6, 2, ENC_BIG_ENDIAN); /* Flags */ proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb, 8, 1, ENC_NA); /* Synch Time */ proto_tree_add_item(macctrl_tree, hf_reg_time, tvb, 9, 2, ENC_BIG_ENDIAN); /* Echoed Pending Grants */ proto_tree_add_item(macctrl_tree, hf_reg_grants, tvb, 11, 1, ENC_NA); break; case MACCTRL_REGISTER_ACK: /* Flags */ proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb, 6, 1, ENC_NA); /* Echoed Assigned Port */ proto_tree_add_item(macctrl_tree, hf_reg_ack_port, tvb, 7, 2, ENC_BIG_ENDIAN); /* Echoed Synch Time */ proto_tree_add_item(macctrl_tree, hf_reg_ack_time, tvb, 9, 2, ENC_BIG_ENDIAN); break; case MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE: if (!addresses_equal(&pinfo->dst, &macctrl_dst_address)) { expert_add_info(pinfo, opcode_item, &ei_macctrl_dst_address); } ti = proto_tree_add_bitmask(macctrl_tree, tvb, 2, hf_macctrl_cbfc_enbv, ett_macctrl_cbfc_enbv, macctrl_cbfc_enbv_list, ENC_BIG_ENDIAN); if (tvb_get_guint8(tvb, 2) != 0) { expert_add_info(pinfo, ti, &ei_macctrl_cbfc_enbv); } pause_times_tree = proto_tree_add_subtree(macctrl_tree, tvb, 4, 8*2, ett_macctrl_cbfc_pause_times, NULL, "CBFC Class Pause Times"); for (i=0; i<8; i++) { proto_tree_add_item(pause_times_tree, *macctrl_cbfc_pause_times_list[i], tvb, 4+i*2, 2, ENC_BIG_ENDIAN); } break; default: expert_add_info(pinfo, opcode_item, &ei_macctrl_opcode); break; } }
bool isMatch(address *addr) { return addresses_equal(&addr_, addr); }
bool isMatch(wlan_hdr_t *wlan_hdr) { bool is_bssid_match = false; bool is_ssid_match = false; bool update_bssid = false; bool update_ssid = false; // We want (but might not have) a unicast BSSID and a named SSID. Try // to match the current packet and update our information if possible. if (addresses_equal(&bssid_, &wlan_hdr->bssid)) { is_bssid_match = true; } if ((wlan_hdr->stats.ssid_len > 0) && (wlan_hdr->stats.ssid[0] != 0)) { QByteArray hdr_ssid = QByteArray::fromRawData((const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len); if (ssid_ == hdr_ssid) { is_ssid_match = true; } } if (is_bssid_match && is_ssid_match) return true; // Probe requests. if (wlan_hdr->type == MGT_PROBE_REQ) { // Probes with visible SSIDs. Unicast or broadcast. if (is_ssid_match) { if (is_broadcast_ && !is_broadcast_bssid(&wlan_hdr->bssid)) { update_bssid = true; } // Probes with hidden SSIDs. Unicast. } else if ((wlan_hdr->stats.ssid_len == 1) && (wlan_hdr->stats.ssid[0] == 0)) { if (!is_broadcast_ && addresses_equal(&bssid_, &wlan_hdr->bssid)) { is_bssid_match = true; update_ssid = true; } // Probes with no SSID. Broadcast. } else if (ssid_.isEmpty() && wlan_hdr->stats.ssid_len < 1) { if (is_broadcast_ && is_broadcast_bssid(&wlan_hdr->bssid)) { return true; } } // Non-probe requests (responses, beacons, etc) } else { if (is_ssid_match) { if (is_broadcast_ && !is_broadcast_bssid(&wlan_hdr->bssid)) { update_bssid = true; } } else if (wlan_hdr->stats.ssid_len < 1) { // No SSID. is_ssid_match = true; } if (is_bssid_match) { if ((ssid_.isEmpty() || ssid_[0] == '\0') && (wlan_hdr->stats.ssid_len > 0) && (wlan_hdr->stats.ssid[0] != 0) ) { update_ssid = true; } } } if (update_bssid) { updateBssid(wlan_hdr); is_bssid_match = true; } if (update_ssid) { ssid_ = QByteArray::fromRawData((const char *)wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len); setText(col_ssid_, format_text(wlan_hdr->stats.ssid, wlan_hdr->stats.ssid_len)); is_ssid_match = true; } return is_bssid_match && is_ssid_match; }
/* 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); } p_t38_conv = (t38_conv *)conversation_get_proto_data(p_conv, proto_t38); /* create the conversation if it doesn'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); } if (!p_t38_packet_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; }
static void dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *ftp_tree; proto_tree *reqresp_tree; proto_item *ti, *hidden_item; gint offset; const guchar *line; guint32 code; gchar code_str[4]; gboolean is_port_request = FALSE; gboolean is_eprt_request = FALSE; gboolean is_pasv_response = FALSE; gboolean is_epasv_response = FALSE; gint next_offset; int linelen; int tokenlen = 0; const guchar *next_token; guint32 pasv_ip; guint32 pasv_offset; guint32 ftp_ip; guint32 ftp_ip_len; guint32 eprt_offset; guint32 eprt_af = 0; guint32 eprt_ip; guint16 eprt_ipv6[8]; guint32 eprt_ip_len = 0; guint16 ftp_port; guint32 ftp_port_len; 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, 0, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, 0, 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)); ti = proto_tree_add_item(tree, proto_ftp, tvb, 0, -1, ENC_NA); ftp_tree = proto_item_add_subtree(ti, ett_ftp); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, is_request); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, is_request == FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); /* Put the line into the protocol tree. */ ti = proto_tree_add_format_text(ftp_tree, tvb, 0, next_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) { proto_tree_add_item(reqresp_tree, hf_ftp_request_command, tvb, 0, tokenlen, ENC_ASCII|ENC_NA); if (strncmp(line, "PORT", tokenlen) == 0) is_port_request = TRUE; /* * EPRT request command, as per RFC 2428 */ else if (strncmp(line, "EPRT", tokenlen) == 0) is_eprt_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 && g_ascii_isdigit(line[0]) && g_ascii_isdigit(line[1]) && g_ascii_isdigit(line[2])) { /* * One-line reply, or first or last line * of a multi-line reply. */ tvb_get_nstringz0(tvb, 0, sizeof(code_str), code_str); code = (guint32)strtoul(code_str, NULL, 10); proto_tree_add_uint(reqresp_tree, hf_ftp_response_code, tvb, 0, 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 */ 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; /* * 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, &pasv_offset, &ftp_ip_len, &ftp_port_len)) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip, tvb, pasv_offset + (tokenlen+1) , ftp_ip_len, ftp_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_active_port, tvb, pasv_offset + 1 + (tokenlen+1) + ftp_ip_len, ftp_port_len, 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) { 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, &pasv_offset, &ftp_ip_len, &ftp_port_len)) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_pasv_ip, tvb, pasv_offset + 4, ftp_ip_len, pasv_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, pasv_offset + 4 + 1 + ftp_ip_len, ftp_port_len, 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) { 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_eprt_request) { /* * RFC2428 - sect. 2 * This frame contains a EPRT request; let's dissect it and set up a * conversation for the data connection. */ if (parse_eprt_request(line, linelen, &eprt_af, &eprt_ip, eprt_ipv6, &ftp_port, &eprt_ip_len, &ftp_port_len)) { /* since parse_eprt_request() returned TRUE, we know that we have a valid address family */ eprt_offset = tokenlen + 1 + 1; /* token, space, 1st delimiter */ proto_tree_add_uint(reqresp_tree, hf_ftp_eprt_af, tvb, eprt_offset, 1, eprt_af); eprt_offset += 1 + 1; /* addr family, 2nd delimiter */ if (eprt_af == EPRT_AF_IPv4) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_eprt_ip, tvb, eprt_offset, eprt_ip_len, eprt_ip); set_address(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&eprt_ip); } else if (eprt_af == EPRT_AF_IPv6) { proto_tree_add_ipv6(reqresp_tree, hf_ftp_eprt_ipv6, tvb, eprt_offset, eprt_ip_len, (const struct e_in6_addr *)eprt_ipv6); set_address(&ftp_ip_address, AT_IPv6, 16, eprt_ipv6); } eprt_offset += eprt_ip_len + 1; /* addr, 3rd delimiter */ proto_tree_add_uint(reqresp_tree, hf_ftp_eprt_port, tvb, eprt_offset, ftp_port_len, ftp_port); /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &ftp_ip_address, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &pinfo->src, &ftp_ip_address, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } else { proto_tree_add_expert(reqresp_tree, pinfo, &ei_ftp_eprt_args_invalid, tvb, offset - linelen - 1, linelen); } } if (is_epasv_response) { if (linelen != 0) { proto_item *addr_it; /* * RFC2428 - sect. 3 * This frame contains an EPSV response; set up a * conversation for the data. */ if (parse_extended_pasv_response(line, linelen, &ftp_port, &pasv_offset, &ftp_port_len)) { /* Add IP address and port number to tree */ if (ftp_ip_address.type == AT_IPv4) { guint32 addr; memcpy(&addr, ftp_ip_address.data, 4); addr_it = proto_tree_add_ipv4(reqresp_tree, hf_ftp_epsv_ip, tvb, 0, 0, addr); PROTO_ITEM_SET_GENERATED(addr_it); } else if (ftp_ip_address.type == AT_IPv6) { addr_it = proto_tree_add_ipv6(reqresp_tree, hf_ftp_epsv_ipv6, tvb, 0, 0, (const struct e_in6_addr *)ftp_ip_address.data); PROTO_ITEM_SET_GENERATED(addr_it); } proto_tree_add_uint(reqresp_tree, hf_ftp_epsv_port, tvb, pasv_offset + 4, ftp_port_len, ftp_port); /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } else { proto_tree_add_expert(reqresp_tree, pinfo, &ei_ftp_epsv_args_invalid, tvb, offset - linelen - 1, linelen); } } } /* * 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_format_text(ftp_tree, tvb, offset, next_offset - offset); offset = next_offset; } }
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); } }