Wednesday, April 25, 2012

Enumerating network listeners and IPC sockets on OS X

TCP listeners are easy, this gives you numeric port numbers for sockets in state LISTEN:
$ sudo lsof -P -iTCP -sTCP:listen
COMMAND PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
launchd   1 root   21u  IPv6 0xffffff8014bfb9c0      0t0  TCP localhost:631 (LISTEN)
launchd   1 root   22u  IPv4 0xffffff8014c00500      0t0  TCP localhost:631 (LISTEN)
launchd   1 root  179u  IPv6 0xffffff8014bfb600      0t0  TCP *:22 (LISTEN)
launchd   1 root  183u  IPv4 0xffffff8014bfda40      0t0  TCP *:22 (LISTEN)
And UDP is similar, but you don't get the state information (the FAQ says you should be able to specify "-sUDP:^idle" and similar, but lsof 4.84 on Lion wouldn't accept it):
$ sudo lsof -P -iUDP
COMMAND    PID           USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
launchd      1           root   13u  IPv4 0xffffff8014647dd8      0t0  UDP *:137
launchd      1           root   14u  IPv4 0xffffff8014647c60      0t0  UDP *:138
UserEvent   14           root    6u  IPv4 0xffffff801561b8d0      0t0  UDP *:*
If you are going to script these I find these commands give the fastest and most useful answers:
lsof +c15 -P -n -iUDP -u^_mdnsresponder
lsof +c15 -P -n -iTCP -sTCP:listen
You might also be interested in launchd daemons listening on UNIX domain sockets for IPC, and xinetd-style (look for the inetdCompatibility key) daemons. Here is a quick and dirty bit of python to look for enabled daemons using sockets (you will want to check /Library/LaunchDaemons too):

#! /usr/bin/python
import os
from Foundation import NSDictionary

def GetPlistKey(plist, key):
  mach_info = NSDictionary.dictionaryWithContentsOfFile_(plist)
  if mach_info:
    if key in mach_info:
      return mach_info[key]
  else:
    return None

for plist in os.listdir('/System/Library/LaunchDaemons'):
  plist_path = os.path.join('/System/Library/LaunchDaemons', plist)
  sockets = GetPlistKey(plist_path, 'Sockets')
  disabled = GetPlistKey(plist_path, 'Disabled')
  if not disabled and sockets:
    print plist_path

No comments: