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):