Merge pull request #18 from NNdroid/master

add tls support
This commit is contained in:
net-byte 2022-05-16 17:26:15 +08:00 committed by GitHub
commit 6aa9f33e1f
6 changed files with 218 additions and 17 deletions

View File

@ -13,6 +13,7 @@ A simple VPN written in golang.
* VPN over tcp * VPN over tcp
* VPN over udp * VPN over udp
* VPN over websocket * VPN over websocket
* VPN over tls
# Usage # Usage
@ -23,6 +24,12 @@ Usage of ./vtun:
tun interface cidr (default "172.16.0.10/24") tun interface cidr (default "172.16.0.10/24")
-c6 string -c6 string
tun interface ipv6 cidr (default "fced:9999::9999/64") tun interface ipv6 cidr (default "fced:9999::9999/64")
-certificate string
tls certificate file path
-privatekey string
tls certificate key file path
-sni string
tls handshake sni
-dn string -dn string
device name device name
-g client global mode -g client global mode

View File

@ -13,6 +13,7 @@
* 支持tcp * 支持tcp
* 支持udp * 支持udp
* 支持websocket * 支持websocket
* 支持tls
# 用法 # 用法
@ -23,6 +24,12 @@ Usage of ./vtun:
tun interface cidr (default "172.16.0.10/24") tun interface cidr (default "172.16.0.10/24")
-c6 string -c6 string
tun interface ipv6 cidr (default "fced:9999::9999/64") tun interface ipv6 cidr (default "fced:9999::9999/64")
-certificate string
tls certificate file path
-privatekey string
tls certificate key file path
-sni string
tls handshake sni
-dn string -dn string
device name device name
-g client global mode -g client global mode

View File

@ -1,20 +1,23 @@
package config package config
type Config struct { type Config struct {
DeviceName string DeviceName string
LocalAddr string LocalAddr string
ServerAddr string ServerAddr string
IntranetServerIP string IntranetServerIP string
IntranetServerIPv6 string IntranetServerIPv6 string
CIDR string CIDR string
CIDRv6 string CIDRv6 string
Key string Key string
Protocol string Protocol string
WebSocketPath string WebSocketPath string
ServerMode bool ServerMode bool
GlobalMode bool GlobalMode bool
Obfs bool Obfs bool
MTU int MTU int
Timeout int Timeout int
LocalGateway string LocalGateway string
TLSCertificateFilePath string
TLSCertificateKeyFilePath string
TLSSni string
} }

12
main.go
View File

@ -15,6 +15,7 @@ import (
"github.com/net-byte/vtun/tcp" "github.com/net-byte/vtun/tcp"
"github.com/net-byte/vtun/tun" "github.com/net-byte/vtun/tun"
"github.com/net-byte/vtun/udp" "github.com/net-byte/vtun/udp"
"github.com/net-byte/vtun/tls"
"github.com/net-byte/vtun/ws" "github.com/net-byte/vtun/ws"
) )
@ -29,12 +30,15 @@ func main() {
flag.StringVar(&config.IntranetServerIP, "sip", "172.16.0.1", "intranet server ip") flag.StringVar(&config.IntranetServerIP, "sip", "172.16.0.1", "intranet server ip")
flag.StringVar(&config.IntranetServerIPv6, "sip6", "fced:9999::1", "intranet server ipv6") flag.StringVar(&config.IntranetServerIPv6, "sip6", "fced:9999::1", "intranet server ipv6")
flag.StringVar(&config.Key, "k", "freedom@2022", "key") flag.StringVar(&config.Key, "k", "freedom@2022", "key")
flag.StringVar(&config.Protocol, "p", "wss", "protocol tcp/udp/ws/wss") flag.StringVar(&config.Protocol, "p", "wss", "protocol tcp/udp/ws/tls/wss")
flag.StringVar(&config.WebSocketPath, "path", "/freedom", "websocket path") flag.StringVar(&config.WebSocketPath, "path", "/freedom", "websocket path")
flag.BoolVar(&config.ServerMode, "S", false, "server mode") flag.BoolVar(&config.ServerMode, "S", false, "server mode")
flag.BoolVar(&config.GlobalMode, "g", false, "client global mode") flag.BoolVar(&config.GlobalMode, "g", false, "client global mode")
flag.BoolVar(&config.Obfs, "obfs", false, "enable data obfuscation") flag.BoolVar(&config.Obfs, "obfs", false, "enable data obfuscation")
flag.IntVar(&config.Timeout, "t", 30, "dial timeout in seconds") flag.IntVar(&config.Timeout, "t", 30, "dial timeout in seconds")
flag.StringVar(&config.TLSCertificateFilePath, "certificate", "", "tls certificate file path")
flag.StringVar(&config.TLSCertificateKeyFilePath, "privatekey", "", "tls certificate key file path")
flag.StringVar(&config.TLSSni, "sni", "", "tls handshake sni")
flag.Parse() flag.Parse()
initConfig(&config) initConfig(&config)
go startApp(config) go startApp(config)
@ -78,6 +82,12 @@ func startApp(config config.Config) {
} else { } else {
ws.StartClient(config) ws.StartClient(config)
} }
case "tls":
if config.ServerMode {
tls.StartServer(config)
} else {
tls.StartClient(config)
}
default: default:
if config.ServerMode { if config.ServerMode {
ws.StartServer(config) ws.StartServer(config)

80
tls/tlsclient.go Normal file
View File

@ -0,0 +1,80 @@
package tls
import (
"crypto/tls"
"io"
"log"
"net"
"time"
"github.com/net-byte/vtun/common/cache"
"github.com/net-byte/vtun/common/cipher"
"github.com/net-byte/vtun/common/config"
"github.com/net-byte/vtun/tun"
"github.com/songgao/water"
)
// Start tls client
func StartClient(config config.Config) {
log.Printf("vtun tls client started on %v", config.LocalAddr)
iface := tun.CreateTun(config)
go tunToTLS(config, iface)
for {
tlsconfig := &tls.Config{
//InsecureSkipVerify: true,
}
if config.TLSSni != "" {
tlsconfig.ServerName = config.TLSSni
}
conn, err := tls.Dial("tcp", config.ServerAddr, tlsconfig)
if err != nil {
time.Sleep(3 * time.Second)
continue
}
cache.GetCache().Set("tlsconn", conn, 24 * time.Hour)
tlsToTun(config, conn, iface)
cache.GetCache().Delete("tlsconn")
}
}
func tunToTLS(config config.Config, iface *water.Interface) {
packet := make([]byte, config.MTU)
for {
n, err := iface.Read(packet)
if err != nil || n == 0 {
continue
}
if v, ok := cache.GetCache().Get("tlsconn"); ok {
b := packet[:n]
if config.Obfs {
packet = cipher.XOR(packet)
}
tlsconn := v.(net.Conn)
tlsconn.SetWriteDeadline(time.Now().Add(time.Duration(config.Timeout) * time.Second))
_, err = tlsconn.Write(b)
if err != nil {
continue
}
}
}
}
func tlsToTun(config config.Config, tlsconn net.Conn, iface *water.Interface) {
defer tlsconn.Close()
packet := make([]byte, config.MTU)
for {
tlsconn.SetReadDeadline(time.Now().Add(time.Duration(config.Timeout) * time.Second))
n, err := tlsconn.Read(packet)
if err != nil || err == io.EOF {
break
}
b := packet[:n]
if config.Obfs {
b = cipher.XOR(b)
}
_, err = iface.Write(b)
if err != nil {
break
}
}
}

94
tls/tlsserver.go Normal file
View File

@ -0,0 +1,94 @@
package tls
import (
"crypto/tls"
"log"
"net"
"io"
"time"
"github.com/net-byte/vtun/common/cache"
"github.com/net-byte/vtun/common/cipher"
"github.com/net-byte/vtun/common/config"
"github.com/net-byte/vtun/common/netutil"
"github.com/net-byte/vtun/tun"
"github.com/songgao/water"
)
//Start tls server
func StartServer(config config.Config) {
log.Printf("vtun tls server started on %v", config.LocalAddr)
iface := tun.CreateTun(config)
cert, err := tls.LoadX509KeyPair(config.TLSCertificateFilePath, config.TLSCertificateKeyFilePath)
if err != nil {
log.Println(err)
return
}
tlsconfig := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
PreferServerCipherSuites: true,
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
},
}
ln, err := tls.Listen("tcp", config.LocalAddr, tlsconfig)
if err != nil {
log.Println(err)
return
}
// server -> client
go toClient(config, iface)
// client -> server
for {
conn, err := ln.Accept()
if err != nil {
continue
}
go toServer(config, conn, iface)
}
}
func toClient(config config.Config, iface *water.Interface) {
packet := make([]byte, config.MTU)
for {
n, err := iface.Read(packet)
if err != nil || err == io.EOF || n == 0 {
continue
}
b := packet[:n]
if key := netutil.GetDstKey(b); key != "" {
if v, ok := cache.GetCache().Get(key); ok {
if config.Obfs {
b = cipher.XOR(b)
}
v.(net.Conn).Write(b)
}
}
}
}
// todo fallback to http
func toServer(config config.Config, tlsconn net.Conn, iface *water.Interface) {
defer tlsconn.Close()
packet := make([]byte, config.MTU)
for {
tlsconn.SetReadDeadline(time.Now().Add(time.Duration(config.Timeout) * time.Second))
n, err := tlsconn.Read(packet)
if err != nil || err == io.EOF {
break
}
b := packet[:n]
if config.Obfs {
b = cipher.XOR(b)
}
if key := netutil.GetSrcKey(b); key != "" {
cache.GetCache().Set(key, tlsconn, 10*time.Minute)
iface.Write(b)
}
}
}