diff --git a/README.md b/README.md index c925688..e8486af 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ we can set up local listeners as proxy servers, and forward requests to internet |ssr | | |√| |client only |ssh | | |√| |client only |trojan | | |√|√|client only -|vless |√|√|√|√|client only +|vless |√|√|√|√|client & server |vmess | | |√| |client only |redir |√| | | |linux only |redir6 |√| | | |linux only(ipv6) diff --git a/go.mod b/go.mod index cedbcd0..9a39d6b 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,9 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/xtaci/kcp-go/v5 v5.5.17 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 - golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect - golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d // indirect + golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 // indirect + golang.org/x/sys v0.0.0-20201007082116-8445cc04cbdf // indirect + golang.org/x/tools v0.0.0-20201007032633-0806396f153e // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect ) diff --git a/go.sum b/go.sum index 56c27e9..a5ddc78 100644 --- a/go.sum +++ b/go.sum @@ -141,8 +141,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgN golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c h1:dk0ukUIHmGHqASjP0iue2261isepFCC6XRCSd1nHgDw= -golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c/go.mod h1:iQL9McJNjoIa5mjH6nYTCTZXUN6RP+XW3eib7Ya3XcI= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -167,14 +167,18 @@ golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201007082116-8445cc04cbdf h1:AvBTl0xbF/KtHyvm61X4gSPF7/dKJ/xQqJwKr1Qu9no= +golang.org/x/sys v0.0.0-20201007082116-8445cc04cbdf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU= golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d h1:vWQvJ/Z0Lu+9/8oQ/pAYXNzbc7CMnBl+tULGVHOy3oE= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201007032633-0806396f153e h1:FJA2W4BQfMGZ+CD/tiAc39HXecuRsJl3EuczaSUu/Yk= +golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= diff --git a/main.go b/main.go index 4ebd7e5..c2dcbc4 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ import ( ) var ( - version = "0.11.1" + version = "0.11.2" config = parseConfig() ) diff --git a/proxy/redir/redir_linux.go b/proxy/redir/redir_linux.go index a5f4e28..d929806 100644 --- a/proxy/redir/redir_linux.go +++ b/proxy/redir/redir_linux.go @@ -4,7 +4,6 @@ package redir import ( - "errors" "net" "net/url" "strings" @@ -13,14 +12,6 @@ import ( "github.com/nadoo/glider/log" "github.com/nadoo/glider/proxy" - "github.com/nadoo/glider/proxy/socks" -) - -const ( - // SO_ORIGINAL_DST from linux/include/uapi/linux/netfilter_ipv4.h - SO_ORIGINAL_DST = 80 - // IP6T_SO_ORIGINAL_DST from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h - IP6T_SO_ORIGINAL_DST = 80 ) // RedirProxy struct. @@ -85,13 +76,16 @@ func (s *RedirProxy) ListenAndServe() { } // Serve serves connections. -func (s *RedirProxy) Serve(c net.Conn) { - defer c.Close() +func (s *RedirProxy) Serve(cc net.Conn) { + defer cc.Close() - if c, ok := c.(*net.TCPConn); ok { - c.SetKeepAlive(true) + c, ok := cc.(*net.TCPConn) + if !ok { + log.F("[redir] not a tcp connection, can not chain redir proxy") + return } + c.SetKeepAlive(true) tgt, err := getOrigDst(c, s.ipv6) if err != nil { log.F("[redir] failed to get target address: %v", err) @@ -123,61 +117,49 @@ func (s *RedirProxy) Serve(c net.Conn) { } // Get the original destination of a TCP connection. -func getOrigDst(conn net.Conn, ipv6 bool) (socks.Addr, error) { - c, ok := conn.(*net.TCPConn) - if !ok { - return nil, errors.New("only work with TCP connection") - } - f, err := c.File() +func getOrigDst(c *net.TCPConn, ipv6 bool) (*net.TCPAddr, error) { + rc, err := c.SyscallConn() if err != nil { return nil, err } - defer f.Close() - - fd := f.Fd() - - // The File() call above puts both the original socket fd and the file fd in blocking mode. - // Set the file fd back to non-blocking mode and the original socket fd will become non-blocking as well. - // Otherwise blocking I/O will waste OS threads. - if err := syscall.SetNonblock(int(fd), true); err != nil { - return nil, err - } - - if ipv6 { - return getorigdstIPv6(fd) - } - - return getorigdst(fd) + var addr *net.TCPAddr + rc.Control(func(fd uintptr) { + if ipv6 { + addr, err = ipv6_getorigdst(fd) + } else { + addr, err = getorigdst(fd) + } + }) + return addr, err } // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c -func getorigdst(fd uintptr) (socks.Addr, error) { - raw := syscall.RawSockaddrInet4{} +func getorigdst(fd uintptr) (*net.TCPAddr, error) { + const _SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h + var raw syscall.RawSockaddrInet4 siz := unsafe.Sizeof(raw) - if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { + if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, _SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { return nil, err } - - addr := make([]byte, 1+net.IPv4len+2) - addr[0] = socks.ATypIP4 - copy(addr[1:1+net.IPv4len], raw.Addr[:]) - port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian - addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] - return addr, nil + var addr net.TCPAddr + addr.IP = raw.Addr[:] + port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian + addr.Port = int(port[0])<<8 | int(port[1]) + return &addr, nil } // Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c -func getorigdstIPv6(fd uintptr) (socks.Addr, error) { - raw := syscall.RawSockaddrInet6{} +// NOTE: I haven't tried yet but it should work since Linux 3.8. +func ipv6_getorigdst(fd uintptr) (*net.TCPAddr, error) { + const _IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h + var raw syscall.RawSockaddrInet6 siz := unsafe.Sizeof(raw) - if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { + if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, _IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { return nil, err } - - addr := make([]byte, 1+net.IPv6len+2) - addr[0] = socks.ATypIP6 - copy(addr[1:1+net.IPv6len], raw.Addr[:]) - port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian - addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1] - return addr, nil + var addr net.TCPAddr + addr.IP = raw.Addr[:] + port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian + addr.Port = int(port[0])<<8 | int(port[1]) + return &addr, nil } diff --git a/proxy/redir/redir_linux_386.go b/proxy/redir/redir_linux_386.go index c8fca33..32f692d 100644 --- a/proxy/redir/redir_linux_386.go +++ b/proxy/redir/redir_linux_386.go @@ -5,8 +5,7 @@ import ( "unsafe" ) -// https://github.com/golang/go/blob/9e6b79a5dfb2f6fe4301ced956419a0da83bd025/src/syscall/syscall_linux_386.go#L196 -const GETSOCKOPT = 15 +const GETSOCKOPT = 15 // https://golang.org/src/syscall/syscall_linux_386.go#L183 func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { var a [6]uintptr diff --git a/proxy/redir/redir_linux_other.go b/proxy/redir/redir_linux_other.go index a2677b9..9547282 100644 --- a/proxy/redir/redir_linux_other.go +++ b/proxy/redir/redir_linux_other.go @@ -4,7 +4,6 @@ package redir import "syscall" -// GETSOCKOPT from syscall const GETSOCKOPT = syscall.SYS_GETSOCKOPT func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { diff --git a/proxy/tls/tls.go b/proxy/tls/tls.go index 38e64b6..c33e14e 100644 --- a/proxy/tls/tls.go +++ b/proxy/tls/tls.go @@ -38,39 +38,27 @@ func init() { func NewTLS(s string, d proxy.Dialer, p proxy.Proxy) (*TLS, error) { u, err := url.Parse(s) if err != nil { - log.F("parse url err: %s", err) + log.F("[tls] parse url err: %s", err) return nil, err } - addr := u.Host - - colonPos := strings.LastIndex(addr, ":") - if colonPos == -1 { - colonPos = len(addr) - } - serverName := addr[:colonPos] - query := u.Query() - skipVerify := query.Get("skipVerify") - certFile := query.Get("cert") - keyFile := query.Get("key") - - if customServer := query.Get("serverName"); customServer != "" { - serverName = customServer - } - t := &TLS{ dialer: d, proxy: p, - addr: addr, - serverName: serverName, - skipVerify: false, - certFile: certFile, - keyFile: keyFile, + addr: u.Host, + serverName: query.Get("serverName"), + skipVerify: query.Get("skipVerify") == "true", + certFile: query.Get("cert"), + keyFile: query.Get("key"), } - if skipVerify == "true" { - t.skipVerify = true + if t.serverName == "" { + host, port, _ := net.SplitHostPort(t.addr) + if port == "" { + t.addr = net.JoinHostPort(t.addr, "443") + } + t.serverName = host } return t, nil diff --git a/proxy/trojan/trojan.go b/proxy/trojan/trojan.go index 849d907..b55f419 100644 --- a/proxy/trojan/trojan.go +++ b/proxy/trojan/trojan.go @@ -9,7 +9,6 @@ import ( "encoding/hex" "net" "net/url" - "strings" "github.com/nadoo/glider/log" "github.com/nadoo/glider/pool" @@ -37,14 +36,25 @@ func init() { func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) { u, err := url.Parse(s) if err != nil { - log.F("[trojan] parse err: %s", err) + log.F("[trojan] parse url err: %s", err) return nil, err } + query := u.Query() t := &Trojan{ - dialer: d, - proxy: p, - addr: u.Host, + dialer: d, + proxy: p, + addr: u.Host, + skipVerify: query.Get("skipVerify") == "true", + serverName: query.Get("serverName"), + } + + if t.serverName == "" { + host, port, _ := net.SplitHostPort(t.addr) + if port == "" { + t.addr = net.JoinHostPort(t.addr, "443") + } + t.serverName = host } // pass @@ -52,24 +62,12 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) { hash.Write([]byte(u.User.Username())) hex.Encode(t.pass[:], hash.Sum(nil)) - // serverName - colonPos := strings.LastIndex(t.addr, ":") - if colonPos == -1 { - colonPos = len(t.addr) - } - t.serverName = t.addr[:colonPos] - - // skipVerify - if u.Query().Get("skipVerify") == "true" { - t.skipVerify = true - } - t.tlsConfig = &tls.Config{ ServerName: t.serverName, InsecureSkipVerify: t.skipVerify, NextProtos: []string{"http/1.1"}, ClientSessionCache: tls.NewLRUClientSessionCache(64), - MinVersion: tls.VersionTLS10, + MinVersion: tls.VersionTLS12, } return t, nil diff --git a/proxy/vless/addr.go b/proxy/vless/addr.go index 00fa57d..fbf8b4c 100644 --- a/proxy/vless/addr.go +++ b/proxy/vless/addr.go @@ -117,7 +117,7 @@ func ReadAddrString(r io.Reader) (string, error) { return AddrString(atyp, host, port), nil } -// AddrString returns a addr string inf format "host:port". +// AddrString returns a addr string in format of "host:port". func AddrString(atyp Atyp, addr Addr, port Port) string { var host string diff --git a/proxy/ws/ws.go b/proxy/ws/ws.go index 8523d31..39ecba2 100644 --- a/proxy/ws/ws.go +++ b/proxy/ws/ws.go @@ -5,7 +5,6 @@ import ( "errors" "net" "net/url" - "strings" "github.com/nadoo/glider/log" "github.com/nadoo/glider/proxy" @@ -39,26 +38,20 @@ func NewWS(s string, d proxy.Dialer) (*WS, error) { addr = d.Addr() } - host := u.Query().Get("host") - if host == "" { - colonPos := strings.LastIndex(addr, ":") - if colonPos == -1 { - colonPos = len(addr) - } - host = addr[:colonPos] - } - - client, err := NewClient(host, u.Path) - if err != nil { - log.F("[ws] create ws client error: %s", err) - return nil, err - } - p := &WS{ dialer: d, addr: addr, - host: host, - client: client, + host: u.Query().Get("host"), + } + + if p.host == "" { + p.host, _, _ = net.SplitHostPort(addr) + } + + p.client, err = NewClient(p.host, u.Path) + if err != nil { + log.F("[ws] create ws client error: %s", err) + return nil, err } return p, nil