feat: remove ACL from TPROXY & TUN

This commit is contained in:
Toby 2021-11-24 23:04:34 -08:00
parent a1515b1943
commit 6eb49eef12
9 changed files with 40 additions and 295 deletions

View file

@ -204,12 +204,10 @@ func client(config *clientConfig) {
if err != nil { if err != nil {
logrus.WithField("error", err).Fatal("Failed to initialize TUN server") logrus.WithField("error", err).Fatal("Failed to initialize TUN server")
} }
tunServer.ACLEngine = aclEngine tunServer.RequestFunc = func(addr net.Addr, reqAddr string) {
tunServer.RequestFunc = func(addr net.Addr, reqAddr string, action acl.Action, arg string) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"action": actionToString(action, arg), "src": addr.String(),
"src": addr.String(), "dst": reqAddr,
"dst": reqAddr,
}).Debugf("TUN %s request", strings.ToUpper(addr.Network())) }).Debugf("TUN %s request", strings.ToUpper(addr.Network()))
} }
tunServer.ErrorFunc = func(addr net.Addr, reqAddr string, err error) { tunServer.ErrorFunc = func(addr net.Addr, reqAddr string, err error) {
@ -305,12 +303,11 @@ func client(config *clientConfig) {
if len(config.TCPTProxy.Listen) > 0 { if len(config.TCPTProxy.Listen) > 0 {
go func() { go func() {
rl, err := tproxy.NewTCPTProxy(client, transport.DefaultTransport, rl, err := tproxy.NewTCPTProxy(client, transport.DefaultTransport,
config.TCPTProxy.Listen, time.Duration(config.TCPTProxy.Timeout)*time.Second, aclEngine, config.TCPTProxy.Listen, time.Duration(config.TCPTProxy.Timeout)*time.Second,
func(addr, reqAddr net.Addr, action acl.Action, arg string) { func(addr, reqAddr net.Addr) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"action": actionToString(action, arg), "src": addr.String(),
"src": addr.String(), "dst": reqAddr.String(),
"dst": reqAddr.String(),
}).Debug("TCP TProxy request") }).Debug("TCP TProxy request")
}, },
func(addr, reqAddr net.Addr, err error) { func(addr, reqAddr net.Addr, err error) {
@ -338,7 +335,7 @@ func client(config *clientConfig) {
if len(config.UDPTProxy.Listen) > 0 { if len(config.UDPTProxy.Listen) > 0 {
go func() { go func() {
rl, err := tproxy.NewUDPTProxy(client, transport.DefaultTransport, rl, err := tproxy.NewUDPTProxy(client, transport.DefaultTransport,
config.UDPTProxy.Listen, time.Duration(config.UDPTProxy.Timeout)*time.Second, aclEngine, config.UDPTProxy.Listen, time.Duration(config.UDPTProxy.Timeout)*time.Second,
func(addr net.Addr) { func(addr net.Addr) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"src": addr.String(), "src": addr.String(),

View file

@ -1,15 +1,11 @@
package tproxy package tproxy
import ( import (
"errors"
"fmt"
"github.com/LiamHaworth/go-tproxy" "github.com/LiamHaworth/go-tproxy"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"github.com/tobyxdd/hysteria/pkg/utils" "github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"strconv"
"time" "time"
) )
@ -18,15 +14,13 @@ type TCPTProxy struct {
Transport transport.Transport Transport transport.Transport
ListenAddr *net.TCPAddr ListenAddr *net.TCPAddr
Timeout time.Duration Timeout time.Duration
ACLEngine *acl.Engine
ConnFunc func(addr, reqAddr net.Addr, action acl.Action, arg string) ConnFunc func(addr, reqAddr net.Addr)
ErrorFunc func(addr, reqAddr net.Addr, err error) ErrorFunc func(addr, reqAddr net.Addr, err error)
} }
func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration, func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration,
aclEngine *acl.Engine, connFunc func(addr, reqAddr net.Addr),
connFunc func(addr, reqAddr net.Addr, action acl.Action, arg string),
errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) { errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) {
tAddr, err := transport.LocalResolveTCPAddr(listen) tAddr, err := transport.LocalResolveTCPAddr(listen)
if err != nil { if err != nil {
@ -37,7 +31,6 @@ func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen s
Transport: transport, Transport: transport,
ListenAddr: tAddr, ListenAddr: tAddr,
Timeout: timeout, Timeout: timeout,
ACLEngine: aclEngine,
ConnFunc: connFunc, ConnFunc: connFunc,
ErrorFunc: errorFunc, ErrorFunc: errorFunc,
} }
@ -60,66 +53,15 @@ func (r *TCPTProxy) ListenAndServe() error {
// Under TPROXY mode, we are effectively acting as the remote server // Under TPROXY mode, we are effectively acting as the remote server
// So our LocalAddr is actually the target to which the user is trying to connect // So our LocalAddr is actually the target to which the user is trying to connect
// and our RemoteAddr is the local address where the user initiates the connection // and our RemoteAddr is the local address where the user initiates the connection
host, port, err := utils.SplitHostPort(c.LocalAddr().String()) r.ConnFunc(c.RemoteAddr(), c.LocalAddr())
rc, err := r.HyClient.DialTCP(c.LocalAddr().String())
if err != nil { if err != nil {
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
return return
} }
action, arg := acl.ActionProxy, "" defer rc.Close()
var ipAddr *net.IPAddr err = utils.PipePairWithTimeout(c, rc, r.Timeout)
var resErr error r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
if r.ACLEngine != nil {
action, arg, ipAddr, resErr = r.ACLEngine.ResolveAndMatch(host)
// Doesn't always matter if the resolution fails, as we may send it through HyClient
}
r.ConnFunc(c.RemoteAddr(), c.LocalAddr(), action, arg)
var closeErr error
defer func() {
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), closeErr)
}()
// Handle according to the action
switch action {
case acl.ActionDirect:
if resErr != nil {
closeErr = resErr
return
}
rc, err := r.Transport.LocalDialTCP(nil, &net.TCPAddr{
IP: ipAddr.IP,
Port: int(port),
Zone: ipAddr.Zone,
})
if err != nil {
closeErr = err
return
}
defer rc.Close()
closeErr = utils.PipePairWithTimeout(c, rc, r.Timeout)
return
case acl.ActionProxy:
rc, err := r.HyClient.DialTCP(c.LocalAddr().String())
if err != nil {
closeErr = err
return
}
defer rc.Close()
closeErr = utils.PipePairWithTimeout(c, rc, r.Timeout)
return
case acl.ActionBlock:
closeErr = errors.New("blocked in ACL")
return
case acl.ActionHijack:
rc, err := r.Transport.LocalDial("tcp", net.JoinHostPort(arg, strconv.Itoa(int(port))))
if err != nil {
closeErr = err
return
}
defer rc.Close()
closeErr = utils.PipePairWithTimeout(c, rc, r.Timeout)
return
default:
closeErr = fmt.Errorf("unknown action %d", action)
return
}
}() }()
} }
} }

View file

@ -4,7 +4,6 @@ package tproxy
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
@ -14,8 +13,7 @@ import (
type TCPTProxy struct{} type TCPTProxy struct{}
func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration, func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration,
aclEngine *acl.Engine, connFunc func(addr, reqAddr net.Addr),
connFunc func(addr, reqAddr net.Addr, action acl.Action, arg string),
errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) { errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) {
return nil, errors.New("not supported on the current system") return nil, errors.New("not supported on the current system")
} }

View file

@ -3,12 +3,9 @@ package tproxy
import ( import (
"errors" "errors"
"github.com/LiamHaworth/go-tproxy" "github.com/LiamHaworth/go-tproxy"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -23,14 +20,12 @@ type UDPTProxy struct {
Transport transport.Transport Transport transport.Transport
ListenAddr *net.UDPAddr ListenAddr *net.UDPAddr
Timeout time.Duration Timeout time.Duration
ACLEngine *acl.Engine
ConnFunc func(addr net.Addr) ConnFunc func(addr net.Addr)
ErrorFunc func(addr net.Addr, err error) ErrorFunc func(addr net.Addr, err error)
} }
func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration, func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration,
aclEngine *acl.Engine,
connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*UDPTProxy, error) { connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*UDPTProxy, error) {
uAddr, err := transport.LocalResolveUDPAddr(listen) uAddr, err := transport.LocalResolveUDPAddr(listen)
if err != nil { if err != nil {
@ -41,7 +36,6 @@ func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen s
Transport: transport, Transport: transport,
ListenAddr: uAddr, ListenAddr: uAddr,
Timeout: timeout, Timeout: timeout,
ACLEngine: aclEngine,
ConnFunc: connFunc, ConnFunc: connFunc,
ErrorFunc: errorFunc, ErrorFunc: errorFunc,
} }
@ -52,53 +46,9 @@ func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen s
} }
type connEntry struct { type connEntry struct {
LocalConn *net.UDPConn LocalConn *net.UDPConn
HyConn core.UDPConn HyConn core.UDPConn
DirectConn *net.UDPConn Deadline atomic.Value
Deadline atomic.Value
}
func (r *UDPTProxy) sendPacket(entry *connEntry, dstAddr *net.UDPAddr, data []byte) error {
entry.Deadline.Store(time.Now().Add(r.Timeout))
host, port, err := utils.SplitHostPort(dstAddr.String())
if err != nil {
return err
}
action, arg := acl.ActionProxy, ""
var ipAddr *net.IPAddr
var resErr error
if r.ACLEngine != nil && entry.DirectConn != nil {
action, arg, ipAddr, resErr = r.ACLEngine.ResolveAndMatch(host)
// Doesn't always matter if the resolution fails, as we may send it through HyClient
}
switch action {
case acl.ActionDirect:
if resErr != nil {
return resErr
}
_, err = entry.DirectConn.WriteToUDP(data, &net.UDPAddr{
IP: ipAddr.IP,
Port: int(port),
Zone: ipAddr.Zone,
})
return err
case acl.ActionProxy:
return entry.HyConn.WriteTo(data, dstAddr.String())
case acl.ActionBlock:
// Do nothing
return nil
case acl.ActionHijack:
hijackAddr := net.JoinHostPort(arg, strconv.Itoa(int(port)))
rAddr, err := r.Transport.LocalResolveUDPAddr(hijackAddr)
if err != nil {
return err
}
_, err = entry.DirectConn.WriteToUDP(data, rAddr)
return err
default:
// Do nothing
return nil
}
} }
func (r *UDPTProxy) ListenAndServe() error { func (r *UDPTProxy) ListenAndServe() error {
@ -120,7 +70,8 @@ func (r *UDPTProxy) ListenAndServe() error {
connMapMutex.RUnlock() connMapMutex.RUnlock()
if entry != nil { if entry != nil {
// Existing conn // Existing conn
_ = r.sendPacket(entry, dstAddr, buf[:n]) entry.Deadline.Store(time.Now().Add(r.Timeout))
_ = entry.HyConn.WriteTo(buf[:n], dstAddr.String())
} else { } else {
// New // New
r.ConnFunc(srcAddr) r.ConnFunc(srcAddr)
@ -136,23 +87,12 @@ func (r *UDPTProxy) ListenAndServe() error {
_ = localConn.Close() _ = localConn.Close()
continue continue
} }
var directConn *net.UDPConn
if r.ACLEngine != nil {
directConn, err = r.Transport.LocalListenUDP(nil)
if err != nil {
r.ErrorFunc(srcAddr, err)
_ = localConn.Close()
_ = hyConn.Close()
continue
}
}
// Send // Send
entry := &connEntry{ entry := &connEntry{
LocalConn: localConn, LocalConn: localConn,
HyConn: hyConn, HyConn: hyConn,
DirectConn: directConn,
} }
_ = r.sendPacket(entry, dstAddr, buf[:n]) entry.Deadline.Store(time.Now().Add(r.Timeout))
// Add it to the map // Add it to the map
connMapMutex.Lock() connMapMutex.Lock()
connMap[srcAddr.String()] = entry connMap[srcAddr.String()] = entry
@ -168,21 +108,6 @@ func (r *UDPTProxy) ListenAndServe() error {
_, _ = localConn.Write(bs) _, _ = localConn.Write(bs)
} }
}() }()
if directConn != nil {
go func() {
buf := make([]byte, udpBufferSize)
for {
n, _, err := directConn.ReadFrom(buf)
if n > 0 {
entry.Deadline.Store(time.Now().Add(r.Timeout))
_, _ = localConn.Write(buf[:n])
}
if err != nil {
break
}
}
}()
}
// Timeout cleanup routine // Timeout cleanup routine
go func() { go func() {
for { for {
@ -192,9 +117,6 @@ func (r *UDPTProxy) ListenAndServe() error {
connMapMutex.Lock() connMapMutex.Lock()
_ = localConn.Close() _ = localConn.Close()
_ = hyConn.Close() _ = hyConn.Close()
if directConn != nil {
_ = directConn.Close()
}
delete(connMap, srcAddr.String()) delete(connMap, srcAddr.String())
connMapMutex.Unlock() connMapMutex.Unlock()
r.ErrorFunc(srcAddr, ErrTimeout) r.ErrorFunc(srcAddr, ErrTimeout)
@ -204,6 +126,7 @@ func (r *UDPTProxy) ListenAndServe() error {
} }
} }
}() }()
_ = hyConn.WriteTo(buf[:n], dstAddr.String())
} }
} }
if err != nil { if err != nil {

View file

@ -4,7 +4,6 @@ package tproxy
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
@ -16,7 +15,6 @@ var ErrTimeout = errors.New("inactivity timeout")
type UDPTProxy struct{} type UDPTProxy struct{}
func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration, func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration,
aclEngine *acl.Engine,
connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*UDPTProxy, error) { connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*UDPTProxy, error) {
return nil, errors.New("not supported on the current system") return nil, errors.New("not supported on the current system")
} }

View file

@ -5,7 +5,6 @@ package tun
import ( import (
tun2socks "github.com/eycorsican/go-tun2socks/core" tun2socks "github.com/eycorsican/go-tun2socks/core"
"github.com/eycorsican/go-tun2socks/tun" "github.com/eycorsican/go-tun2socks/tun"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"io" "io"
@ -19,9 +18,8 @@ type Server struct {
Timeout time.Duration Timeout time.Duration
TunDev io.ReadWriteCloser TunDev io.ReadWriteCloser
Transport transport.Transport Transport transport.Transport
ACLEngine *acl.Engine
RequestFunc func(addr net.Addr, reqAddr string, action acl.Action, arg string) RequestFunc func(addr net.Addr, reqAddr string)
ErrorFunc func(addr net.Addr, reqAddr string, err error) ErrorFunc func(addr net.Addr, reqAddr string, err error)
udpConnMap map[tun2socks.UDPConn]*udpConnInfo udpConnMap map[tun2socks.UDPConn]*udpConnInfo

View file

@ -4,7 +4,6 @@ package tun
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"io" "io"
@ -17,9 +16,8 @@ type Server struct {
Timeout time.Duration Timeout time.Duration
TunDev io.ReadWriteCloser TunDev io.ReadWriteCloser
Transport transport.Transport Transport transport.Transport
ACLEngine *acl.Engine
RequestFunc func(addr net.Addr, reqAddr string, action acl.Action, arg string) RequestFunc func(addr net.Addr, reqAddr string)
ErrorFunc func(addr net.Addr, reqAddr string, err error) ErrorFunc func(addr net.Addr, reqAddr string, err error)
} }
@ -30,13 +28,13 @@ const (
func NewServerWithTunDev(hyClient *core.Client, transport transport.Transport, func NewServerWithTunDev(hyClient *core.Client, transport transport.Transport,
timeout time.Duration, timeout time.Duration,
tunDev io.ReadWriteCloser) (*Server, error) { tunDev io.ReadWriteCloser) (*Server, error) {
return nil, errors.New("TUN mode is not available when build with CGO_ENABLED=0") return nil, errors.New("TUN mode is not available in this build")
} }
func NewServer(hyClient *core.Client, transport transport.Transport, func NewServer(hyClient *core.Client, transport transport.Transport,
timeout time.Duration, timeout time.Duration,
name, address, gateway, mask string, dnsServers []string, persist bool) (*Server, error) { name, address, gateway, mask string, dnsServers []string, persist bool) (*Server, error) {
return nil, errors.New("TUN mode is not available when build with CGO_ENABLED=0") return nil, errors.New("TUN mode is not available in this build")
} }
func (s *Server) ListenAndServe() error { func (s *Server) ListenAndServe() error {

View file

@ -3,23 +3,14 @@
package tun package tun
import ( import (
"errors"
"fmt"
tun2socks "github.com/eycorsican/go-tun2socks/core" tun2socks "github.com/eycorsican/go-tun2socks/core"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/utils" "github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"strconv"
) )
func (s *Server) Handle(conn net.Conn, target *net.TCPAddr) error { func (s *Server) Handle(conn net.Conn, target *net.TCPAddr) error {
action, arg := acl.ActionProxy, ""
var resErr error
if s.ACLEngine != nil {
action, arg, _, resErr = s.ACLEngine.ResolveAndMatch(target.IP.String())
}
if s.RequestFunc != nil { if s.RequestFunc != nil {
s.RequestFunc(conn.LocalAddr(), target.String(), action, arg) s.RequestFunc(conn.LocalAddr(), target.String())
} }
var closeErr error var closeErr error
defer func() { defer func() {
@ -27,44 +18,13 @@ func (s *Server) Handle(conn net.Conn, target *net.TCPAddr) error {
s.ErrorFunc(conn.LocalAddr(), target.String(), closeErr) s.ErrorFunc(conn.LocalAddr(), target.String(), closeErr)
} }
}() }()
switch action { rc, err := s.HyClient.DialTCP(target.String())
case acl.ActionDirect: if err != nil {
if resErr != nil { closeErr = err
closeErr = resErr return err
return resErr
}
rc, err := s.Transport.LocalDialTCP(nil, target)
if err != nil {
closeErr = err
return err
}
go s.relayTCP(conn, rc)
return nil
case acl.ActionProxy:
rc, err := s.HyClient.DialTCP(target.String())
if err != nil {
closeErr = err
return err
}
go s.relayTCP(conn, rc)
return nil
case acl.ActionBlock:
closeErr = errors.New("blocked in ACL")
// caller will abort the connection when err != nil
return closeErr
case acl.ActionHijack:
rc, err := s.Transport.LocalDial("tcp", net.JoinHostPort(arg, strconv.Itoa(target.Port)))
if err != nil {
closeErr = err
return err
}
go s.relayTCP(conn, rc)
return nil
default:
closeErr = fmt.Errorf("unknown action %d", action)
// caller will abort the connection when err != nil
return closeErr
} }
go s.relayTCP(conn, rc)
return nil
} }
func (s *Server) relayTCP(clientConn, relayConn net.Conn) { func (s *Server) relayTCP(clientConn, relayConn net.Conn) {

View file

@ -3,13 +3,9 @@
package tun package tun
import ( import (
"bytes"
"errors" "errors"
"fmt"
tun2socks "github.com/eycorsican/go-tun2socks/core" tun2socks "github.com/eycorsican/go-tun2socks/core"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"io"
"net" "net"
"strconv" "strconv"
"sync/atomic" "sync/atomic"
@ -66,13 +62,8 @@ func (s *Server) fetchUDPInput(conn tun2socks.UDPConn, ci *udpConnInfo) {
} }
func (s *Server) Connect(conn tun2socks.UDPConn, target *net.UDPAddr) error { func (s *Server) Connect(conn tun2socks.UDPConn, target *net.UDPAddr) error {
action, arg := acl.ActionProxy, ""
var resErr error
if s.ACLEngine != nil {
action, arg, _, resErr = s.ACLEngine.ResolveAndMatch(target.IP.String())
}
if s.RequestFunc != nil { if s.RequestFunc != nil {
s.RequestFunc(conn.LocalAddr(), target.String(), action, arg) s.RequestFunc(conn.LocalAddr(), target.String())
} }
var hyConn core.UDPConn var hyConn core.UDPConn
var closeErr error var closeErr error
@ -81,43 +72,9 @@ func (s *Server) Connect(conn tun2socks.UDPConn, target *net.UDPAddr) error {
s.ErrorFunc(conn.LocalAddr(), target.String(), closeErr) s.ErrorFunc(conn.LocalAddr(), target.String(), closeErr)
} }
}() }()
switch action { hyConn, closeErr = s.HyClient.DialUDP()
case acl.ActionDirect: if closeErr != nil {
if resErr != nil {
closeErr = resErr
return resErr
}
var relayConn net.Conn
relayConn, closeErr = s.Transport.LocalDial("udp", target.String())
if closeErr != nil {
return closeErr
}
hyConn = &delegatedUDPConn{
underlayConn: relayConn,
delegatedRemoteAddr: target.String(),
}
case acl.ActionProxy:
hyConn, closeErr = s.HyClient.DialUDP()
if closeErr != nil {
return closeErr
}
case acl.ActionBlock:
closeErr = errors.New("blocked in ACL")
return closeErr return closeErr
case acl.ActionHijack:
hijackAddr := net.JoinHostPort(arg, strconv.Itoa(target.Port))
var relayConn net.Conn
relayConn, closeErr = s.Transport.LocalDial("udp", hijackAddr)
if closeErr != nil {
return closeErr
}
hyConn = &delegatedUDPConn{
underlayConn: relayConn,
delegatedRemoteAddr: target.String(),
}
default:
closeErr = fmt.Errorf("unknown action %d", action)
return nil
} }
ci := udpConnInfo{ ci := udpConnInfo{
hyConn: hyConn, hyConn: hyConn,
@ -154,29 +111,3 @@ func (s *Server) closeUDPConn(conn tun2socks.UDPConn) {
delete(s.udpConnMap, conn) delete(s.udpConnMap, conn)
} }
} }
type delegatedUDPConn struct {
underlayConn net.Conn
delegatedRemoteAddr string
}
func (c *delegatedUDPConn) ReadFrom() (bs []byte, addr string, err error) {
buf := make([]byte, udpBufferSize)
n, err := c.underlayConn.Read(buf)
if n > 0 {
bs = append(bs, buf[0:n]...)
}
if err != nil || err == io.EOF {
addr = c.delegatedRemoteAddr
}
return
}
func (c *delegatedUDPConn) WriteTo(bs []byte, addr string) error {
_, err := io.Copy(c.underlayConn, bytes.NewReader(bs))
return err
}
func (c *delegatedUDPConn) Close() error {
return c.underlayConn.Close()
}