├── .gitignore ├── config ├── intermediary ├── manage │ ├── client.go │ └── server.go ├── conf │ └── config.go ├── handle │ ├── writer.go │ └── reader.go ├── intermediary.go └── stream │ └── stream.go ├── bootstrap ├── client │ ├── debug │ └── main.go ├── intermediary │ └── main.go └── server │ └── main.go ├── server ├── conf │ └── config.go ├── hole │ ├── writer.go │ └── hole.go ├── server.go └── intermediaryclient │ ├── writer.go │ ├── reader.go │ └── client.go ├── client ├── conf │ └── config.go ├── intermediaryclient │ ├── writer.go │ ├── reader.go │ ├── root.go │ └── client.go ├── client.go └── proxy │ └── client.go ├── common ├── rand.go ├── constraints.go ├── compStream.go └── common.go ├── README.md ├── .vscode └── launch.json ├── Gopkg.toml ├── main.go └── Gopkg.lock /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxcweb/go-nat-hole/HEAD/config -------------------------------------------------------------------------------- /intermediary/manage/client.go: -------------------------------------------------------------------------------- 1 | package manage 2 | 3 | func aa() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /bootstrap/client/debug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxcweb/go-nat-hole/HEAD/bootstrap/client/debug -------------------------------------------------------------------------------- /intermediary/conf/config.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | // Config for server 4 | type Config struct { 5 | Listen string 6 | Key string 7 | } 8 | -------------------------------------------------------------------------------- /server/conf/config.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | // Config for server 4 | type Config struct { 5 | Key string 6 | Listen string 7 | RemoteAddr string 8 | Name string 9 | } 10 | -------------------------------------------------------------------------------- /client/conf/config.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | // Config for server 4 | type Config struct { 5 | Key string 6 | Listen string 7 | LocalAddr string 8 | RemoteAddr string 9 | ServerName string 10 | } 11 | -------------------------------------------------------------------------------- /common/rand.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | var r = rand.New(rand.NewSource(time.Now().Unix())) 9 | 10 | //Rand 生产uint32随机数 11 | func Rand() uint32 { 12 | return r.Uint32() 13 | } 14 | -------------------------------------------------------------------------------- /common/constraints.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | const ( 4 | //FlagRegister 注册包 5 | FlagRegister = iota 6 | //FlagRegisterConfirm 注册包确定 7 | FlagRegisterConfirm 8 | //FlagFindServer 发现服务 9 | FlagFindServer 10 | //FlagCreateHole 创建打洞 11 | FlagCreateHole 12 | //FlagCreateHoleFinish 创建打洞完成 13 | FlagCreateHoleFinish 14 | //FlagConnectServer 连接服务端 15 | FlagConnectServer 16 | ) 17 | -------------------------------------------------------------------------------- /server/hole/writer.go: -------------------------------------------------------------------------------- 1 | package hole 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/dxcweb/go-nat-hole/common" 7 | ) 8 | 9 | func sendCreateHoleFinish(p io.Writer, clientID string) { 10 | optBytes := []byte{common.FlagCreateHoleFinish} 11 | dataBytes := []byte(clientID) 12 | data := make([]byte, len(dataBytes)+1) 13 | copy(data[0:1], optBytes) 14 | copy(data[1:], dataBytes) 15 | p.Write(data) 16 | } 17 | -------------------------------------------------------------------------------- /client/intermediaryclient/writer.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/dxcweb/go-nat-hole/common" 7 | ) 8 | 9 | func sendFindServer(p io.Writer, name string) { 10 | optBytes := []byte{common.FlagFindServer} 11 | nameBytes := []byte(name) 12 | data := make([]byte, len(nameBytes)+1) 13 | copy(data[0:1], optBytes) 14 | copy(data[1:], nameBytes) 15 | p.Write(data) 16 | } 17 | -------------------------------------------------------------------------------- /client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/dxcweb/go-nat-hole/client/conf" 5 | "github.com/dxcweb/go-nat-hole/client/intermediaryclient" 6 | "github.com/dxcweb/go-nat-hole/client/proxy" 7 | "github.com/dxcweb/go-nat-hole/common" 8 | ) 9 | 10 | //RunClient 运行客户端 11 | func RunClient(config *conf.Config) { 12 | conn, _ := common.UDPconn(config.LocalAddr) 13 | // 获取连接中介服务器获取目标地址 14 | addr := intermediaryclient.GetServerAddr(config, conn) 15 | proxy.NewProxyClient(config, addr, conn) 16 | } 17 | -------------------------------------------------------------------------------- /server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/dxcweb/go-nat-hole/server/conf" 7 | "github.com/dxcweb/go-nat-hole/server/intermediaryclient" 8 | "github.com/sirupsen/logrus" 9 | ) 10 | 11 | //RunServer 运行服务端 12 | func RunServer(config *conf.Config) { 13 | for { 14 | intermediaryclient.RunIntermediaryClient(config) 15 | logrus.Warn("连接到中介服务器失败,正在重试...\n\n\n") 16 | time.Sleep(time.Second * 3) 17 | } 18 | 19 | // hole.CreateHole(config) 20 | // time.Sleep(time.Second * 3) 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-nat-hole 2 | `` 3 | 服务器:启动intermediary服务 4 | B->服务器:告诉服务器B的名称 5 | A->服务器:我需要链接B的xx端口(服务器获取NAT-A的端口ip) 6 | 服务器->B:NAT-A:端口需要和你链接并代理到ip:端口 7 | B:启动一个UDP服务 8 | B->NAT-A:udp send空消息 9 | B->服务器:udp send 说我已经准备好了,叫A来连我吧(服务器获取NAT-B的端口ip) 10 | 服务器->A:告诉NAT-B的ip和端口 11 | A->NAT-B:开始通讯 12 | `` 13 | 14 | ## build 15 | `` 16 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./bootstrap/intermediary/main.go 17 | `` 18 | 19 | 20 | ## NAPT分了两个大的类型 21 | `` 22 | Symmetric NAT型 (对称型) 需要预测端口,疯狂尝试连接才能打洞成功。暂时不实现吧 23 | Cone NAT型(圆锥型)可以打洞 24 | 25 | `` -------------------------------------------------------------------------------- /intermediary/manage/server.go: -------------------------------------------------------------------------------- 1 | package manage 2 | 3 | import ( 4 | "github.com/dxcweb/go-nat-hole/intermediary/stream" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | //Server 服务端 9 | type Server struct { 10 | name string 11 | p *stream.Stream //流 12 | } 13 | 14 | var servers = make([]*Server, 0, 10) 15 | 16 | //NewServer 新建一个服务 17 | func NewServer(name string, p *stream.Stream) { 18 | server := &Server{name, p} 19 | servers = append(servers, server) 20 | logrus.Info("新建一个服务,当前服务数量", len(servers)) 21 | } 22 | 23 | func CreateHole() { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /client/intermediaryclient/reader.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "github.com/dxcweb/go-nat-hole/common" 5 | "github.com/sirupsen/logrus" 6 | "github.com/xtaci/smux" 7 | ) 8 | 9 | //Reader 解析接受到的消息 10 | func reader(p *smux.Stream, buf []byte, findServerChan chan int, addrChen chan string, s *smux.Session) { 11 | switch buf[0] { 12 | case common.FlagConnectServer: 13 | addr := string(buf[1:]) 14 | findServerChan <- 1 15 | addrChen <- addr 16 | p.Close() 17 | break 18 | default: 19 | p.Close() 20 | logrus.Error("接受到错误操作", buf) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "debug", 12 | "remotePath": "", 13 | "port": 2345, 14 | "host": "127.0.0.1", 15 | "program": "${workspaceRoot}/bootstrap/client/main.go", 16 | "env": {}, 17 | "args": [], 18 | "showLog": true 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /client/intermediaryclient/root.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "net" 5 | "time" 6 | 7 | "github.com/dxcweb/go-nat-hole/client/conf" 8 | "github.com/sirupsen/logrus" 9 | ) 10 | 11 | //GetServerAddr 获取服务端地址 12 | func GetServerAddr(config *conf.Config, conn *net.UDPConn) string { 13 | addrChen := make(chan string, 1) 14 | i := 0 15 | for { 16 | select { 17 | case addr := <-addrChen: 18 | return addr 19 | default: 20 | if i > 0 { 21 | logrus.Warn("连接到中介服务器失败,正在重试...\n\n\n") 22 | time.Sleep(time.Second * 3) 23 | } 24 | RunIntermediaryClient(config, conn, addrChen) 25 | i++ 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server/intermediaryclient/writer.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/dxcweb/go-nat-hole/common" 7 | ) 8 | 9 | func sendRegister(p io.Writer, name string) { 10 | optBytes := []byte{common.FlagRegister} 11 | nameBytes := []byte(name) 12 | data := make([]byte, len(nameBytes)+1) 13 | copy(data[0:1], optBytes) 14 | copy(data[1:], nameBytes) 15 | p.Write(data) 16 | } 17 | 18 | func SendCreateHoleFinish(p io.Writer, clientID string) { 19 | optBytes := []byte{common.FlagCreateHoleFinish} 20 | dataBytes := []byte(clientID) 21 | data := make([]byte, len(dataBytes)+1) 22 | copy(data[0:1], optBytes) 23 | copy(data[1:], dataBytes) 24 | p.Write(data) 25 | } 26 | -------------------------------------------------------------------------------- /server/intermediaryclient/reader.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "io" 5 | "strings" 6 | 7 | "github.com/dxcweb/go-nat-hole/common" 8 | "github.com/dxcweb/go-nat-hole/server/conf" 9 | "github.com/dxcweb/go-nat-hole/server/hole" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | func reader(p io.WriteCloser, buf []byte, registerChan chan int, config *conf.Config) { 14 | switch buf[0] { 15 | case common.FlagRegisterConfirm: 16 | logrus.Info("注册成功,等待接受命令") 17 | registerChan <- 1 18 | break 19 | case common.FlagCreateHole: 20 | data := string(buf[1:]) 21 | dataArr := strings.Split(data, "|") 22 | hole.CreateHole(config, dataArr[0], dataArr[1]) 23 | break 24 | default: 25 | p.Close() 26 | logrus.Error("接受到错误操作", buf) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /bootstrap/intermediary/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/dxcweb/go-nat-hole/intermediary" 7 | "github.com/dxcweb/go-nat-hole/intermediary/conf" 8 | "github.com/urfave/cli" 9 | ) 10 | 11 | func main() { 12 | myApp := cli.NewApp() 13 | myApp.Flags = []cli.Flag{ 14 | cli.StringFlag{ 15 | Name: "listen,l", 16 | Value: ":18888", 17 | Usage: "kcp server listen address", 18 | }, 19 | cli.StringFlag{ 20 | Name: "key", 21 | Value: "123456", 22 | Usage: "客户机与服务器之间的预共享秘密", 23 | EnvVar: "KCPTUN_KEY", 24 | }, 25 | } 26 | myApp.Action = func(c *cli.Context) { 27 | config := conf.Config{} 28 | config.Key = c.String("key") 29 | config.Listen = c.String("listen") 30 | intermediary.RunIntermediary(config) 31 | } 32 | myApp.Run(os.Args) 33 | } 34 | -------------------------------------------------------------------------------- /bootstrap/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/dxcweb/go-nat-hole/server" 7 | "github.com/dxcweb/go-nat-hole/server/conf" 8 | "github.com/urfave/cli" 9 | ) 10 | 11 | func main() { 12 | myApp := cli.NewApp() 13 | myApp.Flags = []cli.Flag{ 14 | cli.StringFlag{ 15 | Name: "key", 16 | Value: "123456", 17 | Usage: "客户机与服务器之间的预共享秘密", 18 | EnvVar: "KCPTUN_KEY", 19 | }, 20 | cli.StringFlag{ 21 | Name: "remoteaddr, r", 22 | Value: "127.0.0.1:18888", 23 | Usage: "intermediary地址", 24 | }, 25 | cli.StringFlag{ 26 | Name: "name, n", 27 | Value: "server", 28 | Usage: "服务名字,用于客户端指定链接的唯一标识", 29 | }, 30 | } 31 | myApp.Action = func(c *cli.Context) { 32 | config := conf.Config{} 33 | config.Key = c.String("key") 34 | config.RemoteAddr = c.String("remoteaddr") 35 | config.Name = c.String("name") 36 | 37 | server.RunServer(&config) 38 | } 39 | myApp.Run(os.Args) 40 | } 41 | -------------------------------------------------------------------------------- /intermediary/handle/writer.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "strconv" 7 | 8 | "github.com/dxcweb/go-nat-hole/common" 9 | ) 10 | 11 | func sendRegisterConfirm(p io.Writer) { 12 | optBytes := []byte{common.FlagRegisterConfirm} 13 | p.Write(optBytes) 14 | } 15 | 16 | func sendCreateHole(p io.Writer, addr string, id uint32) { 17 | idStr := strconv.FormatUint(uint64(id), 10) 18 | optBytes := []byte{common.FlagCreateHole} 19 | buf := bytes.Buffer{} 20 | buf.WriteString(addr) 21 | buf.WriteString("|") 22 | buf.WriteString(idStr) 23 | dataBytes := buf.Bytes() 24 | data := make([]byte, len(dataBytes)+1) 25 | copy(data[0:1], optBytes) 26 | copy(data[1:], dataBytes) 27 | p.Write(data) 28 | } 29 | 30 | func sendConnectServer(p io.Writer, addr string) { 31 | optBytes := []byte{common.FlagConnectServer} 32 | dataBytes := []byte(addr) 33 | data := make([]byte, len(dataBytes)+1) 34 | copy(data[0:1], optBytes) 35 | copy(data[1:], dataBytes) 36 | p.Write(data) 37 | } 38 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [prune] 29 | go-tests = true 30 | unused-packages = true 31 | 32 | [[constraint]] 33 | name = "github.com/xtaci/kcp-go" 34 | version = "3.25.0" 35 | 36 | [[constraint]] 37 | name = "github.com/urfave/cli" 38 | version = "1.20.0" 39 | 40 | [[constraint]] 41 | name = "github.com/sirupsen/logrus" 42 | version = "1.0.5" 43 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | addr := "255.255.255.255:65535" 12 | b := bytes.Buffer{} 13 | b.WriteString(addr) 14 | b.WriteString("|") 15 | b.WriteString("asdf") 16 | // string() 17 | c := b.Bytes() 18 | s := string(c) 19 | fmt.Println(s) 20 | // fmt.Println([]byte()) 21 | // fmt.Println([]byte("255.255.255.255:1")) 22 | } 23 | 24 | func AddrToString(addr []byte) { 25 | s0 := string(int(addr[0])) 26 | s1 := string(int(addr[1])) 27 | s := []string{s0, s1} 28 | fmt.Println(strings.Join(s, ".")) 29 | } 30 | 31 | //AddrToBytes 字符串地址转换为字节 32 | func AddrToBytes(addr string) []byte { 33 | temp := strings.Split(addr, ":") 34 | parts := strings.Split(temp[0], ".") 35 | b0, err := strconv.Atoi(parts[0]) 36 | if err != nil { 37 | return nil 38 | } 39 | b1, _ := strconv.Atoi(parts[1]) 40 | b2, _ := strconv.Atoi(parts[2]) 41 | b3, _ := strconv.Atoi(parts[3]) 42 | 43 | b := make([]byte, 4) 44 | b[0] = byte(b0) 45 | b[1] = byte(b1) 46 | b[2] = byte(b2) 47 | b[3] = byte(b3) 48 | return b 49 | } 50 | -------------------------------------------------------------------------------- /bootstrap/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/dxcweb/go-nat-hole/client" 7 | "github.com/dxcweb/go-nat-hole/client/conf" 8 | "github.com/urfave/cli" 9 | ) 10 | 11 | func main() { 12 | myApp := cli.NewApp() 13 | myApp.Flags = []cli.Flag{ 14 | cli.StringFlag{ 15 | Name: "key", 16 | Value: "123456", 17 | Usage: "客户机与服务器之间的预共享秘密", 18 | EnvVar: "KCPTUN_KEY", 19 | }, 20 | cli.StringFlag{ 21 | Name: "localaddr,l", 22 | Value: ":19900", 23 | Usage: "UDP监听的本机地址", 24 | }, 25 | cli.StringFlag{ 26 | Name: "remoteaddr, r", 27 | Value: "127.0.0.1:18888", 28 | Usage: "intermediary地址", 29 | }, 30 | cli.StringFlag{ 31 | Name: "servername, s", 32 | Value: "server", 33 | Usage: "服务端名称", 34 | }, 35 | } 36 | myApp.Action = func(c *cli.Context) { 37 | config := conf.Config{} 38 | config.Key = c.String("key") 39 | config.LocalAddr = c.String("localaddr") 40 | config.RemoteAddr = c.String("remoteaddr") 41 | config.ServerName = c.String("servername") 42 | 43 | client.RunClient(&config) 44 | } 45 | myApp.Run(os.Args) 46 | } 47 | -------------------------------------------------------------------------------- /common/compStream.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/golang/snappy" 7 | ) 8 | 9 | //CompStream 流压缩 10 | type CompStream struct { 11 | conn net.Conn 12 | w *snappy.Writer 13 | r *snappy.Reader 14 | } 15 | 16 | //Read 读 17 | func (c *CompStream) Read(p []byte) (n int, err error) { 18 | return c.r.Read(p) 19 | } 20 | 21 | //Write 写 22 | func (c *CompStream) Write(p []byte) (n int, err error) { 23 | n, err = c.w.Write(p) 24 | err = c.w.Flush() 25 | return n, err 26 | } 27 | 28 | //Close 关闭 29 | func (c *CompStream) Close() error { 30 | return c.conn.Close() 31 | } 32 | 33 | // LocalAddr returns the local network address. 34 | func (c *CompStream) LocalAddr() net.Addr { 35 | return c.conn.LocalAddr() 36 | } 37 | 38 | // LocalAddr returns the local network address. 39 | func (c *CompStream) RemoteAddr() net.Addr { 40 | return c.conn.RemoteAddr() 41 | } 42 | 43 | //NewCompStream new一个流压缩 44 | func NewCompStream(conn net.Conn) *CompStream { 45 | c := new(CompStream) 46 | c.conn = conn 47 | c.w = snappy.NewBufferedWriter(conn) 48 | c.r = snappy.NewReader(conn) 49 | return c 50 | } 51 | -------------------------------------------------------------------------------- /intermediary/handle/reader.go: -------------------------------------------------------------------------------- 1 | package handle 2 | 3 | import ( 4 | "github.com/dxcweb/go-nat-hole/common" 5 | "github.com/dxcweb/go-nat-hole/intermediary/stream" 6 | "github.com/sirupsen/logrus" 7 | ) 8 | 9 | //Reader 解析接受到的消息 10 | func Reader(p *stream.Stream, buf []byte) { 11 | switch buf[0] { 12 | case common.FlagRegister: 13 | name := string(buf[1:]) 14 | p.SetName(name) 15 | sendRegisterConfirm(p) 16 | logrus.Info("接受到注册事件,来自", name, ",nat:", p.RemoteAddr()) 17 | break 18 | case common.FlagFindServer: 19 | name := string(buf[1:]) 20 | s := stream.GetStreamByName(name) 21 | if s == nil { 22 | logrus.Warn("接受到客户端:", p.RemoteAddr(), ",发现服务请求失败!,服务名:", name) 23 | } else { 24 | sendCreateHole(s, p.RemoteAddr().String(), p.ID()) 25 | logrus.Info("接受到客户端:", p.RemoteAddr(), ",发现服务请求:", name) 26 | } 27 | break 28 | case common.FlagCreateHoleFinish: 29 | clientID := string(buf[1:]) 30 | s := stream.GetStreamByID(clientID) 31 | if s == nil { 32 | logrus.Warn("创建打洞服务:", p.RemoteAddr(), "找不到客户端:", clientID) 33 | } else { 34 | sendConnectServer(s, p.RemoteAddr().String()) 35 | logrus.Info("创建打洞服务:", p.RemoteAddr()) 36 | } 37 | break 38 | default: 39 | p.Close() 40 | logrus.Error("接受到错误操作", buf) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /client/proxy/client.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | "github.com/dxcweb/go-nat-hole/client/conf" 9 | "github.com/dxcweb/go-nat-hole/common" 10 | "github.com/sirupsen/logrus" 11 | kcp "github.com/xtaci/kcp-go" 12 | "github.com/xtaci/smux" 13 | ) 14 | 15 | func NewProxyClient(config *conf.Config, remoteAddr string, conn *net.UDPConn) error { 16 | kcpconn, err := common.NewConn(config.Key, remoteAddr, conn) 17 | defer conn.Close() 18 | if err != nil { 19 | logrus.Error("客户端启动失败:", err) 20 | return err 21 | } 22 | handleClient(kcpconn, config) 23 | return nil 24 | } 25 | 26 | func handleClient(conn *kcp.UDPSession, config *conf.Config) error { 27 | smuxConfig := common.SmuxConfig() 28 | sess, err := smux.Client(common.NewCompStream(conn), smuxConfig) 29 | if err != nil { 30 | logrus.Error("smux.Client失败:", err) 31 | return err 32 | } 33 | p, err := sess.OpenStream() 34 | if err != nil { 35 | logrus.Error("OpenStream失败:", err) 36 | return err 37 | } 38 | findServerChan := make(chan int) 39 | defer func() { 40 | logrus.Info("关闭和服务端的通讯") 41 | p.Close() 42 | close(findServerChan) 43 | time.Sleep(time.Second * 1) 44 | }() 45 | go func() { 46 | for { 47 | logrus.Info("写入数据", p.RemoteAddr()) 48 | p.Write([]byte{3, 3, 3}) 49 | time.Sleep(time.Second * 1) 50 | } 51 | }() 52 | 53 | for { 54 | buf := make([]byte, 1024) 55 | nr, er := p.Read(buf) 56 | if nr > 0 { 57 | fmt.Println("123", buf[:nr]) 58 | } 59 | if er != nil { 60 | fmt.Println(333) 61 | break 62 | } 63 | } 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /intermediary/intermediary.go: -------------------------------------------------------------------------------- 1 | package intermediary 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/dxcweb/go-nat-hole/common" 7 | "github.com/dxcweb/go-nat-hole/intermediary/conf" 8 | "github.com/dxcweb/go-nat-hole/intermediary/handle" 9 | "github.com/dxcweb/go-nat-hole/intermediary/stream" 10 | "github.com/sirupsen/logrus" 11 | "github.com/xtaci/smux" 12 | ) 13 | 14 | //RunIntermediary 运行中介服务器 15 | func RunIntermediary(config conf.Config) error { 16 | lis, err := common.UDPServer(config.Key, config.Listen) 17 | if err != nil { 18 | logrus.Error("监听UDP端口失败:", err) 19 | return err 20 | } 21 | logrus.Info("中介服务器启动成功端口为:", config.Listen) 22 | for { 23 | if conn, err := lis.AcceptKCP(); err == nil { 24 | common.SetConnOption(conn) 25 | go handleMux(common.NewCompStream(conn), &config) 26 | } else { 27 | logrus.Error("lis.AcceptKCP错误", err) 28 | } 29 | } 30 | } 31 | 32 | // 多路复用 33 | func handleMux(conn *common.CompStream, config *conf.Config) { 34 | fmt.Println(1234) 35 | smuxConfig := common.SmuxConfig() 36 | 37 | mux, err := smux.Server(conn, smuxConfig) 38 | if err != nil { 39 | logrus.Error("启动多路复用服务失败", err) 40 | return 41 | } 42 | defer mux.Close() 43 | for { 44 | p, err := stream.AcceptStream(mux) 45 | fmt.Println("aaaaa") 46 | if err != nil { 47 | logrus.Error("错误123") 48 | return 49 | } 50 | go func() { 51 | defer p.Close() 52 | buf := make([]byte, 32*1024) 53 | for { 54 | n, er := p.Read(buf) 55 | if n > 0 { 56 | handle.Reader(p, buf[0:n]) 57 | } 58 | if er != nil { 59 | // if er != io.EOF { 60 | // logrus.Info("错误", er) 61 | // } 62 | break 63 | } 64 | } 65 | }() 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /server/intermediaryclient/client.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "io" 5 | "time" 6 | 7 | "github.com/dxcweb/go-nat-hole/common" 8 | "github.com/dxcweb/go-nat-hole/server/conf" 9 | "github.com/sirupsen/logrus" 10 | kcp "github.com/xtaci/kcp-go" 11 | "github.com/xtaci/smux" 12 | ) 13 | 14 | //RunIntermediaryClient 运行中介服务器客户端 15 | func RunIntermediaryClient(config *conf.Config) error { 16 | conn, err := common.UDPClientSimple(config.Key, config.RemoteAddr) 17 | if err != nil { 18 | logrus.Error("服务端启动失败:", err) 19 | return err 20 | } 21 | handleClient(conn, config) 22 | return nil 23 | } 24 | 25 | func handleClient(conn *kcp.UDPSession, config *conf.Config) error { 26 | smuxConfig := common.SmuxConfig() 27 | sess, err := smux.Client(common.NewCompStream(conn), smuxConfig) 28 | if err != nil { 29 | logrus.Error("smux.Client失败:", err) 30 | return err 31 | } 32 | p, err := sess.OpenStream() 33 | if err != nil { 34 | logrus.Error("OpenStream失败:", err) 35 | return err 36 | } 37 | registerChan := make(chan int, 1) 38 | defer func() { 39 | p.Close() 40 | close(registerChan) 41 | time.Sleep(time.Second * 1) 42 | }() 43 | go register(p, config.Name, registerChan) 44 | for { 45 | buf := make([]byte, 1024) 46 | nr, er := p.Read(buf) 47 | if nr > 0 { 48 | reader(p, buf[0:nr], registerChan, config) 49 | } 50 | if er != nil { 51 | // if er != io.EOF { 52 | // logrus.Info("错误", er) 53 | // } 54 | break 55 | } 56 | } 57 | return nil 58 | } 59 | 60 | func register(p io.Writer, name string, exitChan chan int) { 61 | sendCount := 1 62 | for { 63 | select { 64 | case <-exitChan: 65 | return 66 | default: 67 | logrus.Info("发送注册消息,发送次数:", sendCount) 68 | sendRegister(p, name) 69 | sendCount++ 70 | time.Sleep(time.Second * 3) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /client/intermediaryclient/client.go: -------------------------------------------------------------------------------- 1 | package intermediaryclient 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "time" 8 | 9 | "github.com/dxcweb/go-nat-hole/client/conf" 10 | "github.com/dxcweb/go-nat-hole/common" 11 | "github.com/sirupsen/logrus" 12 | kcp "github.com/xtaci/kcp-go" 13 | "github.com/xtaci/smux" 14 | ) 15 | 16 | //RunIntermediaryClient 运行客户端 17 | func RunIntermediaryClient(config *conf.Config, conn *net.UDPConn, addrChen chan string) error { 18 | kcpconn, err := common.NewConn(config.Key, config.RemoteAddr, conn) 19 | // defer kcpconn.Close() 20 | if err != nil { 21 | logrus.Error("客户端启动失败:", err) 22 | return err 23 | } 24 | handleClient(kcpconn, config, addrChen) 25 | return nil 26 | } 27 | func handleClient(conn *kcp.UDPSession, config *conf.Config, addrChen chan string) error { 28 | smuxConfig := common.SmuxConfig() 29 | sess, err := smux.Client(common.NewCompStream(conn), smuxConfig) 30 | if err != nil { 31 | logrus.Error("smux.Client失败:", err) 32 | return err 33 | } 34 | p, err := sess.OpenStream() 35 | if err != nil { 36 | logrus.Error("OpenStream失败:", err) 37 | return err 38 | } 39 | findServerChan := make(chan int) 40 | defer func() { 41 | logrus.Info("关闭和中介服务器的通讯") 42 | p.Close() 43 | close(findServerChan) 44 | time.Sleep(time.Second * 1) 45 | }() 46 | go findServer(p, config.ServerName, findServerChan) 47 | for { 48 | buf := make([]byte, 1024) 49 | nr, er := p.Read(buf) 50 | if nr > 0 { 51 | reader(p, buf[0:nr], findServerChan, addrChen, sess) 52 | } 53 | if er != nil { 54 | fmt.Println(333) 55 | break 56 | } 57 | } 58 | return nil 59 | } 60 | 61 | func findServer(p io.Writer, name string, exitChan chan int) { 62 | sendCount := 1 63 | for { 64 | select { 65 | case <-exitChan: 66 | fmt.Println("aqsdfasdfasd") 67 | return 68 | default: 69 | logrus.Info("发送发现服务,发送次数:", sendCount) 70 | sendFindServer(p, name) 71 | sendCount++ 72 | time.Sleep(time.Second * 3) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/klauspost/cpuid" 6 | packages = ["."] 7 | revision = "ae7887de9fa5d2db4eaa8174a7eff2c1ac00f2da" 8 | version = "v1.1" 9 | 10 | [[projects]] 11 | name = "github.com/klauspost/reedsolomon" 12 | packages = ["."] 13 | revision = "6bb6130ff6a76a904c1841707d65603aec9cc288" 14 | version = "v1.6" 15 | 16 | [[projects]] 17 | name = "github.com/pkg/errors" 18 | packages = ["."] 19 | revision = "645ef00459ed84a119197bfb8d8205042c6df63d" 20 | version = "v0.8.0" 21 | 22 | [[projects]] 23 | name = "github.com/sirupsen/logrus" 24 | packages = ["."] 25 | revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" 26 | version = "v1.0.5" 27 | 28 | [[projects]] 29 | branch = "master" 30 | name = "github.com/templexxx/cpufeat" 31 | packages = ["."] 32 | revision = "3794dfbfb04749f896b521032f69383f24c3687e" 33 | 34 | [[projects]] 35 | name = "github.com/templexxx/xor" 36 | packages = ["."] 37 | revision = "0af8e873c554da75f37f2049cdffda804533d44c" 38 | version = "0.1.2" 39 | 40 | [[projects]] 41 | name = "github.com/tjfoc/gmsm" 42 | packages = ["sm4"] 43 | revision = "98aa888b79d8de04afe0fccf45ed10594efc858b" 44 | version = "v1.1" 45 | 46 | [[projects]] 47 | name = "github.com/xtaci/kcp-go" 48 | packages = ["."] 49 | revision = "42bc1dfefff592fdb3affa793980c4f6ab4213e5" 50 | version = "v3.25" 51 | 52 | [[projects]] 53 | branch = "master" 54 | name = "golang.org/x/crypto" 55 | packages = [ 56 | "blowfish", 57 | "cast5", 58 | "internal/subtle", 59 | "pbkdf2", 60 | "salsa20", 61 | "salsa20/salsa", 62 | "ssh/terminal", 63 | "tea", 64 | "twofish", 65 | "xtea" 66 | ] 67 | revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" 68 | 69 | [[projects]] 70 | branch = "master" 71 | name = "golang.org/x/net" 72 | packages = [ 73 | "bpf", 74 | "internal/iana", 75 | "internal/socket", 76 | "ipv4" 77 | ] 78 | revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9" 79 | 80 | [[projects]] 81 | branch = "master" 82 | name = "golang.org/x/sys" 83 | packages = [ 84 | "unix", 85 | "windows" 86 | ] 87 | revision = "a200a19cb90b19de298170992778b1fda7217bd6" 88 | 89 | [solve-meta] 90 | analyzer-name = "dep" 91 | analyzer-version = 1 92 | inputs-digest = "4e955bf300e354ea285d42d804444c0babeda4d7b5bdcbcc0e688e4e9243f1e3" 93 | solver-name = "gps-cdcl" 94 | solver-version = 1 95 | -------------------------------------------------------------------------------- /intermediary/stream/stream.go: -------------------------------------------------------------------------------- 1 | package stream 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | "time" 7 | 8 | "github.com/dxcweb/go-nat-hole/common" 9 | "github.com/xtaci/smux" 10 | ) 11 | 12 | //Stream 流 13 | type Stream struct { 14 | p *smux.Stream 15 | id uint32 16 | name string 17 | } 18 | 19 | var streams = make([]*Stream, 0, 20) 20 | 21 | func GetStreamByName(name string) *Stream { 22 | for _, value := range streams { 23 | if value.name == name { 24 | return value 25 | } 26 | } 27 | return nil 28 | } 29 | func GetStreamByID(s string) *Stream { 30 | id64, err := strconv.ParseUint(s, 10, 32) 31 | if err != nil { 32 | return nil 33 | } 34 | id := uint32(id64) 35 | for _, value := range streams { 36 | if value.id == id { 37 | return value 38 | } 39 | } 40 | return nil 41 | } 42 | 43 | //SetName 设置名称 44 | func (s *Stream) SetName(name string) { 45 | s.name = name 46 | } 47 | 48 | //AcceptStream 接受流 49 | func AcceptStream(mux *smux.Session) (*Stream, error) { 50 | p, err := mux.AcceptStream() 51 | if err != nil { 52 | return nil, err 53 | } 54 | s := &Stream{ 55 | p: p, 56 | id: common.Rand(), 57 | } 58 | streams = append(streams, s) 59 | return s, nil 60 | } 61 | 62 | //ID 返回id 63 | func (s *Stream) ID() uint32 { 64 | return s.id 65 | } 66 | 67 | //Close Close 68 | func (s *Stream) Close() error { 69 | return s.p.Close() 70 | } 71 | 72 | // LocalAddr satisfies net.Conn interface 73 | func (s *Stream) LocalAddr() net.Addr { 74 | return s.p.LocalAddr() 75 | } 76 | 77 | func (s *Stream) Read(b []byte) (n int, err error) { 78 | return s.p.Read(b) 79 | } 80 | 81 | // RemoteAddr satisfies net.Conn interface 82 | func (s *Stream) RemoteAddr() net.Addr { 83 | return s.p.RemoteAddr() 84 | } 85 | 86 | // SetDeadline sets both read and write deadlines as defined by 87 | // net.Conn.SetDeadline. 88 | // A zero time value disables the deadlines. 89 | func (s *Stream) SetDeadline(t time.Time) error { 90 | return s.p.SetDeadline(t) 91 | } 92 | 93 | // SetReadDeadline sets the read deadline as defined by 94 | // net.Conn.SetReadDeadline. 95 | // A zero time value disables the deadline. 96 | func (s *Stream) SetReadDeadline(t time.Time) error { 97 | return s.p.SetReadDeadline(t) 98 | } 99 | 100 | // SetWriteDeadline sets the write deadline as defined by 101 | // net.Conn.SetWriteDeadline. 102 | // A zero time value disables the deadline. 103 | func (s *Stream) SetWriteDeadline(t time.Time) error { 104 | return s.p.SetWriteDeadline(t) 105 | } 106 | 107 | // Write implements net.Conn 108 | func (s *Stream) Write(b []byte) (n int, err error) { 109 | return s.p.Write(b) 110 | } 111 | -------------------------------------------------------------------------------- /server/hole/hole.go: -------------------------------------------------------------------------------- 1 | package hole 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | "github.com/dxcweb/go-nat-hole/common" 9 | "github.com/dxcweb/go-nat-hole/intermediary/stream" 10 | "github.com/dxcweb/go-nat-hole/server/conf" 11 | "github.com/sirupsen/logrus" 12 | "github.com/xtaci/smux" 13 | ) 14 | 15 | func CreateHole(config *conf.Config, clientAddr, clientID string) { 16 | conn := newUdpconn(config.Key) 17 | pc, _ := openStream(config.Key, clientAddr, conn) 18 | pi, _ := openStream(config.Key, config.RemoteAddr, conn) 19 | logrus.Info("开始打洞目标地址:", pc.RemoteAddr()) 20 | pc.Write([]byte{1}) 21 | time.Sleep(time.Second * 1) 22 | // pc.Close() 23 | sendCreateHoleFinish(pi, clientID) 24 | pi.Close() 25 | } 26 | 27 | func openStream(key, raddr string, conn *net.UDPConn) (*smux.Stream, error) { 28 | kcpconn, err := common.NewConn(key, raddr, conn) 29 | if err != nil { 30 | logrus.Error("服务端启动失败:", err) 31 | return nil, err 32 | } 33 | smuxConfig := common.SmuxConfig() 34 | sess, err := smux.Client(common.NewCompStream(kcpconn), smuxConfig) 35 | if err != nil { 36 | logrus.Error("smux.Client失败:", err) 37 | return nil, err 38 | } 39 | p, err := sess.OpenStream() 40 | if err != nil { 41 | logrus.Error("OpenStream失败:", err) 42 | return nil, err 43 | } 44 | return p, nil 45 | } 46 | func newServer(key string, conn *net.UDPConn) error { 47 | lis, err := common.UDPServerByConn(key, conn) 48 | if err != nil { 49 | logrus.Error("监听UDP端口失败:", err) 50 | return err 51 | } 52 | for { 53 | if conn, err := lis.AcceptKCP(); err == nil { 54 | common.SetConnOption(conn) 55 | go handleMux(common.NewCompStream(conn)) 56 | } else { 57 | logrus.Error("lis.AcceptKCP错误", err) 58 | } 59 | } 60 | } 61 | 62 | // 多路复用 63 | func handleMux(conn *common.CompStream) { 64 | fmt.Println(123123, conn.RemoteAddr()) 65 | smuxConfig := common.SmuxConfig() 66 | mux, err := smux.Server(conn, smuxConfig) 67 | if err != nil { 68 | logrus.Error("启动多路复用服务失败", err) 69 | return 70 | } 71 | defer mux.Close() 72 | for { 73 | p, err := stream.AcceptStream(mux) 74 | if err != nil { 75 | logrus.Error("错误123") 76 | return 77 | } 78 | fmt.Println(31) 79 | go func() { 80 | defer p.Close() 81 | buf := make([]byte, 32*1024) 82 | for { 83 | n, er := p.Read(buf) 84 | if n > 0 { 85 | fmt.Println("接受到消息:", buf[0:n]) 86 | } 87 | if er != nil { 88 | // if er != io.EOF { 89 | // logrus.Info("错误", er) 90 | // } 91 | break 92 | } 93 | } 94 | }() 95 | } 96 | } 97 | 98 | var temp *net.UDPConn 99 | 100 | func newUdpconn(key string) *net.UDPConn { 101 | if temp == nil { 102 | localAddr := ":19102" 103 | conn, _ := common.UDPconn(localAddr) 104 | go newServer(key, conn) 105 | temp = conn 106 | } 107 | return temp 108 | } 109 | -------------------------------------------------------------------------------- /common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "crypto/sha1" 5 | "net" 6 | "time" 7 | 8 | "github.com/pkg/errors" 9 | "github.com/sirupsen/logrus" 10 | kcp "github.com/xtaci/kcp-go" 11 | "github.com/xtaci/smux" 12 | "golang.org/x/crypto/pbkdf2" 13 | ) 14 | 15 | var ( 16 | // SALT is use for pbkdf2 key expansion 17 | SALT = "go-nat-hole" 18 | dataShard = 10 19 | parityShard = 10 20 | //SockBuf socket buffer size in bytes 21 | SockBuf = 4194304 22 | ) 23 | 24 | func UDPconn(localAddr string) (*net.UDPConn, error) { 25 | laddr, err := net.ResolveUDPAddr("udp", localAddr) 26 | if err != nil { 27 | return nil, errors.Wrap(err, "net.ResolveUDPAddr") 28 | } 29 | return net.ListenUDP("udp", laddr) 30 | } 31 | 32 | //GetBlockCrypt NewAESBlockCrypt 33 | func GetBlockCrypt(key string) kcp.BlockCrypt { 34 | pass := pbkdf2.Key([]byte(key), []byte(SALT), 4096, 32, sha1.New) 35 | block, _ := kcp.NewAESBlockCrypt(pass[:16]) 36 | return block 37 | } 38 | 39 | //UDPServer 启动一个UDP服务 40 | func UDPServer(key, listen string) (*kcp.Listener, error) { 41 | block := GetBlockCrypt(key) 42 | lis, err := kcp.ListenWithOptions(listen, block, dataShard, parityShard) 43 | if err != nil { 44 | return nil, err 45 | } 46 | // TODO 不知道DSCP是啥 47 | // if err := lis.SetDSCP(0); err != nil { 48 | // logrus.Warn("SetDSCP:", err) 49 | // } 50 | if err := lis.SetReadBuffer(SockBuf); err != nil { 51 | logrus.Warn("SetReadBuffer:", err) 52 | } 53 | if err := lis.SetWriteBuffer(SockBuf); err != nil { 54 | logrus.Warn("SetWriteBuffer:", err) 55 | } 56 | 57 | return lis, nil 58 | } 59 | 60 | //UDPServerByConn 启动一个UDP服务 61 | func UDPServerByConn(key string, conn *net.UDPConn) (*kcp.Listener, error) { 62 | block := GetBlockCrypt(key) 63 | lis, err := kcp.ServeConn(block, dataShard, parityShard, &connectedUDPConn{conn}) 64 | if err != nil { 65 | return nil, err 66 | } 67 | // TODO 不知道DSCP是啥 68 | // if err := lis.SetDSCP(0); err != nil { 69 | // logrus.Warn("SetDSCP:", err) 70 | // } 71 | if err := lis.SetReadBuffer(SockBuf); err != nil { 72 | logrus.Warn("SetReadBuffer:", err) 73 | } 74 | if err := lis.SetWriteBuffer(SockBuf); err != nil { 75 | logrus.Warn("SetWriteBuffer:", err) 76 | } 77 | 78 | return lis, nil 79 | } 80 | 81 | //UDPClient 启动一个UDP客户端 82 | func UDPClient(key, localAddr, remoteAddr string) (*kcp.UDPSession, error) { 83 | block := GetBlockCrypt(key) 84 | 85 | raddr, err := net.ResolveUDPAddr("udp", remoteAddr) 86 | if err != nil { 87 | return nil, errors.Wrap(err, "net.ResolveUDPAddr") 88 | } 89 | var laddr *net.UDPAddr 90 | if localAddr != "" { 91 | laddr, err = net.ResolveUDPAddr("udp", localAddr) 92 | if err != nil { 93 | return nil, errors.Wrap(err, "net.ResolveUDPAddr") 94 | } 95 | } 96 | udpconn, err := net.DialUDP("udp", laddr, raddr) 97 | if err != nil { 98 | return nil, errors.Wrap(err, "net.DialUDP") 99 | } 100 | conn, err := kcp.NewConn(remoteAddr, block, dataShard, parityShard, &connectedUDPConn{udpconn}) 101 | if err != nil { 102 | return nil, err 103 | } 104 | 105 | SetConnOption(conn) 106 | 107 | // TODO 不知道DSCP是啥 108 | // if err := conn.SetDSCP(0); err != nil { 109 | // logrus.Warn("SetDSCP:", err) 110 | // } 111 | if err := conn.SetReadBuffer(SockBuf); err != nil { 112 | logrus.Warn("SetReadBuffer:", err) 113 | } 114 | if err := conn.SetWriteBuffer(SockBuf); err != nil { 115 | logrus.Warn("SetWriteBuffer:", err) 116 | } 117 | 118 | return conn, nil 119 | } 120 | 121 | func NewConn(key, raddr string, conn *net.UDPConn) (*kcp.UDPSession, error) { 122 | block := GetBlockCrypt(key) 123 | // raddr := "127.0.0.1:18888" 124 | kcpconn, err := kcp.NewConn(raddr, block, dataShard, parityShard, conn) 125 | 126 | if err != nil { 127 | return nil, err 128 | } 129 | 130 | SetConnOption(kcpconn) 131 | 132 | // TODO 不知道DSCP是啥 133 | // if err := conn.SetDSCP(0); err != nil { 134 | // logrus.Warn("SetDSCP:", err) 135 | // } 136 | if err := kcpconn.SetReadBuffer(SockBuf); err != nil { 137 | logrus.Warn("SetReadBuffer:", err) 138 | } 139 | if err := kcpconn.SetWriteBuffer(SockBuf); err != nil { 140 | logrus.Warn("SetWriteBuffer:", err) 141 | } 142 | 143 | return kcpconn, nil 144 | } 145 | 146 | //UDPClientSimple 启动一个UDP客户端 147 | func UDPClientSimple(key, remoteAddr string) (*kcp.UDPSession, error) { 148 | return UDPClient(key, "", remoteAddr) 149 | } 150 | 151 | //SetConnOption 设置连接选项 152 | func SetConnOption(conn *kcp.UDPSession) { 153 | conn.SetStreamMode(true) 154 | conn.SetWriteDelay(true) 155 | NoDelay, Interval, Resend, NoCongestion := 1, 10, 2, 1 156 | conn.SetNoDelay(NoDelay, Interval, Resend, NoCongestion) 157 | conn.SetMtu(1350) // 设置UDP数据包的最大传输单元 158 | conn.SetWindowSize(1024, 1024) // 设置发送的窗口大小 159 | conn.SetACKNoDelay(false) //当接收到数据包时立即刷新ACK 160 | } 161 | 162 | //SmuxConfig 多路复用配置 163 | func SmuxConfig() *smux.Config { 164 | smuxConfig := smux.DefaultConfig() 165 | smuxConfig.MaxReceiveBuffer = SockBuf 166 | smuxConfig.KeepAliveInterval = time.Duration(10) * time.Second 167 | return smuxConfig 168 | } 169 | 170 | type connectedUDPConn struct{ *net.UDPConn } 171 | 172 | // WriteTo redirects all writes to the Write syscall, which is 4 times faster. 173 | func (c *connectedUDPConn) WriteTo(b []byte, addr net.Addr) (int, error) { 174 | return c.Write(b) 175 | } 176 | --------------------------------------------------------------------------------