コード例 #1
0
const char *get_conversation_port(guint32 port, port_type ptype, gboolean resolve_names)
{

    if(!resolve_names) ptype = PT_NONE;

    switch(ptype) {
    case(PT_TCP):
        return ep_tcp_port_to_display(port);
    case(PT_UDP):
        return ep_udp_port_to_display(port);
    case(PT_SCTP):
        return ep_sctp_port_to_display(port);
    default:
        return ep_strdup_printf("%d", port);
    }
}
コード例 #2
0
static void
dissect_tpcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	tpcpdu_t    tpcph;
	proto_tree *tpcp_tree = NULL, *field_tree = NULL;
	proto_item *ti, *tf;
	guint8      length    = TPCP_VER_1_LENGTH;

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPCP");
	col_clear(pinfo->cinfo, COL_INFO);

	/* need to find out which version!! */
	tpcph.version = tvb_get_guint8(tvb, 0);
	/* as version 1 and 2 are so similar use the same structure, just don't use as much for version 1*/
	/* XXX: Doing a memcpy into a struct is *not* kosher */
	if (tpcph.version == TPCP_VER_1) {
		length = TPCP_VER_1_LENGTH;
		tvb_memcpy(tvb, (guint8 *) &tpcph, 0, length);
	} else if (tpcph.version == TPCP_VER_2){
		length = TPCP_VER_2_LENGTH;
		tvb_memcpy(tvb, (guint8 *) &tpcph, 0, length);
	} else {
		memset (&tpcph, 0, sizeof (tpcph));
	}


	tpcph.id        = g_ntohs(tpcph.id);
	tpcph.flags     = g_ntohs(tpcph.flags);
	tpcph.cport     = g_ntohs(tpcph.cport);
	tpcph.signature = g_ntohl(tpcph.signature);

	col_add_fstr(pinfo->cinfo, COL_INFO,"%s id %d CPort %s CIP %s SIP %s",
		val_to_str_const(tpcph.type, type_vals, "Unknown"),
		tpcph.id,
		ep_udp_port_to_display(tpcph.cport),
		ip_to_str((guint8 *)&tpcph.caddr),
		ip_to_str((guint8 *)&tpcph.saddr));

	if (tree) {
		ti = proto_tree_add_protocol_format(tree, proto_tpcp, tvb, 0, length,
			"Alteon WebSystems - Transparent Proxy Cache Protocol");

		tpcp_tree = proto_item_add_subtree(ti, ett_tpcp);

		proto_tree_add_uint(tpcp_tree, hf_tpcp_version, tvb, 0, 1, tpcph.version);
		proto_tree_add_uint(tpcp_tree, hf_tpcp_type, tvb, 1, 1, tpcph.type);

		/* flags next , i'll do that when I can work out how to do it :-(   */
		tf = proto_tree_add_text(tpcp_tree, tvb, 2, 2, "Flags: 0x%04x",tpcph.flags);

		field_tree = proto_item_add_subtree(tf, ett_tpcp_flags);
		proto_tree_add_boolean(field_tree, hf_tpcp_flags_tcp, tvb, 2, 2, tpcph.flags);
		proto_tree_add_boolean(field_tree, hf_tpcp_flags_redir, tvb, 2,2, tpcph.flags);
		proto_tree_add_boolean(field_tree, hf_tpcp_flags_xon, tvb, 2, 2, tpcph.flags);
		proto_tree_add_boolean(field_tree, hf_tpcp_flags_xoff, tvb, 2, 2, tpcph.flags);

		proto_tree_add_uint(tpcp_tree, hf_tpcp_id, tvb, 4, 2, tpcph.id);

		proto_tree_add_uint_format_value(tpcp_tree, hf_tpcp_cport, tvb, 6, 2, tpcph.cport,
			"%s", ep_udp_port_to_display(tpcph.cport));

		proto_tree_add_ipv4(tpcp_tree, hf_tpcp_caddr, tvb, 8, 4, tpcph.caddr);

		proto_tree_add_ipv4(tpcp_tree, hf_tpcp_saddr, tvb, 12, 4, tpcph.saddr);

		if (tpcph.version == TPCP_VER_2) {
			proto_tree_add_ipv4(tpcp_tree, hf_tpcp_vaddr, tvb, 16, 4, tpcph.vaddr);
			proto_tree_add_ipv4(tpcp_tree, hf_tpcp_rasaddr, tvb, 20, 4, tpcph.rasaddr);
			proto_tree_add_text(tpcp_tree, tvb, 24, 4, "Signature: %u", tpcph.signature);
		}

	}
}
コード例 #3
0
ファイル: packet-udp.c プロジェクト: jiangxilong/wireshark-1
static void
dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto)
{
  proto_tree *udp_tree = NULL;
  proto_item *ti, *hidden_item, *port_item;
  guint       len;
  guint       reported_len;
  vec_t       cksum_vec[4];
  guint32     phdr[2];
  guint16     computed_cksum;
  guint16     expected_cksum;
  int         offset = 0;
  e_udphdr   *udph;
  proto_tree *checksum_tree;
  proto_item *item;
  conversation_t *conv = NULL;
  struct udp_analysis *udpd = NULL;
  proto_tree *process_tree;
  gchar *src_port_str, *dst_port_str;

  udph=wmem_new(wmem_packet_scope(), e_udphdr);
  SET_ADDRESS(&udph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
  SET_ADDRESS(&udph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data);

  col_set_str(pinfo->cinfo, COL_PROTOCOL, (ip_proto == IP_PROTO_UDP) ? "UDP" : "UDPlite");
  col_clear(pinfo->cinfo, COL_INFO);

  udph->uh_sport=tvb_get_ntohs(tvb, offset);
  udph->uh_dport=tvb_get_ntohs(tvb, offset+2);

  src_port_str = ep_udp_port_to_display(udph->uh_sport);
  dst_port_str = ep_udp_port_to_display(udph->uh_dport);

  col_add_lstr(pinfo->cinfo, COL_INFO,
    "Source port: ", src_port_str, "  "
    "Destination port: ", dst_port_str,
    COL_ADD_LSTR_TERMINATOR);

  if (tree) {
    if (udp_summary_in_tree) {
      if (ip_proto == IP_PROTO_UDP) {
        ti = proto_tree_add_protocol_format(tree, hfi_udp->id, tvb, offset, 8,
        "User Datagram Protocol, Src Port: %s (%u), Dst Port: %s (%u)",
        src_port_str, udph->uh_sport, dst_port_str, udph->uh_dport);
      } else {
        ti = proto_tree_add_protocol_format(tree, hfi_udplite->id, tvb, offset, 8,
        "Lightweight User Datagram Protocol, Src Port: %s (%u), Dst Port: %s (%u)",
        src_port_str, udph->uh_sport, dst_port_str, udph->uh_dport);
      }
    } else {
      ti = proto_tree_add_item(tree, (ip_proto == IP_PROTO_UDP) ? hfi_udp : hfi_udplite, tvb, offset, 8, ENC_NA);
    }
    udp_tree = proto_item_add_subtree(ti, ett_udp);

    port_item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_srcport.id, tvb, offset, 2, udph->uh_sport,
                                                 "%s (%u)", src_port_str, udph->uh_sport);
    /* The beginning port number, 32768 + 666 (33434), is from LBL's traceroute.c source code and this code
     * further assumes that 3 attempts are made per hop */
    if ((udph->uh_sport > (32768 + 666)) && (udph->uh_sport <= (32768 + 666 + 30)))
            expert_add_info_format(pinfo, port_item, &ei_udp_possible_traceroute, "Possible traceroute: hop #%u, attempt #%u",
                                   ((udph->uh_sport - 32768 - 666 - 1) / 3) + 1,
                                   ((udph->uh_sport - 32768 - 666 - 1) % 3) + 1
                                   );

    port_item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_dstport.id, tvb, offset + 2, 2, udph->uh_dport,
        "%s (%u)", dst_port_str, udph->uh_dport);
    if ((udph->uh_dport > (32768 + 666)) && (udph->uh_dport <= (32768 + 666 + 30)))
            expert_add_info_format(pinfo, port_item, &ei_udp_possible_traceroute, "Possible traceroute: hop #%u, attempt #%u",
                                   ((udph->uh_dport - 32768 - 666 - 1) / 3) + 1,
                                   ((udph->uh_dport - 32768 - 666 - 1) % 3) + 1
                                   );

    hidden_item = proto_tree_add_uint(udp_tree, &hfi_udp_port, tvb, offset, 2, udph->uh_sport);
    PROTO_ITEM_SET_HIDDEN(hidden_item);
    hidden_item = proto_tree_add_uint(udp_tree, &hfi_udp_port, tvb, offset+2, 2, udph->uh_dport);
    PROTO_ITEM_SET_HIDDEN(hidden_item);
  }

  if (ip_proto == IP_PROTO_UDP) {
    udph->uh_ulen = udph->uh_sum_cov = tvb_get_ntohs(tvb, offset+4);
    if (udph->uh_ulen < 8) {
      /* Bogus length - it includes the header, so it must be >= 8. */
      /* XXX - should handle IPv6 UDP jumbograms (RFC 2675), where the length is zero */
      item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_length.id, tvb, offset + 4, 2,
          udph->uh_ulen, "%u (bogus, must be >= 8)", udph->uh_ulen);
      expert_add_info_format(pinfo, item, &ei_udp_length, "Bad length value %u < 8", udph->uh_ulen);
      col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD UDP LENGTH %u < 8]", udph->uh_ulen);
      return;
    }
    if ((udph->uh_ulen > tvb_reported_length(tvb)) && ! pinfo->fragmented && ! pinfo->flags.in_error_pkt) {
      /* Bogus length - it goes past the end of the IP payload */
      item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_length.id, tvb, offset + 4, 2,
          udph->uh_ulen, "%u (bogus, payload length %u)", udph->uh_ulen, tvb_reported_length(tvb));
      expert_add_info_format(pinfo, item, &ei_udp_length, "Bad length value %u > IP payload length", udph->uh_ulen);
      col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD UDP LENGTH %u > IP PAYLOAD LENGTH]", udph->uh_ulen);
    } else {
      if (tree) {
        proto_tree_add_uint(udp_tree, &hfi_udp_length, tvb, offset + 4, 2, udph->uh_ulen);
        /* XXX - why is this here, given that this is UDP, not Lightweight UDP? */
        hidden_item = proto_tree_add_uint(udp_tree, &hfi_udplite_checksum_coverage, tvb, offset + 4,
                                          0, udph->uh_sum_cov);
        PROTO_ITEM_SET_HIDDEN(hidden_item);
      }
    }
  } else {
    udph->uh_ulen = tvb_reported_length(tvb);
    udph->uh_sum_cov = tvb_get_ntohs(tvb, offset+4);
    if (((udph->uh_sum_cov > 0) && (udph->uh_sum_cov < 8)) || (udph->uh_sum_cov > udph->uh_ulen)) {
      /* Bogus length - it includes the header, so it must be >= 8, and no larger then the IP payload size. */
      if (tree) {
        hidden_item = proto_tree_add_boolean(udp_tree, &hfi_udplite_checksum_coverage_bad, tvb, offset + 4, 2, TRUE);
        PROTO_ITEM_SET_HIDDEN(hidden_item);
        hidden_item = proto_tree_add_uint(udp_tree, &hfi_udp_length, tvb, offset + 4, 0, udph->uh_ulen);
        PROTO_ITEM_SET_HIDDEN(hidden_item);
      }
      item = proto_tree_add_uint_format_value(udp_tree, hfi_udplite_checksum_coverage.id, tvb, offset + 4, 2,
          udph->uh_sum_cov, "%u (bogus, must be >= 8 and <= %u (ip.len-ip.hdr_len))",
          udph->uh_sum_cov, udph->uh_ulen);
      expert_add_info_format(pinfo, item, &ei_udplite_checksum_coverage, "Bad checksum coverage length value %u < 8 or > %u",
                             udph->uh_sum_cov, udph->uh_ulen);
      col_append_fstr(pinfo->cinfo, COL_INFO, " [BAD LIGHTWEIGHT UDP CHECKSUM COVERAGE LENGTH %u < 8 or > %u]",
                        udph->uh_sum_cov, udph->uh_ulen);
      if (!udplite_ignore_checksum_coverage)
        return;
    } else {
      if (tree) {
        hidden_item = proto_tree_add_uint(udp_tree, &hfi_udp_length, tvb, offset + 4, 0, udph->uh_ulen);
        PROTO_ITEM_SET_HIDDEN(hidden_item);
        proto_tree_add_uint(udp_tree, &hfi_udplite_checksum_coverage, tvb, offset + 4, 2, udph->uh_sum_cov);
      }
    }
  }

  udph->uh_sum_cov = (udph->uh_sum_cov) ? udph->uh_sum_cov : udph->uh_ulen;
  udph->uh_sum = tvb_get_ntohs(tvb, offset+6);
  reported_len = tvb_reported_length(tvb);
  len = tvb_captured_length(tvb);
  if (udph->uh_sum == 0) {
    /* No checksum supplied in the packet. */
    if ((ip_proto == IP_PROTO_UDP) && (pinfo->src.type == AT_IPv4)) {
      item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_checksum.id, tvb, offset + 6, 2, 0,
        "0x%04x (none)", 0);

      checksum_tree = proto_item_add_subtree(item, ett_udp_checksum);
      item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_good, tvb,
                             offset + 6, 2, FALSE);
      PROTO_ITEM_SET_GENERATED(item);
      item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_bad, tvb,
                             offset + 6, 2, FALSE);
      PROTO_ITEM_SET_GENERATED(item);
    } else {
      item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_checksum.id, tvb, offset + 6, 2, 0,
        "0x%04x (Illegal)", 0);
      expert_add_info(pinfo, item, &ei_udp_checksum_zero);
      col_append_str(pinfo->cinfo, COL_INFO, " [ILLEGAL CHECKSUM (0)]");

      checksum_tree = proto_item_add_subtree(item, ett_udp_checksum);
      item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_good, tvb,
                             offset + 6, 2, FALSE);
      PROTO_ITEM_SET_GENERATED(item);
      item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_bad, tvb,
                             offset + 6, 2, TRUE);
      PROTO_ITEM_SET_GENERATED(item);
    }
  } else if (!pinfo->fragmented && (len >= reported_len) &&
             (len >= udph->uh_sum_cov) && (reported_len >= udph->uh_sum_cov) &&
             (udph->uh_sum_cov >= 8)) {
    /* The packet isn't part of a fragmented datagram and isn't
       truncated, so we can checksum it.
       XXX - make a bigger scatter-gather list once we do fragment
       reassembly? */

    if (((ip_proto == IP_PROTO_UDP) && udp_check_checksum) ||
        ((ip_proto == IP_PROTO_UDPLITE) && udplite_check_checksum)) {
      /* Set up the fields of the pseudo-header. */
      cksum_vec[0].ptr = (const guint8 *)pinfo->src.data;
      cksum_vec[0].len = pinfo->src.len;
      cksum_vec[1].ptr = (const guint8 *)pinfo->dst.data;
      cksum_vec[1].len = pinfo->dst.len;
      cksum_vec[2].ptr = (const guint8 *)&phdr;
      switch (pinfo->src.type) {

      case AT_IPv4:
        if (ip_proto == IP_PROTO_UDP)
          phdr[0] = g_htonl((ip_proto<<16) | udph->uh_ulen);
        else
          phdr[0] = g_htonl((ip_proto<<16) | reported_len);
        cksum_vec[2].len = 4;
        break;

      case AT_IPv6:
        if (ip_proto == IP_PROTO_UDP)
          phdr[0] = g_htonl(udph->uh_ulen);
        else
          phdr[0] = g_htonl(reported_len);
        phdr[1] = g_htonl(ip_proto);
        cksum_vec[2].len = 8;
        break;

      default:
        /* UDP runs only atop IPv4 and IPv6.... */
        DISSECTOR_ASSERT_NOT_REACHED();
        break;
      }
      cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, udph->uh_sum_cov);
      cksum_vec[3].len = udph->uh_sum_cov;
      computed_cksum = in_cksum(&cksum_vec[0], 4);
      if (computed_cksum == 0) {
        item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_checksum.id, tvb,
          offset + 6, 2, udph->uh_sum, "0x%04x [correct]", udph->uh_sum);

        checksum_tree = proto_item_add_subtree(item, ett_udp_checksum);
        item = proto_tree_add_uint(checksum_tree, &hfi_udp_checksum_calculated,
                                   tvb, offset + 6, 2, udph->uh_sum);
        PROTO_ITEM_SET_GENERATED(item);
        item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_good, tvb,
                                      offset + 6, 2, TRUE);
        PROTO_ITEM_SET_GENERATED(item);
        item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_bad, tvb,
                                      offset + 6, 2, FALSE);
        PROTO_ITEM_SET_GENERATED(item);
      } else {
        expected_cksum = in_cksum_shouldbe(udph->uh_sum, computed_cksum);
        item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_checksum.id, tvb,
                                          offset + 6, 2, udph->uh_sum,
          "0x%04x [incorrect, should be 0x%04x (maybe caused by \"UDP checksum offload\"?)]", udph->uh_sum,
          expected_cksum);

        checksum_tree = proto_item_add_subtree(item, ett_udp_checksum);
        item = proto_tree_add_uint(checksum_tree, &hfi_udp_checksum_calculated,
                                   tvb, offset + 6, 2, expected_cksum);
        PROTO_ITEM_SET_GENERATED(item);
        item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_good, tvb,
                                      offset + 6, 2, FALSE);
        PROTO_ITEM_SET_GENERATED(item);
        item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_bad, tvb,
                                      offset + 6, 2, TRUE);
        PROTO_ITEM_SET_GENERATED(item);
        expert_add_info(pinfo, item, &ei_udp_checksum_bad);

        col_append_str(pinfo->cinfo, COL_INFO, " [UDP CHECKSUM INCORRECT]");
      }
    } else {
      item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_checksum.id, tvb,
        offset + 6, 2, udph->uh_sum, "0x%04x [validation disabled]", udph->uh_sum);
      checksum_tree = proto_item_add_subtree(item, ett_udp_checksum);
      item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_good, tvb,
                             offset + 6, 2, FALSE);
      PROTO_ITEM_SET_GENERATED(item);
      item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_bad, tvb,
                             offset + 6, 2, FALSE);
      PROTO_ITEM_SET_GENERATED(item);
    }
  } else {
    item = proto_tree_add_uint_format_value(udp_tree, hfi_udp_checksum.id, tvb,
      offset + 6, 2, udph->uh_sum, "0x%04x [unchecked, not all data available]", udph->uh_sum);

    checksum_tree = proto_item_add_subtree(item, ett_udp_checksum);
    item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_good, tvb,
                             offset + 6, 2, FALSE);
    PROTO_ITEM_SET_GENERATED(item);
    item = proto_tree_add_boolean(checksum_tree, &hfi_udp_checksum_bad, tvb,
                             offset + 6, 2, FALSE);
    PROTO_ITEM_SET_GENERATED(item);
  }

  /* Skip over header */
  offset += 8;

  pinfo->ptype = PT_UDP;
  pinfo->srcport = udph->uh_sport;
  pinfo->destport = udph->uh_dport;

  tap_queue_packet(udp_tap, pinfo, udph);

  /* find(or create if needed) the conversation for this udp session */
  conv=find_or_create_conversation(pinfo);
  udpd=get_udp_conversation_data(conv,pinfo);


  if (udpd) {
    item = proto_tree_add_uint(udp_tree, &hfi_udp_stream, tvb, offset, 0, udpd->stream);
    PROTO_ITEM_SET_GENERATED(item);

    /* Copy the stream index into the header as well to make it available
    * to tap listeners.
    */
    udph->uh_stream = udpd->stream;
  }

  if (udpd && ((udpd->fwd && udpd->fwd->command) || (udpd->rev && udpd->rev->command))) {
    process_tree = proto_tree_add_subtree(udp_tree, tvb, offset, 0, ett_udp_process_info, &ti, "Process Information");
    PROTO_ITEM_SET_GENERATED(ti);
    if (udpd->fwd && udpd->fwd->command) {
      proto_tree_add_uint_format_value(process_tree, hfi_udp_proc_dst_uid.id, tvb, 0, 0,
              udpd->fwd->process_uid, "%u", udpd->fwd->process_uid);
      proto_tree_add_uint_format_value(process_tree, hfi_udp_proc_dst_pid.id, tvb, 0, 0,
              udpd->fwd->process_pid, "%u", udpd->fwd->process_pid);
      proto_tree_add_string_format_value(process_tree, hfi_udp_proc_dst_uname.id, tvb, 0, 0,
              udpd->fwd->username, "%s", udpd->fwd->username);
      proto_tree_add_string_format_value(process_tree, hfi_udp_proc_dst_cmd.id, tvb, 0, 0,
              udpd->fwd->command, "%s", udpd->fwd->command);
    }
    if (udpd->rev->command) {
      proto_tree_add_uint_format_value(process_tree, hfi_udp_proc_src_uid.id, tvb, 0, 0,
              udpd->rev->process_uid, "%u", udpd->rev->process_uid);
      proto_tree_add_uint_format_value(process_tree, hfi_udp_proc_src_pid.id, tvb, 0, 0,
              udpd->rev->process_pid, "%u", udpd->rev->process_pid);
      proto_tree_add_string_format_value(process_tree, hfi_udp_proc_src_uname.id, tvb, 0, 0,
              udpd->rev->username, "%s", udpd->rev->username);
      proto_tree_add_string_format_value(process_tree, hfi_udp_proc_src_cmd.id, tvb, 0, 0,
              udpd->rev->command, "%s", udpd->rev->command);
    }
  }

  /*
   * Call sub-dissectors.
   *
   * XXX - should we do this if this is included in an error packet?
   * It might be nice to see the details of the packet that caused the
   * ICMP error, but it might not be nice to have the dissector update
   * state based on it.
   * Also, we probably don't want to run UDP taps on those packets.
   *
   * We definitely don't want to do it for an error packet if there's
   * nothing left in the packet.
   */
  if (!pinfo->flags.in_error_pkt || (tvb_captured_length_remaining(tvb, offset) > 0))
    decode_udp_ports(tvb, offset, pinfo, tree, udph->uh_sport, udph->uh_dport,
                     udph->uh_ulen);
}
コード例 #4
0
bool FollowStreamDialog::follow(QString previous_filter, bool use_tcp_index)
{
    int                 tmp_fd;
    QString             follow_filter;
    const char          *hostname0 = NULL, *hostname1 = NULL;
    char                *port0 = NULL, *port1 = NULL;
    QString             server_to_client_string;
    QString             client_to_server_string;
    QString             both_directions_string;
    follow_stats_t      stats;
    tcp_stream_chunk    sc;
    size_t              nchars;
    GString *           msg;
    gboolean is_tcp = FALSE, is_udp = FALSE;

    resetStream();

    if (cap_file_ == NULL)
    {
        QMessageBox::warning(this, tr("No capture file."), tr("Please make sure you have a capture file opened."));
        return false;
    }

    if (cap_file_->edt == NULL)
    {
        QMessageBox::warning(this, tr("Error following stream."), tr("Capture file invalid."));
        return false;
    }

    proto_get_frame_protocols(cap_file_->edt->pi.layers, NULL, &is_tcp, &is_udp, NULL, NULL);

    switch (follow_type_)
    {
    case FOLLOW_TCP:
        if (!is_tcp) {
            QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a TCP packet selected."));
            return false;
        }
        break;
    case FOLLOW_UDP:
        removeStreamControls();
        if (!is_udp) {
            QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a UDP packet selected."));
            return false;
        }
        break;
    case FOLLOW_SSL:
        /* we got ssl so we can follow */
        removeStreamControls();
        if (!epan_dissect_packet_contains_field(cap_file_->edt, "ssl")) {
            QMessageBox::critical(this, tr("Error following stream."),
                               tr("Please make sure you have an SSL packet selected."));
            return false;
        }
        break;
    }

    if (follow_type_ == FOLLOW_TCP || follow_type_ == FOLLOW_SSL)
    {
        /* Create a new filter that matches all packets in the TCP stream,
           and set the display filter entry accordingly */
        reset_tcp_reassembly();
    }

    if (use_tcp_index) {
        follow_filter = gchar_free_to_qstring(build_follow_index_filter());
    } else {
        follow_filter = gchar_free_to_qstring(build_follow_conv_filter(&cap_file_->edt->pi));
    }
    if (follow_filter.isEmpty()) {
        QMessageBox::warning(this,
                             tr("Error creating filter for this stream."),
                             tr("A transport or network layer header is needed."));
        return false;
    }

    if (follow_type_ == FOLLOW_TCP || follow_type_ == FOLLOW_SSL)
    {
        /* Create a temporary file into which to dump the reassembled data
           from the TCP stream, and set "data_out_file" to refer to it, so
           that the TCP code will write to it.

           XXX - it might be nicer to just have the TCP code directly
           append stuff to the text widget for the TCP stream window,
           if we can arrange that said window not pop up until we're
           done. */
        gchar *data_out_filename;
        tmp_fd = create_tempfile(&data_out_filename, "follow");
        data_out_filename_ = data_out_filename;

        if (tmp_fd == -1) {
            QMessageBox::warning(this, "Error",
                                 "Could not create temporary file %1: %2",
                                 data_out_filename_, g_strerror(errno));
            data_out_filename_.clear();
            return false;
        }

        data_out_file = fdopen(tmp_fd, "w+b");
        if (data_out_file == NULL) {
            QMessageBox::warning(this, "Error",
                                 "Could not create temporary file %1: %2",
                                 data_out_filename_, g_strerror(errno));
            //ws_close(tmp_fd);
            ws_unlink(data_out_filename_.toUtf8().constData());
            data_out_filename_.clear();
            return false;
        }
    }

    /* append the negation */
    if(!previous_filter.isEmpty()) {
        filter_out_filter_ = QString("%1 and !(%2)")
                .arg(previous_filter).arg(follow_filter);
    }
    else
    {
        filter_out_filter_ = QString("!(%1)").arg(follow_filter);
    }

    switch (follow_type_)
    {
    case FOLLOW_TCP:
    {
        int stream_count = get_tcp_stream_count() - 1;
        ui->streamNumberSpinBox->blockSignals(true);
        ui->streamNumberSpinBox->setMaximum(stream_count);
        ui->streamNumberSpinBox->setValue(get_follow_tcp_index());
        ui->streamNumberSpinBox->blockSignals(false);
        ui->streamNumberSpinBox->setToolTip(tr("%Ln total stream(s).", "", stream_count));
        ui->streamNumberLabel->setToolTip(ui->streamNumberSpinBox->toolTip());

        break;
    }
    case FOLLOW_UDP:
        /* data will be passed via tap callback*/
        msg = register_tap_listener("udp_follow", &follow_info_,
                                    follow_filter.toUtf8().constData(),
                                    0, NULL, udp_queue_packet_data, NULL);
        if (msg) {
            QMessageBox::critical(this, "Error",
                               "Can't register udp_follow tap: %1",
                               msg->str);
            return false;
        }
        break;
    case FOLLOW_SSL:
        /* we got ssl so we can follow */
        msg = register_tap_listener("ssl", &follow_info_,
                                    follow_filter.toUtf8().constData(), 0,
                                    NULL, ssl_queue_packet_data, NULL);
        if (msg)
        {
            QMessageBox::critical(this, "Error",
                          "Can't register ssl tap: %1", msg->str);
            return false;
        }
        break;
    }

    /* Run the display filter so it goes in effect - even if it's the
       same as the previous display filter. */
    emit updateFilter(follow_filter, TRUE);

    switch (follow_type_)
    {
    case FOLLOW_TCP:

        break;
    case FOLLOW_UDP:
        remove_tap_listener(&follow_info_);
        break;
    case FOLLOW_SSL:
        remove_tap_listener(&follow_info_);
        break;
    }

    if (follow_type_ == FOLLOW_TCP)
    {
        /* Check whether we got any data written to the file. */
        if (empty_tcp_stream) {
            QMessageBox::warning(this, "Error",
                                 "The packets in the capture file for that stream have no data.");
            //ws_close(tmp_fd);
            ws_unlink(data_out_filename_.toUtf8().constData());
            data_out_filename_.clear();
            return false;
        }

        /* Go back to the top of the file and read the first tcp_stream_chunk
         * to ensure that the IP addresses and port numbers in the drop-down
         * list are tied to the correct lines displayed by follow_read_stream()
         * later on (which also reads from this file).  Close the file when
         * we're done.
         *
         * We read the data now, before we pop up a window, in case the
         * read fails.  We use the data later.
         */

        rewind(data_out_file);
        nchars=fread(&sc, 1, sizeof(sc), data_out_file);
        if (nchars != sizeof(sc)) {
            if (ferror(data_out_file)) {
                QMessageBox::warning(this, "Error",
                                     QString(tr("Could not read from temporary file %1: %2"))
                                     .arg(data_out_filename_)
                                     .arg(g_strerror(errno)));
            } else {
                QMessageBox::warning(this, "Error",
                                     QString(tr("Short read from temporary file %1: expected %2, got %3"))
                                     .arg(data_out_filename_)
                                     .arg((unsigned long)sizeof(sc))
                                     .arg((unsigned long)nchars));

            }
            //ws_close(tmp_fd);
            ws_unlink(data_out_filename_.toUtf8().constData());
            data_out_filename_.clear();
            return false;
        }
        fclose(data_out_file);
        data_out_file = NULL;
    }

    /* Stream to show */
    follow_stats(&stats);

    if (stats.is_ipv6) {
        struct e_in6_addr ipaddr;
        memcpy(&ipaddr, stats.ip_address[0], 16);
        hostname0 = get_hostname6(&ipaddr);
        memcpy(&ipaddr, (follow_type_ == FOLLOW_TCP) ? stats.ip_address[1] : stats.ip_address[0], 16);
        hostname1 = get_hostname6(&ipaddr);
    } else {
        guint32 ipaddr;
        memcpy(&ipaddr, stats.ip_address[0], 4);
        hostname0 = get_hostname(ipaddr);
        memcpy(&ipaddr, stats.ip_address[1], 4);
        hostname1 = get_hostname(ipaddr);
    }

    switch (follow_type_)
    {
    case FOLLOW_TCP:
        port0 = ep_tcp_port_to_display(stats.port[0]);
        port1 = ep_tcp_port_to_display(stats.port[1]);
        break;
    case FOLLOW_UDP:
        port0 = ep_udp_port_to_display(stats.port[0]);
        port1 = ep_udp_port_to_display(stats.port[1]);
        break;
    case FOLLOW_SSL:
        port0 = ep_tcp_port_to_display(stats.port[0]);
        port1 = ep_tcp_port_to_display(stats.port[1]);
        break;
    }

    follow_info_.is_ipv6 = stats.is_ipv6;

    if (follow_type_ == FOLLOW_TCP)
    {
        /* Host 0 --> Host 1 */
        if(sc.src_port == stats.port[0]) {
            server_to_client_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname0).arg(port0)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname1).arg(port1)
                    .arg(gchar_free_to_qstring(format_size(
                                                   stats.bytes_written[0],
                                               format_size_unit_bytes|format_size_prefix_si)));
        } else {
            server_to_client_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname1).arg(port1)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname0).arg(port0)
                    .arg(gchar_free_to_qstring(format_size(
                                                   stats.bytes_written[0],
                                               format_size_unit_bytes|format_size_prefix_si)));
        }

        /* Host 1 --> Host 0 */
        if(sc.src_port == stats.port[1]) {
            client_to_server_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname0).arg(port0)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname1).arg(port1)
                    .arg(gchar_free_to_qstring(format_size(
                                                   stats.bytes_written[1],
                                               format_size_unit_bytes|format_size_prefix_si)));
        } else {
            client_to_server_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname1).arg(port1)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname0).arg(port0)
                    .arg(gchar_free_to_qstring(format_size(
                                                   stats.bytes_written[1],
                                               format_size_unit_bytes|format_size_prefix_si)));
        }

    }
    else
    {
        if(follow_info_.client_port == stats.port[0]) {
            server_to_client_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname0).arg(port0)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname1).arg(port1)
                    .arg(gchar_free_to_qstring(format_size(
                                                   follow_info_.bytes_written[0],
                                               format_size_unit_bytes|format_size_prefix_si)));

            client_to_server_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname0).arg(port0)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname1).arg(port1)
                    .arg(gchar_free_to_qstring(format_size(
                                                   follow_info_.bytes_written[1],
                                               format_size_unit_bytes|format_size_prefix_si)));
        } else {
            server_to_client_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname1).arg(port1)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname0).arg(port0)
                    .arg(gchar_free_to_qstring(format_size(
                                                   follow_info_.bytes_written[0],
                                               format_size_unit_bytes|format_size_prefix_si)));

            client_to_server_string =
                    QString("%1:%2 %3 %4:%5 (%6)")
                    .arg(hostname1).arg(port1)
                    .arg(UTF8_RIGHTWARDS_ARROW)
                    .arg(hostname0).arg(port0)
                    .arg(gchar_free_to_qstring(format_size(
                                                   follow_info_.bytes_written[1],
                                               format_size_unit_bytes|format_size_prefix_si)));
        }
    }

    /* Both Stream Directions */
    switch (follow_type_)
    {
    case FOLLOW_TCP:
        both_directions_string = QString("Entire conversation (%1)")
                .arg(gchar_free_to_qstring(format_size(
                                               stats.bytes_written[0] + stats.bytes_written[1],
                     format_size_unit_bytes|format_size_prefix_si)));
        this->setWindowTitle(QString("Follow TCP Stream (%1)").arg(follow_filter));
        break;
    case FOLLOW_UDP:
        both_directions_string = QString("Entire conversation (%1)")
                .arg(gchar_free_to_qstring(format_size(
                                               follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
                     format_size_unit_bytes|format_size_prefix_si)));
        this->setWindowTitle(QString("Follow UDP Stream (%1)").arg(follow_filter));
        break;
    case FOLLOW_SSL:
        both_directions_string = QString("Entire conversation (%1)")
                .arg(gchar_free_to_qstring(format_size(
                                               follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
                     format_size_unit_bytes|format_size_prefix_si)));
        this->setWindowTitle(QString("Follow SSL Stream (%1)").arg(follow_filter));
        break;
    }

    ui->cbDirections->clear();
    this->ui->cbDirections->addItem(both_directions_string);
    this->ui->cbDirections->addItem(client_to_server_string);
    this->ui->cbDirections->addItem(server_to_client_string);

    follow_stream();
    fillHintLabel(-1);

    data_out_file = NULL;

    return true;
}