Learning More About Network Sockets
The DevOps Zone is brought to you in partnership with Go Continuous Delivery. Learn the 5 key patterns to setting up a successful deployment pipeline, including designing parallel workflows, running tests in parallel, and more.
While reading through some of the neo4j code a few weeks ago I realised that I didn’t have a very good understanding about the mechanics behind network ports/sockets so I thought I’d try to learn more.
In particular I’d not considered what binding a socket to different network interfaces meant so I decided to setup a few examples using netcat to help me understand better.
To start with let’s list the network interfaces that I have on my machine using ifconfig:
$ ifconfig -u lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=3<RXCSUM,TXCSUM> inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether xxxxxxxxxxxx inet6 fe80::9afe:94ff:fe4f:ee50%en0 prefixlen 64 scopeid 0x4 inet 192.168.1.89 netmask 0xffffff00 broadcast 192.168.1.255 media: autoselect status: active p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304 ether xxxxxxxxxxxx media: autoselect status: inactive
‘p2p0′ isn’t active so we’ll only be able to use the other two to make a socket connection on the machine.
We’ll use netcat to setup a server socket on port 4444 listening on the loopback interface:
$ nc -l -k 127.0.0.1 4444
We can use lsof to see how this has been setup:
$ lsof -Pni :4444 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 34178 markhneedham 35u IPv6 0x114b98295506482d 0t0 TCP 127.0.0.1:4444 (LISTEN)
Let’s try and connect to that port using netcat:
$ nc -v 127.0.0.1 4444 Connection to 127.0.0.1 4444 port [tcp/krb524] succeeded!
That works as we’d expect but if we try to connect using the IP of the ‘en0′ interface we’ll get an error:
$ nc -v 192.168.1.89 4444 nc: connect to 192.168.1.89 port 4444 (tcp) failed: Connection refused
However, if we setup netcat to listen on the wildcard interface (0.0.0.0) then we would be able to connect to 4444 regardless of the interface:
$ nc -l -k 0.0.0.0 4444
$ nc -v 192.168.1.89 4444 Connection to 192.168.1.89 4444 port [tcp/krb524] succeeded! $ nc -v 127.0.0.1 4444 Connection to 127.0.0.1 4444 port [tcp/krb524] succeeded!
If we check lsof it will confirm that we are listening on 4444 on all interfaces:
$ lsof -Pni :4444 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 37725 markhneedham 3u IPv4 0x114b98294ba8dfd5 0t0 TCP *:4444 (LISTEN)
One thing I hadn’t realised is that you can set up two different processes listening on the same port but on different interfaces. e.g.
$ nc -l -k 127.0.0.1 4444 $ nc -l -k 0.0.0.0 4444
We can see from lsof how this has been setup:
$ lsof -Pni :4444 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 38306 markhneedham 3u IPv4 0x114b98294ba8dfd5 0t0 TCP *:4444 (LISTEN) nc 38331 markhneedham 3u IPv4 0x114b98294cc53fd5 0t0 TCP 127.0.0.1:4444 (LISTEN)
If we make a socket connection to 127.0.0.1 it goes to our first netcat and if we use 192.168.1.89 the second one is used.
Finally, if we try to bind a server socket on an interface that we don’t own netcat will fail in a fairly predictable way:
$ nc -l -k 192.168.1.90 4444 nc: Can't assign requested address