Ethereal-dev: [Ethereal-dev] Process information patch
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Gerald Combs <gerald@xxxxxxxxxxxx>
Date: Sun, 14 Oct 2001 21:06:29 -0500 (CDT)
A while back Ryan Schneider suggested adding the ability to display information about the process associated with a particular packet. Attached is some code that does just that for TCP and UDP packets under Linux. It only works during live capture, and only when real-time data display is enabled. It's currently a proof-of-concept, and is in no way ready for production. I'm sending it to the list in case anyone wants to play with it.
Index: packet-frame.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-frame.c,v
retrieving revision 1.9
diff -u -r1.9 packet-frame.c
--- packet-frame.c 2001/09/14 07:10:05 1.9
+++ packet-frame.c 2001/10/15 01:19:43
@@ -34,6 +34,12 @@
#include "tvbuff.h"
#include "packet-frame.h"
+#if defined (linux)
+# include "conversation.h"
+# include "resolv.h"
+# include "process_info.h"
+#endif
+
static int proto_frame = -1;
static int hf_frame_arrival_time = -1;
static int hf_frame_time_delta = -1;
@@ -42,6 +48,9 @@
static int hf_frame_packet_len = -1;
static int hf_frame_capture_len = -1;
static int hf_frame_p2p_dir = -1;
+static int hf_frame_proc_uid = -1;
+static int hf_frame_proc_pid = -1;
+static int hf_frame_proc_cmd = -1;
static int proto_short = -1;
int proto_malformed = -1;
@@ -62,6 +71,10 @@
proto_item *ti;
nstime_t ts;
int cap_len, pkt_len;
+#ifdef linux
+ conversation_t *conversation;
+ process_info_t *proc_info;
+#endif
pinfo->current_proto = "Frame";
@@ -143,6 +156,25 @@
"[Malformed Frame: %s]", pinfo->current_proto );
}
ENDTRY;
+
+#ifdef linux
+ if (pinfo->ptype == PT_TCP || pinfo->ptype == PT_UDP) {
+ conversation = find_conversation(&pinfo->src, &pinfo->dst,
+ pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ if (conversation) {
+ proc_info = conversation_get_proto_data(conversation, proto_frame);
+ if (tree && proc_info->found) {
+ proto_tree_add_uint(fh_tree, hf_frame_proc_uid, tvb,
+ 0, 0, proc_info->uid);
+ proto_tree_add_uint(fh_tree, hf_frame_proc_pid, tvb,
+ 0, 0, proc_info->pid);
+ proto_tree_add_string(fh_tree, hf_frame_proc_cmd, tvb,
+ 0, 0, proc_info->cmd);
+ }
+ }
+ }
+#endif
+
}
void
@@ -177,6 +209,18 @@
{ &hf_frame_p2p_dir,
{ "Point-to-Point Direction", "frame.p2p_dir", FT_UINT8, BASE_DEC, VALS(p2p_dirs), 0x0,
+ "", HFILL }},
+
+ { &hf_frame_proc_uid,
+ { "Process UID", "frame.proc_uid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_frame_proc_pid,
+ { "Process PID", "frame.proc_pid", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+
+ { &hf_frame_proc_cmd,
+ { "Process Command", "frame.proc_cmd", FT_STRING, BASE_NONE, NULL, 0x0,
"", HFILL }},
};
static gint *ett[] = {
Index: packet-tcp.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-tcp.c,v
retrieving revision 1.111
diff -u -r1.111 packet-tcp.c
--- packet-tcp.c 2001/10/01 08:29:35 1.111
+++ packet-tcp.c 2001/10/15 01:19:44
@@ -44,6 +44,8 @@
#endif
#include "resolv.h"
+#include "packet_info.h"
+#include "process_info.h"
#include "ipproto.h"
#include "follow.h"
#include "prefs.h"
@@ -1067,7 +1069,14 @@
pinfo->ptype = PT_TCP;
pinfo->srcport = th_sport;
pinfo->destport = th_dport;
+
+ /* Get the proccess information */
+#ifdef linux
+
+ get_linux_proc_info(pinfo);
+#endif
+
/* Check the packet length to see if there's more data
(it could be an ACK-only packet) */
length_remaining = tvb_length_remaining(tvb, offset);
Index: packet-udp.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/packet-udp.c,v
retrieving revision 1.95
diff -u -r1.95 packet-udp.c
--- packet-udp.c 2001/09/27 10:19:14 1.95
+++ packet-udp.c 2001/10/15 01:19:44
@@ -216,6 +216,12 @@
}
}
+#ifdef linux
+
+ get_linux_proc_info(pinfo);
+
+#endif
+
/* Skip over header */
offset += 8;
Index: epan/Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ethereal/epan/Makefile.am,v
retrieving revision 1.27
diff -u -r1.27 Makefile.am
--- Makefile.am 2001/09/14 07:33:04 1.27
+++ Makefile.am 2001/10/15 01:19:44
@@ -67,6 +67,8 @@
pint.h \
plugins.c \
plugins.h \
+ process_info.c \
+ process_info.h \
proto.c \
proto.h \
resolv.c \
/* process_info.c
* Routines for process information lookup
*
* $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@xxxxxxxxxxxx>
* Copyright 2001 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if defined (linux)
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
/* General includes */
#include "packet.h"
#include "conversation.h"
#include "packet_info.h"
#include "process_info.h"
/* Linux-specific includes */
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
/*
* Given a pinfo struct with a TCP or UDP socket pair defined, look
* up the corresponding process information.
*
* /proc/net/{tcp|udp} provides the UID associated with each connection,
* but not the PID. To get the process info, we have to inspect each
* /proc/nnn/fd/mm to find the link to our socket inode.
*
* In order to make things a little more efficient, we skip PID directories
* that don't match our UID.
*
* XXX - Should we also skip the first few (3) file descriptors?
*/
#define MAX_PROC_STR_LEN 32 /* /proc/1234/fd/1234 or socket:[12345] */
#define MAX_PROC_NET_HDR_LEN 150
#define PROC_NET_HDR " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode \n"
#define PROC_NET_TCP_PATH "/proc/net/tcp"
#define PROC_NET_UDP_PATH "/proc/net/udp"
extern gboolean
get_linux_proc_info(packet_info *pinfo) {
DIR *dir, *pdir;
FILE *fp;
struct dirent *de, *pde;
struct stat st_buf;
char big_str[MAX_PROC_NET_HDR_LEN];
char *d_name, path[MAX_PROC_STR_LEN], fdpath[MAX_PROC_STR_LEN];
char lbuf[MAX_PROC_STR_LEN], linkstr[MAX_PROC_STR_LEN];
int len = 0;
guint32 locaddr, remaddr, uid, inode = 0;
guint16 locport, remport;
conversation_t *conversation;
static int proto_frame = -1;
/* uid_t uid;
ino_t inode = 0;
*/
static process_info_t *proc_not_found = NULL;
process_info_t *proc_info;
/* Find the frame protocol number */
proto_frame = proto_get_id_by_filter_name("frame");
/* XXX - Add IPv6 support */
if (pinfo->net_src.type != AT_IPv4 || pinfo->net_dst.type != AT_IPv4) {
return FALSE;
}
if (pinfo->ptype != PT_TCP && pinfo->ptype != PT_UDP) {
return FALSE;
}
/* Find out if the process info has already been looked up.
If not, create a new conversation. */
conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (conversation) {
proc_info = conversation_get_proto_data(conversation, proto_frame);
if (proc_info->tries < 1)
return proc_info->found;
} else {
proc_info = g_malloc(sizeof(process_info_t));
proc_info->found = FALSE;
proc_info->tries = 4;
proc_info->uid = 0;
proc_info->pid = 0;
proc_info->cmd = NULL;
conversation = conversation_new(&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
conversation_add_proto_data(conversation, proto_frame, (void *) proc_info);
}
/* Initialize proc_not_found if needed. */
if (!proc_not_found) {
proc_not_found = g_malloc(sizeof(process_info_t));
proc_not_found->found = FALSE;
proc_not_found->tries = 0;
proc_not_found->uid = 0;
proc_not_found->pid = 0;
proc_not_found->cmd = NULL;
}
if (pinfo->ptype == PT_TCP) {
fp = fopen(PROC_NET_TCP_PATH, "r");
} else if (pinfo->ptype == PT_UDP) {
fp = fopen(PROC_NET_UDP_PATH, "r");
} else {
return FALSE;
}
if (fgets(big_str, MAX_PROC_NET_HDR_LEN - 1, fp) == NULL) {
return FALSE;
}
if (strcmp(big_str, PROC_NET_HDR) != 0) {
return FALSE;
}
/* From net/ipv4/proc.c in the Linux 2.2.14 sources:
*
* sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
* " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u"
*
* The local and remote addresses that are fed to sprintf are in network byte
* order. On little endian systems, this means they are printed in /proc/net/tcp in
* reverse order. However, scanning them back in should store them in network byte
* order.
*/
while (fgets(big_str, MAX_PROC_NET_HDR_LEN - 1, fp) != NULL) {
/*
* Sheesh. For some reason, fscanf _won't_ scan 32-bit hex values on
* my system, but sscanf _will_.
* - gcc
*/
len = sscanf(big_str, "%*d: %8x:%x %8x:%4x"
" %*2x %*8x:%*8x %*2x:%*8x %*8x %d %*d %u \n",
&locaddr, (unsigned int *) &locport, &remaddr, (unsigned int *) &remport, &uid, &inode);
if (len < 6)
break;
if ((memcmp(pinfo->net_src.data, &locaddr, 4) == 0 &&
memcmp(&pinfo->srcport, &locport, 2) == 0 &&
memcmp(pinfo->net_dst.data, &remaddr, 4) == 0 &&
memcmp(&pinfo->destport, &remport, 2) == 0) ||
(memcmp(pinfo->net_dst.data, &locaddr, 4) == 0 &&
memcmp(&pinfo->destport, &locport, 2) == 0 &&
memcmp(pinfo->net_src.data, &remaddr, 4) == 0 &&
memcmp(&pinfo->srcport, &remport, 2) == 0)) {
break;
}
len = 0;
}
fclose(fp);
if (len < 6) {
goto not_found;
}
sprintf(linkstr, "socket:[%d]", inode); /* The point of this exercise */
dir = opendir("/proc");
while ((de = readdir(dir)) != NULL) {
d_name = de->d_name;
while (*d_name != '\0') { /* Is the name all digits, i.e. a PID? */
if (! isdigit(*d_name))
break;
d_name++;
}
if (*d_name == '\0') {
snprintf(path, MAX_PROC_STR_LEN, "/proc/%s", de->d_name);
path[MAX_PROC_STR_LEN - 1] = '\0';
snprintf(path, MAX_PROC_STR_LEN, "/proc/%s/fd", de->d_name);
path[MAX_PROC_STR_LEN - 1] = '\0';
if ((pdir = opendir(path)) != NULL) {
while ((pde = readdir(pdir)) != NULL) {
snprintf(fdpath, MAX_PROC_STR_LEN, "%s/%s", path, pde->d_name);
fdpath[MAX_PROC_STR_LEN - 1] = '\0';
len = readlink(fdpath, lbuf, MAX_PROC_STR_LEN);
if (len > 0 && len < MAX_PROC_STR_LEN) {
lbuf[len] = '\0';
if (strcmp(lbuf, linkstr) == 0) {
/* We have a winner */
/* For setuid programs, the UID returned by /proc/net/{tcp|udp} shows
* the set UID and not the original UID.
*/
snprintf(path, MAX_PROC_STR_LEN, "/proc/%s", de->d_name);
path[MAX_PROC_STR_LEN - 1] = '\0';
if(stat(path, &st_buf) != 0) {
closedir(pdir);
closedir(dir);
goto not_found;
}
uid = st_buf.st_uid;
snprintf(path, MAX_PROC_STR_LEN, "/proc/%s/cmdline", de->d_name);
path[MAX_PROC_STR_LEN - 1] = '\0';
fp = fopen(path, "r");
if (fp == NULL) {
closedir(pdir);
closedir(dir);
goto not_found;
}
if (fgets(big_str, MAX_PROC_NET_HDR_LEN - 1, fp) != NULL) {
/* XXX - Parse out the command args. The buffer read contains
null-separated strings */
proc_info->found = TRUE;
proc_info->tries = 0;
proc_info->uid = uid;
proc_info->pid = atoi(de->d_name);
proc_info->cmd = g_strdup(big_str);
return TRUE;
}
fclose(fp);
}
}
}
closedir(pdir);
}
}
}
closedir(dir);
not_found:
if (conversation) {
if (proc_info->tries > 0) {
proc_info->tries--;
return FALSE;
}
g_free(proc_info);
}
conversation = conversation_new(&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
conversation_add_proto_data(conversation, proto_frame, (void *) proc_not_found);
return FALSE;
}
/* XXX - add clear_linux_proc_info, which frees up the command strings. */
#endif
/* process_info.h
* Definitions for process information lookup
*
* $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@xxxxxxxx>
* Copyright 2001 Gerald Combs
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PROCESS_INFO_H__
#define __PROCESS_INFO_H__
#ifdef linux
/*
* For a given populated pinfo struct, find the process and user info
* associated with the socket pair.
*/
typedef struct {
gboolean found;
gint tries;
guint32 uid;
guint32 pid;
gchar *cmd; /* XXX - put in a lookup table later. */
} process_info_t;
gboolean get_linux_proc_info(packet_info *pinfo);
#endif
#endif /* __PROCESS_INFO_H__ */
- Prev by Date: [Ethereal-dev] packet-smb
- Next by Date: Re: [Ethereal-dev] packet-smb
- Previous by thread: Re: [Ethereal-dev] WSP-patch
- Next by thread: Re: [Ethereal-dev] UCP Dissector bugfixes
- Index(es):





