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

View file

@ -1,15 +1,11 @@
package tproxy
import (
"errors"
"fmt"
"github.com/LiamHaworth/go-tproxy"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"github.com/tobyxdd/hysteria/pkg/utils"
"net"
"strconv"
"time"
)
@ -18,15 +14,13 @@ type TCPTProxy struct {
Transport transport.Transport
ListenAddr *net.TCPAddr
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)
}
func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, 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)) (*TCPTProxy, error) {
tAddr, err := transport.LocalResolveTCPAddr(listen)
if err != nil {
@ -37,7 +31,6 @@ func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen s
Transport: transport,
ListenAddr: tAddr,
Timeout: timeout,
ACLEngine: aclEngine,
ConnFunc: connFunc,
ErrorFunc: errorFunc,
}
@ -60,66 +53,15 @@ func (r *TCPTProxy) ListenAndServe() error {
// 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
// and our RemoteAddr is the local address where the user initiates the connection
host, port, err := utils.SplitHostPort(c.LocalAddr().String())
if err != nil {
return
}
action, arg := acl.ActionProxy, ""
var ipAddr *net.IPAddr
var resErr error
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:
r.ConnFunc(c.RemoteAddr(), c.LocalAddr())
rc, err := r.HyClient.DialTCP(c.LocalAddr().String())
if err != nil {
closeErr = err
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), 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
}
err = utils.PipePairWithTimeout(c, rc, r.Timeout)
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
}()
}
}

View file

@ -4,7 +4,6 @@ package tproxy
import (
"errors"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"net"
@ -14,8 +13,7 @@ import (
type TCPTProxy struct{}
func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, 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)) (*TCPTProxy, error) {
return nil, errors.New("not supported on the current system")
}

View file

@ -3,12 +3,9 @@ package tproxy
import (
"errors"
"github.com/LiamHaworth/go-tproxy"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"github.com/tobyxdd/hysteria/pkg/utils"
"net"
"strconv"
"sync"
"sync/atomic"
"time"
@ -23,14 +20,12 @@ type UDPTProxy struct {
Transport transport.Transport
ListenAddr *net.UDPAddr
Timeout time.Duration
ACLEngine *acl.Engine
ConnFunc func(addr net.Addr)
ErrorFunc func(addr net.Addr, err error)
}
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) {
uAddr, err := transport.LocalResolveUDPAddr(listen)
if err != nil {
@ -41,7 +36,6 @@ func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen s
Transport: transport,
ListenAddr: uAddr,
Timeout: timeout,
ACLEngine: aclEngine,
ConnFunc: connFunc,
ErrorFunc: errorFunc,
}
@ -54,53 +48,9 @@ func NewUDPTProxy(hyClient *core.Client, transport transport.Transport, listen s
type connEntry struct {
LocalConn *net.UDPConn
HyConn core.UDPConn
DirectConn *net.UDPConn
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 {
conn, err := tproxy.ListenUDP("udp", r.ListenAddr)
if err != nil {
@ -120,7 +70,8 @@ func (r *UDPTProxy) ListenAndServe() error {
connMapMutex.RUnlock()
if entry != nil {
// Existing conn
_ = r.sendPacket(entry, dstAddr, buf[:n])
entry.Deadline.Store(time.Now().Add(r.Timeout))
_ = entry.HyConn.WriteTo(buf[:n], dstAddr.String())
} else {
// New
r.ConnFunc(srcAddr)
@ -136,23 +87,12 @@ func (r *UDPTProxy) ListenAndServe() error {
_ = localConn.Close()
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
entry := &connEntry{
LocalConn: localConn,
HyConn: hyConn,
DirectConn: directConn,
}
_ = r.sendPacket(entry, dstAddr, buf[:n])
entry.Deadline.Store(time.Now().Add(r.Timeout))
// Add it to the map
connMapMutex.Lock()
connMap[srcAddr.String()] = entry
@ -168,21 +108,6 @@ func (r *UDPTProxy) ListenAndServe() error {
_, _ = 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
go func() {
for {
@ -192,9 +117,6 @@ func (r *UDPTProxy) ListenAndServe() error {
connMapMutex.Lock()
_ = localConn.Close()
_ = hyConn.Close()
if directConn != nil {
_ = directConn.Close()
}
delete(connMap, srcAddr.String())
connMapMutex.Unlock()
r.ErrorFunc(srcAddr, ErrTimeout)
@ -204,6 +126,7 @@ func (r *UDPTProxy) ListenAndServe() error {
}
}
}()
_ = hyConn.WriteTo(buf[:n], dstAddr.String())
}
}
if err != nil {

View file

@ -4,7 +4,6 @@ package tproxy
import (
"errors"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"net"
@ -16,7 +15,6 @@ var ErrTimeout = errors.New("inactivity timeout")
type UDPTProxy struct{}
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) {
return nil, errors.New("not supported on the current system")
}

View file

@ -5,7 +5,6 @@ package tun
import (
tun2socks "github.com/eycorsican/go-tun2socks/core"
"github.com/eycorsican/go-tun2socks/tun"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"io"
@ -19,9 +18,8 @@ type Server struct {
Timeout time.Duration
TunDev io.ReadWriteCloser
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)
udpConnMap map[tun2socks.UDPConn]*udpConnInfo

View file

@ -4,7 +4,6 @@ package tun
import (
"errors"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"io"
@ -17,9 +16,8 @@ type Server struct {
Timeout time.Duration
TunDev io.ReadWriteCloser
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)
}
@ -30,13 +28,13 @@ const (
func NewServerWithTunDev(hyClient *core.Client, transport transport.Transport,
timeout time.Duration,
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,
timeout time.Duration,
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 {

View file

@ -3,23 +3,14 @@
package tun
import (
"errors"
"fmt"
tun2socks "github.com/eycorsican/go-tun2socks/core"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/utils"
"net"
"strconv"
)
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 {
s.RequestFunc(conn.LocalAddr(), target.String(), action, arg)
s.RequestFunc(conn.LocalAddr(), target.String())
}
var closeErr error
defer func() {
@ -27,20 +18,6 @@ func (s *Server) Handle(conn net.Conn, target *net.TCPAddr) error {
s.ErrorFunc(conn.LocalAddr(), target.String(), closeErr)
}
}()
switch action {
case acl.ActionDirect:
if resErr != nil {
closeErr = resErr
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
@ -48,23 +25,6 @@ func (s *Server) Handle(conn net.Conn, target *net.TCPAddr) error {
}
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
}
}
func (s *Server) relayTCP(clientConn, relayConn net.Conn) {

View file

@ -3,13 +3,9 @@
package tun
import (
"bytes"
"errors"
"fmt"
tun2socks "github.com/eycorsican/go-tun2socks/core"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"io"
"net"
"strconv"
"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 {
action, arg := acl.ActionProxy, ""
var resErr error
if s.ACLEngine != nil {
action, arg, _, resErr = s.ACLEngine.ResolveAndMatch(target.IP.String())
}
if s.RequestFunc != nil {
s.RequestFunc(conn.LocalAddr(), target.String(), action, arg)
s.RequestFunc(conn.LocalAddr(), target.String())
}
var hyConn core.UDPConn
var closeErr error
@ -81,44 +72,10 @@ func (s *Server) Connect(conn tun2socks.UDPConn, target *net.UDPAddr) error {
s.ErrorFunc(conn.LocalAddr(), target.String(), closeErr)
}
}()
switch action {
case acl.ActionDirect:
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
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{
hyConn: hyConn,
target: net.JoinHostPort(target.IP.String(), strconv.Itoa(target.Port)),
@ -154,29 +111,3 @@ func (s *Server) closeUDPConn(conn tun2socks.UDPConn) {
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()
}