From eff3b509db11947bffc8196062cd9ff10b7d072b Mon Sep 17 00:00:00 2001 From: ICKelin Date: Thu, 13 May 2021 21:33:20 +0800 Subject: [PATCH] feature: use tproxy and multi forward(alpha) --- ChangeLog | 5 +- Dockerfiles/gtund/gtund.conf | 18 ------- Dockerfiles/gtund/gtund.yaml | 8 +++ Dockerfiles/gtund/start.sh | 2 +- NEWS | 8 --- README-EN.md | 44 +++++----------- cmd/gtun/gtun.toml | 8 --- cmd/gtund/etc/gtund.conf | 10 ---- cmd/gtund/gtund.toml | 16 ------ common/common.go | 96 ----------------------------------- common/cs.go | 40 --------------- etc/gtun.conf | 9 ---- etc/gtun.yaml | 20 ++++++++ etc/gtund.yaml | 8 +++ go.mod | 1 + go.sum | 1 + gtun/client.go | 15 +++--- gtun/config.go | 39 +++++++------- gtun/main.go | 44 +++++++++------- gtun/tcpforward.go | 6 ++- gtun/udpforward.go | 6 ++- gtund/config.go | 14 ++--- gtund/server.go | 2 +- makefile.sh | 11 +--- qrcode.jpg | Bin 27875 -> 0 bytes 25 files changed, 128 insertions(+), 303 deletions(-) delete mode 100644 Dockerfiles/gtund/gtund.conf create mode 100644 Dockerfiles/gtund/gtund.yaml delete mode 100644 NEWS delete mode 100644 cmd/gtun/gtun.toml delete mode 100644 cmd/gtund/etc/gtund.conf delete mode 100644 cmd/gtund/gtund.toml delete mode 100644 common/common.go delete mode 100644 common/cs.go delete mode 100644 etc/gtun.conf create mode 100644 etc/gtun.yaml create mode 100644 etc/gtund.yaml delete mode 100644 qrcode.jpg diff --git a/ChangeLog b/ChangeLog index 56d49a6..15bae5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,4 +14,7 @@ In this case, you can use your local raspberry pi/vm as a public service. 2018.08.30 - Refactor code. \ No newline at end of file + Refactor code. + +2021.05.13 + use tproxy for traffic redirect, support multi forwards eg: CN, US \ No newline at end of file diff --git a/Dockerfiles/gtund/gtund.conf b/Dockerfiles/gtund/gtund.conf deleted file mode 100644 index 16aa2d7..0000000 --- a/Dockerfiles/gtund/gtund.conf +++ /dev/null @@ -1,18 +0,0 @@ -name="us-node-1-1" -istap=false - -[server] -listen=":9623" -auth_key="gtun-cs-token" -nameservers=["8.8.8.8", "8.8.4.4"] -#route_url="http://www.ipdeny.com/ipblocks/data/countries/us.zone" - -[dhcp] -cidr="100.64.240.1/24" -gateway="100.64.240.1" -nameserver="8.8.8.8" - -[log] -level="debug" -path="log.log" -days=3 \ No newline at end of file diff --git a/Dockerfiles/gtund/gtund.yaml b/Dockerfiles/gtund/gtund.yaml new file mode 100644 index 0000000..24a52e8 --- /dev/null +++ b/Dockerfiles/gtund/gtund.yaml @@ -0,0 +1,8 @@ +server: + listen: ":9098" + authKey: "rewrite with your auth key" + +log: + days: 5 + level: "info" + path: "gtund.log" \ No newline at end of file diff --git a/Dockerfiles/gtund/start.sh b/Dockerfiles/gtund/start.sh index 668e19c..02d3c9f 100644 --- a/Dockerfiles/gtund/start.sh +++ b/Dockerfiles/gtund/start.sh @@ -1,2 +1,2 @@ #!/usr/bin/env bash -/gtund -c /gtund.conf +/gtund -c /gtund.yaml diff --git a/NEWS b/NEWS deleted file mode 100644 index 3d97114..0000000 --- a/NEWS +++ /dev/null @@ -1,8 +0,0 @@ -- Plugins System - Writting plugin extention such as dns plugin - -- app - To controller ip, domain and reverse configuration - -- TUN/TAP device DNAT to local port - Userland Conntrack Flow diff --git a/README-EN.md b/README-EN.md index 5f7612e..241a84e 100644 --- a/README-EN.md +++ b/README-EN.md @@ -1,32 +1,14 @@ -[![Build Status](https://travis-ci.org/ICKelin/gtun.svg?branch=master)](https://travis-ci.org/ICKelin/gtun) -### gtun -Gtun is a game or ip accelator written in golang. Currently only support mac os and linux. - -### Build - -``` - -./makefile.sh - -``` - -More information, reference.travils.yml - -### example - -- ip accelator - -![ip accelator](./ip_accelator.jpg) - -- tunnel - -![tunnel](./tunnel.jpg) - -### thanks -[songgao/water](https://github.com/songgao/water) - -### more -[tun/tap vpn](https://github.com/ICKelin/article/issues/9) - -any [issues](https://github.com/ICKelin/gtun/issues/new) are welcome +## gtun + + + + +go report + + +Build Status + + +license + \ No newline at end of file diff --git a/cmd/gtun/gtun.toml b/cmd/gtun/gtun.toml deleted file mode 100644 index fc5ea30..0000000 --- a/cmd/gtun/gtun.toml +++ /dev/null @@ -1,8 +0,0 @@ -[client] -server = "192.168.31.65:9399" -auth="gtun-cs-token" - -[log] -level="debug" -path="log.log" -days=3 diff --git a/cmd/gtund/etc/gtund.conf b/cmd/gtund/etc/gtund.conf deleted file mode 100644 index ba56c5d..0000000 --- a/cmd/gtund/etc/gtund.conf +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name":"US", - "god_config":{ - "god_hb_interval": 3, - "god_conn_timeout":10, - "god_addr": "127.0.0.1:9623", - "must": false, - "token": "gtun-sg-token" - } -} diff --git a/cmd/gtund/gtund.toml b/cmd/gtund/gtund.toml deleted file mode 100644 index e533522..0000000 --- a/cmd/gtund/gtund.toml +++ /dev/null @@ -1,16 +0,0 @@ -name="us-node-1-1" - -[server] -listen=":9623" -auth_key="gtun-cs-token" -nameservers=["8.8.8.8", "8.8.4.4"] - -[dhcp] -cidr="100.64.240.1/24" -gateway="100.64.240.1" -nameserver="8.8.8.8" - -[log] -level="debug" -path="log.log" -days=3 diff --git a/common/common.go b/common/common.go deleted file mode 100644 index 1d01d5f..0000000 --- a/common/common.go +++ /dev/null @@ -1,96 +0,0 @@ -package common - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "io" - "net" - "time" -) - -const ( - MAX_PAYLOAD = 1<<16 - 1 -) - -const ( - CODE_SUCCESS = 10000 - CODE_REGISTER_FAIL = 10001 - CODE_FAIL = 99999 -) - -var version = "1.1.0" - -func Version() string { - return version -} - -type ResponseBody struct { - Code int `json:"code"` - Message string `json:"message"` - Data interface{} `json:"data"` -} - -func Response(data interface{}, err error) []byte { - g2s := &ResponseBody{} - - if err != nil { - g2s.Code = CODE_FAIL - g2s.Message = err.Error() - g2s.Data = data - } else { - g2s.Code = CODE_SUCCESS - g2s.Message = "success" - g2s.Data = data - } - - bytes, _ := json.Marshal(g2s) - return bytes -} - -func Encode(cmd byte, payload []byte) ([]byte, error) { - buff := make([]byte, 0) - - if len(payload) > MAX_PAYLOAD { - return nil, fmt.Errorf("too big payload") - } - - plen := make([]byte, 2) - binary.BigEndian.PutUint16(plen, uint16(len(payload))+1) - buff = append(buff, plen...) - buff = append(buff, cmd) - buff = append(buff, payload...) - - return buff, nil -} - -func Decode(conn net.Conn) (byte, []byte, error) { - plen := make([]byte, 2) - conn.SetReadDeadline(time.Now().Add(time.Second * 10)) - _, err := io.ReadFull(conn, plen) - conn.SetReadDeadline(time.Time{}) - if err != nil { - return 0, nil, err - } - - payloadlength := binary.BigEndian.Uint16(plen) - if payloadlength > 65535 { - return 0, nil, fmt.Errorf("too big ippkt size %d", payloadlength) - } - - resp := make([]byte, payloadlength) - nr, err := io.ReadFull(conn, resp) - if err != nil { - return 0, nil, err - } - - if nr < 1 { - return 0, nil, fmt.Errorf("invalid pkt") - } - - if nr != int(payloadlength) { - return resp[0], resp[1:nr], fmt.Errorf("invalid payloadlength %d %d", nr, int(payloadlength)) - } - - return resp[0], resp[1:nr], nil -} diff --git a/common/cs.go b/common/cs.go deleted file mode 100644 index c9c7a6d..0000000 --- a/common/cs.go +++ /dev/null @@ -1,40 +0,0 @@ -package common - -// S => gtund(gtun server) -// C => gtun(gtun client) -const ( - C2C_DATA = byte(0x00) - - C2S_DATA = byte(0x01) - S2C_DATA = byte(0x02) - - C2S_HEARTBEAT = byte(0x03) - S2C_HEARTBEAT = byte(0x04) - - C2S_AUTHORIZE = byte(0x05) - S2C_AUTHORIZE = byte(0x06) -) - -var os = map[string]int{ - "linux": 1, - "darwin": 2, - "windows": 3, -} - -func OSID(goos string) int { - return os[goos] -} - -type C2SAuthorize struct { - Version string `json:"version"` - OS int `json:"os"` - Key string `json:"key"` -} - -type S2CAuthorize struct { - Status string `json:"status"` - AccessIP string `json:"access_ip"` - Nameservers []string `json:"nameservers"` - Gateway string `json:"gateway"` - RouteScriptUrl string `json:"route_script_url"` -} diff --git a/etc/gtun.conf b/etc/gtun.conf deleted file mode 100644 index 9857963..0000000 --- a/etc/gtun.conf +++ /dev/null @@ -1,9 +0,0 @@ -[client] -server = "192.168.1.2:9091" -auth="gtun-cs-token" - -[registry] -addr="http://127.0.0.1:9093" -token="gtun-cr-token" -must=false - diff --git a/etc/gtun.yaml b/etc/gtun.yaml new file mode 100644 index 0000000..e11d4b9 --- /dev/null +++ b/etc/gtun.yaml @@ -0,0 +1,20 @@ +forwards: + US: + server: "127.0.0.1:9098" + authKey: "rewrite with your auth key" + tcp: + listenAddr: ":8098" + udp: + listenAddr: ":8098" + CN: + server: "127.0.0.1:9097" + authKey: "rewrite with your auth key" + tcp: + listenAddr: ":8097" + udp: + listenAddr: ":8097" + +logs: + days: 5 + level: "info" + path: "gtund.log" \ No newline at end of file diff --git a/etc/gtund.yaml b/etc/gtund.yaml new file mode 100644 index 0000000..24a52e8 --- /dev/null +++ b/etc/gtund.yaml @@ -0,0 +1,8 @@ +server: + listen: ":9098" + authKey: "rewrite with your auth key" + +log: + days: 5 + level: "info" + path: "gtund.log" \ No newline at end of file diff --git a/go.mod b/go.mod index cd70ce3..13b5866 100644 --- a/go.mod +++ b/go.mod @@ -24,4 +24,5 @@ require ( github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect github.com/xtaci/smux v2.0.1+incompatible golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + gopkg.in/yaml.v2 v2.3.0 ) diff --git a/go.sum b/go.sum index 4fe2a2b..be74813 100644 --- a/go.sum +++ b/go.sum @@ -318,6 +318,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/gtun/client.go b/gtun/client.go index 9e0f59a..501c6dd 100644 --- a/gtun/client.go +++ b/gtun/client.go @@ -8,11 +8,10 @@ import ( "github.com/hashicorp/yamux" ) -var defaultRegion = "US" - type ClientConfig struct { - ServerAddr string `toml:"server"` - AuthKey string `toml:"auth"` + Region string + ServerAddr string + AuthKey string } type Client struct { @@ -31,7 +30,7 @@ func (client *Client) Run() { for { conn, err := net.DialTimeout("tcp", client.cfg.ServerAddr, time.Second*10) if err != nil { - logs.Error("connect to server fail: %v", err) + logs.Error("connect to %s fail: %v", client.cfg.ServerAddr, err) time.Sleep(time.Second * 3) continue } @@ -43,14 +42,14 @@ func (client *Client) Run() { continue } - sess := newSession(mux, defaultRegion) - client.sessionMgr.AddSession(defaultRegion, sess) + sess := newSession(mux, client.cfg.Region) + client.sessionMgr.AddSession(client.cfg.Region, sess) select { case <-sess.conn.CloseChan(): break } - client.sessionMgr.DeleteSession(defaultRegion) + client.sessionMgr.DeleteSession(client.cfg.Region) logs.Warn("reconnect") } } diff --git a/gtun/config.go b/gtun/config.go index 4fff15e..3dff819 100644 --- a/gtun/config.go +++ b/gtun/config.go @@ -3,33 +3,38 @@ package gtun import ( "io/ioutil" - "github.com/pelletier/go-toml" + "gopkg.in/yaml.v2" ) type Config struct { - ClientConfig *ClientConfig `toml:"client"` - TCPForward TCPForwardConfig `toml:"tcpforward"` - UDPForward UDPForwardConfig `toml:"udpforward"` - Log Log `toml:"log"` + Forwards map[string]ForwardConfig `yaml:"forwards"` + Log Log `yaml:"log"` } -type Log struct { - Days int64 `toml:"days"` - Level string `toml:"level"` - Path string `toml:"path"` +type ForwardConfig struct { + ServerAddr string `yaml:"server"` + AuthKey string `yaml:"authKey"` + TCPForward TCPForwardConfig `yaml:"tcp"` + UDPForward UDPForwardConfig `yaml:"udp"` } type TCPForwardConfig struct { - ListenAddr string `toml:"listen"` - ReadTimeout int `toml:"readTimeout"` - WriteTimeout int `toml:"writeTimeout"` + ListenAddr string `yaml:"listen"` + ReadTimeout int `yaml:"readTimeout"` + WriteTimeout int `yaml:"writeTimeout"` } type UDPForwardConfig struct { - ListenAddr string `toml:"listen"` - ReadTimeout int `toml:"readTimeout"` - WriteTimeout int `toml:"writeTimeout"` - SessionTimeout int `toml:"sessionTimeout"` + ListenAddr string `yaml:"listen"` + ReadTimeout int `yaml:"readTimeout"` + WriteTimeout int `yaml:"writeTimeout"` + SessionTimeout int `yaml:"sessionTimeout"` +} + +type Log struct { + Days int64 `yaml:"days"` + Level string `yaml:"level"` + Path string `yaml:"path"` } func ParseConfig(path string) (*Config, error) { @@ -43,6 +48,6 @@ func ParseConfig(path string) (*Config, error) { func parseConfig(content []byte) (*Config, error) { conf := Config{} - err := toml.Unmarshal(content, &conf) + err := yaml.Unmarshal(content, &conf) return &conf, err } diff --git a/gtun/main.go b/gtun/main.go index 8868cb7..6c480cd 100644 --- a/gtun/main.go +++ b/gtun/main.go @@ -18,24 +18,32 @@ func Main() { } logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days) - tcpfw := NewTCPForward(conf.TCPForward) - lis, err := tcpfw.Listen() - if err != nil { - logs.Error("listen tproxy tcp fail: %v", err) - return + for region, cfg := range conf.Forwards { + tcpfw := NewTCPForward(region, cfg.TCPForward) + lis, err := tcpfw.Listen() + if err != nil { + logs.Error("listen tproxy tcp fail: %v", err) + return + } + + go tcpfw.Serve(lis) + + udpfw := NewUDPForward(region, cfg.UDPForward) + udpConn, err := udpfw.Listen() + if err != nil { + logs.Error("listen tproxy udp fail: %v", err) + return + } + + go udpfw.Serve(udpConn) + + client := NewClient(&ClientConfig{ + ServerAddr: cfg.ServerAddr, + AuthKey: cfg.AuthKey, + Region: region, + }) + go client.Run() } - go tcpfw.Serve(lis) - - udpfw := NewUDPForward(conf.UDPForward) - udpConn, err := udpfw.Listen() - if err != nil { - logs.Error("listen tproxy udp fail: %v", err) - return - } - - go udpfw.Serve(udpConn) - - client := NewClient(conf.ClientConfig) - client.Run() + select {} } diff --git a/gtun/tcpforward.go b/gtun/tcpforward.go index 1102405..1cd53d5 100644 --- a/gtun/tcpforward.go +++ b/gtun/tcpforward.go @@ -16,6 +16,7 @@ var ( ) type TCPForward struct { + region string listenAddr string // writeTimeout defines the tcp connection write timeout in second // default value set to 10 seconds @@ -30,7 +31,7 @@ type TCPForward struct { sessMgr *SessionManager } -func NewTCPForward(cfg TCPForwardConfig) *TCPForward { +func NewTCPForward(region string, cfg TCPForwardConfig) *TCPForward { tcpReadTimeout := cfg.ReadTimeout if tcpReadTimeout <= 0 { tcpReadTimeout = defaultTCPTimeout @@ -41,6 +42,7 @@ func NewTCPForward(cfg TCPForwardConfig) *TCPForward { tcpWriteTimeout = int(defaultTCPTimeout) } return &TCPForward{ + region: region, listenAddr: cfg.ListenAddr, writeTimeout: time.Duration(tcpWriteTimeout) * time.Second, readTimeout: time.Duration(tcpReadTimeout) * time.Second, @@ -89,7 +91,7 @@ func (f *TCPForward) forwardTCP(conn net.Conn) { dip, dport, _ := net.SplitHostPort(conn.LocalAddr().String()) sip, sport, _ := net.SplitHostPort(conn.RemoteAddr().String()) - sess := f.sessMgr.GetSession(defaultRegion) + sess := f.sessMgr.GetSession(f.region) if sess == nil { logs.Error("no route to host: %s", dip) return diff --git a/gtun/udpforward.go b/gtun/udpforward.go index 96280d0..d2a4309 100644 --- a/gtun/udpforward.go +++ b/gtun/udpforward.go @@ -29,6 +29,7 @@ type udpSession struct { } type UDPForward struct { + region string listenAddr string sessionTimeout int readTimeout time.Duration @@ -45,7 +46,7 @@ type UDPForward struct { udpsessLock sync.Mutex } -func NewUDPForward(cfg UDPForwardConfig) *UDPForward { +func NewUDPForward(region string, cfg UDPForwardConfig) *UDPForward { readTimeout := cfg.ReadTimeout if readTimeout <= 0 { readTimeout = defaultUDPTimeout @@ -62,6 +63,7 @@ func NewUDPForward(cfg UDPForwardConfig) *UDPForward { } return &UDPForward{ + region: region, listenAddr: cfg.ListenAddr, readTimeout: time.Duration(readTimeout) * time.Second, writeTimeout: time.Duration(writeTimeout) * time.Second, @@ -154,7 +156,7 @@ func (f *UDPForward) Serve(lconn *net.UDPConn) error { f.udpsessLock.Unlock() } else { f.udpsessLock.Unlock() - sess := f.sessMgr.GetSession(defaultRegion) + sess := f.sessMgr.GetSession(f.region) if sess == nil { logs.Error("no route to host: %s", dip) continue diff --git a/gtund/config.go b/gtund/config.go index b3f8795..06248fb 100644 --- a/gtund/config.go +++ b/gtund/config.go @@ -4,18 +4,18 @@ import ( "encoding/json" "io/ioutil" - "github.com/pelletier/go-toml" + "gopkg.in/yaml.v2" ) type Config struct { - ServerConfig ServerConfig `toml:"server"` // tcp server configuration - Log Log `toml:"log"` + ServerConfig ServerConfig `yaml:"server"` + Log Log `yaml:"log"` } type Log struct { - Days int64 `toml:"days"` - Level string `toml:"level"` - Path string `toml:"path"` + Days int64 `yaml:"days"` + Level string `yaml:"level"` + Path string `yaml:"path"` } func ParseConfig(path string) (*Config, error) { @@ -29,7 +29,7 @@ func ParseConfig(path string) (*Config, error) { func parseConfig(content []byte) (*Config, error) { var c Config - err := toml.Unmarshal(content, &c) + err := yaml.Unmarshal(content, &c) return &c, err } diff --git a/gtund/server.go b/gtund/server.go index 3fed429..1741780 100644 --- a/gtund/server.go +++ b/gtund/server.go @@ -21,7 +21,7 @@ var ( type ServerConfig struct { Listen string `toml:"listen"` - AuthKey string `toml:"auth_key"` + AuthKey string `toml:"authKey"` } type Server struct { diff --git a/makefile.sh b/makefile.sh index 310d2c2..199a29e 100755 --- a/makefile.sh +++ b/makefile.sh @@ -7,18 +7,9 @@ mkdir -p bin/gtund mkdir -p bin/gtund/log GOOS=linux go build -o bin/gtund/gtund cmd/gtund/*.go -cp etc/gtund.conf bin/gtund/ +cp etc/gtund.yaml bin/gtund/ cd cmd/gtun -echo "building gtun_cli_darwin...." -GOOS=darwin go build -o ../../bin/gtun/gtun-darwin_amd64 -echo "builded gtun_cli_darwin...." - echo "building gtun_cli_linux...." GOOS=linux go build -o ../../bin/gtun/gtun-linux_amd64 echo "builded gtun_cli_linux...." - -echo "building gtun_cli_win...." - -GOOS=windows go build -o ../../bin/gtun/gtun-windows_amd64.exe -echo "builded gtun_cli_win...." \ No newline at end of file diff --git a/qrcode.jpg b/qrcode.jpg deleted file mode 100644 index adc9dcaf8c694f1209e94b25c76ee55d7659a932..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27875 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