tls, trojan: use 443 as default port if not specified

This commit is contained in:
nadoo 2020-10-07 21:06:49 +08:00
parent e7ebcbcde5
commit 8495f16a76
11 changed files with 91 additions and 127 deletions

View File

@ -53,7 +53,7 @@ we can set up local listeners as proxy servers, and forward requests to internet
|ssr | | |√| |client only |ssr | | |√| |client only
|ssh | | |√| |client only |ssh | | |√| |client only
|trojan | | |√|√|client only |trojan | | |√|√|client only
|vless |√|√|√|√|client only |vless |√|√|√|√|client & server
|vmess | | |√| |client only |vmess | | |√| |client only
|redir |√| | | |linux only |redir |√| | | |linux only
|redir6 |√| | | |linux only(ipv6) |redir6 |√| | | |linux only(ipv6)

5
go.mod
View File

@ -11,8 +11,9 @@ require (
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/xtaci/kcp-go/v5 v5.5.17 github.com/xtaci/kcp-go/v5 v5.5.17
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 // indirect
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d // 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 gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
) )

12
go.sum
View File

@ -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-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 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 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-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c/go.mod h1:iQL9McJNjoIa5mjH6nYTCTZXUN6RP+XW3eib7Ya3XcI= 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-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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-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 h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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.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-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-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 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-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-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-20201007032633-0806396f153e h1:FJA2W4BQfMGZ+CD/tiAc39HXecuRsJl3EuczaSUu/Yk=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= 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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View File

@ -18,7 +18,7 @@ import (
) )
var ( var (
version = "0.11.1" version = "0.11.2"
config = parseConfig() config = parseConfig()
) )

View File

@ -4,7 +4,6 @@
package redir package redir
import ( import (
"errors"
"net" "net"
"net/url" "net/url"
"strings" "strings"
@ -13,14 +12,6 @@ import (
"github.com/nadoo/glider/log" "github.com/nadoo/glider/log"
"github.com/nadoo/glider/proxy" "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. // RedirProxy struct.
@ -85,13 +76,16 @@ func (s *RedirProxy) ListenAndServe() {
} }
// Serve serves connections. // Serve serves connections.
func (s *RedirProxy) Serve(c net.Conn) { func (s *RedirProxy) Serve(cc net.Conn) {
defer c.Close() defer cc.Close()
if c, ok := c.(*net.TCPConn); ok { c, ok := cc.(*net.TCPConn)
c.SetKeepAlive(true) if !ok {
log.F("[redir] not a tcp connection, can not chain redir proxy")
return
} }
c.SetKeepAlive(true)
tgt, err := getOrigDst(c, s.ipv6) tgt, err := getOrigDst(c, s.ipv6)
if err != nil { if err != nil {
log.F("[redir] failed to get target address: %v", err) 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. // Get the original destination of a TCP connection.
func getOrigDst(conn net.Conn, ipv6 bool) (socks.Addr, error) { func getOrigDst(c *net.TCPConn, ipv6 bool) (*net.TCPAddr, error) {
c, ok := conn.(*net.TCPConn) rc, err := c.SyscallConn()
if !ok {
return nil, errors.New("only work with TCP connection")
}
f, err := c.File()
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer f.Close() var addr *net.TCPAddr
rc.Control(func(fd uintptr) {
fd := f.Fd() if ipv6 {
addr, err = ipv6_getorigdst(fd)
// The File() call above puts both the original socket fd and the file fd in blocking mode. } else {
// Set the file fd back to non-blocking mode and the original socket fd will become non-blocking as well. addr, err = getorigdst(fd)
// Otherwise blocking I/O will waste OS threads. }
if err := syscall.SetNonblock(int(fd), true); err != nil { })
return nil, err return addr, err
}
if ipv6 {
return getorigdstIPv6(fd)
}
return getorigdst(fd)
} }
// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
func getorigdst(fd uintptr) (socks.Addr, error) { func getorigdst(fd uintptr) (*net.TCPAddr, error) {
raw := syscall.RawSockaddrInet4{} const _SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h
var raw syscall.RawSockaddrInet4
siz := unsafe.Sizeof(raw) 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 return nil, err
} }
var addr net.TCPAddr
addr := make([]byte, 1+net.IPv4len+2) addr.IP = raw.Addr[:]
addr[0] = socks.ATypIP4 port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian
copy(addr[1:1+net.IPv4len], raw.Addr[:]) addr.Port = int(port[0])<<8 | int(port[1])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian return &addr, nil
addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1]
return addr, nil
} }
// Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c // Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
func getorigdstIPv6(fd uintptr) (socks.Addr, error) { // NOTE: I haven't tried yet but it should work since Linux 3.8.
raw := syscall.RawSockaddrInet6{} 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) 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 return nil, err
} }
var addr net.TCPAddr
addr := make([]byte, 1+net.IPv6len+2) addr.IP = raw.Addr[:]
addr[0] = socks.ATypIP6 port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian
copy(addr[1:1+net.IPv6len], raw.Addr[:]) addr.Port = int(port[0])<<8 | int(port[1])
port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian return &addr, nil
addr[1+net.IPv6len], addr[1+net.IPv6len+1] = port[0], port[1]
return addr, nil
} }

View File

@ -5,8 +5,7 @@ import (
"unsafe" "unsafe"
) )
// https://github.com/golang/go/blob/9e6b79a5dfb2f6fe4301ced956419a0da83bd025/src/syscall/syscall_linux_386.go#L196 const GETSOCKOPT = 15 // https://golang.org/src/syscall/syscall_linux_386.go#L183
const GETSOCKOPT = 15
func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error {
var a [6]uintptr var a [6]uintptr

View File

@ -4,7 +4,6 @@ package redir
import "syscall" import "syscall"
// GETSOCKOPT from syscall
const GETSOCKOPT = syscall.SYS_GETSOCKOPT const GETSOCKOPT = syscall.SYS_GETSOCKOPT
func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error {

View File

@ -38,39 +38,27 @@ func init() {
func NewTLS(s string, d proxy.Dialer, p proxy.Proxy) (*TLS, error) { func NewTLS(s string, d proxy.Dialer, p proxy.Proxy) (*TLS, error) {
u, err := url.Parse(s) u, err := url.Parse(s)
if err != nil { if err != nil {
log.F("parse url err: %s", err) log.F("[tls] parse url err: %s", err)
return nil, err return nil, err
} }
addr := u.Host
colonPos := strings.LastIndex(addr, ":")
if colonPos == -1 {
colonPos = len(addr)
}
serverName := addr[:colonPos]
query := u.Query() 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{ t := &TLS{
dialer: d, dialer: d,
proxy: p, proxy: p,
addr: addr, addr: u.Host,
serverName: serverName, serverName: query.Get("serverName"),
skipVerify: false, skipVerify: query.Get("skipVerify") == "true",
certFile: certFile, certFile: query.Get("cert"),
keyFile: keyFile, keyFile: query.Get("key"),
} }
if skipVerify == "true" { if t.serverName == "" {
t.skipVerify = true host, port, _ := net.SplitHostPort(t.addr)
if port == "" {
t.addr = net.JoinHostPort(t.addr, "443")
}
t.serverName = host
} }
return t, nil return t, nil

View File

@ -9,7 +9,6 @@ import (
"encoding/hex" "encoding/hex"
"net" "net"
"net/url" "net/url"
"strings"
"github.com/nadoo/glider/log" "github.com/nadoo/glider/log"
"github.com/nadoo/glider/pool" "github.com/nadoo/glider/pool"
@ -37,14 +36,25 @@ func init() {
func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) { func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
u, err := url.Parse(s) u, err := url.Parse(s)
if err != nil { if err != nil {
log.F("[trojan] parse err: %s", err) log.F("[trojan] parse url err: %s", err)
return nil, err return nil, err
} }
query := u.Query()
t := &Trojan{ t := &Trojan{
dialer: d, dialer: d,
proxy: p, proxy: p,
addr: u.Host, 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 // pass
@ -52,24 +62,12 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
hash.Write([]byte(u.User.Username())) hash.Write([]byte(u.User.Username()))
hex.Encode(t.pass[:], hash.Sum(nil)) 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{ t.tlsConfig = &tls.Config{
ServerName: t.serverName, ServerName: t.serverName,
InsecureSkipVerify: t.skipVerify, InsecureSkipVerify: t.skipVerify,
NextProtos: []string{"http/1.1"}, NextProtos: []string{"http/1.1"},
ClientSessionCache: tls.NewLRUClientSessionCache(64), ClientSessionCache: tls.NewLRUClientSessionCache(64),
MinVersion: tls.VersionTLS10, MinVersion: tls.VersionTLS12,
} }
return t, nil return t, nil

View File

@ -117,7 +117,7 @@ func ReadAddrString(r io.Reader) (string, error) {
return AddrString(atyp, host, port), nil 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 { func AddrString(atyp Atyp, addr Addr, port Port) string {
var host string var host string

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"net" "net"
"net/url" "net/url"
"strings"
"github.com/nadoo/glider/log" "github.com/nadoo/glider/log"
"github.com/nadoo/glider/proxy" "github.com/nadoo/glider/proxy"
@ -39,26 +38,20 @@ func NewWS(s string, d proxy.Dialer) (*WS, error) {
addr = d.Addr() 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{ p := &WS{
dialer: d, dialer: d,
addr: addr, addr: addr,
host: host, host: u.Query().Get("host"),
client: client, }
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 return p, nil