'Why is my Mac slow?' - How to debug Mac (some) networking problems

A lot of times when I'm asked to debug a Unix, Linux, or macOS system, I'll hear a complaint like "The network seems slow", or just "It seems slow", followed by the usual "What is it doing?"

I actually think that last question is a wonderful one: What is this computer doing?

Introduction

You can see a lot of information about Unix, Linux, and Mac processes using the ps command or the top utility, but it seems like many system administrators don't know how to find networking information, at least not without a network sniffer.

On a Mac/macOS system you can find out what servers your Mac is connected to, what ports are in use, and what processes (or applications) are accessing the internet. In this macOS networking tutorial I'll demonstrate how to use the Unix/Linux lsof command on a macOS system to see very cool and helpful network-related information.

Debug macOS network problems with 'lsof'

If you haven't used it before, "lsof" stands for "list open files", and while I normally use it to list the files opened by a particular user or process, it can be used to get great networking information as well.

Diving right in, I now use the Unix/Linux lsof command to find out what ports are in use on a macOS system, as well as which applications are accessing which servers on the internet.

The basic lsof command I use is shown here:

sudo lsof -i -P

Typically I start with this command, and then use other versions of this command if I need other information. Here's some abbreviated, sample networking output from this lsof command:

$ sudo lsof -i -P

COMMAND     PID           USER   FD   TYPE    DEVICE SIZE/OFF   NODE NAME
launchd       1           root   13u  IPv6 0x3cefbe8      0t0    TCP localhost:631 (LISTEN)
launchd       1           root   14u  IPv4 0x4020e64      0t0    TCP host2.foo.com:631 (LISTEN)
ntpd         15           root   20u  IPv4 0x3ceba38      0t0    UDP *:123
ntpd         15           root   21u  IPv6 0x3ceb6d8      0t0    UDP *:123
ntpd         15           root   22u  IPv6 0x3ceccc8      0t0    UDP localhost:123
ntpd         15           root   23u  IPv4 0x3cecbf0      0t0    UDP host2.foo.com:123
ntpd         15           root   24u  IPv6 0x3cecb18      0t0    UDP localhost:123
ntpd         15           root   25u  IPv6 0x3cebb10      0t0    UDP Macintosh-2.local:123
ntpd         15           root   26u  IPv4 0x3ceb378      0t0    UDP 192.168.1.101:123
ntpd         15           root   27u  IPv6 0x3cec6e0      0t0    UDP Macintosh-2.local:123
mDNSRespo    25 _mdnsresponder    7u  IPv4 0x3ceca40      0t0    UDP *:5353
mDNSRespo    25 _mdnsresponder    8u  IPv6 0x3cec890      0t0    UDP *:5353
mDNSRespo    25 _mdnsresponder    9u  IPv4 0x3ce9368      0t0    UDP *:59492
mDNSRespo    25 _mdnsresponder   11u  IPv4 0x3cea0e8      0t0    UDP *:65456
mDNSRespo    25 _mdnsresponder   12u  IPv4 0x3ce9878      0t0    UDP *:59834
mDNSRespo    25 _mdnsresponder   13u  IPv4 0x3cea7a8      0t0    UDP *:65080
mDNSRespo    25 _mdnsresponder   14u  IPv4 0x3ce9950      0t0    UDP *:59946
mDNSRespo    25 _mdnsresponder   15u  IPv4 0x3cea880      0t0    UDP *:56912
configd      38           root    9u  IPv4 0x3cecda0      0t0    UDP *:*
configd      38           root   12u  IPv6 0x4641da0      0t0 ICMPV6 *:*
configd      38           root   13u  IPv6 0x4641e78      0t0 ICMPV6 *:*
blued        50           root    3u  IPv4 0x3cec380      0t0    UDP *:*
prl_dhcpd    72           root    4u  IPv4 0x3cec020      0t0    UDP *:*
SystemUIS   118             al    9u  IPv4 0x3ceb7b0      0t0    UDP *:*
iTunes      175             al   21u  IPv4 0x61e6270      0t0    TCP *:3689 (LISTEN)
iTunes      175             al   22u  IPv6 0x3cef984      0t0    TCP *:3689 (LISTEN)
ping       4488             al    3u  IPv4 0x4641cc8      0t0   ICMP *:*
firefox-b  9764             al   30u  IPv4 0x3f9366c      0t0    TCP 192.168.1.101:63639->iw-in-f138.1e100.net:80 (ESTABLISHED)
firefox-b  9764             al  106u  IPv6 0x3cef4bc      0t0    TCP localhost:58884->localhost:58883 (TIME_WAIT)
eclipse   11384             al   19u  IPv6 0x3cef258      0t0    TCP *:59291 (LISTEN)
eclipse   11384             al   20u  IPv6 0x3cee664      0t0    TCP localhost:58727->localhost:58726 (TIME_WAIT)

As you can see, this basic command is very nice because it shows the name of the application (the COMMAND column), the process id (PID), user, protocol (TCP, UDP, ICMP), and port and server information. If you've used the macOS netstat command before, you know this is much more information than you can get from netstat.

macOS lsof command options

Here's a quick look at the lsof command options I used in that command:

-i  list all internet files
-P  inhibits conversion of port numbers to port names

As mentioned, I mostly just use those two options, but here is a list of other lsof command arguments you can use related to networking:

-n  inhibits conversion of network numbers to host names (makes lsof faster)
-N  information about NFS files
-R  show the parent process id (PPID)
-T  (there are many, many TCP options available; too many to list here)
-U  Unix domain socket files

In a network debugging application I'm currently writing, I also use the -n option shown here. I've read that this is a good idea when you don't know if there is a network problem, such as a DNS problem, that might cause this command to significantly slow down.

Next, I'll show a few lsof command options that I also use to debug Mac networking issues.

Show only TCP (or UDP, ICMP) with lsof

To show only TCP connections run an lsof command like this:

lsof -i TCP

Similarly, to see all UDP ports, use this command:

lsof -i UDP

Show ports in a LISTEN state with lsof

To see ports in a LISTEN state, use one of the previous commands, and simply grep for LISTEN:

sudo lsof -i -P | grep LISTEN

Or, to look for records in a state of LISTEN, ESTABLISHED, CLOSED, or WAIT, pipe the output into egrep, like this:

sudo lsof -i -P | egrep 'LISTEN|ESTABLISHED|CLOSED|WAIT'

Mac OS X - lsof versus netstat

I think lsof gives you much more information than you can get with the current macOS version of the netstat command. For instance, here's the output from a netstat command where I try to look at TCP information:

$ netstat -p TCP -a

Active Internet connections (including servers)
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)
tcp4       0      0  *.59291                *.*                    LISTEN
tcp6       0      0  *.daap                 *.*                    LISTEN
tcp4       0      0  *.daap                 *.*                    LISTEN
tcp4       0      0  host2.foo.com.ipp      *.*                    LISTEN
tcp6       0      0  localhost.ipp          *.*                    LISTEN

Personally I think this netstat output isn't very useful, and I much prefer the lsof command information that gives you the name of the process, the PID, PPID, and much more.

Other useful macOS lsof commands

Before going, although the following lsof commands aren't directly related to macOS networks, ports, sockets, or the internet, they are very useful whenever you need to know what files are in use by a particular user or application (process).

To see the files opened by a user named alvin, use this command:

lsof -u alvin

To see the files opened by a particular process (such as the "firefox" process shown above), give the lsof command the PID (process ID), like this:

lsof -p 9764

(I promise, you'll be amazed at the files an application like Firefox keeps open at any one time. It currently has a reference to every image file on my Mac Desktop, which strikes me as pretty crazy.)

Internet domain socket states (states you see with lsof or netstat)

As a final note, when debugging OS X network ports, internet connections, etc., it really helps to understand the different states a socket can be in. Here's a list of the possible socket states, courtesy of the netstat man command:

CLOSED:       The socket is not in use.

LISTEN:       The socket is listening for incoming connections. Unconnected
              listening sockets like these are only displayed when using the -a option.

SYN_SENT:     The socket is actively trying to establish a connection to a
              remote peer.

SYN_RCVD:     The socket has passively received a connection request from a
              remote peer.

ESTABLISHED:  The socket has an established connection between a local
              application and a remote peer.

CLOSE_WAIT:   The socket connection has been closed by the remote peer,
              and the system is waiting for the local application to close 
              its half of the connection.

LAST_ACK:     The socket connection has been closed by the remote peer, the
              local application has closed its half of the connection, and the system
              is waiting for the remote peer to acknowledge the close.

FIN_WAIT_1:   The socket connection has been closed by the local
              application, the remote peer has not yet acknowledged the close, and the
              system is waiting for it to close its half of the connection.

FIN_WAIT_2:   The socket connection has been closed by the local
              application, the remote peer has acknowledged the close, and the system
              is waiting for it to close its half of the connection.

CLOSING:      The socket connection has been closed by the local application
              and the remote peer simultaneously, and the remote peer has not yet
              acknowledged the close attempt of the local application.

TIME_WAIT:    The socket connection has been closed by the local
              application, the remote peer has closed its half of the connection, and
              the system is waiting to be sure that the remote peer received the last
              acknowledgement.

More macOS networking, port, and socket information

I really don't want to oversimplify this networking/port/internet/security topic, so until I can take more time to break it down, I strongly encourage you to read the man pages for the netstat and lsof commands.