예제 #1
0
//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;
}
예제 #2
0
/*
 * 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;
}
예제 #3
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;
}
예제 #4
0
//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;
}
예제 #5
0
/* 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;
}
예제 #6
0
/* 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;
}
예제 #7
0
/* 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;
}
예제 #8
0
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);
}
예제 #9
0
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;
}
예제 #10
0
/*
 * 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;
}
예제 #11
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_++;
    }
예제 #12
0
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;
  }
}
예제 #13
0
 bool isMatch(address *addr) {
     return addresses_equal(&addr_, addr);
 }
예제 #14
0
    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;
    }
예제 #15
0
/* 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;
}
예제 #16
0
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;
    }
}
예제 #17
0
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);
        }
    }