Ctrl

Thoughts of a simple, single-threaded human constantly trying to find the meaning of life live, love and learn in the modern world.

Network Kittens and UDP

The other day, I was playing around with a statsd server. I wanted to hit it with some UDP packets using the CLI.

Following the minimum-working-example reasoning process (my favorite!), I soon found myself using netcat to setup up a simple UDP "server" and "client".

Netcats

The network tool netcat is also called the "TCP/IP swiss army knife".

What I didn't know is that there are many netcat flavors like netcat-traditional, netcat-openbsd, GNU netcat, as well as other netcat-like tools like ncat, socat.

I am using Debian, so I searched and found the 3 following packages:

# apt-cache search netcat --names-only
netcat-openbsd - TCP/IP swiss army knife
netcat - TCP/IP swiss army knife -- transitional package
netcat-traditional - TCP/IP swiss army knife

Let's examine each.

The netcat package is a dummy/transitional package:

# apt-cache show netcat | grep Description-en -A 2
Description-en: TCP/IP swiss army knife -- transitional package
 This is a "dummy" package that depends on lenny's default version of
 netcat, to ease upgrades. It may be safely removed.

The netcat-traditional is very old and it is also named netcat 1.10:

Netcat was created in the year 1995 and was developed until first
months of the 1996, when it reached version 1.10, released by Avian
Research (avian.org).

This is the traditional netcat,
    Copyright: © 1995-1996, Avian Research

The GNU netcat is quite old too:

Current Version:
GNU Netcat 0.7.1

Released on:
11 Jan 2004

The netcat-openbsd looks promising. One interesting point is that it is not in fact the OpenBSD code. Rather it is the OpenBSD code with Debian patches/changes:

# apt-cache policy netcat-openbsd
netcat-openbsd:
  Installed: 1.130-3
  Candidate: 1.130-3
  Version table:
 *** 1.130-3 500
        500 http://ftp.gr.debian.org/debian stretch/main amd64 Packages
        500 http://httpredir.debian.org/debian stretch/main amd64 Packages
        500 http://http.debian.net/debian stretch/main amd64 Packages
        100 /var/lib/dpkg/status

So there we have it, we want to use netcat-openbsd.

But which version do we already use?

To find out which version of netcat you are currently using, you can follow some symlinks:

$ which nc
/bin/nc
$ ls -al /bin/nc
lrwxrwxrwx 1 root root 20 Nov 29 18:17 /bin/nc -> /etc/alternatives/nc
$ ls -al /etc/alternatives/nc
lrwxrwxrwx 1 root root 15 Dec 27 18:18 /etc/alternatives/nc -> /bin/nc.openbsd
$ ls -al /bin/nc.openbsd
-rwxr-xr-x 1 root root 31208 Mar  3  2017 /bin/nc.openbsd

BTW, you can use the freaking cool namei command for the same job:

$ namei `which nc`
f: /bin/nc
 d /
 d bin
 l nc -> /etc/alternatives/nc
   d /
   d etc
   d alternatives
   l nc -> /bin/nc.openbsd
     d /
     d bin
     - nc.openbsd

Finally, make sure you read the correct man page, depending on the version of netcat you are using:

$ man nc
$ man nc.openbsd
$ man nc.traditional

Another interesting thing here is that although the man nc.openbsd page states:

-l      Used to specify that nc should listen for an incoming connection
        rather than initiate a connection to a remote host.
        It is an error to use this option in conjunction with the -p, -s,
        or -z options.  Additionally, any timeouts specified with the -w
        option are ignored.

It is quite OK to use -l and -p options together:

# /bin/nc.openbsd -l -p 9876

This appears to be a fix from the Debian team, without the relevant documentation (man page) update...

Fun with netcat and UDP

First, set up a netcat server, listening on port 9876, waiting for UDP packets:

$ /bin/nc.openbsd -v -4 -l -p 9876 -u -k -w 0

The server is now waiting.

Use another shell to fire up a netcat client and send a UDP packet to the server:

$ echo -e lala | /bin/nc.openbsd -v -4 -w 0 -u localhost 9876

Indeed, the server receives the message:

$ /bin/nc.openbsd -v -4 -l -p 9876 -u -k -w 0
XXlala

Seems nice and easy right? Actually, a lot of things went awry until I got it to work.

There seems to be a very strange behavior of netcat:

When nc is listening to a UDP socket,
it "locks on" to the source port and
source IP of the first packet it receives.

The solution for this is to use the -k option on the server side:

-k      Forces nc to stay listening for another connection after its
        current connection is completed. It is an error to use this
        option without the -l option. When used together with the -u
        option, the server socket is not connected and it can receive
        UDP datagrams from multiple hosts.

Funny. One would expect that the -u option also implies -k, since UDP is a connection-less protocol.

The -w option is needed both in the server and the client side.

Also, the Debian netcat version 1.130-3 has a bug when using both options -u and -v. This bug is fixed in version 1.178-3.

And, what about those leading XX characters in the server output?

Socat

So, after spending some of my time on netcat, I decided to drop it and use socat.

The server is now:

$ socat - udp4-listen:9876,reuseaddr,fork

And the client is now:

$ socat - udp-sendto:127.0.0.1:9876

Simple and beautiful :)

I can even kill the client, re-spawn it, and still get the messages to appear in the server!


Copyright © 2018 Vasileios Souleles - Theme Skeleton - Blog Engine Pelican - Powered by Python - Made with ❤ in Vim