Hari Mahadevan
Hari Mahadevan

Reputation: 920

How to programmatically get the pid of a socket's peer in MacOS?

In MacOS, other than launching lsof command, is there way to get the process id of a socket's peer from within a TCP server that is bound to localhost? If there isn't, is lsof guaranteed to be present in all OSX versions starting from 10.11 (El Capitan)?

EDIT: The server process is running within the current user context (it does not have elevated privileges). And the connecting process is also expected to be running at the same privilege level.

TIA.

Upvotes: 0

Views: 1131

Answers (2)

Davy Durham
Davy Durham

Reputation: 402

This is surprisingly easy, despite the apparent ignorance around the Internet of this solution. LOCAL_PEERPID is your friend here.

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <stdio.h>

pid_t pid = -1;
socklen_t len = sizeof(pid);

if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERPID, &pid, &len) == -1) {
    printf("failed: %d\n", errno);
} else {
    printf("pid: %d\n", pid);
}

where sockfd is the socket file descriptor you need to input.

The rest of the LOCAL_PEER* family of options could also be of interest, depending on which exact piece of information is required:

// Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/Mac0SX.sdk/usr/include/sys/un.h
#define LOCAL_PEERCRED   0x001  /* retrieve peer credentials */
#define LOCAL_PEERPID    0x002  /* retrieve peer pid */
#define LOCAL_PEEREPID   0x003  /* retrieve eff. peer pid */
#define LOCAL_PEERUUID   0x004  /* retrieve peer UUID */
#define LOCAL_PEEREUUID  0x005  /* retrieve eff. peer UUID */
#define LOCAL_PEERTOKEN  0x006  /* retrieve peer audit token */

Higher-level abstractions around the API exist in other languages:

Upvotes: 0

Technologeeks
Technologeeks

Reputation: 7907

There is, but it's very proprietary and won't work outside Darwin. You can use the com.apple.network.statistics PF_SYSTEM socket to effectively do what netstat(1) and the Darwin-specific nettop(1) do, and get all socket activity (including updated in real time).

The private NetworkStatistics.framework even contains wrappers for this and (so far) it doesn't need entitlements or root privileges. Check the code sample in Listing 16-26 at http://newosxbook.com/bonus/vol1ch16.html for exact details, and couple that with getpeername(2).

FYI, this still isn't a good idea, because any process can easily spoof its name. If you're already in macOS and you are dealing with code signed processes, a much better option is, once you have the PID in hand, to use the csops(2) system call to obtain the code signing identity, which can't be spoofed.

Upvotes: 3

Related Questions