mirror of
https://github.com/cmz0228/hysteria-dev.git
synced 2025-06-08 13:29:53 +00:00
commit
0626a3e505
22
README.md
22
README.md
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
[中文 README](README.zh.md)
|
[中文 README](README.zh.md)
|
||||||
|
|
||||||
Hysteria is a TCP relay & SOCKS5/HTTP proxy tool optimized for networks of poor quality (e.g. satellite connections,
|
Hysteria is a TCP/UDP relay & SOCKS5/HTTP proxy tool optimized for networks of poor quality (e.g. satellite connections,
|
||||||
congested public Wi-Fi, connecting from China to servers abroad) powered by a custom version of QUIC protocol.
|
congested public Wi-Fi, connecting from China to servers abroad) powered by a custom version of QUIC protocol.
|
||||||
|
|
||||||
It is essentially a spiritual successor of my abandoned project https://github.com/dragonite-network/dragonite-java
|
It is essentially a spiritual successor of my abandoned project https://github.com/dragonite-network/dragonite-java
|
||||||
@ -87,14 +87,19 @@ Same as the server side, create a `config.json` under the root directory of the
|
|||||||
"http": {
|
"http": {
|
||||||
"listen": "127.0.0.1:8080"
|
"listen": "127.0.0.1:8080"
|
||||||
},
|
},
|
||||||
"relay": {
|
"relay_tcp": {
|
||||||
"listen": "127.0.0.1:2222",
|
"listen": "127.0.0.1:2222",
|
||||||
"remote": "123.123.123.123:22"
|
"remote": "123.123.123.123:22"
|
||||||
|
},
|
||||||
|
"relay_udp": {
|
||||||
|
"listen": "127.0.0.1:5333",
|
||||||
|
"remote": "8.8.8.8:53"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This config enables a SOCKS5 proxy (with both TCP & UDP support), an HTTP proxy, and a TCP relay to `123.123.123.123:22`
|
This config enables a SOCKS5 proxy (with both TCP & UDP support), an HTTP proxy, a TCP relay to `123.123.123.123:22` and
|
||||||
|
a UDP relay to `8.8.8.8:53`
|
||||||
at the same time. Please modify or remove these entries according to your actual needs.
|
at the same time. Please modify or remove these entries according to your actual needs.
|
||||||
|
|
||||||
If your server certificate is not issued by a trusted CA, you need to specify the CA used
|
If your server certificate is not issued by a trusted CA, you need to specify the CA used
|
||||||
@ -217,11 +222,16 @@ hysteria_traffic_uplink_bytes_total{auth="aGFja2VyISE="} 37452
|
|||||||
"cert": "/home/ubuntu/my_cert.crt", // Cert file (HTTPS proxy)
|
"cert": "/home/ubuntu/my_cert.crt", // Cert file (HTTPS proxy)
|
||||||
"key": "/home/ubuntu/my_key.crt" // Key file (HTTPS proxy)
|
"key": "/home/ubuntu/my_key.crt" // Key file (HTTPS proxy)
|
||||||
},
|
},
|
||||||
"relay": {
|
"relay_tcp": {
|
||||||
"listen": "127.0.0.1:2222", // Relay listen address
|
"listen": "127.0.0.1:2222", // TCP relay Listen address
|
||||||
"remote": "123.123.123.123:22", // Relay remote address
|
"remote": "123.123.123.123:22", // TCP relay remote address
|
||||||
"timeout": 300 // TCP timeout in seconds
|
"timeout": 300 // TCP timeout in seconds
|
||||||
},
|
},
|
||||||
|
"relay_udp": {
|
||||||
|
"listen": "127.0.0.1:5333", // UDP relay Listen address
|
||||||
|
"remote": "8.8.8.8:53", // UDP relay remote address
|
||||||
|
"timeout": 60 // UDP session timeout in seconds
|
||||||
|
},
|
||||||
"acl": "my_list.acl", // See ACL below
|
"acl": "my_list.acl", // See ACL below
|
||||||
"obfs": "AMOGUS", // Obfuscation password
|
"obfs": "AMOGUS", // Obfuscation password
|
||||||
"auth": "[BASE64]", // Authentication payload in Base64
|
"auth": "[BASE64]", // Authentication payload in Base64
|
||||||
|
22
README.zh.md
22
README.zh.md
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
[6]: https://t.me/hysteria_github
|
[6]: https://t.me/hysteria_github
|
||||||
|
|
||||||
Hysteria 是专门针对恶劣网络环境进行优化的 TCP 连接转发和代理工具(双边加速),比如卫星网络、拥挤的公共 Wi-Fi、在中国连接国外服务器等。
|
Hysteria 是专门针对恶劣网络环境进行优化的 TCP/UDP 转发和代理工具(双边加速),比如卫星网络、拥挤的公共 Wi-Fi、在中国连接国外服务器等。
|
||||||
基于修改版的 QUIC 协议。
|
基于修改版的 QUIC 协议。
|
||||||
|
|
||||||
是我此前弃坑的项目 https://github.com/dragonite-network/dragonite-java 的续作。
|
是我此前弃坑的项目 https://github.com/dragonite-network/dragonite-java 的续作。
|
||||||
@ -80,14 +80,19 @@ Hysteria 是专门针对恶劣网络环境进行优化的 TCP 连接转发和代
|
|||||||
"http": {
|
"http": {
|
||||||
"listen": "127.0.0.1:8080"
|
"listen": "127.0.0.1:8080"
|
||||||
},
|
},
|
||||||
"relay": {
|
"relay_tcp": {
|
||||||
"listen": "127.0.0.1:2222",
|
"listen": "127.0.0.1:2222",
|
||||||
"remote": "123.123.123.123:22"
|
"remote": "123.123.123.123:22"
|
||||||
|
},
|
||||||
|
"relay_udp": {
|
||||||
|
"listen": "127.0.0.1:5333",
|
||||||
|
"remote": "8.8.8.8:53"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
这个配置同时开了 SOCK5 (支持 TCP & UDP) 代理,HTTP 代理和到 `123.123.123.123:22` 的 TCP 转发。请根据自己实际需要修改和删减。
|
这个配置同时开了 SOCK5 (支持 TCP & UDP) 代理,HTTP 代理,到 `123.123.123.123:22` 的 TCP 转发和到 `8.8.8.8:53` 的 UDP 转发。
|
||||||
|
请根据自己实际需要修改和删减。
|
||||||
|
|
||||||
如果你的服务端证书不是由受信任的 CA 签发的,需要用 `"ca": "/path/to/file.ca"` 指定使用的 CA 或者用 `"insecure": true` 忽略所有
|
如果你的服务端证书不是由受信任的 CA 签发的,需要用 `"ca": "/path/to/file.ca"` 指定使用的 CA 或者用 `"insecure": true` 忽略所有
|
||||||
证书错误(不推荐)。
|
证书错误(不推荐)。
|
||||||
@ -205,11 +210,16 @@ hysteria_traffic_uplink_bytes_total{auth="aGFja2VyISE="} 37452
|
|||||||
"cert": "/home/ubuntu/my_cert.crt", // 证书 (变为 HTTPS 代理)
|
"cert": "/home/ubuntu/my_cert.crt", // 证书 (变为 HTTPS 代理)
|
||||||
"key": "/home/ubuntu/my_key.crt" // 证书密钥 (变为 HTTPS 代理)
|
"key": "/home/ubuntu/my_key.crt" // 证书密钥 (变为 HTTPS 代理)
|
||||||
},
|
},
|
||||||
"relay": {
|
"relay_tcp": {
|
||||||
"listen": "127.0.0.1:2222", // 转发监听地址
|
"listen": "127.0.0.1:2222", // TCP 转发监听地址
|
||||||
"remote": "123.123.123.123:22", // 转发目标地址
|
"remote": "123.123.123.123:22", // TCP 转发目标地址
|
||||||
"timeout": 300 // TCP 超时秒数
|
"timeout": 300 // TCP 超时秒数
|
||||||
},
|
},
|
||||||
|
"relay_udp": {
|
||||||
|
"listen": "127.0.0.1:5333", // UDP 转发监听地址
|
||||||
|
"remote": "8.8.8.8:53", // UDP 转发目标地址
|
||||||
|
"timeout": 60 // UDP 超时秒数
|
||||||
|
},
|
||||||
"acl": "my_list.acl", // 见下文 ACL
|
"acl": "my_list.acl", // 见下文 ACL
|
||||||
"obfs": "AMOGUS", // 混淆密码
|
"obfs": "AMOGUS", // 混淆密码
|
||||||
"auth": "[BASE64]", // Base64 验证密钥
|
"auth": "[BASE64]", // Base64 验证密钥
|
||||||
|
@ -181,10 +181,10 @@ func client(config *clientConfig) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.Relay.Listen) > 0 {
|
if len(config.TCPRelay.Listen) > 0 {
|
||||||
go func() {
|
go func() {
|
||||||
rl, err := relay.NewRelay(client, config.Relay.Listen, config.Relay.Remote,
|
rl, err := relay.NewTCPRelay(client, config.TCPRelay.Listen, config.TCPRelay.Remote,
|
||||||
time.Duration(config.Relay.Timeout)*time.Second,
|
time.Duration(config.TCPRelay.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(),
|
||||||
@ -201,12 +201,40 @@ func client(config *clientConfig) {
|
|||||||
"src": addr.String(),
|
"src": addr.String(),
|
||||||
}).Debug("TCP relay EOF")
|
}).Debug("TCP relay EOF")
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithField("error", err).Fatal("Failed to initialize TCP relay")
|
logrus.WithField("error", err).Fatal("Failed to initialize TCP relay")
|
||||||
}
|
}
|
||||||
logrus.WithField("addr", config.Relay.Listen).Info("TCP relay up and running")
|
logrus.WithField("addr", config.TCPRelay.Listen).Info("TCP relay up and running")
|
||||||
|
errChan <- rl.ListenAndServe()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.UDPRelay.Listen) > 0 {
|
||||||
|
go func() {
|
||||||
|
rl, err := relay.NewUDPRelay(client, config.UDPRelay.Listen, config.UDPRelay.Remote,
|
||||||
|
time.Duration(config.UDPRelay.Timeout)*time.Second,
|
||||||
|
func(addr net.Addr) {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"src": addr.String(),
|
||||||
|
}).Debug("UDP relay request")
|
||||||
|
},
|
||||||
|
func(addr net.Addr, err error) {
|
||||||
|
if err != relay.ErrTimeout {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"error": err,
|
||||||
|
"src": addr.String(),
|
||||||
|
}).Info("UDP relay error")
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"src": addr.String(),
|
||||||
|
}).Debug("UDP relay session closed")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("error", err).Fatal("Failed to initialize UDP relay")
|
||||||
|
}
|
||||||
|
logrus.WithField("addr", config.UDPRelay.Listen).Info("UDP relay up and running")
|
||||||
errChan <- rl.ListenAndServe()
|
errChan <- rl.ListenAndServe()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -80,11 +80,16 @@ type clientConfig struct {
|
|||||||
Cert string `json:"cert"`
|
Cert string `json:"cert"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
} `json:"http"`
|
} `json:"http"`
|
||||||
Relay struct {
|
TCPRelay struct {
|
||||||
Listen string `json:"listen"`
|
Listen string `json:"listen"`
|
||||||
Remote string `json:"remote"`
|
Remote string `json:"remote"`
|
||||||
Timeout int `json:"timeout"`
|
Timeout int `json:"timeout"`
|
||||||
} `json:"relay"`
|
} `json:"relay_tcp"`
|
||||||
|
UDPRelay struct {
|
||||||
|
Listen string `json:"listen"`
|
||||||
|
Remote string `json:"remote"`
|
||||||
|
Timeout int `json:"timeout"`
|
||||||
|
} `json:"relay_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"`
|
||||||
@ -96,11 +101,15 @@ type clientConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *clientConfig) Check() error {
|
func (c *clientConfig) Check() error {
|
||||||
if len(c.SOCKS5.Listen) == 0 && len(c.HTTP.Listen) == 0 && len(c.Relay.Listen) == 0 {
|
if len(c.SOCKS5.Listen) == 0 && len(c.HTTP.Listen) == 0 &&
|
||||||
return errors.New("no SOCKS5, HTTP or relay listen address")
|
len(c.TCPRelay.Listen) == 0 && len(c.UDPRelay.Listen) == 0 {
|
||||||
|
return errors.New("no SOCKS5, HTTP, TCP relay or UDP relay listen address")
|
||||||
}
|
}
|
||||||
if len(c.Relay.Listen) > 0 && len(c.Relay.Remote) == 0 {
|
if len(c.TCPRelay.Listen) > 0 && len(c.TCPRelay.Remote) == 0 {
|
||||||
return errors.New("no relay remote address")
|
return errors.New("no TCP relay remote address")
|
||||||
|
}
|
||||||
|
if len(c.UDPRelay.Listen) > 0 && len(c.UDPRelay.Remote) == 0 {
|
||||||
|
return errors.New("no UDP relay remote address")
|
||||||
}
|
}
|
||||||
if c.SOCKS5.Timeout != 0 && c.SOCKS5.Timeout <= 4 {
|
if c.SOCKS5.Timeout != 0 && c.SOCKS5.Timeout <= 4 {
|
||||||
return errors.New("invalid SOCKS5 timeout")
|
return errors.New("invalid SOCKS5 timeout")
|
||||||
@ -108,8 +117,11 @@ func (c *clientConfig) Check() error {
|
|||||||
if c.HTTP.Timeout != 0 && c.HTTP.Timeout <= 4 {
|
if c.HTTP.Timeout != 0 && c.HTTP.Timeout <= 4 {
|
||||||
return errors.New("invalid HTTP timeout")
|
return errors.New("invalid HTTP timeout")
|
||||||
}
|
}
|
||||||
if c.Relay.Timeout != 0 && c.Relay.Timeout <= 4 {
|
if c.TCPRelay.Timeout != 0 && c.TCPRelay.Timeout <= 4 {
|
||||||
return errors.New("invalid relay timeout")
|
return errors.New("invalid TCP relay timeout")
|
||||||
|
}
|
||||||
|
if c.UDPRelay.Timeout != 0 && c.UDPRelay.Timeout <= 4 {
|
||||||
|
return errors.New("invalid UDP relay timeout")
|
||||||
}
|
}
|
||||||
if len(c.Server) == 0 {
|
if len(c.Server) == 0 {
|
||||||
return errors.New("no server address")
|
return errors.New("no server address")
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Relay struct {
|
type TCPRelay struct {
|
||||||
HyClient *core.Client
|
HyClient *core.Client
|
||||||
ListenAddr *net.TCPAddr
|
ListenAddr *net.TCPAddr
|
||||||
Remote string
|
Remote string
|
||||||
@ -15,17 +15,15 @@ type Relay struct {
|
|||||||
|
|
||||||
ConnFunc func(addr net.Addr)
|
ConnFunc func(addr net.Addr)
|
||||||
ErrorFunc func(addr net.Addr, err error)
|
ErrorFunc func(addr net.Addr, err error)
|
||||||
|
|
||||||
tcpListener *net.TCPListener
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRelay(hyClient *core.Client, 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)) (*Relay, error) {
|
connFunc func(addr net.Addr), errorFunc func(addr net.Addr, err error)) (*TCPRelay, 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
|
||||||
}
|
}
|
||||||
r := &Relay{
|
r := &TCPRelay{
|
||||||
HyClient: hyClient,
|
HyClient: hyClient,
|
||||||
ListenAddr: tAddr,
|
ListenAddr: tAddr,
|
||||||
Remote: remote,
|
Remote: remote,
|
||||||
@ -36,15 +34,14 @@ func NewRelay(hyClient *core.Client, listen, remote string, timeout time.Duratio
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Relay) ListenAndServe() error {
|
func (r *TCPRelay) ListenAndServe() error {
|
||||||
var err error
|
listener, err := net.ListenTCP("tcp", r.ListenAddr)
|
||||||
r.tcpListener, err = net.ListenTCP("tcp", r.ListenAddr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer r.tcpListener.Close()
|
defer listener.Close()
|
||||||
for {
|
for {
|
||||||
c, err := r.tcpListener.AcceptTCP()
|
c, err := listener.AcceptTCP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
135
pkg/relay/udp.go
Normal file
135
pkg/relay/udp.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package relay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/tobyxdd/hysteria/pkg/core"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const udpBufferSize = 65535
|
||||||
|
|
||||||
|
const udpMinTimeout = 4 * time.Second
|
||||||
|
|
||||||
|
var ErrTimeout = errors.New("inactivity timeout")
|
||||||
|
|
||||||
|
type UDPRelay struct {
|
||||||
|
HyClient *core.Client
|
||||||
|
ListenAddr *net.UDPAddr
|
||||||
|
Remote string
|
||||||
|
Timeout time.Duration
|
||||||
|
|
||||||
|
ConnFunc func(addr net.Addr)
|
||||||
|
ErrorFunc func(addr net.Addr, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
uAddr, err := net.ResolveUDPAddr("udp", listen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := &UDPRelay{
|
||||||
|
HyClient: hyClient,
|
||||||
|
ListenAddr: uAddr,
|
||||||
|
Remote: remote,
|
||||||
|
Timeout: timeout,
|
||||||
|
ConnFunc: connFunc,
|
||||||
|
ErrorFunc: errorFunc,
|
||||||
|
}
|
||||||
|
if timeout == 0 {
|
||||||
|
r.Timeout = 1 * time.Minute
|
||||||
|
} else if timeout < udpMinTimeout {
|
||||||
|
r.Timeout = udpMinTimeout
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type cmEntry struct {
|
||||||
|
HyConn core.UDPConn
|
||||||
|
Addr *net.UDPAddr
|
||||||
|
LastActiveTime atomic.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *UDPRelay) ListenAndServe() error {
|
||||||
|
conn, err := net.ListenUDP("udp", r.ListenAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
// src <-> HyClient UDPConn
|
||||||
|
connMap := make(map[string]*cmEntry)
|
||||||
|
var connMapMutex sync.RWMutex
|
||||||
|
// Timeout cleanup routine
|
||||||
|
stopChan := make(chan bool)
|
||||||
|
defer close(stopChan)
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(udpMinTimeout)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-stopChan:
|
||||||
|
return
|
||||||
|
case t := <-ticker.C:
|
||||||
|
allowedLAT := t.Add(-r.Timeout)
|
||||||
|
connMapMutex.Lock()
|
||||||
|
for k, v := range connMap {
|
||||||
|
if v.LastActiveTime.Load().(time.Time).Before(allowedLAT) {
|
||||||
|
// Timeout
|
||||||
|
r.ErrorFunc(v.Addr, ErrTimeout)
|
||||||
|
_ = v.HyConn.Close()
|
||||||
|
delete(connMap, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connMapMutex.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Read loop
|
||||||
|
buf := make([]byte, udpBufferSize)
|
||||||
|
for {
|
||||||
|
n, rAddr, err := conn.ReadFromUDP(buf)
|
||||||
|
if n > 0 {
|
||||||
|
connMapMutex.RLock()
|
||||||
|
cme := connMap[rAddr.String()]
|
||||||
|
connMapMutex.RUnlock()
|
||||||
|
if cme != nil {
|
||||||
|
// Existing conn
|
||||||
|
cme.LastActiveTime.Store(time.Now())
|
||||||
|
_ = cme.HyConn.WriteTo(buf[:n], r.Remote)
|
||||||
|
} else {
|
||||||
|
// New
|
||||||
|
r.ConnFunc(rAddr)
|
||||||
|
hyConn, err := r.HyClient.DialUDP()
|
||||||
|
if err != nil {
|
||||||
|
r.ErrorFunc(rAddr, err)
|
||||||
|
} else {
|
||||||
|
// Add it to the map
|
||||||
|
ent := &cmEntry{HyConn: hyConn, Addr: rAddr}
|
||||||
|
ent.LastActiveTime.Store(time.Now())
|
||||||
|
connMapMutex.Lock()
|
||||||
|
connMap[rAddr.String()] = ent
|
||||||
|
connMapMutex.Unlock()
|
||||||
|
// Start remote to local
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
bs, _, err := hyConn.ReadFrom()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ent.LastActiveTime.Store(time.Now())
|
||||||
|
_, _ = conn.WriteToUDP(bs, rAddr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Send the packet
|
||||||
|
_ = hyConn.WriteTo(buf[:n], r.Remote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user