/** Dissector for SoupBinTCP messages */
static void
dissect_soupbintcp_common(
    tvbuff_t    *tvb,
    packet_info *pinfo,
    proto_tree  *tree)
{
    struct conv_data *conv_data;
    struct pdu_data  *pdu_data;
    const char       *pkt_name;
    const char       *tmp_buf;
    proto_item       *ti;
    proto_tree       *soupbintcp_tree = NULL;
    conversation_t   *conv            = NULL;
    guint16           expected_len;
    guint8            pkt_type;
    gint              offset          = 0;
    guint             this_seq        = 0, next_seq;
    heur_dtbl_entry_t *hdtbl_entry;

    /* Get the 16-bit big-endian SOUP packet length */
    expected_len = tvb_get_ntohs(tvb, 0);

    /* Get the 1-byte SOUP message type */
    pkt_type = tvb_get_guint8(tvb, 2);

    /* Since we use the packet name a few times, get and save that value */
    pkt_name = val_to_str(pkt_type, pkt_type_val, "Unknown (%u)");

    /* Set the protocol name in the summary display */
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SoupBinTCP");

    /* Set the packet name in the info column */
    col_add_str(pinfo->cinfo, COL_INFO, pkt_name);

    /* Sequence number tracking
     *
     * SOUP does not number packets from client to server (the server
     * acknowledges all important messages, so the client should use
     * the acks to figure out if the server received the message, and
     * otherwise resend it).
     *
     * Packets from server to client are numbered, but it's implicit.
     * The Login Accept packet contains the next sequence number that
     * the server will send, and the client needs to count the
     * Sequenced Data packets that it receives to know what their
     * sequence numbers are.
     *
     * So, we grab the next sequence number from the Login Acceptance
     * packet, and save it in a conversation_t we associate with the
     * TCP session.  Then, for each Sequenced Data packet we receive,
     * the first time it's processed (when PINFO_FD_VISITED() is
     * false), we write it into the PDU's frame's private data pointer
     * and increment the saved sequence number (in the conversation_t).
     *
     * If the visited flag is true, then we've dissected this packet
     * already, and so we can fetch the sequence number from the
     * frame's private data area.
     *
     * In either case, if there's any problem, we report zero as the
     * sequence number, and try to continue dissecting. */

    /* If first dissection of Login Accept, save sequence number */
    if (pkt_type == 'A' && !PINFO_FD_VISITED(pinfo)) {
        tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, 13, 20, ENC_ASCII);
        next_seq = atoi(tmp_buf);

        /* Create new conversation for this session */
        conv = conversation_new(PINFO_FD_NUM(pinfo),
                                &pinfo->src,
                                &pinfo->dst,
                                pinfo->ptype,
                                pinfo->srcport,
                                pinfo->destport,
                                0);

        /* Store starting sequence number for session's packets */
        conv_data = (struct conv_data *)wmem_alloc(wmem_file_scope(), sizeof(struct conv_data));
        conv_data->next_seq = next_seq;
        conversation_add_proto_data(conv, proto_soupbintcp, conv_data);
    }

    /* Handle sequence numbering for a Sequenced Data packet */
    if (pkt_type == 'S') {
        if (!PINFO_FD_VISITED(pinfo)) {
            /* Get next expected sequence number from conversation */
            conv = find_conversation(PINFO_FD_NUM(pinfo),
                                     &pinfo->src,
                                     &pinfo->dst,
                                     pinfo->ptype,
                                     pinfo->srcport,
                                     pinfo->destport,
                                     0);
            if (!conv) {
                this_seq = 0;
            } else {
                conv_data = (struct conv_data *)conversation_get_proto_data(conv,
                                                        proto_soupbintcp);
                if (conv_data) {
                    this_seq = conv_data->next_seq++;
                } else {
                    this_seq = 0;
                }

                pdu_data = (struct pdu_data *)wmem_alloc(
                    wmem_file_scope(),
                    sizeof(struct pdu_data));
                pdu_data->seq_num = this_seq;
                p_add_proto_data(wmem_file_scope(), pinfo, proto_soupbintcp, 0, pdu_data);
            }
        } else {
            pdu_data = (struct pdu_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_soupbintcp, 0);
            if (pdu_data) {
                this_seq = pdu_data->seq_num;
            } else {
                this_seq = 0;
            }
        }

        col_append_fstr(pinfo->cinfo, COL_INFO, ", SeqNum = %u", this_seq);
    }

    if (tree) {
        /* Create sub-tree for SoupBinTCP details */
        ti = proto_tree_add_item(tree,
                                 proto_soupbintcp,
                                 tvb, 0, -1, ENC_NA);

        soupbintcp_tree = proto_item_add_subtree(ti, ett_soupbintcp);

        /* Append the packet name to the sub-tree item */
        proto_item_append_text(ti, ", %s", pkt_name);

        /* Length */
        proto_tree_add_item(soupbintcp_tree,
                            hf_soupbintcp_packet_length,
                            tvb, offset, 2, ENC_BIG_ENDIAN);
        offset += 2;

        /* Type */
        proto_tree_add_item(soupbintcp_tree,
                            hf_soupbintcp_packet_type,
                            tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;

        switch (pkt_type) {
        case '+': /* Debug Message */
            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_text,
                                tvb, offset, expected_len - 1, ENC_ASCII|ENC_NA);
            break;

        case 'A': /* Login Accept */
            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_session,
                                tvb, offset, 10, ENC_ASCII|ENC_NA);
            offset += 10;

            tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 20, ENC_ASCII);
            proto_tree_add_string_format_value(soupbintcp_tree,
                                               hf_soupbintcp_next_seq_num,
                                               tvb, offset, 20,
                                               "X", "%d", atoi(tmp_buf));
            break;

        case 'J': /* Login Reject */
            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_reject_code,
                                tvb, offset, 1, ENC_BIG_ENDIAN);
            break;

        case 'U': /* Unsequenced Data */
            /* Display handled by sub-dissector */
            break;

        case 'S': /* Sequenced Data */
            proto_item_append_text(ti, ", SeqNum=%u", this_seq);
            proto_tree_add_string_format_value(soupbintcp_tree,
                                               hf_soupbintcp_seq_num,
                                               tvb, offset, 0,
                                               "X",
                                               "%u (Calculated)",
                                               this_seq);

            /* Display handled by sub-dissector */
            break;

        case 'L': /* Login Request */
            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_username,
                                tvb, offset, 6, ENC_ASCII|ENC_NA);
            offset += 6;

            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_password,
                                tvb, offset, 10, ENC_ASCII|ENC_NA);
            offset += 10;

            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_session,
                                tvb, offset, 10, ENC_ASCII|ENC_NA);
            offset += 10;

            tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 20, ENC_ASCII);
            proto_tree_add_string_format_value(soupbintcp_tree,
                                               hf_soupbintcp_req_seq_num,
                                               tvb, offset, 20,
                                               "X", "%d", atoi(tmp_buf));
            break;

        case 'H': /* Server Heartbeat */
            break;

        case 'O': /* Logout Request */
            break;

        case 'R': /* Client Heartbeat */
            break;

        case 'Z': /* End of Session */
            break;

        default:
            /* Unknown */
            proto_tree_add_item(tree,
                                hf_soupbintcp_message,
                                tvb, offset, -1, ENC_NA);
            break;
        }
    }

    /* Call sub-dissector for encapsulated data */
    if (pkt_type == 'S' || pkt_type == 'U') {
        tvbuff_t         *sub_tvb;

        /* Sub-dissector tvb starts at 3 (length (2) + pkt_type (1)) */
        sub_tvb = tvb_new_subset_remaining(tvb, 3);

#if 0   /* XXX: It's not valid for a soupbintcp subdissector to call       */
        /*  conversation_set_dissector() since the conversation is really  */
        /*  a TCP conversation.  (A 'soupbintcp' port type would need to   */
        /*  be defined to be able to use conversation_set_dissector()).    */
        /* In addition, no current soupbintcp subdissector calls           */
        /*  conversation_set_dissector().                                  */

        /* If this packet is part of a conversation, call dissector
         * for the conversation if available */
        if (try_conversation_dissector(&pinfo->dst, &pinfo->src, pinfo->ptype,
                                       pinfo->srcport, pinfo->destport,
                                       sub_tvb, pinfo, tree, NULL)) {
            return;
        }
#endif

        /* Otherwise, try heuristic dissectors */
        if (dissector_try_heuristic(heur_subdissector_list,
                                    sub_tvb,
                                    pinfo,
                                    tree,
                                    &hdtbl_entry,
                                    NULL)) {
            return;
        }

        /* Otherwise, give up, and just print the bytes in hex */
        if (tree) {
            proto_tree_add_item(soupbintcp_tree,
                                hf_soupbintcp_message,
                                sub_tvb, 0, -1,
                                ENC_NA);
        }
    }
}
Exemple #2
0
static void
decode_dccp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
                  proto_tree *tree, int sport, int dport)
{
    tvbuff_t *next_tvb;
    int       low_port, high_port;

    next_tvb = tvb_new_subset_remaining(tvb, offset);

    /*
     * determine if this packet is part of a conversation and call dissector
     * for the conversation if available
     */
    if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_DCCP, sport,
                                   dport, next_tvb, pinfo, tree)) {
        return;
    }

    if (try_heuristic_first) {
        /* do lookup with the heuristic subdissector table */
        if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo,
                                    tree, NULL)) {
            return;
        }
    }

    /*
     * Do lookups with the subdissector table.
     * We try the port number with the lower value first, followed by the
     * port number with the higher value.  This means that, for packets
     * where a dissector is registered for *both* port numbers:
     *
     * 1) we pick the same dissector for traffic going in both directions;
     *
     * 2) we prefer the port number that's more likely to be the right
     * one (as that prefers well-known ports to reserved ports);
     *
     * although there is, of course, no guarantee that any such strategy
     * will always pick the right port number.
     * XXX - we ignore port numbers of 0, as some dissectors use a port
     * number of 0 to disable the port.
     */
    if (sport > dport) {
        low_port  = dport;
        high_port = sport;
    } else {
        low_port  = sport;
        high_port = dport;
    }

    if (low_port != 0 &&
        dissector_try_uint(dccp_subdissector_table, low_port,
                           next_tvb, pinfo, tree)) {
        return;
    }

    if (high_port != 0 &&
        dissector_try_uint(dccp_subdissector_table, high_port,
                           next_tvb, pinfo, tree)) {
        return;
    }

    if (!try_heuristic_first) {
        /* do lookup with the heuristic subdissector table */
        if (dissector_try_heuristic(heur_subdissector_list, next_tvb,
                                    pinfo, tree, NULL)) {
            return;
        }
    }

    /* Oh, well, we don't know this; dissect it as data. */
    call_dissector(data_handle, next_tvb, pinfo, tree);
}
Exemple #3
0
void
decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
	proto_tree *tree, int uh_sport, int uh_dport, int uh_ulen)
{
  tvbuff_t *next_tvb;
  int low_port, high_port;
  gint len, reported_len;

  len = tvb_length_remaining(tvb, offset);
  reported_len = tvb_reported_length_remaining(tvb, offset);
  if (uh_ulen != -1) {
    /* This is the length from the UDP header; the payload should be cut
       off at that length.  (If our caller passed a value here, they
       are assumed to have checked that it's >= 8, and hence >= offset.)

       XXX - what if it's *greater* than the reported length? */
    if (uh_ulen - offset < reported_len)
      reported_len = uh_ulen - offset;
    if (len > reported_len)
      len = reported_len;
  }

  next_tvb = tvb_new_subset(tvb, offset, len, reported_len);

  /* If the user has a "Follow UDP Stream" window loading, pass a pointer
   * to the payload tvb through the tap system. */
  if(have_tap_listener(udp_follow_tap))
	  tap_queue_packet(udp_follow_tap, pinfo, next_tvb);

/* determine if this packet is part of a conversation and call dissector */
/* for the conversation if available */

  if (try_conversation_dissector(&pinfo->dst, &pinfo->src, PT_UDP,
		uh_dport, uh_sport, next_tvb, pinfo, tree)){
    return;
  }

  if (try_heuristic_first) {
    /* do lookup with the heuristic subdissector table */
    if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, NULL))
      return;
  }

  /* Do lookups with the subdissector table.
     We try the port number with the lower value first, followed by the
     port number with the higher value.  This means that, for packets
     where a dissector is registered for *both* port numbers:

	1) we pick the same dissector for traffic going in both directions;

	2) we prefer the port number that's more likely to be the right
	   one (as that prefers well-known ports to reserved ports);

     although there is, of course, no guarantee that any such strategy
     will always pick the right port number.

     XXX - we ignore port numbers of 0, as some dissectors use a port
     number of 0 to disable the port, and as RFC 768 says that the source
     port in UDP datagrams is optional and is 0 if not used. */
  if (uh_sport > uh_dport) {
    low_port = uh_dport;
    high_port = uh_sport;
  } else {
    low_port = uh_sport;
    high_port = uh_dport;
  }
  if (low_port != 0 &&
      dissector_try_uint(udp_dissector_table, low_port, next_tvb, pinfo, tree))
    return;
  if (high_port != 0 &&
      dissector_try_uint(udp_dissector_table, high_port, next_tvb, pinfo, tree))
    return;

  if (!try_heuristic_first) {
    /* do lookup with the heuristic subdissector table */
    if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, NULL))
      return;
  }

  call_dissector(data_handle,next_tvb, pinfo, tree);
}