Monday, 15 June 2009

Part 2: Monitoring SSH status in Mac OS X Terminal

<< Part 1: Monitoring AFP Status in Mac OS X Terminal

At the end of the last post, I gave the following solution to see whether AFP is enabled via Terminal:

netstat -naf inet6 | grep [*][.]548[\ ].*LIST

If the above command returns nil (or blank) then AFP is disabled. If it returns a line similar to the below, then AFP is enabled:

tcp6 0 0 *.548 *.* LISTEN

As always, there are a multitude of different ways to return similar information e.g. If we replace the -f inet6 option of netstat (which looks for address families using inet6) with the -p option (-p stands for protocol), we can then ask netstat to list all TCP services e.g. the following does pretty much the same thing as above:

netstat -nap TCP | grep [*][.]548[\ ].*LIST

however, returns all TCP services on port 548 i.e. tcp4 and tcp6 entries in return:

tcp4 0 0 *.548 *.* LISTEN
tcp6 0 0 *.548 *.* LISTEN

I'm going to use the -p option to delve once again into netstat, to view whether SSH (Remote Login) is enabled in the terminal or not. However, this time, instead of building something up from the basic building blocks, lets take a look at the final terminal command and break it down:

netstat -nap TCP | cut -c 22-40 | grep -w [*][.]22[\ ]

If you've read the previous post you should be able to see where I'm heading.

First of all, we're using netstat to return a list of current network connections and statistics using the options (-a) all (-n) network addresses which use the TCP (-p) protocol. That's pretty straight forward.

We're then piping ( | ) the output through cut which allows us to only select a portion of each line using the -c option to specify the character positions we want returned.

Why are we doing this? Well, we are only interested in ports running on our local machine, not on other servers. If we're not careful, netstat will return a result for this command based on a SSH service running on a foreign server rather than our own.

e.g. Here's a sample output from netstat based on a connection to google along with the standard netstat column headings:

Proto Recv-Q Send-Q Local Address Foreign Address
tcp4 0 0 192.168.0.5.54400 209.85.227.191.80

The example above is only a http (port 80) connection, however if I was connected via SSH, the foreign address in this case would be: 209.85.227.192.22 (port 22 being the standard SSH port). If I issued the command without cut i.e.

netstat -nap TCP | grep -w [*][.]22[\ ]

I could return a result based on the foreign address connection instead of the local address.

So in order to remove from the nestat output any reference to ports being used in the foreign address column we are using cut -c 22-40. What we're essentially saying is, give me the result from netstat but only the characters 22-40 of each line. e.g. If I issued this command:

netstat -nap TCP | cut -c 22-40

I just get a result of:

Local Address
192.168.0.5.54400

Instead of:

Proto Recv-Q Send-Q Local Address Foreign Address
tcp4 0 0 192.168.0.5.54400 209.85.227.191.80

Ok, that now leaves us with the final grep command:
grep -w [*][.]22[\ ]

This time we're using the -w option which forces grep to return only the lines that contain an exact match. What we're looking for in the netstat output is a local address listening port of *.22 i.e. port 22 of localhost. We need to enclose * and . in [ square braces ] to force grep to include them as part of the pattern as they otherwise have a special meaning for pattern matching in regular expressions.

Usually, or rather, by default, SSH runs over port 22. For security reasons and other, SSH is often run on a custom port, so you'll need to substitute 22 for your unique port number if you've changed the default setting in e.g. /etc/services depending on your set up.

Finally, we want to force an exact pattern match of *.22 not *.223 or *.2202 etc... so we need to add a forced blank space at the end of the pattern using an escape character followed by a space and both surrounded by square brackets [\ ]

Put that all together:

netstat -nap TCP | cut -c 22-40 | grep -w [*][.]22[\ ]

and hey presto:

*.22
*.22

If you get a result similar to the above, Remote Login (SSH) is enabled in System Prefs. If you get nothing, it's disabled.

(PS This is probably, not fool proof. E.g. if you're running SSH over port 443 and you've also got a https server running, you're going to run into problems monitoring which service is enabled. However, I imagine you're going to come across problems anyhow trying to run two different services over the same port before you're even faced with this problem? Comments please!)

Coming soon... monitoring to see if you have active connections

Friday, 12 June 2009

Part 1: Monitoring AFP Status in Mac OS X Terminal

There's two freeware apps that might be useful to take a look at before we start:

  1. The first is GeekTool which I've only come across recently. It's a great way to run multiple terminal commands which overlay on top of your desktop, which when you're playing around in unix is a useful way to monitor the output of various commands without continuously having to retype them.
  2. The second is CLIX a useful 'teaching aid' for unix on Mac OS X. I learnt some useful tail and cut commands from CLIX to get just the output from the terminal that I was looking for.

Ok, here we go... At it's essence, Who Is Connected? was designed to monitor AFP and SSH connections in Mac OS X. If all it did initially was to show whether or not AFP and SSH are enabled or not in the menu bar, I'd be happy : )

So this is where I started. How could I achieve this via terminal? Let's take look at Apple File Sharing (AFP) first:

AFP is short for AppleTalk Filing Protocol, a network sharing protocol used in an AppleTalk network. So my starting point was the Apple GUI Network Utility for a unix command Netstat. Network Utility resides in your Applications > Utilities folder and you can click on Netstat in the tabs across the top. Here you can find some pretty verbose information regarding your current network status.

Choosing the option: Display the state of all current socket connections gives a long list of all local and foreign addresses, connections and port numbers. You can return the same output by opening Terminal (Applications > Utilities) and typing:

netstat -a

The -a option shows the status of all sockets including those used by server processes i.e. afp.

If you look down this list, and you have Apple File Sharing enabled in System Preferences, you'll notice that the output includes the lines:

Proto Recv-Q Send-Q Local Address Foreign Address

tcp4 0 0 *.afpovertcp *.* LISTEN

tcp6 0 0 *.afpovert *.* LISTEN


Netstat is telling us that there is a server process LISTEN-ing for remote connections from any address (*.*) that want to connect to a service running on the local machine called afpovertcp (afp-over-tcp).


Disable Apple File Sharing in System Preferences and run Netstat again. This line disappears i.e. the computer is no longer listening for incoming AFP connections.


Great! so netstat tells us whether or not AFP is enabled in System Preferences. But I don't want to navigate through the verbose output of nestat each time to view this. Fortunately, there are various unix commands to help us limit the output of netstat to just what we are looking for.


First, we can limit the output of nestat and speed up it's response by limiting the results it returns to look at one particular address family, in this case we can use inet6:


netstat -a -f inet6


Try it! Secondly we can 'pipe' the output of netstat through grep - to limit the output to the exact line that we are looking for:


netstat -a -f inet6 | grep afpovert


This command firstly runs netstat -a -f inet6 but only returns the lines which include the text afpovert. i.e. grep is acting like a filter to return only the lines we are interested in. Here's the result:


tcp6 0 0 *.afpovert *.* LISTEN


However, the response time is still slower that what I'd like as netstat is still having to run a command to investigate all network connections on the inet6 family of addresses, before it returns its result subsequently filtered by grep. If you're running Tiger, you'll see what I mean.


If we look at the options of netstat:


man nestat


We find we can add the -n option to only show us port numbers rather than an interpreted symbolic address i.e. if we know what port number AFP is running on, we can look for this in netstat's output, rather than asking netstat to do extra work of displaying the symbolic address of all connections. Fortunately, AFP consistently runs on port 548 so we can change our command to:


netstat -naf inet6 | grep 548


Great! an instant result:


tcp6 0 0 *.548 *.* LISTEN


So if I run this command and it returns a result, then I know that AFP is enabled in my System Preferences. Or do I?


Actually, my grep command isn't sophisticated enough. What if there is a different service running on port 5482? or 1548? or any combination of numbers which includes the pattern 548? We will then return an incorrect result as to whether file sharing is enabled or not. We need to improve our grep filter to match exactly what we are looking for in netstat's result.


Lets first ensure we include the *. before the 548 so no numbers can preceed the actual port value we are looking for:


netstat -naf inet6 | grep [*][.]548


As * and . are special characters as part of regular expressions, we need to surround them each with a [ square brace ]. Finally we want to ensure there is a blank space character after 548. To do this, we need to use an escape character \ and a space surrounded by square braces to ensure we force grep to pattern match exactly the number we are looking for. Our expression then becomes:


netstat -naf inet6 | grep [*][.]548[\ ]


For good measure, lets also ask grep to also only return results from netstat of connections which are actively listening for connections, as the AFP service should do:


netstat -naf inet6 | grep [*][.]548[\ ].*LIST


The . after the square brace means 'concatenate' or add the next thing that comes to the query. The following * effectively means: any number of characters inbetween the end of the space character we've just looked for until the next pattern. LIST is for LISTEN in order to remove pattern matching of other connections from the list e.g. ESTABLISHED etc...


So here we have our command for checking if AFP is enabled:


netstat -naf inet6 | grep [*][.]548[\ ].*LIST


phew!


Tuesday, 9 June 2009

Preview: Who Is Connected?

Monitoring SSH & AFP Status for Mac OS X


I've always wanted to glance up into the menu bar and see the status of Apple File Sharing (AFP) and Remote Login (SSH) on my Mac. Apple provide a whole range of menu bar (NSStatus) options for AirPort, bluetooth, sound, date, time, battery life etc... But not for file sharing.


In fact, not only would I like to see what's happening in relation to File Sharing and SSH connections, I'd like to be notified of new connections. Having to jump into System Preferences in order to view current sharing status and monitor netstat via terminal to review current connections, seems a little too labour intensive for such a simple request.


After extensive Googling, I was surprised that I couldn't find any ready made solutions. The best I could find was AFPStatus over at sparrer-online.de, however, I wanted something with a smaller footprint, a simpler icon and additional functionality of monitoring incoming SSH connections.


After playing around with AppleScript and the excellent Growl notification framework, I quickly had a working version of a simple notification application which highlighted new incoming SSH connections. So how big would the step be to get this working as a true app for Mac OS X?


Having wanted to for a while, I had finally found an excuse to take the plunge and dive into Xcode. So over the next few blogs, I'll run through my journey of creating Version 1.0 of Who Is Connected? due for release June 09.




>> Part 1: Monitoring AFP Status in Mac OS X Terminal