Confirm Actively Listening TCP Ports with lsof

Listening TCP ports in macOS

I was researching SSH daemon configuration on my macOS Catalina system and realised that lsof is still the best tool for meaningfully confirming network ports that are LISTENed to.

What does it mean for port to LISTEN?

All the network services in Linux (and Windows, actually) operating systems start with the same basic pattern: some process is managing incoming network connections.

Nowadays most of network services are directly managing their own network connections – meaning service like SSH daemon or Apache web server are made available via main process (sshd or httpd in my examples) constantly running and waiting for incoming network connections on specific port. For SSH server, default port is 22. For web servers, default ports are 80 and 443.

When we say a port is LISTENing, it means there’s a process running on your system that’s monitoring this specific port. SSH is therefore listening on/for port 22, Apache (httpd) is listening for port 80 and possibly 443.

Meaningful TCP ports reporting vs Default

You may remember that netstat command shows network ports as well, but its implementations are sometimes limited to just confirming that a certain port is listened to, without helping us understand what process is doing that port listening:

greys@mcfly:~ $ netstat -na |grep LISTEN | grep 22
tcp46 0 0 *.22000 *.* LISTEN
tcp4 0 0 *.22 *.* LISTEN
tcp6 0 0 *.22 *.* LISTEN

That’s why I prefer the lsof tool – it’s reporting processes information, which means any output you get is bound to contain processes numbers (PIDs) and most likely process names (binary names like sshd or httpd).

Use lsof to show listening TCP ports

lsof command has specific options for reporting processes with network activity: -iTCP will report TCP specific information, and -sTCP:LISTEN qualifier will filter just the processes that are listening for incoming connections on TCP ports (rather than client processes that only initiate outgoing network connections).

Don’t Forget to run lsof with sudo!

Normally lsof is super useful even with standard user privileges, but since I’m investigating a system service (SSH server), I have to run lsof as root. Otherwise lsof will report a list of network services, but hide the ones running above your standard user privilege level.

On modern Linux servers, lsof without sudo won’t show me anything:

greys@s2:~ $ lsof -iTCP -sTCP:LISTEN
greys@s2:~ $

My complete command to list all the services listening for incoming TCP connections in will therefore look like this (this is the macOS example):

greys@mcfly:~ $ sudo lsof -iTCP -sTCP:LISTEN
launchd       1  root    8u  IPv6 0xc37c60e6e93432f1      0t0  TCP *:ssh (LISTEN)
launchd       1  root    9u  IPv4 0xc37c60e6e934d8f1      0t0  TCP *:ssh (LISTEN)
launchd       1  root   10u  IPv6 0xc37c60e6e9343911      0t0  TCP *:rfb (LISTEN)
launchd       1  root   11u  IPv4 0xc37c60e6e934e2b9      0t0  TCP *:rfb (LISTEN)
launchd       1  root   21u  IPv6 0xc37c60e6e93432f1      0t0  TCP *:ssh (LISTEN)
launchd       1  root   24u  IPv4 0xc37c60e6e934d8f1      0t0  TCP *:ssh (LISTEN)
launchd       1  root   29u  IPv6 0xc37c60e6e9343911      0t0  TCP *:rfb (LISTEN)
launchd       1  root   32u  IPv4 0xc37c60e6e934e2b9      0t0  TCP *:rfb (LISTEN)
launchd       1  root   40u  IPv6 0xc37c60e6e9342cd1      0t0  TCP localhost:intu-ec-client (LISTEN)
launchd       1  root   46u  IPv6 0xc37c60e6e9342cd1      0t0  TCP localhost:intu-ec-client (LISTEN)
launchd       1  root   47u  IPv4 0xc37c60e6e934cf29      0t0  TCP localhost:intu-ec-client (LISTEN)
launchd       1  root   48u  IPv4 0xc37c60e6e934cf29      0t0  TCP localhost:intu-ec-client (LISTEN)
kdc         120  root    5u  IPv6 0xc37c60e6e93426b1      0t0  TCP *:kerberos (LISTEN)
kdc         120  root    7u  IPv4 0xc37c60e6e934f649      0t0  TCP *:kerberos (LISTEN)
rapportd    625 greys    4u  IPv4 0xc37c60e6ef7969d9      0t0  TCP *:49263 (LISTEN)
rapportd    625 greys    5u  IPv6 0xc37c60e6e9342091      0t0  TCP *:49263 (LISTEN)
ARDAgent    697 greys    9u  IPv6 0xc37c60e6e9341a71      0t0  TCP *:net-assistant (LISTEN)
Dropbox    1148 greys  128u  IPv4 0xc37c60e6eefd8561      0t0  TCP *:17500 (LISTEN)
Dropbox    1148 greys  129u  IPv6 0xc37c60e703f137b1      0t0  TCP *:17500 (LISTEN)
Dropbox    1148 greys  154u  IPv4 0xc37c60e6f88c09d9      0t0  TCP localhost:17603 (LISTEN)
Dropbox    1148 greys  168u  IPv4 0xc37c60e6f8940011      0t0  TCP localhost:17600 (LISTEN)
dynamicli  1204 greys    7u  IPv4 0xc37c60e6f908f9d9      0t0  TCP localhost:51456 (LISTEN)
dynamicli  1205 greys    7u  IPv4 0xc37c60e6f9a453a1      0t0  TCP localhost:51549 (LISTEN)
dynamicli  1205 greys   16u  IPv4 0xc37c60e6f9b0a8f1      0t0  TCP localhost:51551 (LISTEN)
com.docke  1341 greys    7u  IPv4 0xc37c60e6fa8222b9      0t0  TCP localhost:51725 (LISTEN)
com.docke  1345 greys   15u  IPv4 0xc37c60e6eefd7b99      0t0  TCP localhost:sun-sr-https (LISTEN)

Confirming what process is listening on a specific port

While we’re at it, here’s how the previous command can be modified to confirm a specific service listening on SSH port 22:

greys@mcfly:~ $ sudo lsof -iTCP -sTCP:LISTEN | grep ssh
launchd 1 root 8u IPv6 0xc37c60e6e93432f1 0t0 TCP *:ssh (LISTEN)
launchd 1 root 9u IPv4 0xc37c60e6e934d8f1 0t0 TCP *:ssh (LISTEN)
launchd 1 root 21u IPv6 0xc37c60e6e93432f1 0t0 TCP *:ssh (LISTEN)
launchd 1 root 24u IPv4 0xc37c60e6e934d8f1 0t0 TCP *:ssh (LISTEN)

IMPORTANT: Note that because SSH is a standard service, lsof reports its name (ssh) rather than port number (22) in the last column of output. TCP *:ssh means process is listening for TCP port for SSH service.

I was expecting sshd, actually. But turns out remote access via SSH is managed by launchd process in recent macOS versions. Once someone logs in though, you’ll see sshd process spun up to manage the connection.

That’s it for today, hope you learned something new!

See Also

How To Change Mac Hostname with scutil

Changing hostname with scutil in macOS

Standard command like hostname will still work in macOS, but perhaps it’s best to use the native way of updating system information on your Mac? scutil command is here to help.

Change Hostname with scutil

Simply run this command in your Terminal window:

greys@macbook:/ $ sudo scutil --set HostName "maverick"

if you now start new Terminal window or even just start new shell, you should see the new hostname:

greys@macbook:/ $ sudo scutil –set HostName “maverick”
greys@macbook:/ $ bash
greys@maverick:/ $ hostname

That’s it for today!

See Also

Attach Interface to Specific Firewall Zone in RHEL 8


One of the first things I had to do on my recently built RHEL 8 PC was to move the primary network interface from public (default) zone to home zone – to make sure any firewall ports I open stay private enough.

How To List Which Zones and Interfaces are Active

Using the get-active-zones option of the firewall-cmd command, it’s possible to confirm where eno1 interface is at the moment. It’s already in the home zone cause I made the update earlier:

root@redhat:~ # firewall-cmd --get-active-zones
  interfaces: eno1
  interfaces: virbr0

Attach Interface to a Firewall Zone

Here’s how one can move specified interface into a zone we want:

root@redhat:~ # firewall-cmd --zone=home --change-interface=eno1

Just to show how it works, I’m going to move eno1 into public zone and back to home one:

root@redhat:~ # firewall-cmd --zone=public --change-interface=eno1
root@redhat:~ # firewall-cmd --get-active-zones
  interfaces: virbr0
  interfaces: eno1

Making Sure Firewall Changes Are Permanent

Don’t forget that after confirming a working firewall configuration, you need to re-run the same command with permanent option – this will update necessary files to make sure your firewall changes can survive a reboot:

root@redhat:~ # firewall-cmd --zone=home --change-interface=eno1 --permanent
The interface is under control of NetworkManager, setting zone to 'home'.

That’s it for today. Am really enjoying RHEL 8 configuration and still have this feeling I barely scratch the surface with all the new improvements this Red Hat Enterprise Linux brings.

See Also

Confirm Firewall Configuration in RHEL 8

List Firewall Rules in RHEL 8

I’m fascinated by the improvements and new features in RHEL 8, plus it’s a primary distro used in most corporate environments – so expect to quite a number of posts related to it in the nearest future.

The default interface for managing firewalls in RHEL 8 is firewalld and specifically firewall-cmd command.

Show Active Zones in RHEL 8

There’s a concept of zones – security domains – in RHEL 8 firewalls. You assign each of available network interfaces on your Red Hat Enterprise Linux system to one or more of these domains.

That’s why the first step is to confirm these zones, to see which ones are actively managing access for each network device:

root@rhel8:~ # firewall-cmd --get-active-zones
interfaces: enp2s0
interfaces: virbr0

List All Rules for Firewall Zone in RHEL 8

I’m interested in the primary physical network interface – enp2s0. It belongs to the home zone as per previous command, so that’s the zone we’ll list all the rules fore:

root@rhel8:~ # firewall-cmd --list-all --zone=home
home (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp2s0
  services: cockpit dhcpv6-client mdns samba-client ssh
  ports: 5901/tcp
  masquerade: no
  rich rules: 

From the output below, I have highlighted additionally enabled ports – 5901 is the one for VNC client that allows me to access graphics desktop session on my RHEL 8 PC remotely.

That’s it for today! Thanks for stopping by and talk soon!

See Also

Troubleshooting: ifconfig Not Found in Debian

I’ve actually written about ifconfig not found before, but noticed recently another possible scenario so will mention it today.

Make Sure Net-Tools Package is Installed

This is still the most common reason for your shell not finding the ifconfig command: it’s just not installed by default. So install it using apt command:

$ apt install net-tools

Call ifconfig Using Full Path

This is the thing I noticed on my Debian VM earlier today: your regular user may not have /sbin directory in its PATH. Which means ifconfig command will still not work if you just type the command name:

greys@debian9:~$ ifconfig
-bash: ifconfig: command not found
You have new mail in /var/mail/greys

But if you type the full path to the command, it will work:

greys@debian9:~$ /sbin/ifconfig
enp0s3: flags=4163 mtu 1500
inet 192.168.1.XX netmask broadcast
inet6 fe80::a00:27ff:febe:8a41 prefixlen 64 scopeid 0x20
ether 08:00:27:be:8a:41 txqueuelen 1000 (Ethernet)
RX packets 26263716 bytes 9251567381 (8.6 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 131362 bytes 12206621 (11.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Update PATH Variable to Include /sbin

Edit the .profile file in your home directory. For me it’s /home/greys/.profile.

Somewhere towards the end of it there should be a PATH variable updates section, on my VM it includes linuxbrew that I installed recently:

set PATH so it includes user's private bin if it exists

if [ -d "$HOME/bin" ] ; then

eval $(/home/greys/.linuxbrew/bin/brew shellenv)

We need to update this section. And if there isn’t one, just create another one at the end of the file. Both changes should aim to add /sbin directory to the PATH variable.

Update the file:


… with this:


… or create new one:


Save the file and read it again to test:

greys@debian9:~$ source .profile
/home/greys/.linuxbrew/Homebrew/Library/Homebrew/ line 4: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory

That’s it, type ifconfig and it should work now:

greys@debian9:~$ ifconfig
enp0s3: flags=4163  mtu 1500
         inet 192.168.1.XX  netmask  broadcast
         inet6 fe80::a00:27ff:febe:8a41  prefixlen 64  scopeid 0x20
         ether 08:00:27:be:8a:41  txqueuelen 1000  (Ethernet)
         RX packets 26267641  bytes 9252896750 (8.6 GiB)
         RX errors 0  dropped 0  overruns 0  frame 0
         TX packets 131600  bytes 12231427 (11.6 MiB)
         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

See Also

5 Ways to Use nslookup

Even after a few years of blogging I still manage to find must-have and must-know commands that I barely mentioned here. nslookup is one such command – it’s an indispensable network troubleshooting tool when it comes to troubleshooting DNS issues.

Even after a few years of blogging I still manage to find must-have and must-know commands that I barely mentioned here. nslookup is one such command – it’s an indispensable network troubleshooting tool when it comes to troubleshooting DNS issues.

Get IP address for a Hostname

This is the most common nslookup command usage: you know a hostname or a domain name, and you want to get an IP address.

greys@maverick:~ $ nslookup

Non-authoritative answer:

Get hostname from an IP address

This is the opposite of the previous step, but it’s not always returning the opposite result. You see, if your domain name points to an IP address this IP address is not always pointing back to your domain:

greys@maverick:~ $ nslookup

Non-authoritative answer:    name =

Confirm Name Servers for a Domain

When something about DNS resolution doesn’t make sense, I usually go back to basics: confirm the actual Name Servers that provide name resolution for the hostname or domain name.

For this, we need to make nslookup query specifically the NS records for a given hostname:

greys@maverick:~ $ nslookup -query=ns

Non-authoritative answer: nameserver = nameserver =

The output confirms that NS servers called alec and beth from Cloudflare are managing my domain.

Confirm Mail Servers for a Domain

Another really cool thing is that nslookup can get you MX recourds – they are pointing to the mail (SMTP) servers accepting emails on behalf of the domain:

greys@maverick:~ $ nslookup -query=mx

Non-authoritative answer:    mail exchanger = 1    mail exchanger = 5

This output confirms that my email is handled by Google, because I’m using the gSuite.

Query a Specific DNS Server Using nslookup

You may have noticed from examples that nslookup always reports my home office server ( that it uses for making DNS queries.

Sometimes you want to know if other DNS servers resolve the name correctly, and so this example shows you how. Mind you, this must be either your local network (corporate) DNS server or a public NS server – otherwise your request may be rejected (because by default NS servers only resolve their own domains, not all the domains for the rest of the internet).

Here’s how I can resolve using Cloudflare’s public DNS service:

greys@maverick:~ $ nslookup

Non-authoritative answer:

… or Google Public DNS:

greys@maverick:~ $ nslookup

Non-authoritative answer:

That’s it for today! There’s quite a few things nslookup is good for, but I think I’ll need to explain some DNS (Domain Name Service) basics first.

See Also

Disable portmapper in CentOS 7

If you don’t have any other network services running on your Linux system, you probably don’t need portmapper running. Here are the steps to check and to disable portmap.

What portmapper does

Portm apper is a special Unix/Linux service that runs on networked systems that provide RPC (Remote Procedure Call) based services, like NFS.

Port mapper service is called portmapper and always runs on TCP and UDP ports 111.

IMPORTANT: back in 2015 portmapper was confirmed as vulnerable for Distributed Denial of Service attacks (DDoS) – so it’s considered a good practice to disable it or at least protect using firewall.

List RPC services

You can use rpcinfo command to list currently active RPC services on your system.

In my example below there’s nothing else running RPC, just the portmapper itself:

root@s5:~ # rpcinfo -p
program vers proto port service
100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100000 4 udp 111 portmapper
100000 3 udp 111 portmapper
100000 2 udp 111 portmapper

Stop portmapper in CentOS 7

Somewhat confusing, the service providing portmapper functionality is always called rpcbind.

First, let’s stop the portmapper service:

root@s5:~ # systemctl stop rpcbind
Warning: Stopping rpcbind.service, but it can still be activated by:
root@s5:~ # systemctl stop rpcbind.socket

Prevent portmapper from restarting upon reboot

Now, let’s make sure the service is also disabled:

root@s5:~ # systemctl disable rpcbind
Removed symlink /etc/systemd/system/

And just to confirm it’s all done correctly, let’s run rpcinfo again, it will return an error now:

root@s5:~ # rpcinfo -p
rpcinfo: can't contact portmapper: RPC: Remote system error - Connection refused

See Also

Ubiquiti UniFi controller on Ubuntu 18.10

I have a tiny server in home office, it used to be a Window 8 based entertainment box but I reinstalled it with Ubuntu 18.10 recently enough to run home automation. There has’t been any particular function assigned to this server but I have finally decided what role it will play: it will be an always-on Ubiquiti UniFi controller for my home office network!

My Ubuntu 18.10 server parameters

Like I said, it’s a fairly modest hardware and not a server grade at all. But thanks to 64-bit support (UEFI 32-bit boot though!) and low power consumtion, this is a perfect system for the always-on server:

  • Processor: Intel(R) Atom(TM) CPU Z3735F @ 1.33GHz – quad-core
  • RAM: 2GB 1333Mhz
  • Storage: internal 32GB flash storage
  • Operating System: custom Ubuntu 18.10 (64-bit OS but with 32-bit boot loader)

UniFi Network Management Controller

Ubiquiti have a few ranges of hardware, and I’m a big fan of the UniFi series of Software-Defined Networking (SDN) – very easy to setup and manager, plus you get quite a few updates via firmware, without having to change the hardware.

Network Management Controller is a piece of software or hardware that is running UniFi controller software that keeps track of all your UniFi devices and configurations. It has its own database for keeping track of settings and states and accepts network (browser or app) connections for remote management.

The mobile app for remote management is pretty cool.

UniFi Appliances I use in my Home Office

Ubiquiti Security Gateway (USG)

Wonderful little device for powerful traffic management, remote access (VPN) deployment and deep packet inspection (DPI) for visual understanding of how your network clients are consuming Internet traffic.

Ubiquiti UniFi Switch 8 60W (US-8-60W)

I have a number of switches like this, they’re great for building out a small office network and integrate with Network Management Console – meaning you see traffic and port status.

I also really like that this switch has 4 PoE (Power over Ethernet) ports, so you can plug in IP cameras and WiFi hotspots that support PoE – means you don’t need to run a separate power cable for them.

Installing UniFi Controller with installation scripts

Although there are official software repositories and RPM/DEB file downloads available from Ubiquiti, they’re kind of awkward to use: you still need to resolve software dependencies and preinstall a bunch of stuff.

So after a bit of researching online, I found that Glenn R from Ubiquiti’s community forums has prepared scripts for automatic installation of UniFi controller: UniFi Installation Scripts.

There’s a script available for the most recent Debian and Ubuntu builds, so if you want to install controller software on Ubuntu 16.04, Ubuntu 18.04, Ubuntu 18.10, Debian 8 or Debian 9 – there’s no better way that using one of these scripts.

The procedure is simple:

  1. Go to the UniFi Installation Scripts page
  2. Download the script for your controller version (5.9.x is the stable branch) and operating system
  3. Make the downloaded script executable (chmod +x
  4. Execute the script as root
  5. Enjoy! (browse to your server’s IP address and port 8443)

Here’s how my end result looks:

Screen Shot 2019-02-07 at 17.15.29.png

Do you use UniFi? Want to learn more about configuring or managing UniFi solutions? Let me know and I will wite a few follow-up posts.

Show Network Errors with netstat

netstat command is a mightly utility found in majority of Unix and Linux distributions.

Among other things like showing network routes and reporting network connections and ports, netstat can also report if your network interfaces have any trouble sending or receiving packets.

Report network errors with netstat

The basic format for this functionality is shown below:

greys@s5:~ $ netstat -ni

Screen Shot 2019-01-31 at 17.38.31.png

IMPORANT: always double-check the interface name you’re checking. I have highlighted the physical interface in my example, because it’s important: your virtual interfaces are unlikely to provide any useful network reliability info – so you always must be checking the primary, physical interfaces (or primary, virtual ones if you’re looking at a VM).

No errors in RX-ERR (receive errors) or TX-ERR (send errors), which is pretty impressive for a dedicated server that’s been online for a year:

greys@s5:~ $ uptime
17:34:30 up 366 days, 2:39, 1 user, load average: 0.11, 0.14, 0.19

See Also

Test TCP connectivity with curl

You probably know about curl command: it’s great for downloading web pages or files from a Unix command line. But there’s another great usage curl command has: testing TCP ports connectivity.

Say, you’re helping with some firewall changes and need to confirm that connection from your server to some remote host and specific TCP port still works.

Here’s how you can do it using curl command and its telnet functionality.

Test SSH port connection with curl

In this example, SSH connection works because:

  1. We get the “Connected” status
  2. We see the SSH version prompt: SSH-2.0-OpenSSH_7.4
greys@server:~ $ curl -v telnet://
* About to connect() to port 22 (#0)
* Trying
* Connected to ( port 22 (#0)

Test jBoss port 8080 with curl

This scenario shows that connection is refused (probably because there’s no service running on that port).

IMPORANT: you would probably get a different message if firewall blocks the 8080 port. Connection refused is a clear sign that port is accessible, but nothing’s responding on it.

greys@server:~ $ curl -v telnet://
* About to connect() to port 8080 (#0)
* Trying
* Connection refused
* Failed connect to; Connection refused
* Closing connection 0
curl: (7) Failed connect to; Connection refused

See Also