mirror of
https://github.com/cmz0228/hysteria-dev.git
synced 2025-06-09 05:49:54 +00:00
ACL for TCP TProxy
This commit is contained in:
parent
787ed14c4d
commit
70fd2ffc0d
@ -243,9 +243,10 @@ 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, config.TCPTProxy.Listen,
|
rl, err := tproxy.NewTCPTProxy(client, config.TCPTProxy.Listen,
|
||||||
time.Duration(config.TCPTProxy.Timeout)*time.Second,
|
time.Duration(config.TCPTProxy.Timeout)*time.Second, aclEngine,
|
||||||
func(addr, reqAddr net.Addr) {
|
func(addr, reqAddr net.Addr, 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.String(),
|
"dst": reqAddr.String(),
|
||||||
}).Debug("TCP TProxy request")
|
}).Debug("TCP TProxy request")
|
||||||
|
@ -195,7 +195,7 @@ func (c *Client) openStreamWithReconnect() (quic.Session, quic.Stream, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) DialTCP(addr string) (net.Conn, error) {
|
func (c *Client) DialTCP(addr string) (net.Conn, error) {
|
||||||
host, port, err := splitHostPort(addr)
|
host, port, err := utils.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -366,7 +366,7 @@ func (c *quicPktConn) ReadFrom() ([]byte, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *quicPktConn) WriteTo(p []byte, addr string) error {
|
func (c *quicPktConn) WriteTo(p []byte, addr string) error {
|
||||||
host, port, err := splitHostPort(addr)
|
host, port, err := utils.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -384,15 +384,3 @@ func (c *quicPktConn) Close() error {
|
|||||||
c.CloseFunc()
|
c.CloseFunc()
|
||||||
return c.Stream.Close()
|
return c.Stream.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitHostPort(hostport string) (string, uint16, error) {
|
|
||||||
host, port, err := net.SplitHostPort(hostport)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
portUint, err := strconv.ParseUint(port, 10, 16)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
return host, uint16(portUint), err
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,7 @@ package http
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/utils"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -24,11 +25,7 @@ func NewProxyHTTPServer(hyClient *core.Client, idleTimeout time.Duration, aclEng
|
|||||||
proxy.Tr = &http.Transport{
|
proxy.Tr = &http.Transport{
|
||||||
Dial: func(network, addr string) (net.Conn, error) {
|
Dial: func(network, addr string) (net.Conn, error) {
|
||||||
// Parse addr string
|
// Parse addr string
|
||||||
host, port, err := net.SplitHostPort(addr)
|
host, port, err := utils.SplitHostPort(addr)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
portUint, err := strconv.ParseUint(port, 10, 16)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -49,7 +46,7 @@ func NewProxyHTTPServer(hyClient *core.Client, idleTimeout time.Duration, aclEng
|
|||||||
}
|
}
|
||||||
return net.DialTCP(network, nil, &net.TCPAddr{
|
return net.DialTCP(network, nil, &net.TCPAddr{
|
||||||
IP: ipAddr.IP,
|
IP: ipAddr.IP,
|
||||||
Port: int(portUint),
|
Port: int(port),
|
||||||
Zone: ipAddr.Zone,
|
Zone: ipAddr.Zone,
|
||||||
})
|
})
|
||||||
case acl.ActionProxy:
|
case acl.ActionProxy:
|
||||||
@ -57,7 +54,7 @@ func NewProxyHTTPServer(hyClient *core.Client, idleTimeout time.Duration, aclEng
|
|||||||
case acl.ActionBlock:
|
case acl.ActionBlock:
|
||||||
return nil, errors.New("blocked by ACL")
|
return nil, errors.New("blocked by ACL")
|
||||||
case acl.ActionHijack:
|
case acl.ActionHijack:
|
||||||
return net.Dial(network, net.JoinHostPort(arg, port))
|
return net.Dial(network, net.JoinHostPort(arg, strconv.Itoa(int(port))))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown action %d", action)
|
return nil, fmt.Errorf("unknown action %d", action)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
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/utils"
|
"github.com/tobyxdd/hysteria/pkg/utils"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,13 +16,15 @@ type TCPTProxy struct {
|
|||||||
HyClient *core.Client
|
HyClient *core.Client
|
||||||
ListenAddr *net.TCPAddr
|
ListenAddr *net.TCPAddr
|
||||||
Timeout time.Duration
|
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)
|
ErrorFunc func(addr, reqAddr net.Addr, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration,
|
func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration, aclEngine *acl.Engine,
|
||||||
connFunc func(addr, reqAddr net.Addr), errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) {
|
connFunc func(addr, reqAddr net.Addr, action acl.Action, arg string),
|
||||||
|
errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) {
|
||||||
tAddr, err := net.ResolveTCPAddr("tcp", listen)
|
tAddr, err := net.ResolveTCPAddr("tcp", listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -27,6 +33,7 @@ func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration,
|
|||||||
HyClient: hyClient,
|
HyClient: hyClient,
|
||||||
ListenAddr: tAddr,
|
ListenAddr: tAddr,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
|
ACLEngine: aclEngine,
|
||||||
ConnFunc: connFunc,
|
ConnFunc: connFunc,
|
||||||
ErrorFunc: errorFunc,
|
ErrorFunc: errorFunc,
|
||||||
}
|
}
|
||||||
@ -49,15 +56,66 @@ 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
|
||||||
r.ConnFunc(c.RemoteAddr(), c.LocalAddr())
|
host, port, err := utils.SplitHostPort(c.LocalAddr().String())
|
||||||
rc, err := r.HyClient.DialTCP(c.LocalAddr().String())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
|
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 := net.DialTCP("tcp", nil, &net.TCPAddr{
|
||||||
|
IP: ipAddr.IP,
|
||||||
|
Port: int(port),
|
||||||
|
Zone: ipAddr.Zone,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
closeErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
err = utils.PipePairWithTimeout(c, rc, r.Timeout)
|
closeErr = utils.PipePairWithTimeout(c, rc, r.Timeout)
|
||||||
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
|
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 := net.Dial("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
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ package tproxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/acl"
|
||||||
"github.com/tobyxdd/hysteria/pkg/core"
|
"github.com/tobyxdd/hysteria/pkg/core"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
@ -11,8 +12,9 @@ import (
|
|||||||
|
|
||||||
type TCPTProxy struct{}
|
type TCPTProxy struct{}
|
||||||
|
|
||||||
func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration,
|
func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration, aclEngine *acl.Engine,
|
||||||
connFunc func(addr, reqAddr net.Addr), errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) {
|
connFunc func(addr, reqAddr net.Addr, action acl.Action, arg string),
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
pkg/utils/misc.go
Normal file
18
pkg/utils/misc.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SplitHostPort(hostport string) (string, uint16, error) {
|
||||||
|
host, port, err := net.SplitHostPort(hostport)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
portUint, err := strconv.ParseUint(port, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
return host, uint16(portUint), err
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user