tap: add chain support

This commit is contained in:
ginuerzh 2020-01-10 22:20:41 +08:00
parent 42bf481ded
commit e8d5687d65

View File

@ -15,7 +15,6 @@ import (
"github.com/shadowsocks/go-shadowsocks2/shadowstream" "github.com/shadowsocks/go-shadowsocks2/shadowstream"
"github.com/songgao/water" "github.com/songgao/water"
"github.com/songgao/water/waterutil" "github.com/songgao/water/waterutil"
"github.com/xtaci/tcpraw"
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
) )
@ -472,12 +471,14 @@ func (l *tapListener) Close() error {
type tapHandler struct { type tapHandler struct {
options *HandlerOptions options *HandlerOptions
routes sync.Map routes sync.Map
chExit chan struct{}
} }
// TapHandler creates a handler for tap tunnel. // TapHandler creates a handler for tap tunnel.
func TapHandler(opts ...HandlerOption) Handler { func TapHandler(opts ...HandlerOption) Handler {
h := &tapHandler{ h := &tapHandler{
options: &HandlerOptions{}, options: &HandlerOptions{},
chExit: make(chan struct{}, 1),
} }
for _, opt := range opts { for _, opt := range opts {
opt(h.options) opt(h.options)
@ -499,44 +500,76 @@ func (h *tapHandler) 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("[tap] %s: %v", conn.LocalAddr(), err) log.Logf("[tap] %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.transportTap(conn, pc, raddr)
}()
if err != nil {
log.Logf("[tap] %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 *tapHandler) 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("[tap] %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("[tap] %s - %s: remote addr: %v", conn.LocalAddr(), pc.LocalAddr(), err)
return
}
}
h.transportTap(conn, pc, ra)
} }
func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, raddr net.Addr) error { func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, raddr net.Addr) error {
@ -550,6 +583,10 @@ func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, raddr net.A
n, err := tap.Read(b) n, err := tap.Read(b)
if err != nil { if err != nil {
select {
case h.chExit <- struct{}{}:
default:
}
return err return err
} }
@ -654,6 +691,10 @@ func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, raddr net.A
} }
if _, err := tap.Write(b[:n]); err != nil { if _, err := tap.Write(b[:n]); err != nil {
select {
case h.chExit <- struct{}{}:
default:
}
return err return err
} }
return nil return nil
@ -670,7 +711,6 @@ func (h *tapHandler) transportTap(tap 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("[tap] %s - %s: %v", tap.LocalAddr(), conn.LocalAddr(), err)
return err return err
} }