mirror of
https://github.com/cedar2025/hysteria.git
synced 2025-07-04 18:30:20 +00:00
TCP TProxy implementation, no UDP or ACL support yet
This commit is contained in:
parent
444bb5daec
commit
787ed14c4d
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/tobyxdd/hysteria/pkg/obfs"
|
"github.com/tobyxdd/hysteria/pkg/obfs"
|
||||||
"github.com/tobyxdd/hysteria/pkg/relay"
|
"github.com/tobyxdd/hysteria/pkg/relay"
|
||||||
"github.com/tobyxdd/hysteria/pkg/socks5"
|
"github.com/tobyxdd/hysteria/pkg/socks5"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/tproxy"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@ -239,6 +240,38 @@ func client(config *clientConfig) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(config.TCPTProxy.Listen) > 0 {
|
||||||
|
go func() {
|
||||||
|
rl, err := tproxy.NewTCPTProxy(client, config.TCPTProxy.Listen,
|
||||||
|
time.Duration(config.TCPTProxy.Timeout)*time.Second,
|
||||||
|
func(addr, reqAddr net.Addr) {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"src": addr.String(),
|
||||||
|
"dst": reqAddr.String(),
|
||||||
|
}).Debug("TCP TProxy request")
|
||||||
|
},
|
||||||
|
func(addr, reqAddr net.Addr, err error) {
|
||||||
|
if err != io.EOF {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
"src": addr.String(),
|
||||||
|
"dst": reqAddr.String(),
|
||||||
|
}).Info("TCP TProxy error")
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"src": addr.String(),
|
||||||
|
"dst": reqAddr.String(),
|
||||||
|
}).Debug("TCP TProxy EOF")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("error", err).Fatal("Failed to initialize TCP TProxy")
|
||||||
|
}
|
||||||
|
logrus.WithField("addr", config.TCPTProxy.Listen).Info("TCP TProxy up and running")
|
||||||
|
errChan <- rl.ListenAndServe()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
err = <-errChan
|
err = <-errChan
|
||||||
logrus.WithField("error", err).Fatal("Client shutdown")
|
logrus.WithField("error", err).Fatal("Client shutdown")
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,14 @@ type clientConfig struct {
|
|||||||
Remote string `json:"remote"`
|
Remote string `json:"remote"`
|
||||||
Timeout int `json:"timeout"`
|
Timeout int `json:"timeout"`
|
||||||
} `json:"relay_udp"`
|
} `json:"relay_udp"`
|
||||||
|
TCPTProxy struct {
|
||||||
|
Listen string `json:"listen"`
|
||||||
|
Timeout int `json:"timeout"`
|
||||||
|
} `json:"tproxy_tcp"`
|
||||||
|
UDPTProxy struct {
|
||||||
|
Listen string `json:"listen"`
|
||||||
|
Timeout int `json:"timeout"`
|
||||||
|
} `json:"tproxy_udp"`
|
||||||
ACL string `json:"acl"`
|
ACL string `json:"acl"`
|
||||||
Obfs string `json:"obfs"`
|
Obfs string `json:"obfs"`
|
||||||
Auth []byte `json:"auth"`
|
Auth []byte `json:"auth"`
|
||||||
@ -102,8 +110,9 @@ type clientConfig struct {
|
|||||||
|
|
||||||
func (c *clientConfig) Check() error {
|
func (c *clientConfig) Check() error {
|
||||||
if len(c.SOCKS5.Listen) == 0 && len(c.HTTP.Listen) == 0 &&
|
if len(c.SOCKS5.Listen) == 0 && len(c.HTTP.Listen) == 0 &&
|
||||||
len(c.TCPRelay.Listen) == 0 && len(c.UDPRelay.Listen) == 0 {
|
len(c.TCPRelay.Listen) == 0 && len(c.UDPRelay.Listen) == 0 &&
|
||||||
return errors.New("no SOCKS5, HTTP, TCP relay or UDP relay listen address")
|
len(c.TCPTProxy.Listen) == 0 && len(c.UDPTProxy.Listen) == 0 {
|
||||||
|
return errors.New("no SOCKS5, HTTP, relay or TProxy listen address")
|
||||||
}
|
}
|
||||||
if len(c.TCPRelay.Listen) > 0 && len(c.TCPRelay.Remote) == 0 {
|
if len(c.TCPRelay.Listen) > 0 && len(c.TCPRelay.Remote) == 0 {
|
||||||
return errors.New("no TCP relay remote address")
|
return errors.New("no TCP relay remote address")
|
||||||
@ -123,6 +132,12 @@ func (c *clientConfig) Check() error {
|
|||||||
if c.UDPRelay.Timeout != 0 && c.UDPRelay.Timeout <= 4 {
|
if c.UDPRelay.Timeout != 0 && c.UDPRelay.Timeout <= 4 {
|
||||||
return errors.New("invalid UDP relay timeout")
|
return errors.New("invalid UDP relay timeout")
|
||||||
}
|
}
|
||||||
|
if c.TCPTProxy.Timeout != 0 && c.TCPTProxy.Timeout <= 4 {
|
||||||
|
return errors.New("invalid TCP TProxy timeout")
|
||||||
|
}
|
||||||
|
if c.UDPTProxy.Timeout != 0 && c.UDPTProxy.Timeout <= 4 {
|
||||||
|
return errors.New("invalid UDP TProxy timeout")
|
||||||
|
}
|
||||||
if len(c.Server) == 0 {
|
if len(c.Server) == 0 {
|
||||||
return errors.New("no server address")
|
return errors.New("no server address")
|
||||||
}
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module github.com/tobyxdd/hysteria
|
|||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
|
||||||
github.com/elazarl/goproxy v0.0.0-20200426045556-49ad98f6dac1
|
github.com/elazarl/goproxy v0.0.0-20200426045556-49ad98f6dac1
|
||||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2
|
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
|
2
go.sum
2
go.sum
@ -9,6 +9,8 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
|
|||||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed h1:eqa6queieK8SvoszxCu0WwH7lSVeL4/N/f1JwOMw1G4=
|
||||||
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed/go.mod h1:rA52xkgZwql9LRZXWb2arHEFP6qSR48KY2xOfWzEciQ=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
|
63
pkg/tproxy/tcp_linux.go
Normal file
63
pkg/tproxy/tcp_linux.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package tproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/LiamHaworth/go-tproxy"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/core"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/utils"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TCPTProxy struct {
|
||||||
|
HyClient *core.Client
|
||||||
|
ListenAddr *net.TCPAddr
|
||||||
|
Timeout time.Duration
|
||||||
|
|
||||||
|
ConnFunc func(addr, reqAddr net.Addr)
|
||||||
|
ErrorFunc func(addr, reqAddr net.Addr, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration,
|
||||||
|
connFunc func(addr, reqAddr net.Addr), errorFunc func(addr, reqAddr net.Addr, err error)) (*TCPTProxy, error) {
|
||||||
|
tAddr, err := net.ResolveTCPAddr("tcp", listen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := &TCPTProxy{
|
||||||
|
HyClient: hyClient,
|
||||||
|
ListenAddr: tAddr,
|
||||||
|
Timeout: timeout,
|
||||||
|
ConnFunc: connFunc,
|
||||||
|
ErrorFunc: errorFunc,
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *TCPTProxy) ListenAndServe() error {
|
||||||
|
listener, err := tproxy.ListenTCP("tcp", r.ListenAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
for {
|
||||||
|
c, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
defer c.Close()
|
||||||
|
// 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
|
||||||
|
r.ConnFunc(c.RemoteAddr(), c.LocalAddr())
|
||||||
|
rc, err := r.HyClient.DialTCP(c.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rc.Close()
|
||||||
|
err = utils.PipePairWithTimeout(c, rc, r.Timeout)
|
||||||
|
r.ErrorFunc(c.RemoteAddr(), c.LocalAddr(), err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
21
pkg/tproxy/tcp_stub.go
Normal file
21
pkg/tproxy/tcp_stub.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package tproxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/core"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TCPTProxy struct{}
|
||||||
|
|
||||||
|
func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration,
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *TCPTProxy) ListenAndServe() error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -46,7 +46,7 @@ func Pipe2Way(rw1, rw2 io.ReadWriter, count func(int)) error {
|
|||||||
return <-errChan
|
return <-errChan
|
||||||
}
|
}
|
||||||
|
|
||||||
func PipePairWithTimeout(conn *net.TCPConn, stream io.ReadWriteCloser, timeout time.Duration) error {
|
func PipePairWithTimeout(conn net.Conn, stream io.ReadWriteCloser, timeout time.Duration) error {
|
||||||
errChan := make(chan error, 2)
|
errChan := make(chan error, 2)
|
||||||
// TCP to stream
|
// TCP to stream
|
||||||
go func() {
|
go func() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user