A port forwarding tool with encryption and authentication that just works like ssh tunnel, but Zero Config for client.
It is currently a simple project and the author is not familiar with security, we take no responsibility for any security flaws.
Welcome to create issues and pull requests.
- You need to expose local port to public ip with encryption, and you just want specific users to visit it.
- You don't like teaching your users how to config the client program.
- Works just like ssh tunnel, but using
Noiseprotocol. - Client's binary executable is auto generated from server, user can run it without any config by hand, and only generated clients can communicate with server for auth.
- Every DH key used is auto generated too, without any copy-and-paste of config files.
remote1 <-> client <-> server <-> remote2
- Server listens on public IP and a public port.
- Remote can be a remote port (google.com:443), a local port (127.0.0.1:xxxx), or dynamic (socks5).
- Client works in any of the following modes:
ssh -Lmode: visit static port of remote2 through server.ssh -Dmode: visit dynamic remote2 through server's builtin socks5 server.ssh -Rmode: expose remote1 (port or dynamic) to server and register a service id.ssh -R visitormode: only clients in this mode with same service id can visit the exposed port.
- Client and server handshake using
Noise_IK_25519_ChaChaPoly_BLAKE2s. - Data transferred with encryption between client and server.
-
Config server with a
config.tomlfile.Example:
host = '192.168.1.1' # host of server port = 8022 # port of server remote = '127.0.0.1:1080' # default static remote (can be customized per client) # remote = 'socks5' # or use dynamic remote
-
Generate server keypair by running
portguard gen-key -c config.toml.After that,
config.tomlbecomes:host = '192.168.1.1' port = 8022 remote = '127.0.0.1:1080' pubkey = '1y3HW8TDxChtke5nyEdLGj+OkQSg8JjLdalSHzD+aWI=' prikey = 'eHg7jR/IZwEZEqeyR27IUTN0py5a3+wP0uM+z9HeWn8='
-
Generate client binary executable using
portguard gen-clisubcommand in 4 different modes:USAGE: portguard gen-cli [OPTIONS] --config <CONFIG> --output <OUTPUT> OPTIONS: -c, --config <CONFIG> location of config file -h, --help Print help information -i, --input <INPUT> location of input binary (current binary by default) -n, --name <NAME> name of client [default: user] -o, --output <OUTPUT> location of output binary -s, --service <SERVICE> service id of a reverse proxy -t, --target <TARGET> client's target address, can be socket address or "socks5"Example of generated config file:
host = '192.168.1.1' port = 8022 remote = '127.0.0.1:1080' pubkey = '1y3HW8TDxChtke5nyEdLGj+OkQSg8JjLdalSHzD+aWI=' prikey = 'eHg7jR/IZwEZEqeyR27IUTN0py5a3+wP0uM+z9HeWn8=' # works like ssh -L # to generate this, run: ./portguard gen-cli -c config.toml -o client -t 127.0.0.1:2333 [[clients]] name = "normal" pubkey = "dnso7kN2vhgLR/DVcAJRy1c9lRns3w7ESfB42szQWVI=" remote = "127.0.0.1:2333" # works like ssh -D # to generate this, run: ./portguard gen-cli -c config.toml -o client_socks5 -t socks5 [[clients]] name = "socks5" pubkey = "+iOiRpafA8/QKVclKZHiRkDSAQv4USkuS5qFJWOT/wk=" remote = "socks5" # works like ssh -R # to generate this, run: ./portguard gen-cli -c config.toml -o rclient -s 1 -t 127.0.0.1:2333 [[clients]] name = "rclient" pubkey = "kJqUC1fRRD9DW24zBmOkEKdEIX/EoSjfMeLxw2QvETI=" remote = ["127.0.0.1:2333", 1] # in order to connect port exposed by ssh -R # to generate this, run: ./portguard gen-cli -c config.toml -o rvisitor -s 1 [[clients]] name = "rvisitor" pubkey = "t+Zb+pfnQ3aIaJZfz0wnnjrUNcW4t8HPzOYf7gEhURc=" remote = 1 # works like ssh (-R + -D) # to generate this, run: ./portguard gen-cli -c config.toml -o rclient -s 2 -t socks5 [[clients]] name = "rclient_socks5" pubkey = "DHfFF3G+KFMHZjEiUwmTEo5+C2WZCtN+M0rirkgX/2c=" remote = ["socks5", 2] # same as "rvisitor" [[clients]] name = "rvisitor_socks5" pubkey = "vmdp+x5bhUkZKA3SGqA5Gv+VX8/XfutzrAfGxk+Q3zo=" remote = 2
-
Run
portguard server -c config.tomlon server side. -
Run generated binary on client side without any configs (local port or server address can be customized with
pgcli -p port -s saddr:sportif you like).
-
I'm not familar with Noise protocol, now in my code every connection between client and server needs to handshake (except reverse proxy mode).Now I think it is a feature. - Set remote address per client.
- Benchmark and improve performance.
- When will a connection be closed? Put it in logs.
- Test.
- UDP ?
--reversearguments is removed for client because role of client can be detected automatically.- clients in server config are now represented as set rather than map.
- add
ssh -Rfeature using yamux (It just works, recommend to use existing projects like frp or rathole with-Lmode) - add
ssh -R+ssh -Dfeature (socks5 reverse proxy) - more tests needed
- add
x86_64-apple-darwinsupport (not tested) - regularize section name
- server can generate client for any platform (windows, linux, macos)
- client can derive its public key using list-key subcommand
- add
ssh -Dfeature with a built-in SOCKS5 server - can overwrite config of existing client
- basic
ssh -Lfeature
Thanks for these projects:
- dend.ro's blog article about self-modify binary, I learned how to modify binary.
- snowstorm, I use NoiseStream from this project for convenience and add some code for timeout when reading from handshake message.
- fast-socks5, I use Socks5Socket from this library as a built-in SOCKS5 server.
- rust-yamux, I use yamux from this library to impl reverse proxy.