sbz's blog

Technical writings and recipes on UNIX, software and systems

Advanced netstat output

Posted at — Jan 1, 2008

Something that really annoys me when using the netstat(8) command on Linux, it does not report the full command line with arguments of the process who owns the given network socket, just the process identifier and the program name in format PID/program name.

By reading the source code of the netstat(8) program from the busybox project here

311	    len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName);
312	    n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1);
313	    if (n < 0)
314		    return FALSE;
315	    cmdline_buf[n] = '\0';
316
317	    /* go through all files in /proc/PID/fd and check whether they are sockets */
318	    strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd");
319	    pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */

We could confirm at line 319 that it just use the argv[0] i.e. the program name without the full command line. It wouldn’t be to hard to create a patch to have the full command line (stored in the variable cmdline_buf) reported here but we’re not gonna do it that way because we will never have a netstat program patched on different Linux hosts.

Instead, I came up with a new bash(1) function called advanced-netstat() that I’m using to achieve that. The function use combination of awk(1) processing to format a new column with the cmdline of the PID extracted from procfs via /proc/${PID}/cmdline:

advanced-netstat() {
    sudo netstat -laputen|head -n 1
    sudo netstat -laputen|head -n 2 | tail -1| tr -d '\n'; echo -n "Program Cmd"; echo
    sudo netstat -laputen|awk '/LISTEN/{
    split($9, procpid, "/")
    cmdline="/proc/" procpid[1]"/cmdline"
    getline procline < cmdline
    trunc=substr(procline, 1, 80)
    gsub("\0", " ", trunc)
    print $_ trunc}'
}

It gives you the following output for a listening faked SSH connection on port ssh/22 using netcat nc(1) :

Standard output

[email protected]:/root# sudo netstat -laputen
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          252280     643/nc
tcp        0      0 172.17.0.2:52590        91.189.88.152:80        TIME_WAIT   0          0          -
tcp        0      0 172.17.0.2:52588        91.189.88.152:80        TIME_WAIT   0          0          -

Modified output

[email protected]:/root# advanced-netstat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name    Program Cmd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          254692     673/nc              nc -l -p 22 -m 10 -q 2 -P sbz -w 10 -v -4

It’s quite handy if you have multiple processes with the same program name running. You could identify correctly who is who instead of trying to figure out by using multiple shell commands each time.

Alternatively, it could have been done using socket stat ss(8) program from the iproute2 Linux project when invoked with ss -l -p -t with display options -l for listen, -p process, -t for tcp but I’m used to netstat.