diff --git a/README.md b/README.md index 823695d..824c399 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ A simple VPN written in Go. * VPN over utls * VPN over dtls * VPN over h2 -* VPN over http -* VPN over tcp +* VPN over http (Use aes-256-gcm encryption by default) +* VPN over tcp (Use aes-256-gcm encryption by default) +* VPN over https (Use aes-256-gcm encryption by default) # Usage ``` @@ -49,7 +50,7 @@ Usage of vtun: -obfs enable data obfuscation -p string - protocol udp/tls/grpc/quic/utls/dtls/h2/http/tcp/ws/wss (default "udp") + protocol udp/tls/grpc/quic/utls/dtls/h2/http/tcp/https/ws/wss (default "udp") -path string websocket path (default "/freedom") -privatekey string diff --git a/README_CN.md b/README_CN.md index 230b63a..763f1bd 100644 --- a/README_CN.md +++ b/README_CN.md @@ -22,6 +22,7 @@ * 支持h2 * 支持http * 支持tcp +* 支持https # 用法 @@ -50,7 +51,7 @@ Usage of vtun: -obfs enable data obfuscation -p string - protocol udp/tls/grpc/quic/utls/dtls/h2/http/tcp/ws/wss (default "udp") + protocol udp/tls/grpc/quic/utls/dtls/h2/http/tcp/https/ws/wss (default "udp") -path string websocket path (default "/freedom") -privatekey string diff --git a/common/xcrypto/xcrypto.go b/common/xcrypto/xcrypto.go new file mode 100644 index 0000000..d48d22a --- /dev/null +++ b/common/xcrypto/xcrypto.go @@ -0,0 +1,63 @@ +package xcrypto + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha1" + "crypto/sha256" +) + +type XCrypto struct { + Key []byte + Nonce []byte + aesGcm cipher.AEAD +} + +func (x *XCrypto) Load(key string) { + x.LoadKey(key) + x.LoadNonce(key) +} + +func (x *XCrypto) LoadKey(key string) { + h := sha256.New() + h.Write([]byte(key)) + x.Key = h.Sum(nil) +} + +func (x *XCrypto) LoadNonce(key string) { + h := sha1.New() + h.Write([]byte(key)) + b := h.Sum(nil) + x.Nonce = b[:12] +} + +func (x *XCrypto) Init(key string) error { + x.Load(key) + return x.init() +} + +func (x *XCrypto) init() error { + block, err := aes.NewCipher(x.Key) + if err != nil { + return err + } + aesGcm, err := cipher.NewGCM(block) + if err != nil { + return err + } + x.aesGcm = aesGcm + return nil +} + +func (x *XCrypto) Encode(pl []byte) ([]byte, error) { + ci := x.aesGcm.Seal(nil, x.Nonce, pl, nil) + return ci, nil +} + +func (x *XCrypto) Decode(ci []byte) ([]byte, error) { + pl, err := x.aesGcm.Open(nil, x.Nonce, ci, nil) + if err != nil { + return nil, err + } + return pl, nil +} diff --git a/h1/h1client.go b/h1/h1client.go index a677bab..cb8fe49 100644 --- a/h1/h1client.go +++ b/h1/h1client.go @@ -3,11 +3,10 @@ package h1 import ( "errors" "fmt" + "github.com/net-byte/vtun/common/xcrypto" "github.com/net-byte/vtun/common/xproto" "log" "net" - "runtime" - "strings" "time" "github.com/golang/snappy" @@ -41,7 +40,6 @@ func StartClient(iFace *water.Interface, config config.Config) { netutil.PrintErr(err, config.Verbose) continue } - //go checkH1SessionAlive(conn, config) cache.GetCache().Set("conn", conn, 24*time.Hour) h1ToTun(config, conn, iFace) cache.GetCache().Delete("conn") @@ -71,10 +69,16 @@ func handshake(config config.Config, conn net.Conn) error { return nil } -// tunToH1 sends packets from tun to tls +// tunToH1 sends packets from tun to h1 func tunToH1(config config.Config, iFace *water.Interface) { authKey := xproto.ParseAuthKeyFromString(config.Key) buffer := make([]byte, config.BufferSize) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } for { n, err := iFace.Read(buffer) if err != nil { @@ -86,6 +90,11 @@ func tunToH1(config config.Config, iFace *water.Interface) { if config.Obfs { b = cipher.XOR(b) } + b, err = xp.Encode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Compress { b = snappy.Encode(nil, b) } @@ -112,11 +121,17 @@ func tunToH1(config config.Config, iFace *water.Interface) { } } -// h1ToTun sends packets from tls to tun +// h1ToTun sends packets from h1 to tun func h1ToTun(config config.Config, conn net.Conn, iFace *water.Interface) { defer conn.Close() header := make([]byte, xproto.ServerSendPacketHeaderLength) packet := make([]byte, config.BufferSize) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } for { n, err := conn.Read(header) if err != nil { @@ -149,6 +164,11 @@ func h1ToTun(config config.Config, conn net.Conn, iFace *water.Interface) { break } } + b, err = xp.Decode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Obfs { b = cipher.XOR(b) } @@ -160,26 +180,3 @@ func h1ToTun(config config.Config, conn net.Conn, iFace *water.Interface) { counter.IncrReadBytes(n) } } - -func checkH1SessionAlive(conn net.Conn, config config.Config) { - os := runtime.GOOS - defer conn.Close() - for { - if os == "windows" { - result := netutil.ExecCmd("ping", "-n", "2", "-l", "21", "-w", "1200", config.ServerIP) - if strings.Contains(result, `100%`) { - netutil.PrintErr(errors.New("ping server failed, reconnecting"), config.Verbose) - break - } - continue - } else if os == "linux" || os == "darwin" { - result := netutil.ExecCmd("ping", "-c", "2", "-s", "21", "-w", "1200", config.ServerIP) - // macos return "100.0% packet loss", linux return "100% packet loss" - if strings.Contains(result, `100.0%`) || strings.Contains(result, `100%`) { - netutil.PrintErr(errors.New("ping server failed, reconnecting"), config.Verbose) - break - } - continue - } - } -} diff --git a/h1/h1server.go b/h1/h1server.go index 9e5c873..c325980 100644 --- a/h1/h1server.go +++ b/h1/h1server.go @@ -10,6 +10,7 @@ import ( "github.com/net-byte/vtun/common/config" "github.com/net-byte/vtun/common/counter" "github.com/net-byte/vtun/common/netutil" + "github.com/net-byte/vtun/common/xcrypto" "github.com/net-byte/vtun/common/xproto" "github.com/net-byte/water" "log" @@ -60,9 +61,15 @@ func StartServer(iFace *water.Interface, config config.Config) { } } -// toClient sends packets from iFace to conn +// toClient sends packets from tun to h1 func toClient(config config.Config, iFace *water.Interface) { buffer := make([]byte, config.BufferSize) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } for { n, err := iFace.Read(buffer) if err != nil { @@ -75,6 +82,11 @@ func toClient(config config.Config, iFace *water.Interface) { if config.Obfs { b = cipher.XOR(b) } + b, err = xp.Encode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Compress { b = snappy.Encode(nil, b) } @@ -103,13 +115,19 @@ func toClient(config config.Config, iFace *water.Interface) { } } -// toServer sends packets from conn to iFace +// toServer sends packets from h1 to tun func toServer(config config.Config, conn net.Conn, iFace *water.Interface) { defer conn.Close() handshake := make([]byte, xproto.ClientHandshakePacketLength) header := make([]byte, xproto.ClientSendPacketHeaderLength) packet := make([]byte, config.BufferSize) authKey := xproto.ParseAuthKeyFromString(config.Key) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } n, err := conn.Read(handshake) if err != nil { netutil.PrintErr(err, config.Verbose) @@ -166,6 +184,11 @@ func toServer(config config.Config, conn net.Conn, iFace *water.Interface) { break } } + b, err = xp.Decode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Obfs { b = cipher.XOR(b) } diff --git a/tcp/tcpclient.go b/tcp/tcpclient.go index 17c08ab..027c18e 100644 --- a/tcp/tcpclient.go +++ b/tcp/tcpclient.go @@ -3,6 +3,7 @@ package tcp import ( "errors" "fmt" + "github.com/net-byte/vtun/common/xcrypto" "github.com/net-byte/vtun/common/xproto" "log" "net" @@ -66,6 +67,12 @@ func handshake(config config.Config, conn net.Conn) error { func tunToTcp(config config.Config, iFace *water.Interface) { authKey := xproto.ParseAuthKeyFromString(config.Key) buffer := make([]byte, config.BufferSize) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } for { n, err := iFace.Read(buffer) if err != nil { @@ -77,6 +84,11 @@ func tunToTcp(config config.Config, iFace *water.Interface) { if config.Obfs { b = cipher.XOR(b) } + b, err = xp.Encode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Compress { b = snappy.Encode(nil, b) } @@ -108,6 +120,12 @@ func tcpToTun(config config.Config, conn net.Conn, iFace *water.Interface) { defer conn.Close() header := make([]byte, xproto.ServerSendPacketHeaderLength) packet := make([]byte, config.BufferSize) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } for { n, err := conn.Read(header) if err != nil { @@ -140,6 +158,11 @@ func tcpToTun(config config.Config, conn net.Conn, iFace *water.Interface) { break } } + b, err = xp.Decode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Obfs { b = cipher.XOR(b) } diff --git a/tcp/tcpserver.go b/tcp/tcpserver.go index c2d5cf9..6a5f7e8 100644 --- a/tcp/tcpserver.go +++ b/tcp/tcpserver.go @@ -9,6 +9,7 @@ import ( "github.com/net-byte/vtun/common/config" "github.com/net-byte/vtun/common/counter" "github.com/net-byte/vtun/common/netutil" + "github.com/net-byte/vtun/common/xcrypto" "github.com/net-byte/vtun/common/xproto" "github.com/net-byte/water" "log" @@ -40,6 +41,12 @@ func StartServer(iFace *water.Interface, config config.Config) { // toClient sends packets from iFace to conn func toClient(config config.Config, iFace *water.Interface) { buffer := make([]byte, config.BufferSize) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } for { n, err := iFace.Read(buffer) if err != nil { @@ -55,6 +62,11 @@ func toClient(config config.Config, iFace *water.Interface) { if config.Obfs { b = cipher.XOR(b) } + b, err = xp.Encode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Compress { b = snappy.Encode(nil, b) } @@ -67,7 +79,6 @@ func toClient(config config.Config, iFace *water.Interface) { if err != nil { netutil.PrintErr(err, config.Verbose) cache.GetCache().Delete(key) - //fmt.Printf("del %s %v\r\n", key, conn) conn.Close() continue } @@ -78,7 +89,6 @@ func toClient(config config.Config, iFace *water.Interface) { if err != nil { netutil.PrintErr(err, config.Verbose) cache.GetCache().Delete(key) - //fmt.Printf("del %s %v\r\n", key, conn) conn.Close() continue } @@ -86,8 +96,6 @@ func toClient(config config.Config, iFace *water.Interface) { fmt.Printf("conn-p write: %v\n", b) } counter.IncrWrittenBytes(n) - //} else { - // fmt.Printf("%s not ok!!!\n", key) } } } @@ -100,6 +108,12 @@ func toServer(config config.Config, conn net.Conn, iFace *water.Interface) { header := make([]byte, xproto.ClientSendPacketHeaderLength) packet := make([]byte, config.BufferSize) authKey := xproto.ParseAuthKeyFromString(config.Key) + xp := &xcrypto.XCrypto{} + err := xp.Init(config.Key) + if err != nil { + netutil.PrintErr(err, config.Verbose) + return + } n, err := conn.Read(handshake) if err != nil { netutil.PrintErr(err, config.Verbose) @@ -165,6 +179,11 @@ func toServer(config config.Config, conn net.Conn, iFace *water.Interface) { break } } + b, err = xp.Decode(b) + if err != nil { + netutil.PrintErr(err, config.Verbose) + break + } if config.Obfs { b = cipher.XOR(b) }