feat: transport refactorization

This commit is contained in:
Toby
2022-01-23 17:00:02 -08:00
parent 013e44a9c5
commit 841810d6ca
26 changed files with 381 additions and 325 deletions

View File

@@ -38,34 +38,34 @@ jobs:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2.4.0 uses: actions/checkout@v2.4.0
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@v1
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file. # By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file. # Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main # queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v1 uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl # 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project # and modify them (or add more) to build your code if your project
# uses a compiled language # uses a compiled language
#- run: | #- run: |
# make bootstrap # make bootstrap
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@v1

View File

@@ -26,7 +26,7 @@ jobs:
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v1.12.0 uses: docker/login-action@v1.12.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}

View File

@@ -94,13 +94,14 @@ func client(config *clientConfig) {
var aclEngine *acl.Engine var aclEngine *acl.Engine
if len(config.ACL) > 0 { if len(config.ACL) > 0 {
var err error var err error
aclEngine, err = acl.LoadFromFile(config.ACL, transport.DefaultTransport, func() (*geoip2.Reader, error) { aclEngine, err = acl.LoadFromFile(config.ACL, transport.DefaultClientTransport.ResolveIPAddr,
if len(config.MMDB) > 0 { func() (*geoip2.Reader, error) {
return loadMMDBReader(config.MMDB) if len(config.MMDB) > 0 {
} else { return loadMMDBReader(config.MMDB)
return loadMMDBReader(DefaultMMDBFilename) } else {
} return loadMMDBReader(DefaultMMDBFilename)
}) }
})
if err != nil { if err != nil {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"error": err, "error": err,
@@ -110,7 +111,7 @@ func client(config *clientConfig) {
} }
// Client // Client
client, err := core.NewClient(config.Server, config.Protocol, auth, tlsConfig, quicConfig, client, err := core.NewClient(config.Server, config.Protocol, auth, tlsConfig, quicConfig,
transport.DefaultTransport, uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps, transport.DefaultClientTransport, uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps,
func(refBPS uint64) congestion.CongestionControl { func(refBPS uint64) congestion.CongestionControl {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS)) return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
}, obfuscator) }, obfuscator)
@@ -130,8 +131,8 @@ func client(config *clientConfig) {
return config.SOCKS5.User == user && config.SOCKS5.Password == password return config.SOCKS5.User == user && config.SOCKS5.Password == password
} }
} }
socks5server, err := socks5.NewServer(client, transport.DefaultTransport, config.SOCKS5.Listen, authFunc, socks5server, err := socks5.NewServer(client, transport.DefaultClientTransport, config.SOCKS5.Listen,
time.Duration(config.SOCKS5.Timeout)*time.Second, aclEngine, config.SOCKS5.DisableUDP, authFunc, time.Duration(config.SOCKS5.Timeout)*time.Second, aclEngine, config.SOCKS5.DisableUDP,
func(addr net.Addr, reqAddr string, action acl.Action, arg string) { func(addr net.Addr, reqAddr string, action acl.Action, arg string) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"action": actionToString(action, arg), "action": actionToString(action, arg),
@@ -186,7 +187,7 @@ func client(config *clientConfig) {
return config.HTTP.User == user && config.HTTP.Password == password return config.HTTP.User == user && config.HTTP.Password == password
} }
} }
proxy, err := hyHTTP.NewProxyHTTPServer(client, transport.DefaultTransport, proxy, err := hyHTTP.NewProxyHTTPServer(client, transport.DefaultClientTransport,
time.Duration(config.HTTP.Timeout)*time.Second, aclEngine, time.Duration(config.HTTP.Timeout)*time.Second, aclEngine,
func(reqAddr string, action acl.Action, arg string) { func(reqAddr string, action acl.Action, arg string) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
@@ -214,8 +215,7 @@ func client(config *clientConfig) {
if timeout == 0 { if timeout == 0 {
timeout = 300 * time.Second timeout = 300 * time.Second
} }
tunServer, err := tun.NewServer(client, transport.DefaultTransport, tunServer, err := tun.NewServer(client, time.Duration(config.TUN.Timeout)*time.Second,
time.Duration(config.TUN.Timeout)*time.Second,
config.TUN.Name, config.TUN.Address, config.TUN.Gateway, config.TUN.Mask, config.TUN.DNS, config.TUN.Persist) config.TUN.Name, config.TUN.Address, config.TUN.Gateway, config.TUN.Mask, config.TUN.DNS, config.TUN.Persist)
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")
@@ -267,8 +267,7 @@ func client(config *clientConfig) {
if len(config.TCPRelays) > 0 { if len(config.TCPRelays) > 0 {
for _, tcpr := range config.TCPRelays { for _, tcpr := range config.TCPRelays {
go func(tcpr Relay) { go func(tcpr Relay) {
rl, err := relay.NewTCPRelay(client, transport.DefaultTransport, rl, err := relay.NewTCPRelay(client, tcpr.Listen, tcpr.Remote,
tcpr.Listen, tcpr.Remote,
time.Duration(tcpr.Timeout)*time.Second, time.Duration(tcpr.Timeout)*time.Second,
func(addr net.Addr) { func(addr net.Addr) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
@@ -307,8 +306,7 @@ func client(config *clientConfig) {
if len(config.UDPRelays) > 0 { if len(config.UDPRelays) > 0 {
for _, udpr := range config.UDPRelays { for _, udpr := range config.UDPRelays {
go func(udpr Relay) { go func(udpr Relay) {
rl, err := relay.NewUDPRelay(client, transport.DefaultTransport, rl, err := relay.NewUDPRelay(client, udpr.Listen, udpr.Remote,
udpr.Listen, udpr.Remote,
time.Duration(udpr.Timeout)*time.Second, time.Duration(udpr.Timeout)*time.Second,
func(addr net.Addr) { func(addr net.Addr) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
@@ -338,8 +336,8 @@ 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, config.TCPTProxy.Listen,
config.TCPTProxy.Listen, time.Duration(config.TCPTProxy.Timeout)*time.Second, time.Duration(config.TCPTProxy.Timeout)*time.Second,
func(addr, reqAddr net.Addr) { func(addr, reqAddr net.Addr) {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"src": addr.String(), "src": addr.String(),
@@ -370,8 +368,8 @@ 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, config.UDPTProxy.Listen,
config.UDPTProxy.Listen, time.Duration(config.UDPTProxy.Timeout)*time.Second, 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(),

21
cmd/resolver.go Normal file
View File

@@ -0,0 +1,21 @@
package main
import (
"context"
"github.com/tobyxdd/hysteria/pkg/utils"
"net"
)
func setResolver(dns string) {
if _, _, err := utils.SplitHostPort(dns); err != nil {
// Append the default DNS port
dns = net.JoinHostPort(dns, "53")
}
dialer := net.Dialer{}
net.DefaultResolver = &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, network, dns)
},
}
}

View File

@@ -149,18 +149,19 @@ func server(config *serverConfig) {
} }
// IPv6 only mode // IPv6 only mode
if config.IPv6Only { if config.IPv6Only {
transport.DefaultTransport = transport.IPv6OnlyTransport transport.DefaultServerTransport.IPv6Only = true
} }
// ACL // ACL
var aclEngine *acl.Engine var aclEngine *acl.Engine
if len(config.ACL) > 0 { if len(config.ACL) > 0 {
aclEngine, err = acl.LoadFromFile(config.ACL, transport.DefaultTransport, func() (*geoip2.Reader, error) { aclEngine, err = acl.LoadFromFile(config.ACL, transport.DefaultServerTransport.ResolveIPAddr,
if len(config.MMDB) > 0 { func() (*geoip2.Reader, error) {
return loadMMDBReader(config.MMDB) if len(config.MMDB) > 0 {
} else { return loadMMDBReader(config.MMDB)
return loadMMDBReader(DefaultMMDBFilename) } else {
} return loadMMDBReader(DefaultMMDBFilename)
}) }
})
if err != nil { if err != nil {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"error": err, "error": err,
@@ -179,7 +180,7 @@ func server(config *serverConfig) {
logrus.WithField("error", err).Fatal("Prometheus HTTP server error") logrus.WithField("error", err).Fatal("Prometheus HTTP server error")
}() }()
} }
server, err := core.NewServer(config.Listen, config.Protocol, tlsConfig, quicConfig, transport.DefaultTransport, server, err := core.NewServer(config.Listen, config.Protocol, tlsConfig, quicConfig, transport.DefaultServerTransport,
uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps, uint64(config.UpMbps)*mbpsToBps, uint64(config.DownMbps)*mbpsToBps,
func(refBPS uint64) congestion.CongestionControl { func(refBPS uint64) congestion.CongestionControl {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS)) return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))

View File

@@ -1,18 +0,0 @@
package main
import (
"context"
"net"
)
func setResolver(addr string) {
if _, _, err := net.SplitHostPort(addr); err != nil {
// Append the default DNS port
addr = net.JoinHostPort(addr, "53")
}
net.DefaultResolver.PreferGo = true
net.DefaultResolver.Dial = func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{}
return d.DialContext(ctx, "udp", addr)
}
}

View File

@@ -7,4 +7,4 @@ services:
network_mode: "host" network_mode: "host"
volumes: volumes:
- ./hysteria.json:/etc/hysteria.json - ./hysteria.json:/etc/hysteria.json
command: ["-config","/etc/hysteria.json","server"] command: [ "-config","/etc/hysteria.json","server" ]

View File

@@ -4,7 +4,6 @@ import (
"bufio" "bufio"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/oschwald/geoip2-golang" "github.com/oschwald/geoip2-golang"
"github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
"os" "os"
"strings" "strings"
@@ -16,7 +15,7 @@ type Engine struct {
DefaultAction Action DefaultAction Action
Entries []Entry Entries []Entry
Cache *lru.ARCCache Cache *lru.ARCCache
Transport transport.Transport ResolveIPAddr func(string) (*net.IPAddr, error)
GeoIPReader *geoip2.Reader GeoIPReader *geoip2.Reader
} }
@@ -25,7 +24,7 @@ type cacheEntry struct {
Arg string Arg string
} }
func LoadFromFile(filename string, transport transport.Transport, geoIPLoadFunc func() (*geoip2.Reader, error)) (*Engine, error) { func LoadFromFile(filename string, resolveIPAddr func(string) (*net.IPAddr, error), geoIPLoadFunc func() (*geoip2.Reader, error)) (*Engine, error) {
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -60,7 +59,7 @@ func LoadFromFile(filename string, transport transport.Transport, geoIPLoadFunc
DefaultAction: ActionProxy, DefaultAction: ActionProxy,
Entries: entries, Entries: entries,
Cache: cache, Cache: cache,
Transport: transport, ResolveIPAddr: resolveIPAddr,
GeoIPReader: geoIPReader, GeoIPReader: geoIPReader,
}, nil }, nil
} }
@@ -69,7 +68,7 @@ func (e *Engine) ResolveAndMatch(host string) (Action, string, *net.IPAddr, erro
ip, zone := parseIPZone(host) ip, zone := parseIPZone(host)
if ip == nil { if ip == nil {
// Domain // Domain
ipAddr, err := e.Transport.LocalResolveIPAddr(host) ipAddr, err := e.ResolveIPAddr(host)
if v, ok := e.Cache.Get(host); ok { if v, ok := e.Cache.Get(host); ok {
// Cache hit // Cache hit
ce := v.(cacheEntry) ce := v.(cacheEntry)

View File

@@ -10,7 +10,7 @@ import (
"github.com/lucas-clemente/quic-go/congestion" "github.com/lucas-clemente/quic-go/congestion"
"github.com/lunixbochs/struc" "github.com/lunixbochs/struc"
"github.com/tobyxdd/hysteria/pkg/obfs" "github.com/tobyxdd/hysteria/pkg/obfs"
transport2 "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" "strconv"
@@ -25,7 +25,7 @@ var (
type CongestionFactory func(refBPS uint64) congestion.CongestionControl type CongestionFactory func(refBPS uint64) congestion.CongestionControl
type Client struct { type Client struct {
transport transport2.Transport transport *transport.ClientTransport
serverAddr string serverAddr string
protocol string protocol string
sendBPS, recvBPS uint64 sendBPS, recvBPS uint64
@@ -45,7 +45,7 @@ type Client struct {
} }
func NewClient(serverAddr string, protocol string, auth []byte, tlsConfig *tls.Config, quicConfig *quic.Config, func NewClient(serverAddr string, protocol string, auth []byte, tlsConfig *tls.Config, quicConfig *quic.Config,
transport transport2.Transport, sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory, transport *transport.ClientTransport, sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory,
obfuscator obfs.Obfuscator) (*Client, error) { obfuscator obfs.Obfuscator) (*Client, error) {
c := &Client{ c := &Client{
transport: transport, transport: transport,
@@ -66,19 +66,10 @@ func NewClient(serverAddr string, protocol string, auth []byte, tlsConfig *tls.C
} }
func (c *Client) connectToServer() error { func (c *Client) connectToServer() error {
serverUDPAddr, err := c.transport.QUICResolveUDPAddr(c.serverAddr) qs, err := c.transport.QUICDial(c.protocol, c.serverAddr, c.tlsConfig, c.quicConfig, c.obfuscator)
if err != nil { if err != nil {
return err return err
} }
pktConn, err := c.transport.QUICPacketConn(c.protocol, false, "", c.serverAddr, c.obfuscator)
if err != nil {
return err
}
qs, err := quic.Dial(pktConn, serverUDPAddr, c.serverAddr, c.tlsConfig, c.quicConfig)
if err != nil {
_ = pktConn.Close()
return err
}
// Control stream // Control stream
ctx, ctxCancel := context.WithTimeout(context.Background(), protocolTimeout) ctx, ctxCancel := context.WithTimeout(context.Background(), protocolTimeout)
stream, err := qs.OpenStreamSync(ctx) stream, err := qs.OpenStreamSync(ctx)

View File

@@ -10,7 +10,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/tobyxdd/hysteria/pkg/acl" "github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/obfs" "github.com/tobyxdd/hysteria/pkg/obfs"
transport2 "github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
) )
@@ -22,7 +22,7 @@ type UDPRequestFunc func(addr net.Addr, auth []byte, sessionID uint32)
type UDPErrorFunc func(addr net.Addr, auth []byte, sessionID uint32, err error) type UDPErrorFunc func(addr net.Addr, auth []byte, sessionID uint32, err error)
type Server struct { type Server struct {
transport transport2.Transport transport *transport.ServerTransport
sendBPS, recvBPS uint64 sendBPS, recvBPS uint64
congestionFactory CongestionFactory congestionFactory CongestionFactory
disableUDP bool disableUDP bool
@@ -41,20 +41,15 @@ type Server struct {
listener quic.Listener listener quic.Listener
} }
func NewServer(addr string, protocol string, tlsConfig *tls.Config, quicConfig *quic.Config, transport transport2.Transport, func NewServer(addr string, protocol string, tlsConfig *tls.Config, quicConfig *quic.Config, transport *transport.ServerTransport,
sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory, disableUDP bool, aclEngine *acl.Engine, sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory, disableUDP bool, aclEngine *acl.Engine,
obfuscator obfs.Obfuscator, connectFunc ConnectFunc, disconnectFunc DisconnectFunc, obfuscator obfs.Obfuscator, connectFunc ConnectFunc, disconnectFunc DisconnectFunc,
tcpRequestFunc TCPRequestFunc, tcpErrorFunc TCPErrorFunc, tcpRequestFunc TCPRequestFunc, tcpErrorFunc TCPErrorFunc,
udpRequestFunc UDPRequestFunc, udpErrorFunc UDPErrorFunc, promRegistry *prometheus.Registry) (*Server, error) { udpRequestFunc UDPRequestFunc, udpErrorFunc UDPErrorFunc, promRegistry *prometheus.Registry) (*Server, error) {
pktConn, err := transport.QUICPacketConn(protocol, true, addr, "", obfuscator) listener, err := transport.QUICListen(protocol, addr, tlsConfig, quicConfig, obfuscator)
if err != nil { if err != nil {
return nil, err return nil, err
} }
listener, err := quic.Listen(pktConn, tlsConfig, quicConfig)
if err != nil {
_ = pktConn.Close()
return nil, err
}
s := &Server{ s := &Server{
listener: listener, listener: listener,
transport: transport, transport: transport,

View File

@@ -19,7 +19,7 @@ const udpBufferSize = 65535
type serverClient struct { type serverClient struct {
CS quic.Session CS quic.Session
Transport transport.Transport Transport *transport.ServerTransport
Auth []byte Auth []byte
ClientAddr net.Addr ClientAddr net.Addr
DisableUDP bool DisableUDP bool
@@ -37,7 +37,7 @@ type serverClient struct {
nextUDPSessionID uint32 nextUDPSessionID uint32
} }
func newServerClient(cs quic.Session, transport transport.Transport, auth []byte, disableUDP bool, ACLEngine *acl.Engine, func newServerClient(cs quic.Session, transport *transport.ServerTransport, auth []byte, disableUDP bool, ACLEngine *acl.Engine,
CTCPRequestFunc TCPRequestFunc, CTCPErrorFunc TCPErrorFunc, CTCPRequestFunc TCPRequestFunc, CTCPErrorFunc TCPErrorFunc,
CUDPRequestFunc UDPRequestFunc, CUDPErrorFunc UDPErrorFunc, CUDPRequestFunc UDPRequestFunc, CUDPErrorFunc UDPErrorFunc,
UpCounterVec, DownCounterVec *prometheus.CounterVec, UpCounterVec, DownCounterVec *prometheus.CounterVec,
@@ -133,7 +133,7 @@ func (c *serverClient) handleMessage(msg []byte) {
if c.ACLEngine != nil { if c.ACLEngine != nil {
action, arg, ipAddr, err = c.ACLEngine.ResolveAndMatch(udpMsg.Host) action, arg, ipAddr, err = c.ACLEngine.ResolveAndMatch(udpMsg.Host)
} else { } else {
ipAddr, err = c.Transport.LocalResolveIPAddr(udpMsg.Host) ipAddr, err = c.Transport.ResolveIPAddr(udpMsg.Host)
} }
if err != nil { if err != nil {
return return
@@ -151,10 +151,13 @@ func (c *serverClient) handleMessage(msg []byte) {
case acl.ActionBlock: case acl.ActionBlock:
// Do nothing // Do nothing
case acl.ActionHijack: case acl.ActionHijack:
hijackAddr := net.JoinHostPort(arg, strconv.Itoa(int(udpMsg.Port))) hijackIPAddr, err := c.Transport.ResolveIPAddr(arg)
addr, err := c.Transport.LocalResolveUDPAddr(hijackAddr)
if err == nil { if err == nil {
_, _ = conn.WriteToUDP(udpMsg.Data, addr) _, _ = conn.WriteToUDP(udpMsg.Data, &net.UDPAddr{
IP: hijackIPAddr.IP,
Port: int(udpMsg.Port),
Zone: hijackIPAddr.Zone,
})
if c.UpCounter != nil { if c.UpCounter != nil {
c.UpCounter.Add(float64(len(udpMsg.Data))) c.UpCounter.Add(float64(len(udpMsg.Data)))
} }
@@ -173,7 +176,7 @@ func (c *serverClient) handleTCP(stream quic.Stream, host string, port uint16) {
if c.ACLEngine != nil { if c.ACLEngine != nil {
action, arg, ipAddr, err = c.ACLEngine.ResolveAndMatch(host) action, arg, ipAddr, err = c.ACLEngine.ResolveAndMatch(host)
} else { } else {
ipAddr, err = c.Transport.LocalResolveIPAddr(host) ipAddr, err = c.Transport.ResolveIPAddr(host)
} }
if err != nil { if err != nil {
_ = struc.Pack(stream, &serverResponse{ _ = struc.Pack(stream, &serverResponse{
@@ -188,7 +191,7 @@ func (c *serverClient) handleTCP(stream quic.Stream, host string, port uint16) {
var conn net.Conn // Connection to be piped var conn net.Conn // Connection to be piped
switch action { switch action {
case acl.ActionDirect, acl.ActionProxy: // Treat proxy as direct on server side case acl.ActionDirect, acl.ActionProxy: // Treat proxy as direct on server side
conn, err = c.Transport.LocalDialTCP(nil, &net.TCPAddr{ conn, err = c.Transport.DialTCP(&net.TCPAddr{
IP: ipAddr.IP, IP: ipAddr.IP,
Port: int(port), Port: int(port),
Zone: ipAddr.Zone, Zone: ipAddr.Zone,
@@ -208,8 +211,20 @@ func (c *serverClient) handleTCP(stream quic.Stream, host string, port uint16) {
}) })
return return
case acl.ActionHijack: case acl.ActionHijack:
hijackAddr := net.JoinHostPort(arg, strconv.Itoa(int(port))) hijackIPAddr, err := c.Transport.ResolveIPAddr(arg)
conn, err = c.Transport.LocalDial("tcp", hijackAddr) if err != nil {
_ = struc.Pack(stream, &serverResponse{
OK: false,
Message: err.Error(),
})
c.CTCPErrorFunc(c.ClientAddr, c.Auth, addrStr, err)
return
}
conn, err = c.Transport.DialTCP(&net.TCPAddr{
IP: hijackIPAddr.IP,
Port: int(port),
Zone: hijackIPAddr.Zone,
})
if err != nil { if err != nil {
_ = struc.Pack(stream, &serverResponse{ _ = struc.Pack(stream, &serverResponse{
OK: false, OK: false,
@@ -249,7 +264,7 @@ func (c *serverClient) handleTCP(stream quic.Stream, host string, port uint16) {
func (c *serverClient) handleUDP(stream quic.Stream) { func (c *serverClient) handleUDP(stream quic.Stream) {
// Like in SOCKS5, the stream here is only used to maintain the UDP session. No need to read anything from it // Like in SOCKS5, the stream here is only used to maintain the UDP session. No need to read anything from it
conn, err := c.Transport.LocalListenUDP(nil) conn, err := c.Transport.ListenUDP(nil)
if err != nil { if err != nil {
_ = struc.Pack(stream, &serverResponse{ _ = struc.Pack(stream, &serverResponse{
OK: false, OK: false,

View File

@@ -7,7 +7,6 @@ import (
"github.com/tobyxdd/hysteria/pkg/utils" "github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"net/http" "net/http"
"strconv"
"time" "time"
"github.com/elazarl/goproxy/ext/auth" "github.com/elazarl/goproxy/ext/auth"
@@ -17,8 +16,8 @@ import (
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
) )
func NewProxyHTTPServer(hyClient *core.Client, transport transport.Transport, idleTimeout time.Duration, aclEngine *acl.Engine, func NewProxyHTTPServer(hyClient *core.Client, transport *transport.ClientTransport, idleTimeout time.Duration,
newDialFunc func(reqAddr string, action acl.Action, arg string), aclEngine *acl.Engine, newDialFunc func(reqAddr string, action acl.Action, arg string),
basicAuthFunc func(user, password string) bool) (*goproxy.ProxyHttpServer, error) { basicAuthFunc func(user, password string) bool) (*goproxy.ProxyHttpServer, error) {
proxy := goproxy.NewProxyHttpServer() proxy := goproxy.NewProxyHttpServer()
proxy.Logger = &nopLogger{} proxy.Logger = &nopLogger{}
@@ -45,7 +44,7 @@ func NewProxyHTTPServer(hyClient *core.Client, transport transport.Transport, id
if resErr != nil { if resErr != nil {
return nil, resErr return nil, resErr
} }
return transport.LocalDialTCP(nil, &net.TCPAddr{ return transport.DialTCP(&net.TCPAddr{
IP: ipAddr.IP, IP: ipAddr.IP,
Port: int(port), Port: int(port),
Zone: ipAddr.Zone, Zone: ipAddr.Zone,
@@ -55,7 +54,15 @@ func NewProxyHTTPServer(hyClient *core.Client, transport transport.Transport, id
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 transport.LocalDial(network, net.JoinHostPort(arg, strconv.Itoa(int(port)))) hijackIPAddr, err := transport.ResolveIPAddr(arg)
if err != nil {
return nil, err
}
return transport.DialTCP(&net.TCPAddr{
IP: hijackIPAddr.IP,
Port: int(port),
Zone: hijackIPAddr.Zone,
})
default: default:
return nil, fmt.Errorf("unknown action %d", action) return nil, fmt.Errorf("unknown action %d", action)
} }

View File

@@ -2,7 +2,6 @@ package relay
import ( import (
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"github.com/tobyxdd/hysteria/pkg/utils" "github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"time" "time"
@@ -10,7 +9,6 @@ import (
type TCPRelay struct { type TCPRelay struct {
HyClient *core.Client HyClient *core.Client
Transport transport.Transport
ListenAddr *net.TCPAddr ListenAddr *net.TCPAddr
Remote string Remote string
Timeout time.Duration Timeout time.Duration
@@ -19,15 +17,14 @@ type TCPRelay struct {
ErrorFunc func(addr net.Addr, err error) ErrorFunc func(addr net.Addr, err error)
} }
func NewTCPRelay(hyClient *core.Client, transport transport.Transport, listen, remote string, timeout time.Duration, func NewTCPRelay(hyClient *core.Client, listen, remote string, timeout time.Duration,
connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*TCPRelay, error) { connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*TCPRelay, error) {
tAddr, err := transport.LocalResolveTCPAddr(listen) tAddr, err := net.ResolveTCPAddr("tcp", listen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &TCPRelay{ r := &TCPRelay{
HyClient: hyClient, HyClient: hyClient,
Transport: transport,
ListenAddr: tAddr, ListenAddr: tAddr,
Remote: remote, Remote: remote,
Timeout: timeout, Timeout: timeout,
@@ -38,7 +35,7 @@ func NewTCPRelay(hyClient *core.Client, transport transport.Transport, listen, r
} }
func (r *TCPRelay) ListenAndServe() error { func (r *TCPRelay) ListenAndServe() error {
listener, err := r.Transport.LocalListenTCP(r.ListenAddr) listener, err := net.ListenTCP("tcp", r.ListenAddr)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -3,7 +3,6 @@ package relay
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -16,7 +15,6 @@ var ErrTimeout = errors.New("inactivity timeout")
type UDPRelay struct { type UDPRelay struct {
HyClient *core.Client HyClient *core.Client
Transport transport.Transport
ListenAddr *net.UDPAddr ListenAddr *net.UDPAddr
Remote string Remote string
Timeout time.Duration Timeout time.Duration
@@ -25,15 +23,14 @@ type UDPRelay struct {
ErrorFunc func(addr net.Addr, err error) ErrorFunc func(addr net.Addr, err error)
} }
func NewUDPRelay(hyClient *core.Client, transport transport.Transport, listen, remote string, timeout time.Duration, func NewUDPRelay(hyClient *core.Client, listen, remote string, timeout time.Duration,
connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*UDPRelay, error) { connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*UDPRelay, error) {
uAddr, err := transport.LocalResolveUDPAddr(listen) uAddr, err := net.ResolveUDPAddr("udp", listen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &UDPRelay{ r := &UDPRelay{
HyClient: hyClient, HyClient: hyClient,
Transport: transport,
ListenAddr: uAddr, ListenAddr: uAddr,
Remote: remote, Remote: remote,
Timeout: timeout, Timeout: timeout,
@@ -52,7 +49,7 @@ type connEntry struct {
} }
func (r *UDPRelay) ListenAndServe() error { func (r *UDPRelay) ListenAndServe() error {
conn, err := r.Transport.LocalListenUDP(r.ListenAddr) conn, err := net.ListenUDP("udp", r.ListenAddr)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -26,7 +26,7 @@ var (
type Server struct { type Server struct {
HyClient *core.Client HyClient *core.Client
Transport transport.Transport Transport *transport.ClientTransport
AuthFunc func(username, password string) bool AuthFunc func(username, password string) bool
Method byte Method byte
TCPAddr *net.TCPAddr TCPAddr *net.TCPAddr
@@ -42,13 +42,13 @@ type Server struct {
tcpListener *net.TCPListener tcpListener *net.TCPListener
} }
func NewServer(hyClient *core.Client, transport transport.Transport, addr string, func NewServer(hyClient *core.Client, transport *transport.ClientTransport, addr string,
authFunc func(username, password string) bool, tcpTimeout time.Duration, authFunc func(username, password string) bool, tcpTimeout time.Duration,
aclEngine *acl.Engine, disableUDP bool, aclEngine *acl.Engine, disableUDP bool,
tcpReqFunc func(addr net.Addr, reqAddr string, action acl.Action, arg string), tcpReqFunc func(addr net.Addr, reqAddr string, action acl.Action, arg string),
tcpErrorFunc func(addr net.Addr, reqAddr string, err error), tcpErrorFunc func(addr net.Addr, reqAddr string, err error),
udpAssocFunc func(addr net.Addr), udpErrorFunc func(addr net.Addr, err error)) (*Server, error) { udpAssocFunc func(addr net.Addr), udpErrorFunc func(addr net.Addr, err error)) (*Server, error) {
tAddr, err := transport.LocalResolveTCPAddr(addr) tAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -118,7 +118,7 @@ func (s *Server) negotiate(c *net.TCPConn) error {
func (s *Server) ListenAndServe() error { func (s *Server) ListenAndServe() error {
var err error var err error
s.tcpListener, err = s.Transport.LocalListenTCP(s.TCPAddr) s.tcpListener, err = net.ListenTCP("tcp", s.TCPAddr)
if err != nil { if err != nil {
return err return err
} }
@@ -187,7 +187,7 @@ func (s *Server) handleTCP(c *net.TCPConn, r *socks5.Request) error {
closeErr = resErr closeErr = resErr
return resErr return resErr
} }
rc, err := s.Transport.LocalDialTCP(nil, &net.TCPAddr{ rc, err := s.Transport.DialTCP(&net.TCPAddr{
IP: ipAddr.IP, IP: ipAddr.IP,
Port: int(port), Port: int(port),
Zone: ipAddr.Zone, Zone: ipAddr.Zone,
@@ -217,7 +217,17 @@ func (s *Server) handleTCP(c *net.TCPConn, r *socks5.Request) error {
closeErr = errors.New("blocked in ACL") closeErr = errors.New("blocked in ACL")
return nil return nil
case acl.ActionHijack: case acl.ActionHijack:
rc, err := s.Transport.LocalDial("tcp", net.JoinHostPort(arg, strconv.Itoa(int(port)))) hijackIPAddr, err := s.Transport.ResolveIPAddr(arg)
if err != nil {
_ = sendReply(c, socks5.RepHostUnreachable)
closeErr = err
return err
}
rc, err := s.Transport.DialTCP(&net.TCPAddr{
IP: hijackIPAddr.IP,
Port: int(port),
Zone: hijackIPAddr.Zone,
})
if err != nil { if err != nil {
_ = sendReply(c, socks5.RepHostUnreachable) _ = sendReply(c, socks5.RepHostUnreachable)
closeErr = err closeErr = err
@@ -241,7 +251,7 @@ func (s *Server) handleUDP(c *net.TCPConn, r *socks5.Request) error {
s.UDPErrorFunc(c.RemoteAddr(), closeErr) s.UDPErrorFunc(c.RemoteAddr(), closeErr)
}() }()
// Start local UDP server // Start local UDP server
udpConn, err := s.Transport.LocalListenUDP(&net.UDPAddr{ udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: s.TCPAddr.IP, IP: s.TCPAddr.IP,
Zone: s.TCPAddr.Zone, Zone: s.TCPAddr.Zone,
}) })
@@ -254,7 +264,7 @@ func (s *Server) handleUDP(c *net.TCPConn, r *socks5.Request) error {
// Local UDP relay conn for ACL Direct // Local UDP relay conn for ACL Direct
var localRelayConn *net.UDPConn var localRelayConn *net.UDPConn
if s.ACLEngine != nil { if s.ACLEngine != nil {
localRelayConn, err = s.Transport.LocalListenUDP(nil) localRelayConn, err = s.Transport.ListenUDP(nil)
if err != nil { if err != nil {
_ = sendReply(c, socks5.RepServerFailure) _ = sendReply(c, socks5.RepServerFailure)
closeErr = err closeErr = err
@@ -385,10 +395,13 @@ func (s *Server) udpServer(clientConn *net.UDPConn, localRelayConn *net.UDPConn,
case acl.ActionBlock: case acl.ActionBlock:
// Do nothing // Do nothing
case acl.ActionHijack: case acl.ActionHijack:
hijackAddr := net.JoinHostPort(arg, strconv.Itoa(int(port))) hijackIPAddr, err := s.Transport.ResolveIPAddr(arg)
rAddr, err := s.Transport.LocalResolveUDPAddr(hijackAddr)
if err == nil { if err == nil {
_, _ = localRelayConn.WriteToUDP(d.Data, rAddr) _, _ = localRelayConn.WriteToUDP(d.Data, &net.UDPAddr{
IP: hijackIPAddr.IP,
Port: int(port),
Zone: hijackIPAddr.Zone,
})
} }
default: default:
// Do nothing // Do nothing

View File

@@ -3,7 +3,6 @@ package tproxy
import ( import (
"github.com/LiamHaworth/go-tproxy" "github.com/LiamHaworth/go-tproxy"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"github.com/tobyxdd/hysteria/pkg/utils" "github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"time" "time"
@@ -11,7 +10,6 @@ import (
type TCPTProxy struct { type TCPTProxy struct {
HyClient *core.Client HyClient *core.Client
Transport transport.Transport
ListenAddr *net.TCPAddr ListenAddr *net.TCPAddr
Timeout time.Duration Timeout time.Duration
@@ -19,16 +17,15 @@ type TCPTProxy struct {
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, listen string, timeout time.Duration,
connFunc func(addr, reqAddr net.Addr), connFunc func(addr, reqAddr net.Addr),
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 := net.ResolveTCPAddr("tcp", listen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &TCPTProxy{ r := &TCPTProxy{
HyClient: hyClient, HyClient: hyClient,
Transport: transport,
ListenAddr: tAddr, ListenAddr: tAddr,
Timeout: timeout, Timeout: timeout,
ConnFunc: connFunc, ConnFunc: connFunc,

View File

@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux // +build !linux
package tproxy package tproxy
@@ -5,14 +6,13 @@ package tproxy
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
"time" "time"
) )
type TCPTProxy struct{} type TCPTProxy struct{}
func NewTCPTProxy(hyClient *core.Client, transport transport.Transport, listen string, timeout time.Duration, func NewTCPTProxy(hyClient *core.Client, listen string, timeout time.Duration,
connFunc func(addr, reqAddr net.Addr), connFunc func(addr, reqAddr net.Addr),
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

@@ -4,7 +4,6 @@ import (
"errors" "errors"
"github.com/LiamHaworth/go-tproxy" "github.com/LiamHaworth/go-tproxy"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -17,7 +16,6 @@ var ErrTimeout = errors.New("inactivity timeout")
type UDPTProxy struct { type UDPTProxy struct {
HyClient *core.Client HyClient *core.Client
Transport transport.Transport
ListenAddr *net.UDPAddr ListenAddr *net.UDPAddr
Timeout time.Duration Timeout time.Duration
@@ -25,15 +23,14 @@ type UDPTProxy struct {
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, listen string, timeout time.Duration,
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 := net.ResolveUDPAddr("udp", listen)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &UDPTProxy{ r := &UDPTProxy{
HyClient: hyClient, HyClient: hyClient,
Transport: transport,
ListenAddr: uAddr, ListenAddr: uAddr,
Timeout: timeout, Timeout: timeout,
ConnFunc: connFunc, ConnFunc: connFunc,

View File

@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux // +build !linux
package tproxy package tproxy
@@ -5,7 +6,6 @@ package tproxy
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"net" "net"
"time" "time"
) )
@@ -14,7 +14,7 @@ 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, listen string, timeout time.Duration,
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")
} }

96
pkg/transport/client.go Normal file
View File

@@ -0,0 +1,96 @@
package transport
import (
"crypto/tls"
"fmt"
"github.com/lucas-clemente/quic-go"
"github.com/tobyxdd/hysteria/pkg/conns/faketcp"
"github.com/tobyxdd/hysteria/pkg/conns/udp"
"github.com/tobyxdd/hysteria/pkg/conns/wechat"
"github.com/tobyxdd/hysteria/pkg/obfs"
"net"
"time"
)
type ClientTransport struct {
Dialer *net.Dialer
}
var DefaultClientTransport = &ClientTransport{
Dialer: &net.Dialer{
Timeout: 8 * time.Second,
},
}
func (ct *ClientTransport) quicPacketConn(proto string, server string, obfs obfs.Obfuscator) (net.PacketConn, error) {
if len(proto) == 0 || proto == "udp" {
conn, err := net.ListenUDP("udp", nil)
if err != nil {
return nil, err
}
if obfs != nil {
oc := udp.NewObfsUDPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else if proto == "wechat-video" {
conn, err := net.ListenUDP("udp", nil)
if err != nil {
return nil, err
}
if obfs != nil {
oc := wechat.NewObfsWeChatUDPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else if proto == "faketcp" {
var conn *faketcp.TCPConn
conn, err := faketcp.Dial("tcp", server)
if err != nil {
return nil, err
}
if obfs != nil {
oc := faketcp.NewObfsFakeTCPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else {
return nil, fmt.Errorf("unsupported protocol: %s", proto)
}
}
func (ct *ClientTransport) QUICDial(proto string, server string, tlsConfig *tls.Config, quicConfig *quic.Config, obfs obfs.Obfuscator) (quic.Session, error) {
serverUDPAddr, err := net.ResolveUDPAddr("udp", server)
if err != nil {
return nil, err
}
pktConn, err := ct.quicPacketConn(proto, server, obfs)
if err != nil {
return nil, err
}
qs, err := quic.Dial(pktConn, serverUDPAddr, server, tlsConfig, quicConfig)
if err != nil {
_ = pktConn.Close()
return nil, err
}
return qs, nil
}
func (ct *ClientTransport) ResolveIPAddr(address string) (*net.IPAddr, error) {
return net.ResolveIPAddr("ip", address)
}
func (ct *ClientTransport) DialTCP(raddr *net.TCPAddr) (*net.TCPConn, error) {
conn, err := ct.Dialer.Dial("tcp", raddr.String())
if err != nil {
return nil, err
}
return conn.(*net.TCPConn), nil
}
func (ct *ClientTransport) ListenUDP(laddr *net.UDPAddr) (*net.UDPConn, error) {
return net.ListenUDP("udp", laddr)
}

105
pkg/transport/server.go Normal file
View File

@@ -0,0 +1,105 @@
package transport
import (
"crypto/tls"
"fmt"
"github.com/lucas-clemente/quic-go"
"github.com/tobyxdd/hysteria/pkg/conns/faketcp"
"github.com/tobyxdd/hysteria/pkg/conns/udp"
"github.com/tobyxdd/hysteria/pkg/conns/wechat"
"github.com/tobyxdd/hysteria/pkg/obfs"
"net"
"time"
)
type ServerTransport struct {
Dialer *net.Dialer
IPv6Only bool
}
var DefaultServerTransport = &ServerTransport{
Dialer: &net.Dialer{
Timeout: 8 * time.Second,
},
IPv6Only: false,
}
func (st *ServerTransport) quicPacketConn(proto string, laddr string, obfs obfs.Obfuscator) (net.PacketConn, error) {
if len(proto) == 0 || proto == "udp" {
laddrU, err := net.ResolveUDPAddr("udp", laddr)
if err != nil {
return nil, err
}
conn, err := net.ListenUDP("udp", laddrU)
if err != nil {
return nil, err
}
if obfs != nil {
oc := udp.NewObfsUDPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else if proto == "wechat-video" {
laddrU, err := net.ResolveUDPAddr("udp", laddr)
if err != nil {
return nil, err
}
conn, err := net.ListenUDP("udp", laddrU)
if err != nil {
return nil, err
}
if obfs != nil {
oc := wechat.NewObfsWeChatUDPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else if proto == "faketcp" {
conn, err := faketcp.Listen("tcp", laddr)
if err != nil {
return nil, err
}
if obfs != nil {
oc := faketcp.NewObfsFakeTCPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else {
return nil, fmt.Errorf("unsupported protocol: %s", proto)
}
}
func (ct *ServerTransport) QUICListen(proto string, listen string, tlsConfig *tls.Config, quicConfig *quic.Config, obfs obfs.Obfuscator) (quic.Listener, error) {
pktConn, err := ct.quicPacketConn(proto, listen, obfs)
if err != nil {
return nil, err
}
l, err := quic.Listen(pktConn, tlsConfig, quicConfig)
if err != nil {
_ = pktConn.Close()
return nil, err
}
return l, nil
}
func (ct *ServerTransport) ResolveIPAddr(address string) (*net.IPAddr, error) {
if ct.IPv6Only {
return net.ResolveIPAddr("ip6", address)
} else {
return net.ResolveIPAddr("ip", address)
}
}
func (ct *ServerTransport) DialTCP(raddr *net.TCPAddr) (*net.TCPConn, error) {
conn, err := ct.Dialer.Dial("tcp", raddr.String())
if err != nil {
return nil, err
}
return conn.(*net.TCPConn), nil
}
func (ct *ServerTransport) ListenUDP(laddr *net.UDPAddr) (*net.UDPConn, error) {
return net.ListenUDP("udp", laddr)
}

View File

@@ -1,148 +0,0 @@
package transport
import (
"fmt"
"github.com/tobyxdd/hysteria/pkg/conns/faketcp"
"github.com/tobyxdd/hysteria/pkg/conns/udp"
"github.com/tobyxdd/hysteria/pkg/conns/wechat"
"github.com/tobyxdd/hysteria/pkg/obfs"
"net"
"time"
)
type Transport interface {
QUICResolveUDPAddr(address string) (*net.UDPAddr, error)
QUICPacketConn(proto string, server bool, laddr, raddr string, obfs obfs.Obfuscator) (net.PacketConn, error)
LocalResolveIPAddr(address string) (*net.IPAddr, error)
LocalResolveTCPAddr(address string) (*net.TCPAddr, error)
LocalResolveUDPAddr(address string) (*net.UDPAddr, error)
LocalDial(network, address string) (net.Conn, error)
LocalDialTCP(laddr, raddr *net.TCPAddr) (*net.TCPConn, error)
LocalListenTCP(laddr *net.TCPAddr) (*net.TCPListener, error)
LocalListenUDP(laddr *net.UDPAddr) (*net.UDPConn, error)
}
var DefaultTransport Transport = &defaultTransport{
Timeout: 8 * time.Second,
}
var IPv6OnlyTransport Transport = &ipv6OnlyTransport{
defaultTransport{
Timeout: 8 * time.Second,
},
}
type defaultTransport struct {
Timeout time.Duration
}
func (t *defaultTransport) QUICResolveUDPAddr(address string) (*net.UDPAddr, error) {
return net.ResolveUDPAddr("udp", address)
}
func (t *defaultTransport) QUICPacketConn(proto string, server bool, laddr, raddr string, obfs obfs.Obfuscator) (net.PacketConn, error) {
if len(proto) == 0 || proto == "udp" {
var laddrU *net.UDPAddr
if len(laddr) > 0 {
var err error
laddrU, err = t.QUICResolveUDPAddr(laddr)
if err != nil {
return nil, err
}
}
conn, err := net.ListenUDP("udp", laddrU)
if err != nil {
return nil, err
}
if obfs != nil {
oc := udp.NewObfsUDPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else if proto == "wechat-video" {
var laddrU *net.UDPAddr
if len(laddr) > 0 {
var err error
laddrU, err = t.QUICResolveUDPAddr(laddr)
if err != nil {
return nil, err
}
}
conn, err := net.ListenUDP("udp", laddrU)
if err != nil {
return nil, err
}
if obfs != nil {
oc := wechat.NewObfsWeChatUDPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else if proto == "faketcp" {
var conn *faketcp.TCPConn
var err error
if server {
conn, err = faketcp.Listen("tcp", laddr)
if err != nil {
return nil, err
}
} else {
conn, err = faketcp.Dial("tcp", raddr)
if err != nil {
return nil, err
}
}
if obfs != nil {
oc := faketcp.NewObfsFakeTCPConn(conn, obfs)
return oc, nil
} else {
return conn, nil
}
} else {
return nil, fmt.Errorf("unsupported protocol: %s", proto)
}
}
func (t *defaultTransport) LocalResolveIPAddr(address string) (*net.IPAddr, error) {
return net.ResolveIPAddr("ip", address)
}
func (t *defaultTransport) LocalResolveTCPAddr(address string) (*net.TCPAddr, error) {
return net.ResolveTCPAddr("tcp", address)
}
func (t *defaultTransport) LocalResolveUDPAddr(address string) (*net.UDPAddr, error) {
return net.ResolveUDPAddr("udp", address)
}
func (t *defaultTransport) LocalDial(network, address string) (net.Conn, error) {
dialer := &net.Dialer{Timeout: t.Timeout}
return dialer.Dial(network, address)
}
func (t *defaultTransport) LocalDialTCP(laddr, raddr *net.TCPAddr) (*net.TCPConn, error) {
dialer := &net.Dialer{Timeout: t.Timeout, LocalAddr: laddr}
conn, err := dialer.Dial("tcp", raddr.String())
if err != nil {
return nil, err
}
return conn.(*net.TCPConn), nil
}
func (t *defaultTransport) LocalListenTCP(laddr *net.TCPAddr) (*net.TCPListener, error) {
return net.ListenTCP("tcp", laddr)
}
func (t *defaultTransport) LocalListenUDP(laddr *net.UDPAddr) (*net.UDPConn, error) {
return net.ListenUDP("udp", laddr)
}
type ipv6OnlyTransport struct {
defaultTransport
}
func (t *ipv6OnlyTransport) LocalResolveIPAddr(address string) (*net.IPAddr, error) {
return net.ResolveIPAddr("ip6", address)
}

View File

@@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package tun package tun
@@ -6,7 +7,6 @@ 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/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"io" "io"
"net" "net"
"sync" "sync"
@@ -14,10 +14,9 @@ import (
) )
type Server struct { type Server struct {
HyClient *core.Client HyClient *core.Client
Timeout time.Duration Timeout time.Duration
TunDev io.ReadWriteCloser TunDev io.ReadWriteCloser
Transport transport.Transport
RequestFunc func(addr net.Addr, reqAddr 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,12 +29,9 @@ const (
MTU = 1500 MTU = 1500
) )
func NewServerWithTunDev(hyClient *core.Client, transport transport.Transport, func NewServerWithTunDev(hyClient *core.Client, timeout time.Duration, tunDev io.ReadWriteCloser) (*Server, error) {
timeout time.Duration,
tunDev io.ReadWriteCloser) (*Server, error) {
s := &Server{ s := &Server{
HyClient: hyClient, HyClient: hyClient,
Transport: transport,
Timeout: timeout, Timeout: timeout,
TunDev: tunDev, TunDev: tunDev,
udpConnMap: make(map[tun2socks.UDPConn]*udpConnInfo), udpConnMap: make(map[tun2socks.UDPConn]*udpConnInfo),
@@ -43,14 +39,13 @@ func NewServerWithTunDev(hyClient *core.Client, transport transport.Transport,
return s, nil return s, nil
} }
func NewServer(hyClient *core.Client, transport transport.Transport, func NewServer(hyClient *core.Client, 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) {
tunDev, err := tun.OpenTunDevice(name, address, gateway, mask, dnsServers, persist) tunDev, err := tun.OpenTunDevice(name, address, gateway, mask, dnsServers, persist)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewServerWithTunDev(hyClient, transport, timeout, tunDev) return NewServerWithTunDev(hyClient, timeout, tunDev)
} }
func (s *Server) ListenAndServe() error { func (s *Server) ListenAndServe() error {

View File

@@ -1,3 +1,4 @@
//go:build !cgo
// +build !cgo // +build !cgo
package tun package tun
@@ -5,17 +6,15 @@ package tun
import ( import (
"errors" "errors"
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/transport"
"io" "io"
"net" "net"
"time" "time"
) )
type Server struct { type Server struct {
HyClient *core.Client HyClient *core.Client
Timeout time.Duration Timeout time.Duration
TunDev io.ReadWriteCloser TunDev io.ReadWriteCloser
Transport transport.Transport
RequestFunc func(addr net.Addr, reqAddr 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)
@@ -25,14 +24,11 @@ const (
MTU = 1500 MTU = 1500
) )
func NewServerWithTunDev(hyClient *core.Client, transport transport.Transport, func NewServerWithTunDev(hyClient *core.Client, timeout time.Duration, tunDev io.ReadWriteCloser) (*Server, error) {
timeout time.Duration,
tunDev io.ReadWriteCloser) (*Server, error) {
return nil, errors.New("TUN mode is not available in this build") 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, 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 in this build") return nil, errors.New("TUN mode is not available in this build")
} }

View File

@@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package tun package tun

View File

@@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package tun package tun