Skip to main content

Build Your Own Socat

This challenge is to build your own version of the Unix command line tool socat. It’s name is a combination of the words SOcket CAT as it is in effect a version of cat that works over socks too.

Socat is a command line utility that establishes two bidirectional byte streams and transfers data between them. Because the streams can be constructed from a large set of different types of data sinks and sources. That can include:

  • Files
  • Pipes
  • Devices (serial line, pseudo-terminal, etc)
  • Sockets (UNIX, IP4, IP6 - raw, UDP, TCP)
  • SSL sockets
  • Proxy CONNECT connections

Basically anything Unix like operating systems treat as a file.

The Challenge - Building Socat

In this coding challenge we’re going to build a clone of the socat tool that can establish bidirectional streams between files, sockets and pipes.

We can learn more about socat using the man socat command:

Socat is a command line based utility that establishes two bidirectional byte
streams and transfers data between them. Because the streams can be constructed
from a large set of different types of data sinks and sources (see address types),
and because lots of address options may be applied to the streams, socat can be
used for many different purposes.

There are lot of options for the socat tool, so do refer back to the man page as you need to throughout the coding challenge.

Step Zero

As I have a background working in C and C-like programming languages, Coding Challenges is zero indexed. As always in step zero your goal is to setup your programming environment of choice, sit, stand or lie in wherever you code best, accompanied by your beverage and/or fuel of choice!

Step 1

In this step your goal is to support forwarding a local port to a remote host and port. With socat the command line to do that looks like this:

% socat - TCP4:eu.httpbin.org:80

This is going to open a TCP connection to the defined host and port.

We can check it’s worked by sending a hand-crafted HTTP request like so:

% socat - TCP4:eu.httpbin.org:80
GET /get HTTP/1.1
Host: eu.httpbin.org
Accept: */*

Be sure to send two newlines after the Accept line. If it’s working you’ll see a response like this:

% socat - TCP4:eu.httpbin.org:80
GET /get HTTP/1.1
Host: eu.httpbin.org
Accept: */*

HTTP/1.1 200 OK
Date: Wed, 04 Dec 2024 15:14:35 GMT
Content-Type: application/json
Content-Length: 225
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "eu.httpbin.org",
"X-Amzn-Trace-Id": "Root=1-675071db-6bd70b51268fe7614cf2c9ff"
},
"origin": "90.242.53.77",
"url": "http://eu.httpbin.org/get"
}

OK, we won’t normally need to hand-craft HTTP requests, but sometimes it’s fun to understand how these things work. If you want to really dig into HTTP, check out RFC9110.

Step 2

In this step your goal is to support writing to a file. The command line for this looks like:

socat -u STDIO FILE:test.txt,create

To test it we can write to the file and check the file then contains what we want:

% socat -u STDIO FILE:test.txt,create
Hello Coding Challenges
% cat test.txt
Hello Coding Challenges

Note you’ll have to send an end of file to socat to terminate the program. If you’re on a Unix-like operating system you can do that by entering: CTRL-D. We’ve used cat to check the file contains the content we entered. By the way building your own cat is another Coding Challenge!

Step 3

In this step your goal is to extend your socat clone to have enough features to support creating a simple network message collector. To do that you need to support the following command line:

% socat -u TCP4-LISTEN:3333,reuseaddr,fork OPEN:./test.log,creat,append

This will set up socat to listen for TCP connections on port 3333, and fork a new instance for every incoming connection. Using this we can use socat as a simple log aggregator, sending logs from one or more servers to a central server.

To check it’s working run your socat and then use netcat to send mock log files to it like so:

% for i in {1..10} ; do echo "Hello, Coding Challenges Log Message $i" | nc localhost 3333 -c; done

Your log file should then contain:

Hello, Coding Challenges Log Message 1
Hello, Coding Challenges Log Message 2
Hello, Coding Challenges Log Message 3
Hello, Coding Challenges Log Message 4
Hello, Coding Challenges Log Message 5
Hello, Coding Challenges Log Message 6
Hello, Coding Challenges Log Message 7
Hello, Coding Challenges Log Message 8
Hello, Coding Challenges Log Message 9
Hello, Coding Challenges Log Message 10

By the way, build your own netcat is also a coding challenge!

Step 4

In this step your goal is to support the exec option so we use it to follow a log file on a server and send it to the message collector. Once you’ve done that you should be able to start the message collector as before:

% socat -u TCP4-LISTEN:3333,reuseaddr,fork OPEN:./test.log,create,append

Start socat tailing the ‘log’ file we’re using to test:

% socat -u EXEC:'tail -f test.txt' TCP4:localhost:3333

And in another terminal simulate log messages being written to the file, i.e.:

% echo "Coding Challenges Log Message" > test.txt
% echo "Another Coding Challenges Log Message" > test.txt

Once that works, congratulations you’ve built quite a useful tool and learned about forking processes, reading and writing files as well as TCP connections in your programming language of choice!

Going Further

There are many other options for socat. Have a read of the manual and see what else it can do. If you’ve never used UDP before that might be an interesting place to start.

Help Others by Sharing Your Solutions!

If you think your solution is an example other developers can learn from please share it, put it on GitHub, GitLab or elsewhere. Then let me know - ping me a message on the Discord Server, via Twitter or LinkedIn or just post about it there and tag me. Alternately please add a link to it in the Coding Challenges Shared Solutions Github repo.

Get The Challenges By Email

If you would like to recieve the coding challenges by email, you can subscribe to the weekly newsletter on SubStack here: