A Weird Imagination

Streams and socket and pipes, oh my

You know, like "lions and tigers and bears, oh my"… okay, not funny, moving on…

The problem#

There's a lot of different ways to transmit streams of bytes between applications on the same host or different hosts with various reasons you might want to use each one. And sometimes the two endpoints might disagree on which one they want to be using.

The solution#

As it turns out, there actually is a single answer to bridging any two byte streams: socat. The documentation has plenty of examples. Here's a few I made up involving named pipes and Unix sockets to go along with my recent posts:

Bridge a pair of named pipes to a Unix socket#

socat UNIX-LISTEN:test.sock 'PIPE:pipe_in!!PIPE:pipe_out'

Builds a bridge such that a client sees a Unix socket test.sock and the server communicates through two named pipes, pipe-in to send data over the socket and pipe_out to read the data received over the socket.

Connect to Unix socket HTTP server via TCP#

socat TCP-LISTEN:8042,fork,bind=localhost \
    UNIX-CONNECT:http.sock

For an HTTP server accepting connections via the Unix socket http.sock, makes it also accept connections via the TCP socket localhost:8042.

Forward a Unix socket over an SSH connection#

socat EXEC:"ssh remote 'socat UNIX-CLIENT:service.sock -'" \
    UNIX-LISTEN:proxy-to-remote.sock

Note ssh can do the same without socat (including supporting either side being a TCP port):

ssh -N -L ./proxy-to-remote.sock:./service.sock remote

But that demonstrates combining socat and ssh for getting access to streams only accessible from a remote computer.

The details#

socat vs. nc#

socat describes itself as "netcat++". nc is the name of netcat's binary, which already points you towards a philosophical difference between the two tools: unlike socat verbose options, nc is terse:

$ nc -l -p 1234
# which can also be written with long options:
$ nc --listen --source-port 1234

is approximately equivalent to

$ socat - TCP-LISTEN:1234

Which one you prefer is a matter of taste: it's a lot more obvious at a glance what the socat command does, but the nc command takes up less space and is faster to type. Additionally, socat has a lot of options and is presumably more flexible than nc.

nc has some complicated history resulting in there being multiple forks, so the exact feature set available on a given system may vary. If you're sticking to TCP/UDP, that's supported in the original, but Unix sockets and more obscure protocols like DCCP or SCTP are only available in some verions, so you can't necessarily rely on them being available on an arbitrary machine. (It also doesn't support named pipes explicitly, but shell redirection can handle them.)

As the older tool, nc is more likely to be available on a given system, which may make it preferable for use in scripts which may run a lot of different systems.

SSH forwarding#

While socat does support SSL/TLS for encryption, often it's more convenient to use SSH for encryption instead. As shown in the example above, the two can be combined where appropriate.

ssh offers the -L and -R options for forwarding TCP (or in newer versions also Unix) sockets. The L and R stand for Local or Remote, referring to which side SSH listens on, forwarding those connections to the other side. That is, -L listens to a TCP or Unix socket on the local side and forwards all connections made to that socket to the other one specified for the remote computer, which is presumably already running a service listening for connections. You can find plenty of example usages online, including this StackExchange answer.

Also used in the example above is the other way to forward streams over SSH: standard input/output. When ssh is run with a command as an argument, the standard input/output pipes are forwarded over the SSH connection. In the example above, this is used to effectively tunnel socat through SSH, although it can be used in general to flexibly run any part of any command pipeline on a different computer.

Comments

Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.

There are no comments yet.