tun: add chain support

This commit is contained in:
ginuerzh 2020-01-10 20:59:31 +08:00
parent 61eec87187
commit 42bf481ded
5 changed files with 142 additions and 57 deletions

View File

@ -187,14 +187,15 @@ func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
return return
} }
var cc net.Conn
if h.options.Chain.IsEmpty() {
raddr, err := net.ResolveUDPAddr("udp", node.Addr) raddr, err := net.ResolveUDPAddr("udp", node.Addr)
if err != nil { if err != nil {
node.MarkDead() node.MarkDead()
log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err) log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
return return
} }
var cc net.Conn
if h.options.Chain.IsEmpty() {
cc, err = net.DialUDP("udp", nil, raddr) cc, err = net.DialUDP("udp", nil, raddr)
if err != nil { if err != nil {
node.MarkDead() node.MarkDead()
@ -208,7 +209,8 @@ func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err) log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
return return
} }
cc = &udpTunnelConn{Conn: cc, raddr: node.Addr}
cc = &udpTunnelConn{Conn: cc, raddr: raddr}
} }
defer cc.Close() defer cc.Close()
@ -763,7 +765,7 @@ func (l *tcpRemoteForwardListener) getSession() (s *muxSession, err error) {
conn.SetDeadline(time.Now().Add(HandshakeTimeout)) conn.SetDeadline(time.Now().Add(HandshakeTimeout))
defer conn.SetDeadline(time.Time{}) defer conn.SetDeadline(time.Time{})
conn, err = socks5Handshake(conn, nil, l.chain.LastNode().User) conn, err = socks5Handshake(conn, userSocks5HandshakeOption(l.chain.LastNode().User))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -798,7 +800,7 @@ func (l *tcpRemoteForwardListener) getSession() (s *muxSession, err error) {
} }
func (l *tcpRemoteForwardListener) waitConnectSOCKS5(conn net.Conn) (net.Conn, error) { func (l *tcpRemoteForwardListener) waitConnectSOCKS5(conn net.Conn) (net.Conn, error) {
conn, err := socks5Handshake(conn, nil, l.chain.LastNode().User) conn, err := socks5Handshake(conn, userSocks5HandshakeOption(l.chain.LastNode().User))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -20,7 +20,7 @@ import (
) )
// Version is the gost version. // Version is the gost version.
const Version = "2.9.0" const Version = "2.9.1-dev"
// Debug is a flag that enables the debug log. // Debug is a flag that enables the debug log.
var Debug bool var Debug bool

View File

@ -1,6 +1,6 @@
name: gost name: gost
type: app type: app
version: '2.9.0' version: '2.9.1'
title: GO Simple Tunnel title: GO Simple Tunnel
summary: A simple security tunnel written in golang summary: A simple security tunnel written in golang
description: | description: |

View File

@ -213,7 +213,9 @@ func (c *socks5Connector) Connect(conn net.Conn, addr string, options ...Connect
if user == nil { if user == nil {
user = c.User user = c.User
} }
cc, err := socks5Handshake(conn, opts.Selector, user) cc, err := socks5Handshake(conn,
selectorSocks5HandshakeOption(opts.Selector),
userSocks5HandshakeOption(user))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -281,7 +283,9 @@ func (c *socks5BindConnector) Connect(conn net.Conn, addr string, options ...Con
if user == nil { if user == nil {
user = c.User user = c.User
} }
cc, err := socks5Handshake(conn, opts.Selector, user) cc, err := socks5Handshake(conn,
selectorSocks5HandshakeOption(opts.Selector),
userSocks5HandshakeOption(user))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -431,7 +435,7 @@ func (tr *socks5MuxBindTransporter) initSession(conn net.Conn, addr string, opts
opts = &HandshakeOptions{} opts = &HandshakeOptions{}
} }
cc, err := socks5Handshake(conn, nil, opts.User) cc, err := socks5Handshake(conn, userSocks5HandshakeOption(opts.User))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -515,7 +519,9 @@ func (c *socks5UDPConnector) Connect(conn net.Conn, addr string, options ...Conn
if user == nil { if user == nil {
user = c.User user = c.User
} }
cc, err := socks5Handshake(conn, opts.Selector, user) cc, err := socks5Handshake(conn,
selectorSocks5HandshakeOption(opts.Selector),
userSocks5HandshakeOption(user))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -594,7 +600,9 @@ func (c *socks5UDPTunConnector) Connect(conn net.Conn, addr string, options ...C
if user == nil { if user == nil {
user = c.User user = c.User
} }
cc, err := socks5Handshake(conn, opts.Selector, user) cc, err := socks5Handshake(conn,
selectorSocks5HandshakeOption(opts.Selector),
userSocks5HandshakeOption(user))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -636,7 +644,7 @@ func (c *socks5UDPTunConnector) Connect(conn net.Conn, addr string, options ...C
} }
log.Logf("[socks5] udp-tun associate on %s OK", baddr) log.Logf("[socks5] udp-tun associate on %s OK", baddr)
return &udpTunnelConn{Conn: conn, raddr: taddr.String()}, nil return &udpTunnelConn{Conn: conn, raddr: taddr}, nil
} }
type socks4Connector struct{} type socks4Connector struct{}
@ -1122,7 +1130,7 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
} }
defer cc.Close() defer cc.Close()
cc, err = socks5Handshake(cc, nil, h.options.Chain.LastNode().User) cc, err = socks5Handshake(cc, userSocks5HandshakeOption(h.options.Chain.LastNode().User))
if err != nil { if err != nil {
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), socksAddr, err) log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), socksAddr, err)
return return
@ -1386,7 +1394,7 @@ func (h *socks5Handler) handleUDPTunnel(conn net.Conn, req *gosocks5.Request) {
} }
defer cc.Close() defer cc.Close()
cc, err = socks5Handshake(cc, nil, h.options.Chain.LastNode().User) cc, err = socks5Handshake(cc, userSocks5HandshakeOption(h.options.Chain.LastNode().User))
if err != nil { if err != nil {
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err) log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), req.Addr, err)
return return
@ -1780,7 +1788,11 @@ func getSOCKS5UDPTunnel(chain *Chain, addr net.Addr) (net.Conn, error) {
conn.SetDeadline(time.Now().Add(HandshakeTimeout)) conn.SetDeadline(time.Now().Add(HandshakeTimeout))
defer conn.SetDeadline(time.Time{}) defer conn.SetDeadline(time.Time{})
cc, err := socks5Handshake(conn, nil, chain.LastNode().User) node := chain.LastNode()
cc, err := socks5Handshake(conn,
userSocks5HandshakeOption(node.User),
noTLSSocks5HandshakeOption(node.GetBool("notls")),
)
if err != nil { if err != nil {
conn.Close() conn.Close()
return nil, err return nil, err
@ -1813,17 +1825,51 @@ func getSOCKS5UDPTunnel(chain *Chain, addr net.Addr) (net.Conn, error) {
return conn, nil return conn, nil
} }
func socks5Handshake(conn net.Conn, selector gosocks5.Selector, user *url.Userinfo) (net.Conn, error) { type socks5HandshakeOptions struct {
selector gosocks5.Selector
user *url.Userinfo
tlsConfig *tls.Config
noTLS bool
}
type socks5HandshakeOption func(opts *socks5HandshakeOptions)
func selectorSocks5HandshakeOption(selector gosocks5.Selector) socks5HandshakeOption {
return func(opts *socks5HandshakeOptions) {
opts.selector = selector
}
}
func userSocks5HandshakeOption(user *url.Userinfo) socks5HandshakeOption {
return func(opts *socks5HandshakeOptions) {
opts.user = user
}
}
func noTLSSocks5HandshakeOption(noTLS bool) socks5HandshakeOption {
return func(opts *socks5HandshakeOptions) {
opts.noTLS = noTLS
}
}
func socks5Handshake(conn net.Conn, opts ...socks5HandshakeOption) (net.Conn, error) {
options := socks5HandshakeOptions{}
for _, opt := range opts {
opt(&options)
}
selector := options.selector
if selector == nil { if selector == nil {
cs := &clientSelector{ cs := &clientSelector{
TLSConfig: &tls.Config{InsecureSkipVerify: true}, TLSConfig: &tls.Config{InsecureSkipVerify: true},
User: user, User: options.user,
} }
cs.AddMethod( cs.AddMethod(
gosocks5.MethodNoAuth, gosocks5.MethodNoAuth,
gosocks5.MethodUserPass, gosocks5.MethodUserPass,
MethodTLS,
) )
if !options.noTLS {
cs.AddMethod(MethodTLS)
}
selector = cs selector = cs
} }
@ -1835,7 +1881,7 @@ func socks5Handshake(conn net.Conn, selector gosocks5.Selector, user *url.Userin
} }
type udpTunnelConn struct { type udpTunnelConn struct {
raddr string raddr net.Addr
net.Conn net.Conn
} }
@ -1859,11 +1905,7 @@ func (c *udpTunnelConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
} }
func (c *udpTunnelConn) Write(b []byte) (n int, err error) { func (c *udpTunnelConn) Write(b []byte) (n int, err error) {
addr, err := net.ResolveUDPAddr("udp", c.raddr) dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(b)), 0, toSocksAddr(c.raddr)), b)
if err != nil {
return
}
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(len(b)), 0, toSocksAddr(addr)), b)
if err = dgram.Write(c.Conn); err != nil { if err = dgram.Write(c.Conn); err != nil {
return return
} }

View File

@ -114,12 +114,14 @@ func (l *tunListener) Close() error {
type tunHandler struct { type tunHandler struct {
options *HandlerOptions options *HandlerOptions
routes sync.Map routes sync.Map
chExit chan struct{}
} }
// TunHandler creates a handler for tun tunnel. // TunHandler creates a handler for tun tunnel.
func TunHandler(opts ...HandlerOption) Handler { func TunHandler(opts ...HandlerOption) Handler {
h := &tunHandler{ h := &tunHandler{
options: &HandlerOptions{}, options: &HandlerOptions{},
chExit: make(chan struct{}, 1),
} }
for _, opt := range opts { for _, opt := range opts {
opt(h.options) opt(h.options)
@ -141,44 +143,76 @@ func (h *tunHandler) Handle(conn net.Conn) {
defer os.Exit(0) defer os.Exit(0)
defer conn.Close() defer conn.Close()
laddr, raddr := h.options.Node.Addr, h.options.Node.Remote
var pc net.PacketConn
var err error var err error
if h.options.TCPMode { var raddr net.Addr
if raddr != "" { if addr := h.options.Node.Remote; addr != "" {
pc, err = tcpraw.Dial("tcp", raddr) raddr, err = net.ResolveUDPAddr("udp", addr)
} else {
pc, err = tcpraw.Listen("tcp", laddr)
}
} else {
addr, _ := net.ResolveUDPAddr("udp", laddr)
pc, err = net.ListenUDP("udp", addr)
}
if err != nil { if err != nil {
log.Logf("[tun] %s: %v", conn.LocalAddr(), err) log.Logf("[tun] %s: remote addr: %v", conn.LocalAddr(), err)
return return
} }
}
var tempDelay time.Duration
for {
err := func() error {
var err error
var pc net.PacketConn
if raddr != nil && !h.options.Chain.IsEmpty() {
var cc net.Conn
cc, err = getSOCKS5UDPTunnel(h.options.Chain, nil)
pc = &udpTunnelConn{Conn: cc, raddr: raddr}
} else {
laddr, _ := net.ResolveUDPAddr("udp", h.options.Node.Addr)
pc, err = net.ListenUDP("udp", laddr)
}
if err != nil {
return err
}
pc, err = h.initTunnelConn(pc)
if err != nil {
return err
}
return h.transportTun(conn, pc, raddr)
}()
if err != nil {
log.Logf("[tun] %s: %v", conn.LocalAddr(), err)
}
select {
case <-h.chExit:
return
default:
}
if err != nil {
if tempDelay == 0 {
tempDelay = 1000 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 6 * time.Second; tempDelay > max {
tempDelay = max
}
time.Sleep(tempDelay)
continue
}
tempDelay = 0
}
}
func (h *tunHandler) initTunnelConn(pc net.PacketConn) (net.PacketConn, error) {
if len(h.options.Users) > 0 && h.options.Users[0] != nil { if len(h.options.Users) > 0 && h.options.Users[0] != nil {
passwd, _ := h.options.Users[0].Password() passwd, _ := h.options.Users[0].Password()
cipher, err := core.PickCipher(h.options.Users[0].Username(), nil, passwd) cipher, err := core.PickCipher(h.options.Users[0].Username(), nil, passwd)
if err != nil { if err != nil {
log.Logf("[tun] %s - %s cipher: %v", conn.LocalAddr(), pc.LocalAddr(), err) return nil, err
return
} }
pc = cipher.PacketConn(pc) pc = cipher.PacketConn(pc)
} }
return pc, nil
var ra net.Addr
if raddr != "" {
ra, err = net.ResolveUDPAddr("udp", raddr)
if err != nil {
log.Logf("[tun] %s - %s: remote addr: %v", conn.LocalAddr(), pc.LocalAddr(), err)
return
}
}
h.transportTun(conn, pc, ra)
} }
func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.Addr) error { func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.Addr) error {
@ -192,6 +226,10 @@ func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.A
n, err := tun.Read(b) n, err := tun.Read(b)
if err != nil { if err != nil {
select {
case h.chExit <- struct{}{}:
default:
}
return err return err
} }
@ -323,6 +361,10 @@ func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.A
} }
if _, err := tun.Write(b[:n]); err != nil { if _, err := tun.Write(b[:n]); err != nil {
select {
case h.chExit <- struct{}{}:
default:
}
return err return err
} }
return nil return nil
@ -339,7 +381,6 @@ func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.A
if err != nil && err == io.EOF { if err != nil && err == io.EOF {
err = nil err = nil
} }
log.Logf("[tun] %s - %s: %v", tun.LocalAddr(), conn.LocalAddr(), err)
return err return err
} }