Is it possible to expose TCP tunnel in Linux as special character device?

socat can do do this and many other things with things resembling "streams"

Something using this basic idea should do it for you:

Machine1$ socat tcp-l:54321,reuseaddr,fork pty,link=/tmp/netchardev,waitslave

Machine2$ socat pty,link=/tmp/netchardev,waitslave tcp:machine1:54321

(adapted from Examples Page)

If you want to encrypt, you could use a variation of ssl-l:54321,reuseaddr,cert=server.pem,cafile=client.crt,fork on machine1, and something like ssl:server-host:1443,cert=client.pem,cafile=server.crt on machine2

(More about socat ssl)


Message-passing needs to be implemented at a higher layer; TCP does not have a notion of a message -- the TCP connections transfer streams of octets.

You can achieve something sort-of like what you request with nc and named pipes, see man mkfifo; or check socat as Alex Stragies indicates.

Without a middle-layer service, the basic problems are (1) that data cannot be written to the network unless there is somebody at the other end listening for it, and (2) that TCP connections are bi-directional.

Because you cannot write data to the network unless somebody is listening for it, you must always start the listener before you can send data. (In a message passing system the process handling the messages will provide some sort of buffering.)

Your example can be easily rewritten:

  • First start a listener on machine2 (the destination):

     nc -l 1234 | ...some processing with the received data...
    

    In your example, this would be

     nc -l 1234 | cat
    

    This will block and wait for somebody to send some data to port 1234.

  • Then you can send some data from machine1 (the source):

    ...make up some data... | nc machine2 1234
    

    In your example, this would be

     echo "Hello" | nc machine2 1234
    

If you want to process the received data in some way and respond you can use the coprocessing facility of the shell. For example, this is a very simple (and very stubborn) web server:

#! /bin/bash

while :; do
  coproc ncfd { nc -l 1234; }
  while :; do
    read line <&${ncfd[0]} || break
    line="$(
      echo "$line" |
      LC_ALL=C tr -cd ' -~'
    )"
    echo >&2 "Received: \"$line\""
    if [ "$line" = "" ]; then
      echo >&${ncfd[1]} "HTTP/1.0 200 OK"
      echo >&${ncfd[1]} "Content-Type: text/html"
      echo >&${ncfd[1]} "Connection: close"
      echo >&${ncfd[1]} ""
      echo >&${ncfd[1]} "<title>It works!</title>"
      echo >&${ncfd[1]} "<center><b>It works!</b></center>"
      echo >&${ncfd[1]} "<center>-- $(date +%Y-%m-%d\ %H:%M:%S) --</center>"
      break
    fi
  done
  kill %%
  sleep 0.1
done

See how the bi-directional communication is achieved between the main body of the script and the coprocess using the file descriptors in the array $ncfd.


If you simply want to connect two computers using a basic program like nc you can redirect from/to /dev/tcp/<host>/<port>.

These are not actual devices but a fiction created by bash, so things like cat /dev/tcp/foo/19 won't work, but cat < /dev/tcp/foo/19 will.