Enable to share the same TCP port for different applications, for example, http and ssh.
It is inspired by @yrutschle 's sslh project, but is implemented in a totally different way and works only on Linux.
The whole workflow is as below:
1. The program will listen on the common tcp port
2. A new connection arrives and will be accepted by tcpmux
3. The program will peek out the data of the first packet and check what protocol this connection is.
The protocol identification code can be internal (or builtin-in) code, or external program.
This enables to use more professional program to protocol identification
4. Once the protocol of the connection is set, the program will deliver the connection to real server, by.
if the server is 1:N mode (one process will serve multiple clients, such as HTTP server),
the connection will be transfered to a TCP proxy server by UNIX socket. The TCP proxy server
will take the client connection, establish a new connection with real server and forward
packets between the connection pairs.
if the server is 1:1 mode, tcpmux will launch the real server and pass the connection fd to the real server.
This tcpmux framework is flexible to implement new features as could:
1. protocol identification
the external protocol identification program is supported
Please refer to sample/sample_extern_ident.c
it is also supported to register internal protocol identifier dyanmically
please refer to sample/sample_xmodule.c
2. access control: user can write access control program to limit IP and time to access one service.
Then configure tcpmux to launch this access control program instead of real server for a protocol.
After access check pass, the access control program can launch the real server.
Please refer to sample/access_control.c
1. Install libconfig
In Ubuntu system, please use
apt install libconfig-dev
2. Compile
make should work
Files will be created:
tcpmux ---- the main program
sample/echo_srv --- a sample echo server for test
sample/sample_xmodule.so --- a sample .so to demo how to register interanal protocol at run-time
sample/sample_extern_ident --- a external identifier sample
sample/tcp_proxy --- a tcp proxy to connect 1:N server
sample/access_control --- a sample access control program
sample/sampe_proxy --- implement a TCP proxy while embedded mulit-clients echo services.
1. start the tcpmux
sudo ./tcpmux -p listen_port -d
sudo: launch sshd needs root priviledge
-p listen_port: optionally. If not present, this will get from config file: ./tcpmux.cfg
-d: run as daemon, optionally
2. start the TCP proxy: (for HTTP)
./sample/tcp_proxy -a http_ip -p http_port -d
3. check configure file ./tcpmux.cfg if the ssh path is correct or not in your system
{proto: "ssh";server:"/usr/sbin/sshd";para:"-i"},
4. do test
4.1 test echo server first
$cat > echo.txt << EOF
echo
hello, world
could you hear me?
Bye
EOF
$nc 127.0.0.1 listen_port < echo.txt
4.2 test ssh
ssh 127.0.0.1 listen_port
4.3 test HTTP
wget 127.0.0.1 listen_port
The configure file is ./tcpmux.cfg and it is self-explainsive enough, I guess.
version = "1.0"
bind_addr= "0.0.0.0"
listen_port=8080
log_level=1 #1 --- info 2 --- debug
#set different protocol identifier programs here
#it could be internal one, built into or dynamic loaded by extension mode
# or an external program to parse the packet data
proto_identifier:
(
#name "internal" is a reserved key word to stand for all internal identifiers
{name:"internal";identifier:"internal";priority:0;disabled:0},
{name:"open";identifier:"./open_ident";priority:1;disabled:1},
{name:"extern0";identifier:"./sample/sample_extern_ident";priority:2;disabled:0}
)
extension_module:
(
{name: "sample"; file: "./sample/sample_xmodule.so"}
)
#
# set the internal identifier's priroty and disable/enable
# name is the protocol identifier's name instead of protocol name
#
internal_identifer:
(
{name: "http";priority:0;disabled: 0},
{name: "echo";priority:1;disabled: 0},
{name: "ssh";priority:1;disabled: 0},
{name: "xecho";priority:2;disabled: 1}, #xecho, xssh is imported by sample_xmodule.so
{name: "xssh";priority:2;disabled: 0}
)
#if the same protocol handler is defined both in proxy_server and in proto_server
#proxy server handler will be called first
proxy_server:
(
{proto:"http"; channel:"/tmp/unix.proxy.0"}
)
proto_server:
(
#sample to launch sshd directly
#{proto: "ssh";server:"/usr/sbin/sshd";para:"-i"},
#sample to add an access check in pipe
{proto: "ssh";server:"./sample/access_control";para:"ssh,/usr/sbin/sshd,-i"},
{proto: "echo"; server:"./sample/echo_srv"}
)
1. protocol identification
I'm trying to find open source protocol identification and porting to the project.
But I do not find out a good one yet.
The samples currently implemented are too simpled and too easy to be attacked.
2. install scripts and packages
I'm not familiar on this part yet.