The lsof? application provides a great way to see what applications are listening on your network ports, but it isn't always available on older OSs, and netstat? is ...

A server may have multiple interfaces, multiple IP addresses on those interfaces, and of course multiple ports open (listening) on them.

Here's a (long, nasty) one-liner bash command line to report in a nice way what ports you currently have open ...

for i in $(netstat -ln|grep "LISTEN "|tr -s " "|cut -d" " -f4|sed -e"s/\([^:]*\):\([^:]*\)/\2=\1/"|sort -n); do PORT=$(echo $i |cut -d= -f1); SN=$(grep "[^[:digit:]]$PORT/tcp" /etc/services|tr -s "  "|cut -f 1); IP=$(echo $i|cut -d= -f2); if [ "$IP" == "" ]; then IPp="L"; elif [  "$IP" == "" ]; then IPp="*"; else IPp=$IP; fi;  if [ "$SN" == "" ]; then  SNn=$PORT; else SNn=$SN; fi; echo "$SNn ($PORT) $IPp"; done

Sample output :-

smtp (25) L
domain (53)
www (80) L
www (80)
www (80)
https (443)
ipp (631) L
953 (953) L
mysql (3306) L
www-php4 (4080) L
4369 (4369) *
xmpp-client (5222) *
5223 (5223) *
xmpp-server (5269) *
5280 (5280) *
5356 (5356) *
5357 (5357) L
postgresql (5432) L
6010 (6010) L
11211 (11211) *
52029 (52029) *
54440 (54440) L

It uses netstat to do the basic report of open ports, then translates the known port numbers found in /etc/services, indicates which are listening only to localhost (L), and which are listening on all interfaces (*).

It's a one-liner because I have multiple servers, and have a handy run-everywhere script that will let me fire off a command to be run on any subset of my machines. It uses double-quotes because I have to enclose the whole thing in single-quotes to prevent early variable expansion on my local workstation. Wow.

As a more readable script, it looks like this :-

for i in $(netstat -ln|grep "LISTEN "|tr -s " "|cut -d" " -f4|sed -e"s/\([^:]*\):\([^:]*\)/\2=\1/"|sort -n)
    PORT=$(echo $i |cut -d= -f1)
    SN=$(grep "[^[:digit:]]$PORT/tcp" /etc/services|tr -s "  "|cut -f 1)
    IP=$(echo $i|cut -d= -f2)

    if [ "$IP" == "" ]
        then IPp="L"
    elif [  "$IP" == "" ]
        then IPp="*"
        else IPp=$IP

    if [ "$SN" == "" ]
        then SNn=$PORT
        else SNn=$SN

    echo "$SNn ($PORT) $IPp"

The sub-shell snippets are :-

  • get the port/address data

    • run netstat -ln
    • find lines with "LISTEN " in them (excludes "LISTENING" by having the space at the end of LISTEN)
    • replace multiple spaces with single spaces, to make cut's job easier
    • get the fourth space-delimited field only
    • change address:port to port=address

      • literally, any non-colon-characters, a colon, any non-colon-characters.
    • sort into numerical order
  • lookup the port number in /etc/services

    • use the current port=address data
    • get the first field in the = separated list (the port)
    • assign that to the variable PORT
    • look for any lines that mention PORT/tcp in /etc/services. Don't allow any other digits in front of PORT (i.e. if PORT = 80, do not select 8080/tcp)
    • replace multiple tabs with a single tab
    • select only the first field (in a tab-separated list, the default for cut)