aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2009-05-14 23:33:17 +0000
committerGerald Combs <gerald@wireshark.org>2009-05-14 23:33:17 +0000
commit9a72434b1e7e716717d8e813b47ed4dc38950f75 (patch)
treeed252079e0ffc2c70921034aacd3edfbaff9be74
parentbec2875b2b09b03612bcdff46157049a399b5324 (diff)
Add support for process flow records to IPFIX, which required adding
support for vendor-specific IEs. Fix variable-length record handling. Add conversation tracking to the UDP dissector and add process flow information to TCP and UDP conversations. This lets us run process flow collectors on one or more machines and have the process username, PID, command name, etc. show up in the TCP and UDP protocol trees. svn path=/trunk/; revision=28366
-rw-r--r--epan/dissectors/packet-netflow.c330
-rw-r--r--epan/dissectors/packet-tcp.c121
-rw-r--r--epan/dissectors/packet-tcp.h40
-rw-r--r--epan/dissectors/packet-udp.c204
-rw-r--r--epan/dissectors/packet-udp.h47
-rw-r--r--epan/sminmpec.h3
6 files changed, 696 insertions, 49 deletions
diff --git a/epan/dissectors/packet-netflow.c b/epan/dissectors/packet-netflow.c
index 2f00264aa9..8149fb6af8 100644
--- a/epan/dissectors/packet-netflow.c
+++ b/epan/dissectors/packet-netflow.c
@@ -71,6 +71,8 @@
#include <epan/prefs.h>
#include <epan/sminmpec.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/dissectors/packet-udp.h>
/* 4739 is IPFIX.
2055 and 9996 are common defaults for Netflow
@@ -111,6 +113,8 @@ static range_t *global_ipfix_ports = NULL;
#define V8PDU_TOSMATRIX_SIZE V8PDU_MATRIX_SIZE
#define V8PDU_PREPORTPROTOCOL_SIZE (4 * 10)
+#define VARIABLE_LENGTH 65535
+
static const value_string v5_sampling_mode[] = {
{0, "No sampling mode configured"},
{1, "Packet Interval sampling mode configured"},
@@ -170,7 +174,7 @@ struct v9_template {
address source_addr;
guint16 option_template; /* 0=data template, 1=option template */
guint16 count_scopes;
- struct v9_template_entry *scopes;
+ struct v9_template_entry *scopes;
struct v9_template_entry *entries;
};
@@ -421,6 +425,21 @@ static int hf_cflow_total_tcp_urg = -1;
static int hf_cflow_ip_total_length64 = -1;
static int hf_cflow_biflow_direction = -1;
+static int hf_pie_cace_local_ipv4_address = -1;
+static int hf_pie_cace_remote_ipv4_address = -1;
+static int hf_pie_cace_local_ipv6_address = -1;
+static int hf_pie_cace_remote_ipv6_address = -1;
+static int hf_pie_cace_local_port = -1;
+static int hf_pie_cace_remote_port = -1;
+static int hf_pie_cace_local_ipv4_id = -1;
+static int hf_pie_cace_local_icmp_id = -1;
+static int hf_pie_cace_local_uid = -1;
+static int hf_pie_cace_local_pid = -1;
+static int hf_pie_cace_local_username_len = -1;
+static int hf_pie_cace_local_username = -1;
+static int hf_pie_cace_local_cmd_len = -1;
+static int hf_pie_cace_local_cmd = -1;
+
const value_string special_mpls_top_label_type[] = {
{0, "Unknown"},
{1, "TE-MIDPT"},
@@ -457,20 +476,20 @@ typedef struct _hdrinfo_t {
address net_src;
} hdrinfo_t;
-typedef int dissect_pdu_t(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+typedef int dissect_pdu_t(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, int offset,
hdrinfo_t * hdrinfo);
-static int dissect_pdu(proto_tree * tree, tvbuff_t * tvb, int offset,
+static int dissect_pdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, int offset,
hdrinfo_t * hdrinfo);
-static int dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb,
+static int dissect_v8_aggpdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree,
int offset, hdrinfo_t * hdrinfo);
-static int dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb,
+static int dissect_v8_flowpdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree,
int offset, hdrinfo_t * hdrinfo);
-static int dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb,
+static int dissect_v9_flowset(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree,
int offset, hdrinfo_t * hdrinfo);
-static int dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb,
+static int dissect_v9_data(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree,
int offset, guint16 id, guint length, hdrinfo_t * hdrinfo);
-static void dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb,
+static guint dissect_v9_pdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree,
int offset, struct v9_template * template);
static int dissect_v9_options(proto_tree * pdutree, tvbuff_t * tvb,
int offset, hdrinfo_t * hdrinfo);
@@ -768,7 +787,7 @@ dissect_netflow(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
}
pdutree = proto_item_add_subtree(pduitem, ett_flow);
- pduret = pduptr(pdutree, tvb, offset, &hdrinfo);
+ pduret = pduptr(tvb, pinfo, pdutree, offset, &hdrinfo);
if (pduret < pdusize) pduret = pdusize; /* padding */
@@ -891,7 +910,7 @@ flow_process_textfield(proto_tree * pdutree, tvbuff_t * tvb, int offset,
}
static int
-dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+dissect_v8_flowpdu(tvbuff_t * tvb _U_, packet_info * pinfo _U_, proto_tree * pdutree, int offset,
hdrinfo_t * hdrinfo)
{
int startoffset = offset;
@@ -957,7 +976,7 @@ dissect_v8_flowpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
*/
static int
-dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+dissect_v8_aggpdu(tvbuff_t * tvb _U_, packet_info * pinfo _U_, proto_tree * pdutree, int offset,
hdrinfo_t * hdrinfo)
{
int startoffset = offset;
@@ -1106,7 +1125,7 @@ dissect_v8_aggpdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
/* Dissect a version 9 FlowSet and return the length we processed. */
static int
-dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t * hdrinfo)
+dissect_v9_flowset(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree, int offset, hdrinfo_t * hdrinfo)
{
int length;
guint16 flowset_id;
@@ -1169,7 +1188,7 @@ dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t *
*/
length -= 4;
if (length > 0) {
- dissect_v9_data(pdutree, tvb, offset, flowset_id,
+ dissect_v9_data(tvb, pinfo, pdutree, offset, flowset_id,
(guint)length, hdrinfo);
}
}
@@ -1178,12 +1197,13 @@ dissect_v9_flowset(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t *
}
static int
-dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+dissect_v9_data(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree, int offset,
guint16 id, guint length, hdrinfo_t * hdrinfo)
{
struct v9_template *template;
proto_tree *data_tree;
proto_item *data_item;
+ guint pdu_len;
template = v9_template_get(id, &hdrinfo->net_src, hdrinfo->src_id);
if (template != NULL && template->length != 0) {
@@ -1195,10 +1215,11 @@ dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
data_tree = proto_item_add_subtree(data_item,
ett_dataflowset);
- dissect_v9_pdu(data_tree, tvb, offset, template);
+ pdu_len = dissect_v9_pdu(tvb, pinfo, data_tree, offset, template);
offset += template->length;
- length -= template->length;
+ /* XXX - Throw an exception */
+ length -= pdu_len < length ? pdu_len : length;
}
if (length != 0) {
proto_tree_add_text(pdutree, tvb, offset, length,
@@ -1214,11 +1235,35 @@ dissect_v9_data(proto_tree * pdutree, tvbuff_t * tvb, int offset,
return (0);
}
-static void
-dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
+#define GOT_LOCAL_ADDR (1 << 0)
+#define GOT_REMOTE_ADDR (1 << 1)
+#define GOT_LOCAL_PORT (1 << 2)
+#define GOT_REMOTE_PORT (1 << 3)
+#define GOT_IPv4_ID (1 << 4)
+#define GOT_ICMP_ID (1 << 5)
+#define GOT_UID (1 << 6)
+#define GOT_PID (1 << 7)
+#define GOT_USERNAME (1 << 8)
+#define GOT_COMMAND (1 << 9)
+
+#define GOT_BASE ( \
+ GOT_LOCAL_ADDR | \
+ GOT_REMOTE_ADDR | \
+ GOT_UID | \
+ GOT_PID | \
+ GOT_USERNAME | \
+ GOT_COMMAND \
+ )
+
+#define GOT_TCP_UDP (GOT_BASE | GOT_LOCAL_PORT | GOT_REMOTE_PORT)
+#define GOT_ICMP (GOT_BASE | GOT_IPv4_ID | GOT_ICMP_ID)
+
+static guint
+dissect_v9_pdu(tvbuff_t * tvb, packet_info * pinfo, proto_tree * pdutree, int offset,
struct v9_template * template)
{
- int i;
+ int orig_offset = offset;
+ int i;
int rev;
nstime_t ts_start[2], ts_end[2];
int offset_s[2], offset_e[2];
@@ -1228,6 +1273,14 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
proto_tree * timetree = 0;
proto_item * timeitem = 0;
guint16 pen_count = 0;
+ address local_addr, remote_addr;
+ guint16 local_port = 0, remote_port = 0, ipv4_id = 0, icmp_id = 0;
+ guint32 uid = 0, pid = 0;
+ int uname_len;
+ gchar * uname_str = NULL;
+ int cmd_len;
+ gchar * cmd_str = NULL;
+ guint16 got_flags = 0;
offset_s[0] = offset_s[1] = offset_e[0] = offset_e[1] = 0;
msec_start[0] = msec_start[1] = msec_end[0] = msec_end[1] = 0;
@@ -1279,6 +1332,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
}
for (i = 0; i < template->count; i++) {
+ guint64 pen_type;
guint16 type, length;
guint32 pen = 0;
@@ -1294,7 +1348,9 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
}
}
- switch (type) {
+ pen_type = pen << 16 | (type & 0x7fff);
+
+ switch (pen_type) {
case 85: /* BYTES_PERMANENT */
case 1: /* bytes */
@@ -1627,7 +1683,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
if (length == 4) {
proto_tree_add_item(pdutree, hf_cflow_ipv6_flowlabel,
tvb, offset, length, FALSE);
- }
+ }
/* RFC3954 defines that length of this field is 3
Bytes */
else if (length == 3) {
@@ -1835,7 +1891,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
proto_tree_add_item(pdutree, hf_cflow_ipv6_exthdr,
tvb, offset, length, FALSE);
break;
-
+
case 70: /* MPLS label1*/
proto_tree_add_mpls_label(pdutree, tvb, offset, length, 1);
break;
@@ -1905,7 +1961,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
proto_tree_add_item(pdutree, hf_cflow_fragment_offset,
tvb, offset, length, FALSE);
break;
-
+
case 89: /* FORWARDING_STATUS */
proto_tree_add_item(pdutree, hf_cflow_forwarding_status,
tvb, offset, length, FALSE);
@@ -1938,7 +1994,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
hf_cflow_exporter_addr_v6,
tvb, offset, length, FALSE);
break;
-
+
case 132: /* droppedOctetDeltaCount */
if (length == 4) {
proto_tree_add_item(pdutree, hf_cflow_drop_octets,
@@ -2007,7 +2063,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
proto_tree_add_item(pdutree, hf_cflow_observation_point_id,
tvb, offset, length, FALSE);
break;
-
+
case 139: /* icmpTypeCodeIPv6 */
proto_tree_add_item(pdutree, hf_cflow_icmp_ipv6_type,
tvb, offset, 1, FALSE);
@@ -2041,7 +2097,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
proto_tree_add_item(pdutree, hf_cflow_mp_id,
tvb, offset, length, FALSE);
break;
-
+
case 144: /* FLOW EXPORTER */
proto_tree_add_item(pdutree, hf_cflow_flow_exporter,
tvb, offset, length, FALSE);
@@ -2162,7 +2218,7 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
"Not Sent Packets: length %u", length);
}
break;
-
+
case 169: /* destinationIPv6Prefix */
if (length == 16) {
proto_tree_add_item(pdutree, hf_cflow_dstnet_v6,
@@ -2499,12 +2555,105 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
tvb, offset, length, FALSE);
break;
+ /* CACE Technologies */
+ case VENDOR_CACE << 16 | 0: /* caceLocalIPv4Address */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_ipv4_address,
+ tvb, offset, length, FALSE);
+ SET_ADDRESS(&local_addr, AT_IPv4, 4, tvb_get_ptr(tvb, offset, 4));
+ got_flags |= GOT_LOCAL_ADDR;
+ break;
+
+ case VENDOR_CACE << 16 | 1: /* caceRemoteIPv4Address */
+ proto_tree_add_item(pdutree, hf_pie_cace_remote_ipv4_address,
+ tvb, offset, length, FALSE);
+ SET_ADDRESS(&remote_addr, AT_IPv4, 4, tvb_get_ptr(tvb, offset, 4));
+ got_flags |= GOT_REMOTE_ADDR;
+ break;
+
+ case VENDOR_CACE << 16 | 2: /* caceLocalIPv6Address */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_ipv6_address,
+ tvb, offset, length, FALSE);
+ SET_ADDRESS(&local_addr, AT_IPv6, 16, tvb_get_ptr(tvb, offset, 16));
+ got_flags |= GOT_LOCAL_ADDR;
+ break;
+
+ case VENDOR_CACE << 16 | 3: /* caceRemoteIPv6Address */
+ proto_tree_add_item(pdutree, hf_pie_cace_remote_ipv6_address,
+ tvb, offset, length, FALSE);
+ SET_ADDRESS(&remote_addr, AT_IPv6, 16, tvb_get_ptr(tvb, offset, 16));
+ got_flags |= GOT_REMOTE_ADDR;
+ break;
+
+ case VENDOR_CACE << 16 | 4: /* caceLocalTransportPort */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_port,
+ tvb, offset, length, FALSE);
+ local_port = tvb_get_ntohs(tvb, offset);
+ got_flags |= GOT_LOCAL_PORT;
+ break;
+
+ case VENDOR_CACE << 16 | 5: /* caceRemoteTransportPort */
+ proto_tree_add_item(pdutree, hf_pie_cace_remote_port,
+ tvb, offset, length, FALSE);
+ remote_port = tvb_get_ntohs(tvb, offset);
+ got_flags |= GOT_REMOTE_PORT;
+ break;
+
+ case VENDOR_CACE << 16 | 6: /* caceLocalIPv4id */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_ipv4_id,
+ tvb, offset, length, FALSE);
+ ipv4_id = tvb_get_ntohs(tvb, offset);
+ got_flags |= GOT_IPv4_ID;
+ break;
+
+ case VENDOR_CACE << 16 | 7: /* caceLocalICMPid */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_icmp_id,
+ tvb, offset, length, FALSE);
+ icmp_id = tvb_get_ntohs(tvb, offset);
+ got_flags |= GOT_ICMP_ID;
+ break;
+
+ case VENDOR_CACE << 16 | 8: /* caceLocalProcessUserId */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_uid,
+ tvb, offset, length, FALSE);
+ uid = tvb_get_ntohl(tvb, offset);
+ got_flags |= GOT_UID;
+ break;
+
+ case VENDOR_CACE << 16 | 9: /* caceLocalProcessId */
+ proto_tree_add_item(pdutree, hf_pie_cace_local_pid,
+ tvb, offset, length, FALSE);
+ pid = tvb_get_ntohl(tvb, offset);
+ got_flags |= GOT_PID;
+ break;
+
+ case VENDOR_CACE << 16 | 10: /* caceLocalProcessUserName */
+ uname_len = tvb_get_guint8(tvb, offset);
+ uname_str = tvb_format_text(tvb, offset+1, uname_len);
+ proto_tree_add_item(pdutree, hf_pie_cace_local_username_len,
+ tvb, offset, 1, FALSE);
+ proto_tree_add_string(pdutree, hf_pie_cace_local_username,
+ tvb, offset+1, uname_len, uname_str);
+ length = uname_len + 1;
+ got_flags |= GOT_USERNAME;
+ break;
+
+ case VENDOR_CACE << 16 | 11: /* caceLocalProcessCommand */
+ cmd_len = tvb_get_guint8(tvb, offset);
+ cmd_str = tvb_format_text(tvb, offset+1, cmd_len);
+ proto_tree_add_item(pdutree, hf_pie_cace_local_cmd_len,
+ tvb, offset, 1, FALSE);
+ proto_tree_add_string(pdutree, hf_pie_cace_local_cmd,
+ tvb, offset+1, cmd_len, cmd_str);
+ length = cmd_len + 1;
+ got_flags |= GOT_COMMAND;
+ break;
+
default:
if ((type & 0x8000) && (pen != REVPEN))
proto_tree_add_text(pdutree, tvb, offset, length,
"(%s) Type %u ",
match_strval(pen, sminmpec_values), type & 0x7fff);
-
+
else
proto_tree_add_text(pdutree, tvb, offset, length,
"%s Type %u %s", pen == REVPEN ? "Reverse" : "",
@@ -2537,6 +2686,16 @@ dissect_v9_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset,
}
}
+ /* XXX - These IDs are currently hard-coded in procflow.py. */
+ if (got_flags == GOT_TCP_UDP && (template->id == 256 || template->id == 258)) {
+ add_tcp_process_info(pinfo->fd->num, &local_addr, &remote_addr, local_port, remote_port, uid, pid, uname_str, cmd_str);
+ }
+ if (got_flags == GOT_TCP_UDP && (template->id == 257 || template->id == 259)) {
+ add_udp_process_info(pinfo->fd->num, &local_addr, &remote_addr, local_port, remote_port, uid, pid, uname_str, cmd_str);
+ }
+
+ return (guint) (offset - orig_offset);
+
}
static int
@@ -2710,7 +2869,7 @@ dissect_v9_template(proto_tree * pdutree, tvbuff_t * tvb, int offset, int len, h
v9_template_add(&template);
remaining -= 4 + sizeof(struct v9_template_entry) * count;
if (pen_count > 0) {
- remaining -= 4 * pen_count;
+ remaining -= 4 * pen_count;
}
}
@@ -2983,22 +3142,25 @@ v9_template_add(struct v9_template *template)
{
int i;
int pen_count = 0;
+ guint tmp_length;
/* Add up the actual length of the data and store in proper byte order */
template->length = 0;
/* Options scope */
for(i = 0; i < template->count_scopes; i++) {
template->scopes[i].type = g_ntohs(template->scopes[i].type);
- template->scopes[i].length = g_ntohs(template->scopes[i].length);
+ tmp_length = g_ntohs(template->scopes[i].length);
+ template->scopes[i].length = tmp_length == VARIABLE_LENGTH ? 0 : tmp_length;
template->length += template->scopes[i].length;
}
for (i = 0; i < template->count; i++) {
template->entries[i + pen_count].type = g_ntohs(template->entries[i + pen_count].type);
- template->entries[i + pen_count].length = g_ntohs(template->entries[i + pen_count].length);
+ tmp_length = g_ntohs(template->entries[i + pen_count].length);
+ template->entries[i + pen_count].length = tmp_length == VARIABLE_LENGTH ? 0 : tmp_length;
template->length += template->entries[i + pen_count].length;
if (template->entries[i + pen_count].type & 0x8000) {
pen_count++;
- *(guint32 *)&template->entries[i + pen_count] =
+ *(guint32 *)&template->entries[i + pen_count] =
g_ntohl(*(guint32 *)&template->entries[i + pen_count]);
}
}
@@ -3030,7 +3192,7 @@ v9_template_get(guint16 id, address * net_src, guint32 src_id)
*/
static int
-dissect_pdu(proto_tree * pdutree, tvbuff_t * tvb, int offset, hdrinfo_t * hdrinfo)
+dissect_pdu(tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * pdutree, int offset, hdrinfo_t * hdrinfo)
{
proto_item *hidden_item;
int startoffset = offset;
@@ -4238,7 +4400,95 @@ proto_register_netflow(void)
{"Scope Unknown", "cflow.scope",
FT_BYTES, BASE_HEX, NULL, 0x0,
"Option Scope Unknown", HFILL}
- }
+ },
+
+ /* Private Information Elements */
+
+ /* CACE Technologies, 32622 / 0 */
+ {&hf_pie_cace_local_ipv4_address,
+ {"Local IPv4 Address", "cflow.pie.cace.localaddr4",
+ FT_IPv4, BASE_HEX, NULL, 0x0,
+ "Local IPv4 Address (caceLocalIPv4Address)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 1 */
+ {&hf_pie_cace_remote_ipv4_address,
+ {"Remote IPv4 Address", "cflow.pie.cace.remoteaddr4",
+ FT_IPv4, BASE_HEX, NULL, 0x0,
+ "Remote IPv4 Address (caceRemoteIPv4Address)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 2 */
+ {&hf_pie_cace_local_ipv6_address,
+ {"Local IPv6 Address", "cflow.pie.cace.localaddr6",
+ FT_IPv6, BASE_HEX, NULL, 0x0,
+ "Local IPv6 Address (caceLocalIPv6Address)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 3 */
+ {&hf_pie_cace_remote_ipv6_address,
+ {"Remote IPv6 Address", "cflow.pie.cace.remoteaddr6",
+ FT_IPv6, BASE_HEX, NULL, 0x0,
+ "Remote IPv6 Address (caceRemoteIPv6Address)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 4 */
+ {&hf_pie_cace_local_port,
+ {"Local Port", "cflow.pie.cace.localport",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Local Transport Port (caceLocalTransportPort)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 5 */
+ {&hf_pie_cace_remote_port,
+ {"Remote Port", "cflow.pie.cace.remoteport",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "Remote Transport Port (caceRemoteTransportPort)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 6 */
+ {&hf_pie_cace_local_ipv4_id,
+ {"Local IPv4 ID", "cflow.pie.cace.localip4id",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "The IPv4 identification header field from a locally-originated packet (caceLocalIPv4id)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 7 */
+ {&hf_pie_cace_local_icmp_id,
+ {"Local ICMP ID", "cflow.pie.cace.localicmpid",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "The ICMP identification header field from a locally-originated ICMPv4 or ICMPv6 echo request (caceLocalICMPid)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 8 */
+ {&hf_pie_cace_local_uid,
+ {"Local User ID", "cflow.pie.cace.localuid",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Local User ID (caceLocalProcessUserId)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 9 */
+ {&hf_pie_cace_local_pid,
+ {"Local Process ID", "cflow.pie.cace.localpid",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Local Process ID (caceLocalProcessId)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 10 */
+ {&hf_pie_cace_local_username_len,
+ {"Local Username Length", "cflow.pie.cace.localusernamelen",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Local User Name Length (caceLocalProcessUserName)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 10 */
+ {&hf_pie_cace_local_username,
+ {"Local User Name", "cflow.pie.cace.localusername",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Local User Name (caceLocalProcessUserName)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 11 */
+ {&hf_pie_cace_local_cmd_len,
+ {"Local Command Length", "cflow.pie.cace.localcmdlen",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "Local Command Length (caceLocalProcessCommand)", HFILL}
+ },
+ /* CACE Technologies, 32622 / 11 */
+ {&hf_pie_cace_local_cmd,
+ {"Local Command", "cflow.pie.cace.localcmd",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "Local Command (caceLocalProcessCommand)", HFILL}
+ }
+
};
static gint *ett[] = {
@@ -4350,3 +4600,15 @@ proto_reg_handoff_netflow(void)
range_foreach(ipfix_ports, ipfix_add_callback);
}
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set shiftwidth=8 tabstop=8 noexpandtab
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c
index ad73e8797f..a34ed243e9 100644
--- a/epan/dissectors/packet-tcp.c
+++ b/epan/dissectors/packet-tcp.c
@@ -159,6 +159,14 @@ static int hf_tcp_option_snack_offset = -1;
static int hf_tcp_option_snack_size = -1;
static int hf_tcp_option_snack_le = -1;
static int hf_tcp_option_snack_re = -1;
+static int hf_tcp_proc_src_uid = -1;
+static int hf_tcp_proc_src_pid = -1;
+static int hf_tcp_proc_src_uname = -1;
+static int hf_tcp_proc_src_cmd = -1;
+static int hf_tcp_proc_dst_uid = -1;
+static int hf_tcp_proc_dst_pid = -1;
+static int hf_tcp_proc_dst_uname = -1;
+static int hf_tcp_proc_dst_cmd = -1;
static gint ett_tcp = -1;
static gint ett_tcp_flags = -1;
@@ -172,6 +180,7 @@ static gint ett_tcp_timestamps = -1;
static gint ett_tcp_segments = -1;
static gint ett_tcp_segment = -1;
static gint ett_tcp_checksum = -1;
+static gint ett_tcp_process_info = -1;
/* not all of the hf_fields below make sense for TCP but we have to provide
@@ -250,8 +259,12 @@ init_tcp_conversation_data(packet_info *pinfo)
memset(&tcpd->flow2, 0, sizeof(tcp_flow_t));
tcpd->flow1.win_scale=-1;
tcpd->flow1.multisegment_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "tcp_multisegment_pdus");
+ tcpd->flow1.username = NULL;
+ tcpd->flow1.command = NULL;
tcpd->flow2.win_scale=-1;
tcpd->flow2.multisegment_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "tcp_multisegment_pdus");
+ tcpd->flow2.username = NULL;
+ tcpd->flow2.command = NULL;
tcpd->acked_table=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "tcp_analyze_acked_table");
tcpd->ts_first.secs=pinfo->fd->abs_ts.secs;
tcpd->ts_first.nsecs=pinfo->fd->abs_ts.nsecs;
@@ -319,6 +332,40 @@ get_tcp_conversation_data(conversation_t *conv, packet_info *pinfo)
return tcpd;
}
+/* Attach process info to a flow */
+/* XXX - We depend on the TCP dissector finding the conversation first */
+void
+add_tcp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command) {
+ conversation_t *conv;
+ struct tcp_analysis *tcpd;
+ tcp_flow_t *flow = NULL;
+
+ conv = find_conversation(frame_num, local_addr, remote_addr, PT_TCP, local_port, remote_port, 0);
+ if (!conv) {
+ return;
+ }
+
+ tcpd = conversation_get_proto_data(conv, proto_tcp);
+ if (!tcpd) {
+ return;
+ }
+
+ if (CMP_ADDRESS(local_addr, &conv->key_ptr->addr1) == 0 && local_port == conv->key_ptr->port1) {
+ flow = &tcpd->flow1;
+ } else if (CMP_ADDRESS(remote_addr, &conv->key_ptr->addr1) == 0 && remote_port == conv->key_ptr->port1) {
+ flow = &tcpd->flow2;
+ }
+ if (!flow || flow->command) {
+ return;
+ }
+
+ flow->process_uid = uid;
+ flow->process_pid = pid;
+ flow->username = se_strdup(username);
+ flow->command = se_strdup(command);
+}
+
+
/* Calculate the timestamps relative to this conversation */
static void
tcp_calculate_timestamps(packet_info *pinfo, struct tcp_analysis *tcpd,
@@ -3553,6 +3600,32 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
+ if (tcpd && (tcpd->fwd || tcpd->rev) && (tcpd->fwd->command || tcpd->rev->command)) {
+ ti = proto_tree_add_text(tcp_tree, tvb, offset, 0, "Process Information");
+ PROTO_ITEM_SET_GENERATED(ti);
+ field_tree = proto_item_add_subtree(ti, ett_tcp_process_info);
+ if (tcpd->fwd->command) {
+ proto_tree_add_uint_format_value(field_tree, hf_tcp_proc_dst_uid, tvb, 0, 0,
+ tcpd->fwd->process_uid, "%u", tcpd->fwd->process_uid);
+ proto_tree_add_uint_format_value(field_tree, hf_tcp_proc_dst_pid, tvb, 0, 0,
+ tcpd->fwd->process_pid, "%u", tcpd->fwd->process_pid);
+ proto_tree_add_string_format_value(field_tree, hf_tcp_proc_dst_uname, tvb, 0, 0,
+ tcpd->fwd->username, "%s", tcpd->fwd->username);
+ proto_tree_add_string_format_value(field_tree, hf_tcp_proc_dst_cmd, tvb, 0, 0,
+ tcpd->fwd->command, "%s", tcpd->fwd->command);
+ }
+ if (tcpd->rev->command) {
+ proto_tree_add_uint_format_value(field_tree, hf_tcp_proc_src_uid, tvb, 0, 0,
+ tcpd->rev->process_uid, "%u", tcpd->rev->process_uid);
+ proto_tree_add_uint_format_value(field_tree, hf_tcp_proc_src_pid, tvb, 0, 0,
+ tcpd->rev->process_pid, "%u", tcpd->rev->process_pid);
+ proto_tree_add_string_format_value(field_tree, hf_tcp_proc_src_uname, tvb, 0, 0,
+ tcpd->rev->username, "%s", tcpd->rev->username);
+ proto_tree_add_string_format_value(field_tree, hf_tcp_proc_src_cmd, tvb, 0, 0,
+ tcpd->rev->command, "%s", tcpd->rev->command);
+ }
+ }
+
/*
* XXX - what, if any, of this should we do if this is included in an
* error packet? It might be nice to see the details of the packet
@@ -3983,6 +4056,38 @@ proto_register_tcp(void)
{ &hf_tcp_ts_delta,
{ "Time since previous frame in this TCP stream", "tcp.time_delta", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
"Time delta from previous frame in this TCP stream", HFILL}},
+
+ { &hf_tcp_proc_src_uid,
+ { "Source process user ID", "tcp.proc.srcuid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Source process user ID", HFILL}},
+
+ { &hf_tcp_proc_src_pid,
+ { "Source process ID", "tcp.proc.srcpid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Source process ID", HFILL}},
+
+ { &hf_tcp_proc_src_uname,
+ { "Source process user name", "tcp.proc.srcuname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Source process user name", HFILL}},
+
+ { &hf_tcp_proc_src_cmd,
+ { "Source process name", "tcp.proc.srccmd", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Source process command name", HFILL}},
+
+ { &hf_tcp_proc_dst_uid,
+ { "Destination process user ID", "tcp.proc.dstuid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Destination process user ID", HFILL}},
+
+ { &hf_tcp_proc_dst_pid,
+ { "Destination process ID", "tcp.proc.dstpid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Destination process ID", HFILL}},
+
+ { &hf_tcp_proc_dst_uname,
+ { "Destination process user name", "tcp.proc.dstuname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Destination process user name", HFILL}},
+
+ { &hf_tcp_proc_dst_cmd,
+ { "Destination process name", "tcp.proc.dstcmd", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Destination process command name", HFILL}}
};
static gint *ett[] = {
@@ -3997,7 +4102,8 @@ proto_register_tcp(void)
&ett_tcp_timestamps,
&ett_tcp_segments,
&ett_tcp_segment,
- &ett_tcp_checksum
+ &ett_tcp_checksum,
+ &ett_tcp_process_info
};
module_t *tcp_module;
@@ -4063,3 +4169,16 @@ proto_reg_handoff_tcp(void)
data_handle = find_dissector("data");
tcp_tap = register_tap("tcp");
}
+
+/*
+ * Editor modelines
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=4 noexpandtab
+ * :indentSize=4:tabSize=4:noTabs=false:
+ */
diff --git a/epan/dissectors/packet-tcp.h b/epan/dissectors/packet-tcp.h
index a261fb0ec3..e3e7bcbdef 100644
--- a/epan/dissectors/packet-tcp.h
+++ b/epan/dissectors/packet-tcp.h
@@ -61,7 +61,7 @@ struct tcpheader {
};
/*
- * Private data passed from the TCP dissector to subdissectors. Passed to the
+ * Private data passed from the TCP dissector to subdissectors. Passed to the
* subdissectors in pinfo->private_data
*/
struct tcpinfo {
@@ -111,9 +111,9 @@ typedef struct _tcp_unacked_t {
struct tcp_acked {
guint32 frame_acked;
nstime_t ts;
-
- guint32 rto_frame;
- nstime_t rto_ts; /* Time since previous packet for
+
+ guint32 rto_frame;
+ nstime_t rto_ts; /* Time since previous packet for
retransmissions. */
guint16 flags;
guint32 dupack_num; /* dup ack number */
@@ -140,16 +140,16 @@ typedef struct _tcp_flow_t {
*/
tcp_unacked_t *segments;
guint32 lastack; /* last seen ack */
- nstime_t lastacktime; /* Time of the last ack packet */
+ nstime_t lastacktime; /* Time of the last ack packet */
guint32 lastnondupack; /* frame number of last seen non dupack */
guint32 dupacknum; /* dupack number */
guint32 nextseq; /* highest seen nextseq */
guint32 nextseqframe; /* frame number for segment with highest
* sequence number
*/
- nstime_t nextseqtime; /* Time of the nextseq packet so we can
- * distinguish between retransmission,
- * fast retransmissions and outoforder
+ nstime_t nextseqtime; /* Time of the nextseq packet so we can
+ * distinguish between retransmission,
+ * fast retransmissions and outoforder
*/
guint32 window; /* last seen window */
gint16 win_scale; /* -1 is we dont know */
@@ -167,8 +167,14 @@ typedef struct _tcp_flow_t {
* all pdus spanning multiple segments for this flow.
*/
emem_tree_t *multisegment_pdus;
+
+ /* Process info, currently discovered via IPFIX */
+ guint32 process_uid; /* UID of local process */
+ guint32 process_pid; /* PID of local process */
+ gchar *username; /* Username of the local process */
+ gchar *command; /* Local process name + path + args */
} tcp_flow_t;
-
+
struct tcp_analysis {
/* These two structs are managed based on comparing the source
@@ -196,7 +202,7 @@ struct tcp_analysis {
/* This pointer is NULL or points to a tcp_acked struct if this
* packet has "interesting" properties such as being a KeepAlive or
- * similar
+ * similar
*/
struct tcp_acked *ta;
/* This structure contains a tree containing all the various ta's
@@ -232,10 +238,22 @@ extern void dissect_tcp_payload(tvbuff_t *tvb, packet_info *pinfo, int offset,
proto_tree *tcp_tree,
struct tcp_analysis *tcpd);
-extern struct tcp_analysis *get_tcp_conversation_data(conversation_t *conv,
+extern struct tcp_analysis *get_tcp_conversation_data(conversation_t *conv,
packet_info *pinfo);
extern gboolean decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, int, int, struct tcp_analysis *);
+/** Associate process information with a given flow
+ *
+ * @param local_addr The local IPv4 or IPv6 address of the process
+ * @param remote_addr The remote IPv4 or IPv6 address of the process
+ * @param local_port The local TCP port of the process
+ * @param remote_port The remote TCP port of the process
+ * @param uid The numeric user ID of the process
+ * @param pid The numeric PID of the process
+ * @param username Ephemeral string containing the full or partial process name
+ * @param command Ephemeral string containing the full or partial process name
+ */
+extern void add_tcp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command);
#endif
diff --git a/epan/dissectors/packet-udp.c b/epan/dissectors/packet-udp.c
index 0a0f2d5fc2..6e35f58701 100644
--- a/epan/dissectors/packet-udp.c
+++ b/epan/dissectors/packet-udp.c
@@ -62,9 +62,18 @@ static int hf_udplite_checksum_coverage_bad = -1;
static int hf_udp_checksum = -1;
static int hf_udp_checksum_good = -1;
static int hf_udp_checksum_bad = -1;
+static int hf_udp_proc_src_uid = -1;
+static int hf_udp_proc_src_pid = -1;
+static int hf_udp_proc_src_uname = -1;
+static int hf_udp_proc_src_cmd = -1;
+static int hf_udp_proc_dst_uid = -1;
+static int hf_udp_proc_dst_pid = -1;
+static int hf_udp_proc_dst_uname = -1;
+static int hf_udp_proc_dst_cmd = -1;
static gint ett_udp = -1;
static gint ett_udp_checksum = -1;
+static gint ett_udp_process_info = -1;
/* Preferences */
@@ -74,6 +83,9 @@ static gboolean udp_summary_in_tree = TRUE;
/* Check UDP checksums */
static gboolean udp_check_checksum = FALSE;
+/* Collect IPFIX process flow information */
+static gboolean udp_process_info = FALSE;
+
/* Ignore an invalid checksum coverage field for UDPLite */
static gboolean udplite_ignore_checksum_coverage = TRUE;
@@ -90,6 +102,121 @@ static dissector_handle_t data_handle;
static gboolean try_heuristic_first = FALSE;
+
+/* Conversation and process code originally copied from packet-tcp.c */
+static struct udp_analysis *
+init_udp_conversation_data(packet_info *pinfo)
+{
+ struct udp_analysis *udpd=NULL;
+
+ /* Initialize the udp protocol data structure to add to the udp conversation */
+ udpd = se_alloc0(sizeof(struct udp_analysis));
+ memset(&udpd->flow1, 0, sizeof(udp_flow_t));
+ memset(&udpd->flow2, 0, sizeof(udp_flow_t));
+ udpd->flow1.username = NULL;
+ udpd->flow1.command = NULL;
+ udpd->flow2.username = NULL;
+ udpd->flow2.command = NULL;
+
+ return udpd;
+}
+
+static conversation_t *
+get_udp_conversation(packet_info *pinfo)
+{
+ conversation_t *conv=NULL;
+
+ /* Have we seen this conversation before? */
+ if( (conv=find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0)) == NULL){
+ /* No this is a new conversation. */
+ conv=conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ }
+ return conv;
+}
+
+static struct udp_analysis *
+get_udp_conversation_data(conversation_t *conv, packet_info *pinfo)
+{
+ int direction;
+ struct udp_analysis *udpd=NULL;
+
+ /* Did the caller supply the conversation pointer? */
+ if( conv==NULL )
+ conv = get_udp_conversation(pinfo);
+
+ /* Get the data for this conversation */
+ udpd=conversation_get_proto_data(conv, proto_udp);
+
+ /* If the conversation was just created or it matched a
+ * conversation with template options, udpd will not
+ * have been initialized. So, initialize
+ * a new udpd structure for the conversation.
+ */
+ if (!udpd) {
+ udpd = init_udp_conversation_data(pinfo);
+ conversation_add_proto_data(conv, proto_udp, udpd);
+ }
+
+ if (!udpd) {
+ return NULL;
+ }
+
+ /* check direction and get ua lists */
+ direction=CMP_ADDRESS(&pinfo->src, &pinfo->dst);
+ /* if the addresses are equal, match the ports instead */
+ if(direction==0) {
+ direction= (pinfo->srcport > pinfo->destport) ? 1 : -1;
+ }
+ if(direction>=0){
+ udpd->fwd=&(udpd->flow1);
+ udpd->rev=&(udpd->flow2);
+ } else {
+ udpd->fwd=&(udpd->flow2);
+ udpd->rev=&(udpd->flow1);
+ }
+
+ return udpd;
+}
+
+/* Attach process info to a flow */
+/* XXX - We depend on the UDP dissector finding the conversation first */
+void
+add_udp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command) {
+ conversation_t *conv;
+ struct udp_analysis *udpd;
+ udp_flow_t *flow = NULL;
+
+ if (!udp_process_info) {
+ return;
+ }
+
+ conv = find_conversation(frame_num, local_addr, remote_addr, PT_UDP, local_port, remote_port, 0);
+ if (!conv) {
+ return;
+ }
+
+ udpd = conversation_get_proto_data(conv, proto_udp);
+ if (!udpd) {
+ return;
+ }
+
+ if (CMP_ADDRESS(local_addr, &conv->key_ptr->addr1) == 0 && local_port == conv->key_ptr->port1) {
+ flow = &udpd->flow1;
+ } else if (CMP_ADDRESS(remote_addr, &conv->key_ptr->addr1) == 0 && remote_port == conv->key_ptr->port1) {
+ flow = &udpd->flow2;
+ }
+ if (!flow || flow->command) {
+ return;
+ }
+
+ flow->process_uid = uid;
+ flow->process_pid = pid;
+ flow->username = se_strdup(username);
+ flow->command = se_strdup(command);
+}
+
+
+
void
decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, int uh_sport, int uh_dport, int uh_ulen)
@@ -187,6 +314,9 @@ dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto)
e_udphdr *udph;
proto_tree *checksum_tree;
proto_item *item;
+ conversation_t *conv = NULL;
+ struct udp_analysis *udpd = NULL;
+ proto_tree *process_tree;
udph=ep_alloc(sizeof(e_udphdr));
SET_ADDRESS(&udph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data);
@@ -417,6 +547,39 @@ dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto)
pinfo->destport = udph->uh_dport;
tap_queue_packet(udp_tap, pinfo, udph);
+
+ /* find(or create if needed) the conversation for this udp session */
+ if (udp_process_info) {
+ conv=get_udp_conversation(pinfo);
+ udpd=get_udp_conversation_data(conv,pinfo);
+ }
+
+ if (udpd && (udpd->fwd || udpd->rev) && (udpd->fwd->command || udpd->rev->command)) {
+ ti = proto_tree_add_text(udp_tree, tvb, offset, 0, "Process Information");
+ PROTO_ITEM_SET_GENERATED(ti);
+ process_tree = proto_item_add_subtree(ti, ett_udp_process_info);
+ if (udpd->fwd->command) {
+ proto_tree_add_uint_format_value(process_tree, hf_udp_proc_dst_uid, tvb, 0, 0,
+ udpd->fwd->process_uid, "%u", udpd->fwd->process_uid);
+ proto_tree_add_uint_format_value(process_tree, hf_udp_proc_dst_pid, tvb, 0, 0,
+ udpd->fwd->process_pid, "%u", udpd->fwd->process_pid);
+ proto_tree_add_string_format_value(process_tree, hf_udp_proc_dst_uname, tvb, 0, 0,
+ udpd->fwd->username, "%s", udpd->fwd->username);
+ proto_tree_add_string_format_value(process_tree, hf_udp_proc_dst_cmd, tvb, 0, 0,
+ udpd->fwd->command, "%s", udpd->fwd->command);
+ }
+ if (udpd->rev->command) {
+ proto_tree_add_uint_format_value(process_tree, hf_udp_proc_src_uid, tvb, 0, 0,
+ udpd->rev->process_uid, "%u", udpd->rev->process_uid);
+ proto_tree_add_uint_format_value(process_tree, hf_udp_proc_src_pid, tvb, 0, 0,
+ udpd->rev->process_pid, "%u", udpd->rev->process_pid);
+ proto_tree_add_string_format_value(process_tree, hf_udp_proc_src_uname, tvb, 0, 0,
+ udpd->rev->username, "%s", udpd->rev->username);
+ proto_tree_add_string_format_value(process_tree, hf_udp_proc_src_cmd, tvb, 0, 0,
+ udpd->rev->command, "%s", udpd->rev->command);
+ }
+ }
+
/*
* Call sub-dissectors.
*
@@ -479,7 +642,39 @@ proto_register_udp(void)
{ &hf_udp_checksum_bad,
{ "Bad Checksum", "udp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
- "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }}
+ "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }},
+
+ { &hf_udp_proc_src_uid,
+ { "Source process user ID", "udp.proc.srcuid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Source process user ID", HFILL}},
+
+ { &hf_udp_proc_src_pid,
+ { "Source process ID", "udp.proc.srcpid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Source process ID", HFILL}},
+
+ { &hf_udp_proc_src_uname,
+ { "Source process user name", "udp.proc.srcuname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Source process user name", HFILL}},
+
+ { &hf_udp_proc_src_cmd,
+ { "Source process name", "udp.proc.srccmd", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Source process command name", HFILL}},
+
+ { &hf_udp_proc_dst_uid,
+ { "Destination process user ID", "udp.proc.dstuid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Destination process user ID", HFILL}},
+
+ { &hf_udp_proc_dst_pid,
+ { "Destination process ID", "udp.proc.dstpid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "Destination process ID", HFILL}},
+
+ { &hf_udp_proc_dst_uname,
+ { "Destination process user name", "udp.proc.dstuname", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Destination process user name", HFILL}},
+
+ { &hf_udp_proc_dst_cmd,
+ { "Destination process name", "udp.proc.dstcmd", FT_STRING, BASE_NONE, NULL, 0x0,
+ "Destination process command name", HFILL}}
};
static hf_register_info hf_lite[] = {
@@ -494,7 +689,8 @@ proto_register_udp(void)
static gint *ett[] = {
&ett_udp,
- &ett_udp_checksum
+ &ett_udp_checksum,
+ &ett_udp_process_info
};
proto_udp = proto_register_protocol("User Datagram Protocol",
@@ -526,6 +722,10 @@ proto_register_udp(void)
"Validate the UDP checksum if possible",
"Whether to validate the UDP checksum",
&udp_check_checksum);
+ prefs_register_bool_preference(udp_module, "process_info",
+ "Collect process flow information",
+ "Collect process flow information from IPFIX",
+ &udp_process_info);
udplite_module = prefs_register_protocol(proto_udplite, NULL);
prefs_register_bool_preference(udplite_module, "ignore_checksum_coverage",
diff --git a/epan/dissectors/packet-udp.h b/epan/dissectors/packet-udp.h
index 4cb043b7f3..c289b241a2 100644
--- a/epan/dissectors/packet-udp.h
+++ b/epan/dissectors/packet-udp.h
@@ -36,6 +36,53 @@ typedef struct _e_udphdr {
address ip_dst;
} e_udphdr;
+/* Conversation and process structures originally copied from packet-tcp.c */
+typedef struct _udp_flow_t {
+ /* Process info, currently discovered via IPFIX */
+ guint32 process_uid; /* UID of local process */
+ guint32 process_pid; /* PID of local process */
+ gchar *username; /* Username of the local process */
+ gchar *command; /* Local process name + path + args */
+} udp_flow_t;
+
+struct udp_analysis {
+ /* These two structs are managed based on comparing the source
+ * and destination addresses and, if they're equal, comparing
+ * the source and destination ports.
+ *
+ * If the source is greater than the destination, then stuff
+ * sent from src is in ual1.
+ *
+ * If the source is less than the destination, then stuff
+ * sent from src is in ual2.
+ *
+ * XXX - if the addresses and ports are equal, we don't guarantee
+ * the behavior.
+ */
+ udp_flow_t flow1;
+ udp_flow_t flow2;
+
+ /* These pointers are set by get_tcp_conversation_data()
+ * fwd point in the same direction as the current packet
+ * and rev in the reverse direction
+ */
+ udp_flow_t *fwd;
+ udp_flow_t *rev;
+};
+
+/** Associate process information with a given flow
+ *
+ * @param local_addr The local IPv4 or IPv6 address of the process
+ * @param remote_addr The remote IPv4 or IPv6 address of the process
+ * @param local_port The local TCP port of the process
+ * @param remote_port The remote TCP port of the process
+ * @param uid The numeric user ID of the process
+ * @param pid The numeric PID of the process
+ * @param username Ephemeral string containing the full or partial process name
+ * @param command Ephemeral string containing the full or partial process name
+ */
+extern void add_udp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command);
+
extern void decode_udp_ports(tvbuff_t *, int, packet_info *,
proto_tree *, int, int, int);
diff --git a/epan/sminmpec.h b/epan/sminmpec.h
index 0ae64f97a3..6ba20936fb 100644
--- a/epan/sminmpec.h
+++ b/epan/sminmpec.h
@@ -75,7 +75,8 @@
#define VENDOR_THE3GPP 10415
#define VENDOR_GEMTEK_SYSTEMS 10529
#define VENDOR_WIFI_ALLIANCE 14122
-#define VENDOR_T_SYSTEMS_NOVA 16787
+#define VENDOR_T_SYSTEMS_NOVA 16787
+#define VENDOR_CACE 32622
WS_VAR_IMPORT const value_string sminmpec_values[];