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/cipher"
|
||||||
"github.com/net-byte/vtun/common/config"
|
"github.com/net-byte/vtun/common/config"
|
||||||
"github.com/net-byte/vtun/tun"
|
"github.com/net-byte/vtun/tun"
|
||||||
|
"github.com/songgao/water/waterutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start client
|
// StartUDPClient start udp client
|
||||||
func Start(config config.Config) {
|
func StartUDPClient(config config.Config) {
|
||||||
config.Init()
|
config.Init()
|
||||||
iface := tun.CreateTun(config.CIDR)
|
iface := tun.CreateTun(config.CIDR)
|
||||||
serverAddr, err := net.ResolveUDPAddr("udp", config.ServerAddr)
|
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)
|
log.Fatalln("failed to listen on UDP socket:", err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
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
|
// read data from server
|
||||||
go func() {
|
go func() {
|
||||||
buf := make([]byte, 1500)
|
buf := make([]byte, 1500)
|
||||||
@ -37,6 +38,9 @@ func Start(config config.Config) {
|
|||||||
}
|
}
|
||||||
// decrypt data
|
// decrypt data
|
||||||
b := cipher.Decrypt(buf[:n])
|
b := cipher.Decrypt(buf[:n])
|
||||||
|
if !waterutil.IsIPv4(b) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
iface.Write(b)
|
iface.Write(b)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -47,6 +51,9 @@ func Start(config config.Config) {
|
|||||||
if err != nil || n == 0 {
|
if err != nil || n == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if !waterutil.IsIPv4(packet) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// encrypt data
|
// encrypt data
|
||||||
b := cipher.Encrypt(packet[:n])
|
b := cipher.Encrypt(packet[:n])
|
||||||
conn.WriteToUDP(b, serverAddr)
|
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.BoolVar(&config.ServerMode, "S", false, "server mode")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if config.ServerMode {
|
|
||||||
switch config.Protocol {
|
switch config.Protocol {
|
||||||
case "udp":
|
case "udp":
|
||||||
|
if config.ServerMode {
|
||||||
server.StartUDPServer(config)
|
server.StartUDPServer(config)
|
||||||
|
} else {
|
||||||
|
client.StartUDPClient(config)
|
||||||
|
}
|
||||||
case "ws":
|
case "ws":
|
||||||
|
if config.ServerMode {
|
||||||
server.StartWSServer(config)
|
server.StartWSServer(config)
|
||||||
|
} else {
|
||||||
|
client.StartWSClient(config)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
client.Start(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/net-byte/vtun/common/cipher"
|
"github.com/net-byte/vtun/common/cipher"
|
||||||
"github.com/net-byte/vtun/common/config"
|
"github.com/net-byte/vtun/common/config"
|
||||||
|
"github.com/net-byte/vtun/common/netutil"
|
||||||
"github.com/net-byte/vtun/tun"
|
"github.com/net-byte/vtun/tun"
|
||||||
"github.com/patrickmn/go-cache"
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/songgao/water"
|
"github.com/songgao/water"
|
||||||
@ -44,8 +45,8 @@ func StartUDPServer(config config.Config) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
iface.Write(b)
|
iface.Write(b)
|
||||||
srcAddr := srcAddr(b)
|
srcAddr := netutil.SrcAddr(b)
|
||||||
dstAddr := dstAddr(b)
|
dstAddr := netutil.DstAddr(b)
|
||||||
if srcAddr == "" || dstAddr == "" {
|
if srcAddr == "" || dstAddr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -70,9 +71,9 @@ func (f *Forwarder) forward(iface *water.Interface, conn *net.UDPConn) {
|
|||||||
if !waterutil.IsIPv4(b) {
|
if !waterutil.IsIPv4(b) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dstAddr := dstAddr(b)
|
srcAddr := netutil.SrcAddr(b)
|
||||||
srcAddr := srcAddr(b)
|
dstAddr := netutil.DstAddr(b)
|
||||||
if dstAddr == "" || srcAddr == "" {
|
if srcAddr == "" || dstAddr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key := fmt.Sprintf("%v->%v", dstAddr, srcAddr)
|
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/gorilla/websocket"
|
||||||
"github.com/net-byte/vtun/common/cipher"
|
"github.com/net-byte/vtun/common/cipher"
|
||||||
"github.com/net-byte/vtun/common/config"
|
"github.com/net-byte/vtun/common/config"
|
||||||
|
"github.com/net-byte/vtun/common/netutil"
|
||||||
"github.com/net-byte/vtun/tun"
|
"github.com/net-byte/vtun/tun"
|
||||||
"github.com/patrickmn/go-cache"
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/songgao/water"
|
"github.com/songgao/water"
|
||||||
@ -57,11 +58,6 @@ func StartWSServer(config config.Config) {
|
|||||||
http.ListenAndServe(config.ServerAddr, nil)
|
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) {
|
func tunToWs(iface *water.Interface, c *cache.Cache) {
|
||||||
buffer := make([]byte, 1500)
|
buffer := make([]byte, 1500)
|
||||||
for {
|
for {
|
||||||
@ -73,8 +69,8 @@ func tunToWs(iface *water.Interface, c *cache.Cache) {
|
|||||||
if !waterutil.IsIPv4(b) {
|
if !waterutil.IsIPv4(b) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
srcAddr := srcAddr(b)
|
srcAddr := netutil.SrcAddr(b)
|
||||||
dstAddr := dstAddr(b)
|
dstAddr := netutil.DstAddr(b)
|
||||||
if srcAddr == "" || dstAddr == "" {
|
if srcAddr == "" || dstAddr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -88,7 +84,7 @@ func tunToWs(iface *water.Interface, c *cache.Cache) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func wsToTun(wsConn *websocket.Conn, 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 {
|
for {
|
||||||
wsConn.SetReadDeadline(time.Now().Add(time.Duration(30) * time.Second))
|
wsConn.SetReadDeadline(time.Now().Add(time.Duration(30) * time.Second))
|
||||||
_, b, err := wsConn.ReadMessage()
|
_, b, err := wsConn.ReadMessage()
|
||||||
@ -99,8 +95,8 @@ func wsToTun(wsConn *websocket.Conn, iface *water.Interface, c *cache.Cache) {
|
|||||||
if !waterutil.IsIPv4(b) {
|
if !waterutil.IsIPv4(b) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
srcAddr := srcAddr(b)
|
srcAddr := netutil.SrcAddr(b)
|
||||||
dstAddr := dstAddr(b)
|
dstAddr := netutil.DstAddr(b)
|
||||||
if srcAddr == "" || dstAddr == "" {
|
if srcAddr == "" || dstAddr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user