This repo is likely to be abondoned, in favor of a rust variant of the same functionality. The rust version is much faster, can saturate 1gbps locally, or 200mbps on alibaba cloud.
The logic is similar but not compatible. Rust variant also provides tcp and quic flavor. Some times, tcp over MTLS performs better than QUIC, especially over long distance.
See https://github.com/wushilin/rust-vpn.git
A secure, single executable (same for client/server) point to point VPN server that uses QUIC protocol. It also supports routing propagation by options
This program only supports LINUX at the moment. But it is easy to port this over to other platform.
Let me know if you need other platform support!
- make sure you have
rootaccess! - make sure your
/usr/sbin/ipis there. It uses the command to manipulate IP address assignment and routes - Make sure your golang is of
1.20or newer.
The program may warn about UDP buffer size, it is OK if you don't want to adjust it. It has no significant effect because the IP Frame is typically max at 1500 bytes.
See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size
In short, if you can and keen to adjust it once and for all, use this command:
# sysctl -w net.core.rmem_max=2500000To make it permenant, edit /etc/sysctl.conf and add
net.core.rmem_max=2500000
then run
# sysctl -pThis program has server mode and client mode.
It has zero allocation. It only need to do a one time allocation. No GC is ever required on this service most likely.
Both server and client must run as root, as we need to manipulate the system tunnel device.
By default tunnel device used is TUN17, you can specify the name by -tunname tun12 to switch to tun12 instead.
Server will start binding to QUIC (UDP) port and wait for client to connect.
Client connects via QUIC with mutual TLS as authentication. This is the security mechanism the VPN is offering.
- Server always load
server.pem,server.key,ca.pemfor TLS configuration. - Client always load
client.pem,client.key,ca.pemfor TLS configuration.
Server and client can specify the cert's common name by -commonName to validate.
If peer certificate's commonName is not matching, connection will be disconnected.
Client and server both can propogate the additional route rules to request remote host to route the IP ranges to local.
If route setup fails, the connection will be reset and all routing rule that had been requested will be deleted.
If more than 1 subnet is required, separate by ;. For example -route "192.168.44.0/24;10.251.116.0/24"
# ./go-vpn -l -b 0.0.0.0:4792 -laddr 172.47.88.1/24 -route "192.168.44.0/24;10.251.116.0/24" -commonName client003Explantion:
- Listen on UDP:
0.0.0.0:4792 - Assign Local Tun Device IP of
172.47.88.1/24 - Request remote to route
192.168.44.0/24;10.251.116.0/24in addition to172.47.88.1/32(the local IP) - Require client certificate is signed by
ca.pemand has commonName ofclient003
# ./go-vpn -s 192.168.44.105:4792 -laddr 192.168.115.211/24 -route "172.19.0.0/16;172.31.0.0/16" -commonName vpnServerExplanation
- Connect to server on UDP:
0.0.0.0:4792 - Assign Local Tun Device IP of
192.168.115.211/24 - Request remote to route
172.19.0.0/16;172.31.0.0/16in addition to192.168.115.211/32(the local IP) - Require client certificate is signed by
ca.pemand has commonName ofvpnServer
NOTE: The server and client IP does not have to be in the same SUBNET!!
Connection will be forever retried. It would eventually re-establish connection whenever network disconnect is encountered.
You can install via
# go install github.com/wushilin/[email protected]The binary should be in your $GOPATH/bin
You can run this as systemd for both server and client.
An example of server:
[Unit]
Description=The VPN by Go
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=simple
#User=service
#Group=service
WorkingDirectory=/opt/vpn
PIDFile=/opt/vpn/vpn.pid
ExecStart=/opt/vpn/go-vpn -l -b 0.0.0.0:24192 -tunname tun99
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
SyslogIdentifier=go-vpn
[Install]
WantedBy=multi-user.target
The service can easily scale beyond 100MiB/s, depending on your network speed and processor speed.
The protocol is secure by default via open standard, TLS may slow down the speed a little bit but I hope you think it is worth it.
The built in certificate is valid for server hostname that looks like *.local. If you want to use the default certificate (not recommended), you can add your server's IP address to client's /etc/hosts as something.local, and connect by that hostname with -s something.local:4792.
Please consider using https://github.com/wushilin/minica
Alternatively, a script version is available at https://github.com/wushilin/minica-script
If you mainly use in intranet, or you mainly uses Secure Transport and don't care about authentication/authorization, you can use the ultrafast version.
It uses udp transport in client/server mode. No security, no encryption. Everything transmitted as if it is IP frames.
It is probably 3~4 times faster.
Usage of ./ultrafast:
-aeskey string
AES 256 encryption key. Will be padded with ' ' or trimmed if not 32 chars
-connect string
Peer UDP host and port in [ip|hostname]:port format. Default is ""
-laddr string
Local interface address. Default 10.99.99.1/30 for server, 10.99.99.2/30 for client
-listen string
UDP Listen address in ip:port format. Default is 0.0.0.0:20192 (default "0.0.0.0:20192")
-tunname string
Device name (default "TUN17")If you don't use aeskey, you are effectively using aeskey of ' ' x 32.
The server will PIN the connection to the first connected peer and will refuse to talk to anyone else.
This will cause clients restarted on a diffrent port number not be able to connect ever again. Therefore, we implemented a encrypted PING to allow client to PING server and let server update the PINed peer address.
NOTE: The AES key is to securely verify client's identity by using AES encrypted payload. It is not meant to encrypt the traffic as that would be slower.
Of course, it can be implemented, just not done yet.
Don't run more than 1 client to talk to the server.