Find original owning process of a Linux socket - c

In Linux and other UNIX-like operating systems, it is possible for two (or more) processes to share an Internet socket. Assuming there is no parent-child relationship between the processes, is there any way to tell what process originally created a socket?
Clarification: I need to determine this from "outside" the processes using the /proc filesystem or similar. I can't modify the code of the processes. I can already tell what processes are sharing sockets by reading /proc/<pid>/fd, but that doesn't tell me what process originally created them.

You can use netstat for this. You should look in the columns 'Local Address' and 'PID/Program name'.
xxx#xxx:~$ netstat -tulpen
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 127.0.0.1:4005 0.0.0.0:* LISTEN 1000 68449 7559/sbcl
tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN 0 3938 -
tcp6 0 0 :::6000 :::* LISTEN 0 3937 -
udp 0 0 0.0.0.0:68 0.0.0.0:* 0 4528 -

doesn't 'lsof -Ua' help?

You can likely find the shared sockets by parsing /proc/net/tcp (and similar "files" for other protocols). There's some docs on /proc/net/tcp here.
You would need to find the socket (perhaps by its IP addresses/port numbers ?) and parse out the inode number. Once you have the inode, you can search through all of /proc/*/fd/* , calling stat for every link and inspect the st_ino member of struct stat until you find a match.
The inode number should match between the 2 processes, so when you've gone through all /proc/*/fd/* you should have found them both.
If what you do know is the process id and socket fd of the first, you might not need to go through /proc/net/tcp, all you need to do is stat the /proc/<pid>/fd/<fd> and search the rest of /proc/*/fd/* for a matching inode. You'd need /proc/net/tcp if you want to fetch the ip addresses/port number though - which you can find if you know the inode number

For purposes creating a test case, consider a situation where multiple ssh-agent processes are running and have open sockets. I.e. A user runs ssh-agent multiple times and loses the socket/PID information given when the agent started:
$ find /tmp -path "*ssh*agent*" 2>/dev/null
/tmp/ssh-0XemJ4YlRtVI/agent.14405
/tmp/ssh-W1Tl4i8HiftZ/agent.21283
/tmp/ssh-w4fyViMab8wr/agent.10966
Later, the user wants to programmatically determine the PID owner of a particular ssh-agent socket (i.e. /tmp/ssh-W1Tl4i8HiftZ/agent.21283):
$ stat /tmp/ssh-W1Tl4i8HiftZ/agent.21283
File: '/tmp/ssh-W1Tl4i8HiftZ/agent.21283'
Size: 0 Blocks: 0 IO Block: 4096 socket
Device: 805h/2053d Inode: 113 Links: 1
Access: (0600/srw-------) Uid: ( 4000/ myname) Gid: ( 4500/ mygrp)
Access: 2018-03-07 21:23:08.373138728 -0600
Modify: 2018-03-07 20:49:43.638291884 -0600
Change: 2018-03-07 20:49:43.638291884 -0600
Birth: -
In this case, because ssh-agent named its socket nicely as a human onlooker can guess that the socket belongs to PID 21284, because the socket name contains a numeric component that is one-off from a PID identified with ps:
$ ps -ef | grep ssh-agent
myname 10967 1 0 16:54 ? 00:00:00 ssh-agent
myname 14406 1 0 20:35 ? 00:00:00 ssh-agent
myname 21284 1 0 20:49 ? 00:00:00 ssh-agent
It seems highly unwise to make any assumption that the PIDs will be so reliable as to always only be off by one, but also, one might suppose that not all socket creators will name the sockets so nicely.
#Cypher's answer points to a straightforward solution to the problem of identifying the PID of the socket owner, but is incomplete as lsof actually can only identify this PID with elevated permissions. Without elevated permissions, no results are forthcoming:
$ lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283
$
With elevated permissions, however, the PID is identified:
$ sudo lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ssh-agent 21284 myname 3u unix 0xffff971aba04cc00 0t0 1785049 /tmp/ssh-W1Tl4i8HiftZ/agent.21283 type=STREAM
In this case, the owner of the PID (myname) and socket was the one doing the query, so it seemed elevated permissions should not be needed. Furthermore, the task performing the query was not supposed to be able to elevate permissions, so I looked for another answer.
This led me to #whoplisp's answer proposing netstat -tulpen as a solution to the OP's problem. While it may have been effective for the OP, the command line is too restrictive to serve as a general purpose command and was completely ineffective in this case (even with elevated permissions).
$ sudo netstat -tulpen | grep -E -- '(agent.21283|ssh-agent)'
$
netstat, however, can come close if a different command-line is used:
$ netstat -ap | grep -E -- '(agent.21283)'
(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)
unix 2 [ ACC ] STREAM LISTENING 1785049 - /tmp/ssh-W1Tl4i8HiftZ/agent.21283
Sadly, here too, the PID is elusive without elevated permissions:
$ sudo netstat -ap | grep -E -- '(agent.21283|ssh-agent)'
unix 2 [ ACC ] STREAM LISTENING 1765316 10967/ssh-agent /tmp/ssh-w4fyViMab8wr/agent.10966
unix 2 [ ACC ] STREAM LISTENING 1777450 14406/ssh-agent /tmp/ssh-0XemJ4YlRtVI/agent.14405
unix 2 [ ACC ] STREAM LISTENING 1785049 21284/ssh-agent /tmp/ssh-W1Tl4i8HiftZ/agent.21283
Of the two solutions, however, lsof clearly wins at the races:
$ time sudo netstat -ap | grep -E -- '(agent.21283|ssh-agent)' >/dev/null
real 0m5.159s
user 0m0.010s
sys 0m0.019s
$ time sudo lsof /tmp/ssh-W1Tl4i8HiftZ/agent.21283 >/dev/null
real 0m0.120s
user 0m0.038s
sys 0m0.066s
Yet another tool exists according to the netstat man page:
$ man netstat | grep -iC1 replace
NOTES
This program is mostly obsolete. Replacement for netstat is ss. Replacement for netstat -r is ip route. Replacement for netstat -i
is ip -s link. Replacement for netstat -g is ip maddr.
Sadly, ss also requires elevated permissions to identify the PID, but, it beats both netstat and lsof execution times:
$ time sudo ss -ap | grep -E "(agent.21283|ssh-agent)"
u_str LISTEN 0 128 /tmp/ssh-w4fyViMab8wr/agent.10966 1765316 * 0 users:(("ssh-agent",pid=10967,fd=3))
u_str LISTEN 0 128 /tmp/ssh-0XemJ4YlRtVI/agent.14405 1777450 * 0 users:(("ssh-agent",pid=14406,fd=3))
u_str LISTEN 0 128 /tmp/ssh-W1Tl4i8HiftZ/agent.21283 1785049 * 0 users:(("ssh-agent",pid=21284,fd=3))
real 0m0.043s
user 0m0.018s
sys 0m0.021s
In conclusion, it might seem that for some PID identification, it appears that elevated permissions are required.
Note: Not all operating systems require elevated permissions. For example, SCO Openserver 5.0.7's lsof seemed to work just fine without elevating permissions.
Caveat: This answer may fail with respect to the OP's qualification for finding "the original creator" of the socket. In the example used, no doubt PID 21283 was the originator of the socket's creation as this PID is identified in the socket name. Neither lsof nor netstat identified PID 21283 as the original creator, though clearly PID 21284 is the current maintainer.

Related

Is there a way to programatically identify the status of a tcp connection/port?

I get a port after seeing the $DISPLAY environment variable, and need to check if the vnc on which the current program is run is connected or not.
❯ netstat -an --tcp | grep 5902
tcp 0 0 0.0.0.0:5902 0.0.0.0:* LISTEN
The above is a netstat output.
On tcp connection established for the port, the following is the output:
$ netstat -an --tcp | grep 5902
tcp 0 0 0.0.0.0:5902 0.0.0.0:* LISTEN
tcp 0 0 172.16.100.219:5902 172.16.100.129:35542 ESTABLISHED
One can call netstat from within C/c++ code something like
port = process_display(std::getenv("DISPLAY"))
is_connected = call_this("netstat -anp | grep <porttocheck> | grep ESTABLISHED | wc -l");
I need the is_connected and do some logic.
However, this relies on variety of factors, if the program is going to run on different machines, I would rather not rely on calling netstat from code.
Is there a better way to check if a port has a established TCP connection, from C code? Parsing /proc/ or something similar also looks very unweildy.
I am ok for a linux only solution.
I think you can create a socket with the port which you want the status of it. If socket successfully created it means that the port was closed otherwise it is open. like this

Capturing tshark standard output with popen in C

I'm trying to capture the standard output from tshark through a program in C.
For that, I use popen() call to open tshark process and read from the returned FILE stream.
Code sample:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE* pipe_fd = popen("tshark -i eth0 -R icmp -2 -T fields -e icmp.checksum -e icmp.seq", "r");
//FILE* pipe_fd = popen("lsof", "r");
if (!pipe_fd) {
fprintf(stderr, "popen failed.\n");
return EXIT_FAILURE;
}
char buffer[2048];
while (NULL != fgets(buffer, sizeof(buffer), pipe_fd)) {
fprintf(stdout, "SO: %s", buffer);
}
pclose(pipe_fd);
printf("tdr FINISHED!\n");
return 0;
}
When I run it, I get only the packet number count, i.e., I get no packet fields info, just the count of packets, with each number overriding the previous in the same place (no lines scroll happening).
Something like this, I guess for 4 packets:
tomas#ubuntu64:~$ sudo ./main
tshark: Lua: Error during loading:
[string "/usr/share/wireshark/init.lua"]:46: dofile has been disabled due to running Wireshark as superuser. See http://wiki.wireshark.org/CaptureSetup/CapturePrivileges for help in running Wireshark as an unprivileged user.
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
4
But if I change in the C program the 'tshark' command argument by 'lsof', I get the standard output just fine.
tomas#ubuntu64:~$ sudo ./main
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
SO: COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
SO: init 1 root cwd DIR 8,1 4096 2 /
SO: init 1 root rtd DIR 8,1 4096 2 /
SO: init 1 root txt REG 8,1 265848 791529 /sbin/init
SO: init 1 root mem REG 8,1 47712 824514 /lib/x86_64-linux-gnu/libnss_files-2.19.so
...
With this result, I'm assuming that there is something special with the way tshark sends the info to the standard output. Does anyone know about this behaviour?
I'm gonna check tshark source code, to see if it can clarify it.
Just a final note.
When I run tshark through the shell, I often get missing packet numbers like:
tomas#ubuntu64:~$ sudo tshark -i eth0 -R icmp -2 -T fields -e icmp.checksum -e icmp.seq
tshark: Lua: Error during loading:
[string "/usr/share/wireshark/init.lua"]:46: dofile has been disabled due to running Wireshark as superuser. See http://wiki.wireshark.org/CaptureSetup/CapturePrivileges for help in running Wireshark as an unprivileged user.
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
0x0ee5 63045
1 0x8ae3 63046
2 0xcfdf 63047
3 0xe4d9 63048
4 0x9db7 63049
5 0x6798 63050
6 0x0175 63051
7 0x9e54 63052
0xa654 63052
9 0xe050 63053
0xe850 63053
11 0x8389 63054
0x8b89 63054
13 0x9b81 63055
0xa381 63055
Missing printed packet numbers 8, 10, 12, 14.
And when I redirect stdout to file, it does not send the count numbers:
tomas#ubuntu64:~$ sudo tshark -i eth0 -R icmp -2 -T fields -e icmp.checksum -e icmp.seq > kk
tomas#ubuntu64:~$ cat kk
0x2073 63321
0x2873 63321
0x7c6a 63322
Another clue that tshark is handling printed packet count and info differently.
Regards,
Tom
Well, even if I finally don't use this way of working with tshark, I think I found the option to use in order to popen tshark. From the manual page, option -l:
Flush the standard output after the information for each packet is printed. (This is not, strictly speaking, line-buffered if -V was
specified; however, it is the same as line-buffered if -V wasn't
specified, as only one line is printed for each packet, and, as -l is
normally used when piping a live capture to a program or script, so
that output for a packet shows up as soon as the packet is seen and
dissected, it should work just as well as true line-buffering. We do
this as a workaround for a deficiency in the Microsoft Visual C++ C
library.)
This may be useful when piping the output of TShark to another
program, as it means that the program to which the output is piped
will see the dissected data for a packet as soon as TShark sees the
packet and generates that output, rather than seeing it only when the
standard output buffer containing that data fills up.
I tested it, and it seems to work.
Just in case anyone needs it.

Get information on PID

I'm trying to get the information on a PID via c or terminal (ideally I would like to get it both ways, multiple methods)
I have a PID and would like to figure out the time it was claimed. By claimed i mean when a program started using it. Or if a PID was reused, when the latest program that is using it, started to use it.
In Linux what I do is lstat "/proc/PID_HERE/exe" or lstat "/proc/PID_HERE/cmdline" but I cant figure out how to do this on Mac OS.
Note: I changed from stat to lstat because a single exe is being used with command line arguments to open multiple instances. So each instance gets a new pid, so I want info on that specific instance, thus on Linux I have to use lstat. So any lstat equivalent to get pid info on mac os?
I think you mean this:
ps -p <PID> -o start=
10:22am
where you substitute in your PID. The start= selects the start time and also suppresses the header line. If you want the header, use
ps -p <PID> -o start
STARTED
10:22am
Alternatively, you can get the start time formated more fully like this:
ps -p <PID> -o lstart=
Fri 26 Sep 10:22:50 2014
By the way, if you want a list of the keywords (like start and lstart above) you can either wade through the manage, or more simply, just give an invalid keyword and it will tell you all the ones it likes :-)
ps -o %rubbish
ps: %rubbish: keyword not found
ps: no valid keywords; valid keywords:
%cpu %mem acflag acflg args blocked caught comm command cpu cputime etime f flags gid group ignored
inblk inblock jobc ktrace ktracep lim login logname lstart majflt minflt msgrcv msgsnd ni nice nivcsw
nsignals nsigs nswap nvcsw nwchan oublk oublock p_ru paddr pagein pcpu pending pgid pid pmem ppid pri
pstime putime re rgid rgroup rss ruid ruser sess sig sigmask sl start stat state stime svgid svuid
tdev time tpgid tsess tsiz tt tty ucomm uid upr user usrpri utime vsize vsz wchan wq wqb wql wqr xstat

Implementing my own ps command

I'm trying to implement my own ps command, called psmod.
I can use linux system call and all utilities of the /proc directory.
I discovered that all directory in /proc directory with a number as their name are the processes in the system. My question is: how can I select only those processes which are active when psmod is called?
I know that in /proc/<pid>/stat there's a letter representing the current status of the process; anyway, for every process in /proc, this letter is S, that is sleeping.
I also tried to send a signal 0 to every process, from 0 to the maximumnumberofprocesses (in my case, 32768), but in this way it discovers far more processes than the ones present in /proc.
So, my question is, how does ps work? The source is a little too complicated for me, so if someone can explain me, I would be grateful.
how does ps work?
The way of learning standard utils - is to check their source code. There are several implementations of ps: procps and busybox; and busybox is smaller and it will be easier to begin with it. There is sources for ps from busybox: http://code.metager.de/source/xref/busybox/procps/. Main loop from ps.c:
632 p = NULL;
633 while ((p = procps_scan(p, need_flags)) != NULL) {
634 format_process(p);
635 }
Implementation of procps_scan is in procps.c (ignore code from inside ENABLE_FEATURE_SHOW_THREADS ifdefs for first time). First call to it will open /proc dir using alloc_procps_scan():
290 sp = alloc_procps_scan();
100 sp->dir = xopendir("/proc");
Then procps_scan will read next entry from /proc directory:
292 for (;;) {
310 entry = readdir(sp->dir);
parse the pid from subdirectory name:
316 pid = bb_strtou(entry->d_name, NULL, 10);
and read /prod/pid/stat:
366 /* These are all retrieved from proc/NN/stat in one go: */
379 /* see proc(5) for some details on this */
380 strcpy(filename_tail, "stat");
381 n = read_to_buf(filename, buf);
Actual unconditional printing is in format_process, ps.c.
So, busybox's simple ps will read data for all processes, and will print all processes (or all processes and all threads if there will be -T option).
how can I select only those processes which are active when psmod is called?
What is "active"? If you want find all processes that exists, do readdir of /proc. If you want to find only non-sleeping, do full read of /proc, check states of every process and print only non-sleeping. The /proc fs is virtual and is it rather fast.
PS: for example, normal ps program prints only processes from current terminal, usually two:
$ ps
PID TTY TIME CMD
7925 pts/13 00:00:00 bash
7940 pts/13 00:00:00 ps
but we can strace it with strace -ttt -o ps.log ps and I see that ps does read every process directory, files stat and status. And the time needed for this (option -tt of strace gives us timestamps of every syscall): XX.719011 - XX.870349 or just 120 ms under strace (which slows all syscalls). It takes only 20 ms in real life according to time ps (I have 250 processes in total):
$ time ps
PID TTY TIME CMD
7925 pts/13 00:00:00 bash
7971 pts/13 00:00:00 ps
real 0m0.021s
user 0m0.006s
sys 0m0.014s
"My question is: how can I select only those processes which are active when psmod is called?"
I hope this command will help you:
top -n 1 | awk "NR > 7" | awk {'print $1,$8,$12'} | grep R
I am on ubuntu 12.

Linux API to determine sockets owned by a process

Is there a Linux library that will enable me to tell what IP sockets are owned by what processes? I guess I'm looking for the programmatic equivalent of lsof -i. Ultimately, I want to correlate packets seen through libpcap to processes.
UPDATE: A couple of people have suggested using /proc/<pid>/net/tcp and udp, but on my system, the same data is shown for every process, so it doesn't help.
I think you first have to look through the open fds in /proc/*/fd, e.g.
4 -> socket:[11147]
and then look for the referenced sockets (by the inode) in /proc/net/tcp (or /proc/net/udp), e.g.
12: B382595D:8B40 D5C43B45:0050 01 00000000:00000000 00:00000000 00000000 1000 0 11065 1 ffff88008bd35480 69 4 12 4 -1
To determine sockets owned by a process you can just use netstat. Here's an example w/output (shortened) of netstat with options that will do what you want.
$ sudo netstat -apeen
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 127.0.0.1:8118 0.0.0.0:* LISTEN 138 744850 13248/privoxy
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 117 9612 2019/postgres
udp 0 0 127.0.0.1:51960 127.0.0.1:51960 ESTABLISHED 117 7957 2019/postgres
udp 0 0 0.0.0.0:68 0.0.0.0:* 0 7740 1989/dhclient
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 2 [ ACC ] STREAM LISTENING 7937 2019/postgres /var/run/postgresql/.s.PGSQL.5432
unix 2 [ ACC ] STREAM LISTENING 958058 8080/emacs /tmp/emacs1000/server
unix 2 [ ACC ] STREAM LISTENING 6969 1625/Xorg /tmp/.X11-unix/X0
unix 2 [ ] DGRAM 9325 1989/dhclient
unix 3 [ ] STREAM CONNECTED 7720 1625/Xorg #/tmp/.X11-unix/X0
Make sure you run netstat as root otherwise you'll get this message:
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
An explanation of the -apeen options from the netstat manpage:
-a, --all
Show both listening and non-listening sockets. With the
--interfaces option, show interfaces that are not up
-p, --program
Show the PID and name of the program to which each socket
belongs.
-e, --extend
Display additional information. Use this option twice for
maximum detail.
--numeric , -n
Show numerical addresses instead of trying to determine symbolic host, port or user names.
--numeric-hosts
shows numerical host addresses but does not affect the resolution of port or user names.
--numeric-ports
shows numerical port numbers but does not affect the resolution of host or user names.
--numeric-users
shows numerical user IDs but does not affect the resolution of host or port names.
The /proc filesystem provides details on each process, including networking information. Open socket information is listed in /proc/net/tcp. The IPv6 sockets are listed separately in the tcp6 file. The socket information includes information such as the local and remote ports, and the socket inode number, which can be mapped back to the process by parsing the /proc/{pid}/fd/* information.
If you aren't familiar with the /proc filesystem, it is basically a virtual filesystem that allows the kernel to publish all sorts of useful information to user-space. The files are normally simple structured text files that are easy to parse.
For example, on my Ubuntu system I used netcat for testing, and ran nc -l -p 8321 to listen on port 8321. Looking at the tcp socket information:
$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:2081 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 26442 1 de0c8e40 300 0 0 2 -1
1: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 7019 1 de0c84c0 300 0 0 2 -1
The first line shows it is listening on all addresses to point 8321 (0x2081). The inode number is 26442, which we can use to look up the matching pid in /proc/{pid}/fd/*, which consists of a bunch of symlinks from the file handle number to the device. So if we look up the pid for netcat, and check its fd mapping:
$ ls -l /proc/7266/fd
total 0
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 0 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 1 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 2 -> /dev/pts/1
lrwx------ 1 gavinb gavinb 64 2009-12-31 09:10 3 -> socket:[26442]
And there we see that file descriptor 3 in this process is mapped to the socket with inode 26442, just as we expect.
So obviously to build a complete map of sockets, you will need to first enumerate all the /proc/**/fd/* files, look up the socket symlinks, then match the socket inode against the tables from /proc/net/tcp which has the endpoint information.
This is the way the lsof tool works (see lsof/dialects/linux/dsocket.c for the implementation).
Wikipedia on procfs
The Linux /proc filesystem as a Programmer's Tool
/proc/<pid>/net is equivalent to /proc/net for all processes in the same network namespace as you – in other words, it's "global" information.
You can do what lsof and fuser do, which is to iterate through both /proc/<pid>/fd/* and /proc/net/* looking for matching inodes. Quick demonstration:
#!/bin/sh
pgrep "$#" | while read pid; do
for fd in /proc/$pid/fd/*; do
name=$(readlink $fd)
case $name in
socket:\[*\])
ino=${name#*:}
for proto in tcp:10 tcp6:10 udp:10 udp6:10 unix:7; do
[[ ! -e /proc/net/${proto%:*} ]] ||
awk "
\$${proto##*:} == ${ino:1:${#ino}-2} {
print \"${proto%:*}:\", \$0
exit 1
}
" /proc/net/${proto%:*} || break
done
;;
esac
done
done
You can extend this to other protocols (I see ax25, ipx, packet, raw, raw6, udplite, udp6lite in /proc/net/ too) or rewrite in a language of your choosing.
You can read them from proc filesystem. The 'files' you probably want to look at are found in
/proc/<pid>/net (namely tcp, udp, unix)
Here's some examples on using the proc filesystem
You could try running lsof with strace and see just which files in /proc it gets data from.
I'd go to the source:
http://ubuntuforums.org/showthread.php?t=1346778

Resources