mirror of
https://github.com/net-byte/vtun
synced 2024-03-14 10:50:03 +08:00
support ws
This commit is contained in:
parent
cec4bcab3b
commit
f0f60ef070
@ -7,10 +7,11 @@ import (
|
||||
"github.com/net-byte/vtun/common/cipher"
|
||||
"github.com/net-byte/vtun/common/config"
|
||||
"github.com/net-byte/vtun/tun"
|
||||
"github.com/songgao/water/waterutil"
|
||||
)
|
||||
|
||||
// Start client
|
||||
func Start(config config.Config) {
|
||||
// StartUDPClient start udp client
|
||||
func StartUDPClient(config config.Config) {
|
||||
config.Init()
|
||||
iface := tun.CreateTun(config.CIDR)
|
||||
serverAddr, err := net.ResolveUDPAddr("udp", config.ServerAddr)
|
||||
@ -26,7 +27,7 @@ func Start(config config.Config) {
|
||||
log.Fatalln("failed to listen on UDP socket:", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
log.Printf("vtun client started on %v,CIDR is %v", config.LocalAddr, config.CIDR)
|
||||
log.Printf("vtun udp client started on %v,CIDR is %v", config.LocalAddr, config.CIDR)
|
||||
// read data from server
|
||||
go func() {
|
||||
buf := make([]byte, 1500)
|
||||
@ -37,6 +38,9 @@ func Start(config config.Config) {
|
||||
}
|
||||
// decrypt data
|
||||
b := cipher.Decrypt(buf[:n])
|
||||
if !waterutil.IsIPv4(b) {
|
||||
continue
|
||||
}
|
||||
iface.Write(b)
|
||||
}
|
||||
}()
|
||||
@ -47,6 +51,9 @@ func Start(config config.Config) {
|
||||
if err != nil || n == 0 {
|
||||
continue
|
||||
}
|
||||
if !waterutil.IsIPv4(packet) {
|
||||
continue
|
||||
}
|
||||
// encrypt data
|
||||
b := cipher.Encrypt(packet[:n])
|
||||
conn.WriteToUDP(b, serverAddr)
|
74
client/wsclient.go
Normal file
74
client/wsclient.go
Normal file
@ -0,0 +1,74 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"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/patrickmn/go-cache"
|
||||
"github.com/songgao/water"
|
||||
"github.com/songgao/water/waterutil"
|
||||
)
|
||||
|
||||
// StartWSClient start ws client
|
||||
func StartWSClient(config config.Config) {
|
||||
config.Init()
|
||||
iface := tun.CreateTun(config.CIDR)
|
||||
c := cache.New(30*time.Minute, 10*time.Minute)
|
||||
log.Printf("vtun ws client started,CIDR is %v", config.CIDR)
|
||||
// read data from tun
|
||||
packet := make([]byte, 1500)
|
||||
for {
|
||||
n, err := iface.Read(packet)
|
||||
if err != nil || n == 0 {
|
||||
continue
|
||||
}
|
||||
b := packet[:n]
|
||||
if !waterutil.IsIPv4(b) {
|
||||
continue
|
||||
}
|
||||
srcAddr := netutil.SrcAddr(b)
|
||||
dstAddr := netutil.DstAddr(b)
|
||||
if srcAddr == "" || dstAddr == "" {
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%v->%v", dstAddr, srcAddr)
|
||||
var conn *websocket.Conn
|
||||
v, ok := c.Get(key)
|
||||
if ok {
|
||||
conn = v.(*websocket.Conn)
|
||||
} else {
|
||||
conn = netutil.ConnectWS(config)
|
||||
if conn == nil {
|
||||
continue
|
||||
}
|
||||
c.Set(key, conn, cache.DefaultExpiration)
|
||||
go wsToTun(c, key, conn, iface)
|
||||
}
|
||||
b = cipher.Encrypt(b)
|
||||
conn.WriteMessage(websocket.BinaryMessage, b)
|
||||
}
|
||||
}
|
||||
|
||||
func wsToTun(c *cache.Cache, key string, wsConn *websocket.Conn, iface *water.Interface) {
|
||||
defer netutil.CloseWS(wsConn)
|
||||
for {
|
||||
wsConn.SetReadDeadline(time.Now().Add(time.Duration(30) * time.Second))
|
||||
_, b, err := wsConn.ReadMessage()
|
||||
if err != nil || err == io.EOF {
|
||||
break
|
||||
}
|
||||
b = cipher.Decrypt(b)
|
||||
if !waterutil.IsIPv4(b) {
|
||||
continue
|
||||
}
|
||||
iface.Write(b[:])
|
||||
}
|
||||
c.Delete(key)
|
||||
}
|
56
common/netutil/netutil.go
Normal file
56
common/netutil/netutil.go
Normal file
@ -0,0 +1,56 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/net-byte/vtun/common/config"
|
||||
"github.com/songgao/water/waterutil"
|
||||
)
|
||||
|
||||
func SrcAddr(b []byte) string {
|
||||
if waterutil.IPv4Protocol(b) == waterutil.UDP || waterutil.IPv4Protocol(b) == waterutil.TCP {
|
||||
ip := waterutil.IPv4Source(b)
|
||||
port := waterutil.IPv4SourcePort(b)
|
||||
addr := fmt.Sprintf("%s:%d", ip.To4().String(), port)
|
||||
return addr
|
||||
} else if waterutil.IPv4Protocol(b) == waterutil.ICMP {
|
||||
ip := waterutil.IPv4Source(b)
|
||||
return ip.To4().String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func DstAddr(b []byte) string {
|
||||
if waterutil.IPv4Protocol(b) == waterutil.UDP || waterutil.IPv4Protocol(b) == waterutil.TCP {
|
||||
ip := waterutil.IPv4Destination(b)
|
||||
port := waterutil.IPv4DestinationPort(b)
|
||||
addr := fmt.Sprintf("%s:%d", ip.To4().String(), port)
|
||||
return addr
|
||||
} else if waterutil.IPv4Protocol(b) == waterutil.ICMP {
|
||||
ip := waterutil.IPv4Destination(b)
|
||||
return ip.To4().String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ConnectWS(config config.Config) *websocket.Conn {
|
||||
u := url.URL{Scheme: "wss", Host: config.ServerAddr, Path: "/way-to-freedom"}
|
||||
header := make(http.Header)
|
||||
header.Set("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36")
|
||||
c, _, err := websocket.DefaultDialer.Dial(u.String(), header)
|
||||
if err != nil {
|
||||
log.Printf("[client] failed to dial websocket %v", err)
|
||||
return nil
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func CloseWS(wsConn *websocket.Conn) {
|
||||
wsConn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5))
|
||||
wsConn.Close()
|
||||
}
|
13
main.go
13
main.go
@ -18,16 +18,19 @@ func main() {
|
||||
flag.BoolVar(&config.ServerMode, "S", false, "server mode")
|
||||
flag.Parse()
|
||||
|
||||
if config.ServerMode {
|
||||
switch config.Protocol {
|
||||
case "udp":
|
||||
if config.ServerMode {
|
||||
server.StartUDPServer(config)
|
||||
} else {
|
||||
client.StartUDPClient(config)
|
||||
}
|
||||
case "ws":
|
||||
if config.ServerMode {
|
||||
server.StartWSServer(config)
|
||||
} else {
|
||||
client.StartWSClient(config)
|
||||
}
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
client.Start(config)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"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/patrickmn/go-cache"
|
||||
"github.com/songgao/water"
|
||||
@ -44,8 +45,8 @@ func StartUDPServer(config config.Config) {
|
||||
continue
|
||||
}
|
||||
iface.Write(b)
|
||||
srcAddr := srcAddr(b)
|
||||
dstAddr := dstAddr(b)
|
||||
srcAddr := netutil.SrcAddr(b)
|
||||
dstAddr := netutil.DstAddr(b)
|
||||
if srcAddr == "" || dstAddr == "" {
|
||||
continue
|
||||
}
|
||||
@ -70,9 +71,9 @@ func (f *Forwarder) forward(iface *water.Interface, conn *net.UDPConn) {
|
||||
if !waterutil.IsIPv4(b) {
|
||||
continue
|
||||
}
|
||||
dstAddr := dstAddr(b)
|
||||
srcAddr := srcAddr(b)
|
||||
if dstAddr == "" || srcAddr == "" {
|
||||
srcAddr := netutil.SrcAddr(b)
|
||||
dstAddr := netutil.DstAddr(b)
|
||||
if srcAddr == "" || dstAddr == "" {
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%v->%v", dstAddr, srcAddr)
|
||||
@ -84,29 +85,3 @@ func (f *Forwarder) forward(iface *water.Interface, conn *net.UDPConn) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func srcAddr(b []byte) string {
|
||||
if waterutil.IPv4Protocol(b) == waterutil.UDP || waterutil.IPv4Protocol(b) == waterutil.TCP {
|
||||
ip := waterutil.IPv4Source(b)
|
||||
port := waterutil.IPv4SourcePort(b)
|
||||
addr := fmt.Sprintf("%s:%d", ip.To4().String(), port)
|
||||
return addr
|
||||
} else if waterutil.IPv4Protocol(b) == waterutil.ICMP {
|
||||
ip := waterutil.IPv4Source(b)
|
||||
return ip.To4().String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func dstAddr(b []byte) string {
|
||||
if waterutil.IPv4Protocol(b) == waterutil.UDP || waterutil.IPv4Protocol(b) == waterutil.TCP {
|
||||
ip := waterutil.IPv4Destination(b)
|
||||
port := waterutil.IPv4DestinationPort(b)
|
||||
addr := fmt.Sprintf("%s:%d", ip.To4().String(), port)
|
||||
return addr
|
||||
} else if waterutil.IPv4Protocol(b) == waterutil.ICMP {
|
||||
ip := waterutil.IPv4Destination(b)
|
||||
return ip.To4().String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"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/patrickmn/go-cache"
|
||||
"github.com/songgao/water"
|
||||
@ -57,11 +58,6 @@ func StartWSServer(config config.Config) {
|
||||
http.ListenAndServe(config.ServerAddr, nil)
|
||||
}
|
||||
|
||||
func closeWS(wsConn *websocket.Conn) {
|
||||
wsConn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5))
|
||||
wsConn.Close()
|
||||
}
|
||||
|
||||
func tunToWs(iface *water.Interface, c *cache.Cache) {
|
||||
buffer := make([]byte, 1500)
|
||||
for {
|
||||
@ -73,8 +69,8 @@ func tunToWs(iface *water.Interface, c *cache.Cache) {
|
||||
if !waterutil.IsIPv4(b) {
|
||||
continue
|
||||
}
|
||||
srcAddr := srcAddr(b)
|
||||
dstAddr := dstAddr(b)
|
||||
srcAddr := netutil.SrcAddr(b)
|
||||
dstAddr := netutil.DstAddr(b)
|
||||
if srcAddr == "" || dstAddr == "" {
|
||||
continue
|
||||
}
|
||||
@ -88,7 +84,7 @@ func tunToWs(iface *water.Interface, c *cache.Cache) {
|
||||
}
|
||||
|
||||
func wsToTun(wsConn *websocket.Conn, iface *water.Interface, c *cache.Cache) {
|
||||
defer closeWS(wsConn)
|
||||
defer netutil.CloseWS(wsConn)
|
||||
for {
|
||||
wsConn.SetReadDeadline(time.Now().Add(time.Duration(30) * time.Second))
|
||||
_, b, err := wsConn.ReadMessage()
|
||||
@ -99,8 +95,8 @@ func wsToTun(wsConn *websocket.Conn, iface *water.Interface, c *cache.Cache) {
|
||||
if !waterutil.IsIPv4(b) {
|
||||
continue
|
||||
}
|
||||
srcAddr := srcAddr(b)
|
||||
dstAddr := dstAddr(b)
|
||||
srcAddr := netutil.SrcAddr(b)
|
||||
dstAddr := netutil.DstAddr(b)
|
||||
if srcAddr == "" || dstAddr == "" {
|
||||
continue
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user