mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-16 13:02:22 +08:00
Add tcpraw for hysteria
This commit is contained in:
parent
fc533cd38d
commit
80422ae16a
2
go.mod
2
go.mod
|
@ -7,6 +7,7 @@ require (
|
|||
github.com/Dreamacro/clash v1.11.8
|
||||
github.com/caddyserver/certmagic v0.17.2
|
||||
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/database64128/tfo-go/v2 v2.0.2
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
|
@ -15,6 +16,7 @@ require (
|
|||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.2
|
||||
github.com/gofrs/uuid v4.3.0+incompatible
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/hashicorp/yamux v0.1.1
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mholt/acmez v1.0.4
|
||||
|
|
5
go.sum
5
go.sum
|
@ -21,6 +21,8 @@ github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc/go.mod h1:+CauB
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
|
@ -80,6 +82,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
|
@ -205,6 +209,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
|
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
|
|
|
@ -5,6 +5,8 @@ package inbound
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/quic-go"
|
||||
|
@ -15,6 +17,7 @@ import (
|
|||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/transport/hysteria"
|
||||
"github.com/sagernet/sing-box/transport/tcpraw"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
@ -25,12 +28,14 @@ var _ adapter.Inbound = (*Hysteria)(nil)
|
|||
|
||||
type Hysteria struct {
|
||||
myInboundAdapter
|
||||
tcpRaw bool
|
||||
quicConfig *quic.Config
|
||||
tlsConfig tls.ServerConfig
|
||||
authKey []byte
|
||||
xplusKey []byte
|
||||
sendBPS uint64
|
||||
recvBPS uint64
|
||||
rawConn net.PacketConn
|
||||
listener quic.Listener
|
||||
udpAccess sync.RWMutex
|
||||
udpSessionId uint32
|
||||
|
@ -110,6 +115,13 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
recvBPS: down,
|
||||
udpSessions: make(map[uint32]chan *hysteria.UDPMessage),
|
||||
}
|
||||
switch options.Mode {
|
||||
case "", "udp":
|
||||
case "faketcp":
|
||||
inbound.tcpRaw = true
|
||||
default:
|
||||
return nil, E.New("unsupported mode: ", options.Mode)
|
||||
}
|
||||
if options.TLS == nil || !options.TLS.Enabled {
|
||||
return nil, C.ErrTLSRequired
|
||||
}
|
||||
|
@ -125,7 +137,16 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
}
|
||||
|
||||
func (h *Hysteria) Start() error {
|
||||
packetConn, err := h.myInboundAdapter.ListenUDP()
|
||||
var (
|
||||
packetConn net.PacketConn
|
||||
err error
|
||||
)
|
||||
if h.tcpRaw {
|
||||
bindAddr := M.SocksaddrFrom(netip.Addr(h.listenOptions.Listen), h.listenOptions.ListenPort)
|
||||
packetConn, err = tcpraw.Listen("tcp", bindAddr.String())
|
||||
} else {
|
||||
packetConn, err = h.myInboundAdapter.ListenUDP()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -135,17 +156,21 @@ func (h *Hysteria) Start() error {
|
|||
}
|
||||
err = h.tlsConfig.Start()
|
||||
if err != nil {
|
||||
packetConn.Close()
|
||||
return err
|
||||
}
|
||||
rawConfig, err := h.tlsConfig.Config()
|
||||
if err != nil {
|
||||
packetConn.Close()
|
||||
return err
|
||||
}
|
||||
listener, err := quic.Listen(packetConn, rawConfig, h.quicConfig)
|
||||
if err != nil {
|
||||
packetConn.Close()
|
||||
return err
|
||||
}
|
||||
h.listener = listener
|
||||
h.rawConn = packetConn
|
||||
h.logger.Info("udp server started at ", listener.Addr())
|
||||
go h.acceptLoop()
|
||||
return nil
|
||||
|
@ -311,6 +336,7 @@ func (h *Hysteria) Close() error {
|
|||
return common.Close(
|
||||
&h.myInboundAdapter,
|
||||
h.listener,
|
||||
h.rawConn,
|
||||
h.tlsConfig,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package option
|
|||
|
||||
type HysteriaInboundOptions struct {
|
||||
ListenOptions
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Up string `json:"up,omitempty"`
|
||||
UpMbps int `json:"up_mbps,omitempty"`
|
||||
Down string `json:"down,omitempty"`
|
||||
|
@ -19,6 +20,7 @@ type HysteriaInboundOptions struct {
|
|||
type HysteriaOutboundOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Up string `json:"up,omitempty"`
|
||||
UpMbps int `json:"up_mbps,omitempty"`
|
||||
Down string `json:"down,omitempty"`
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/transport/hysteria"
|
||||
"github.com/sagernet/sing-box/transport/tcpraw"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
@ -27,6 +28,7 @@ var _ adapter.Outbound = (*Hysteria)(nil)
|
|||
|
||||
type Hysteria struct {
|
||||
myOutboundAdapter
|
||||
tcpRaw bool
|
||||
ctx context.Context
|
||||
dialer N.Dialer
|
||||
serverAddr M.Socksaddr
|
||||
|
@ -38,7 +40,7 @@ type Hysteria struct {
|
|||
recvBPS uint64
|
||||
connAccess sync.Mutex
|
||||
conn quic.Connection
|
||||
rawConn net.Conn
|
||||
rawConn net.PacketConn
|
||||
udpAccess sync.RWMutex
|
||||
udpSessions map[uint32]chan *hysteria.UDPMessage
|
||||
udpDefragger hysteria.Defragger
|
||||
|
@ -114,7 +116,7 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
if down < hysteria.MinSpeedBPS {
|
||||
return nil, E.New("invalid down speed")
|
||||
}
|
||||
return &Hysteria{
|
||||
outbound := &Hysteria{
|
||||
myOutboundAdapter: myOutboundAdapter{
|
||||
protocol: C.TypeHysteria,
|
||||
network: options.Network.Build(),
|
||||
|
@ -131,7 +133,15 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
xplusKey: xplus,
|
||||
sendBPS: up,
|
||||
recvBPS: down,
|
||||
}, nil
|
||||
}
|
||||
switch options.Mode {
|
||||
case "", "udp":
|
||||
case "faketcp":
|
||||
outbound.tcpRaw = true
|
||||
default:
|
||||
return nil, E.New("unsupported mode: ", options.Mode)
|
||||
}
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) {
|
||||
|
@ -163,17 +173,28 @@ func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) {
|
|||
}
|
||||
|
||||
func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) {
|
||||
udpConn, err := h.dialer.DialContext(h.ctx, "udp", h.serverAddr)
|
||||
var packetConn net.PacketConn
|
||||
var remoteAddr net.Addr
|
||||
var err error
|
||||
if h.tcpRaw {
|
||||
packetConn, err = tcpraw.Dial("tcp", h.serverAddr.String())
|
||||
remoteAddr = h.serverAddr.UDPAddr()
|
||||
} else {
|
||||
var conn net.Conn
|
||||
conn, err = h.dialer.DialContext(h.ctx, "udp", h.serverAddr)
|
||||
if err == nil {
|
||||
packetConn = bufio.NewUnbindPacketConn(conn)
|
||||
remoteAddr = conn.RemoteAddr()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var packetConn net.PacketConn
|
||||
packetConn = bufio.NewUnbindPacketConn(udpConn)
|
||||
if h.xplusKey != nil {
|
||||
packetConn = hysteria.NewXPlusPacketConn(packetConn, h.xplusKey)
|
||||
}
|
||||
packetConn = &hysteria.PacketConnWrapper{PacketConn: packetConn}
|
||||
quicConn, err := quic.Dial(packetConn, udpConn.RemoteAddr(), h.serverAddr.AddrString(), h.tlsConfig, h.quicConfig)
|
||||
quicConn, err := quic.Dial(packetConn, remoteAddr, h.serverAddr.AddrString(), h.tlsConfig, h.quicConfig)
|
||||
if err != nil {
|
||||
packetConn.Close()
|
||||
return nil, err
|
||||
|
@ -203,7 +224,7 @@ func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) {
|
|||
}
|
||||
quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS)))
|
||||
h.conn = quicConn
|
||||
h.rawConn = udpConn
|
||||
h.rawConn = packetConn
|
||||
return quicConn, nil
|
||||
}
|
||||
|
||||
|
|
20
test/go.mod
20
test/go.mod
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/spyzhov/ajson v0.7.1
|
||||
github.com/stretchr/testify v1.8.0
|
||||
go.uber.org/goleak v1.2.0
|
||||
golang.org/x/net v0.0.0-20221004154528-8021a29435af
|
||||
golang.org/x/net v0.0.0-20221017152216-f25eb7ecb193
|
||||
)
|
||||
|
||||
//replace github.com/sagernet/sing => ../../sing
|
||||
|
@ -28,12 +28,13 @@ require (
|
|||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/caddyserver/certmagic v0.17.2 // indirect
|
||||
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc // indirect
|
||||
github.com/coreos/go-iptables v0.6.0 // indirect
|
||||
github.com/cretz/bine v0.2.0 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.0.1 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.7 // indirect
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/go-chi/render v1.0.2 // indirect
|
||||
|
@ -42,8 +43,9 @@ require (
|
|||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
|
@ -62,13 +64,13 @@ require (
|
|||
github.com/pires/go-proxyproto v0.6.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/refraction-networking/utls v1.1.2 // indirect
|
||||
github.com/refraction-networking/utls v1.1.5 // indirect
|
||||
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect
|
||||
github.com/sagernet/sing-dns v0.0.0-20220929010544-ee843807aae3 // indirect
|
||||
github.com/sagernet/sing-tun v0.0.0-20221009132126-1ede22e6eb7e // indirect
|
||||
github.com/sagernet/sing-tun v0.0.0-20221012082254-488c3b75f6fd // indirect
|
||||
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
|
||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
||||
|
@ -79,17 +81,17 @@ require (
|
|||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab // indirect
|
||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b // indirect
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b // indirect
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
|
||||
google.golang.org/grpc v1.49.0 // indirect
|
||||
google.golang.org/grpc v1.50.1 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
49
test/go.sum
49
test/go.sum
|
@ -25,12 +25,14 @@ github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc/go.mod h1:+CauB
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/database64128/tfo-go/v2 v2.0.1 h1:VFfturVoq6NmPGfhXO1K15x82KR19aAfw1RYtTzyVv4=
|
||||
github.com/database64128/tfo-go/v2 v2.0.1/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY=
|
||||
github.com/database64128/tfo-go/v2 v2.0.2 h1:5rGgkJeLEKlNaqredfrPQNLnctn1b+1fq/8tdKdOzJg=
|
||||
github.com/database64128/tfo-go/v2 v2.0.2/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -50,8 +52,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
|
@ -92,6 +94,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
|
@ -99,8 +103,8 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg
|
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
|
@ -152,8 +156,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/refraction-networking/utls v1.1.2 h1:a7GQauRt72VG+wtNm0lnrAaCGlyX47gEi1++dSsDBpw=
|
||||
github.com/refraction-networking/utls v1.1.2/go.mod h1:+D89TUtA8+NKVFj1IXWr0p3tSdX1+SqUB7rL0QnGqyg=
|
||||
github.com/refraction-networking/utls v1.1.5 h1:JtrojoNhbUQkBqEg05sP3gDgDj6hIEAAVKbI9lx4n6w=
|
||||
github.com/refraction-networking/utls v1.1.5/go.mod h1:jRQxtYi7nkq1p28HF2lwOH5zQm9aC8rpK0O9lIIzGh8=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34=
|
||||
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g=
|
||||
|
@ -171,8 +175,8 @@ github.com/sagernet/sing-dns v0.0.0-20220929010544-ee843807aae3 h1:AEdyJxEDFq38z
|
|||
github.com/sagernet/sing-dns v0.0.0-20220929010544-ee843807aae3/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
||||
github.com/sagernet/sing-tun v0.0.0-20221009132126-1ede22e6eb7e h1:UIE1wKIr92d2VUWox3On8JQknvewl7aeG+JfthISX0w=
|
||||
github.com/sagernet/sing-tun v0.0.0-20221009132126-1ede22e6eb7e/go.mod h1:qbqV9lwcXJnj1Tw4we7oA6Z8zGE/kCXQBCzuhzRWVw8=
|
||||
github.com/sagernet/sing-tun v0.0.0-20221012082254-488c3b75f6fd h1:TtoZDwg09Cpqi+gCmCtL6w4oEUZ5lHz+vHIjdr1UBNY=
|
||||
github.com/sagernet/sing-tun v0.0.0-20221012082254-488c3b75f6fd/go.mod h1:1u3pjXA9HmH7kRiBJqM3C/zPxrxnCLd3svmqtub/RFU=
|
||||
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685 h1:AZzFNRR/ZwMTceUQ1b/mxx6oyKqmFymdMn/yleJmoVM=
|
||||
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
||||
|
@ -220,9 +224,9 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
|
||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
|
||||
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
|
@ -230,6 +234,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
|
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
|
@ -255,10 +260,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
|
||||
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20221017152216-f25eb7ecb193 h1:3Moaxt4TfzNcQH6DWvlYKraN1ozhBXQHcgvXjRGeim0=
|
||||
golang.org/x/net v0.0.0-20221017152216-f25eb7ecb193/go.mod h1:RpDiru2p0u2F0lLpEoqnP2+7xs0ifAuOcJ442g6GU2s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -293,13 +299,14 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -352,8 +359,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
|
|
@ -9,6 +9,14 @@ import (
|
|||
)
|
||||
|
||||
func TestHysteriaSelf(t *testing.T) {
|
||||
testHysteriaSelf(t, "udp")
|
||||
}
|
||||
|
||||
func TestHysteriaTCPRawSelf(t *testing.T) {
|
||||
testHysteriaSelf(t, "faketcp")
|
||||
}
|
||||
|
||||
func testHysteriaSelf(t *testing.T, mode string) {
|
||||
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
|
@ -29,6 +37,7 @@ func TestHysteriaSelf(t *testing.T) {
|
|||
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Mode: mode,
|
||||
UpMbps: 100,
|
||||
DownMbps: 100,
|
||||
AuthString: "password",
|
||||
|
@ -54,6 +63,7 @@ func TestHysteriaSelf(t *testing.T) {
|
|||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
Mode: mode,
|
||||
UpMbps: 100,
|
||||
DownMbps: 100,
|
||||
AuthString: "password",
|
||||
|
|
19
transport/hysteria/fake.go
Normal file
19
transport/hysteria/fake.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package hysteria
|
||||
|
||||
import "syscall"
|
||||
|
||||
var _ syscall.RawConn = (*FakeSyscallConn)(nil)
|
||||
|
||||
type FakeSyscallConn struct{}
|
||||
|
||||
func (c *FakeSyscallConn) Control(f func(fd uintptr)) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FakeSyscallConn) Read(f func(fd uintptr) (done bool)) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FakeSyscallConn) Write(f func(fd uintptr) (done bool)) error {
|
||||
return nil
|
||||
}
|
|
@ -10,24 +10,47 @@ import (
|
|||
"github.com/sagernet/sing/common"
|
||||
)
|
||||
|
||||
type AbstractPacketConn interface {
|
||||
SetReadBuffer(int) error
|
||||
SetWriteBuffer(int) error
|
||||
File() (*os.File, error)
|
||||
}
|
||||
|
||||
type PacketConnWrapper struct {
|
||||
net.PacketConn
|
||||
}
|
||||
|
||||
func (c *PacketConnWrapper) SetReadBuffer(bytes int) error {
|
||||
return common.MustCast[*net.UDPConn](c.PacketConn).SetReadBuffer(bytes)
|
||||
conn, ok := common.Cast[AbstractPacketConn](c.PacketConn)
|
||||
if !ok {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
return conn.SetReadBuffer(bytes)
|
||||
}
|
||||
|
||||
func (c *PacketConnWrapper) SetWriteBuffer(bytes int) error {
|
||||
return common.MustCast[*net.UDPConn](c.PacketConn).SetWriteBuffer(bytes)
|
||||
conn, ok := common.Cast[AbstractPacketConn](c.PacketConn)
|
||||
if !ok {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
return conn.SetWriteBuffer(bytes)
|
||||
}
|
||||
|
||||
func (c *PacketConnWrapper) SyscallConn() (syscall.RawConn, error) {
|
||||
return common.MustCast[*net.UDPConn](c.PacketConn).SyscallConn()
|
||||
conn, ok := common.Cast[syscall.Conn](c.PacketConn)
|
||||
if !ok {
|
||||
// fix quic-go
|
||||
return &FakeSyscallConn{}, nil
|
||||
}
|
||||
return conn.SyscallConn()
|
||||
}
|
||||
|
||||
func (c *PacketConnWrapper) File() (f *os.File, err error) {
|
||||
return common.MustCast[*net.UDPConn](c.PacketConn).File()
|
||||
r, ok := common.Cast[AbstractPacketConn](c.PacketConn)
|
||||
if !ok {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
return r.File()
|
||||
}
|
||||
|
||||
func (c *PacketConnWrapper) Upstream() any {
|
||||
|
|
609
transport/tcpraw/tcp_linux.go
Normal file
609
transport/tcpraw/tcp_linux.go
Normal file
|
@ -0,0 +1,609 @@
|
|||
//go:build linux && with_tcpraw
|
||||
|
||||
package tcpraw
|
||||
|
||||
// kanged from https://github.com/xtaci/tcpraw
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-iptables/iptables"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
var (
|
||||
errOpNotImplemented = errors.New("operation not implemented")
|
||||
errTimeout = errors.New("timeout")
|
||||
expire = time.Minute
|
||||
)
|
||||
|
||||
// a message from NIC
|
||||
type message struct {
|
||||
bts []byte
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
// a tcp flow information of a connection pair
|
||||
type tcpFlow struct {
|
||||
conn *net.TCPConn // the related system TCP connection of this flow
|
||||
handle *net.IPConn // the handle to send packets
|
||||
seq uint32 // TCP sequence number
|
||||
ack uint32 // TCP acknowledge number
|
||||
networkLayer gopacket.SerializableLayer // network layer header for tx
|
||||
ts time.Time // last packet incoming time
|
||||
buf gopacket.SerializeBuffer // a buffer for write
|
||||
tcpHeader layers.TCP
|
||||
}
|
||||
|
||||
// TCPConn defines a TCP-packet oriented connection
|
||||
type TCPConn struct {
|
||||
die chan struct{}
|
||||
dieOnce sync.Once
|
||||
|
||||
// the main golang sockets
|
||||
tcpconn *net.TCPConn // from net.Dial
|
||||
listener *net.TCPListener // from net.Listen
|
||||
|
||||
// handles
|
||||
handles []*net.IPConn
|
||||
|
||||
// packets captured from all related NICs will be delivered to this channel
|
||||
chMessage chan message
|
||||
|
||||
// all TCP flows
|
||||
flowTable map[string]*tcpFlow
|
||||
flowsLock sync.Mutex
|
||||
|
||||
// iptables
|
||||
iptables *iptables.IPTables
|
||||
iprule []string
|
||||
|
||||
ip6tables *iptables.IPTables
|
||||
ip6rule []string
|
||||
|
||||
// deadlines
|
||||
readDeadline atomic.Value
|
||||
writeDeadline atomic.Value
|
||||
|
||||
// serialization
|
||||
opts gopacket.SerializeOptions
|
||||
}
|
||||
|
||||
// lockflow locks the flow table and apply function `f` to the entry, and create one if not exist
|
||||
func (conn *TCPConn) lockflow(addr net.Addr, f func(e *tcpFlow)) {
|
||||
key := addr.String()
|
||||
conn.flowsLock.Lock()
|
||||
e := conn.flowTable[key]
|
||||
if e == nil { // entry first visit
|
||||
e = new(tcpFlow)
|
||||
e.ts = time.Now()
|
||||
e.buf = gopacket.NewSerializeBuffer()
|
||||
}
|
||||
f(e)
|
||||
conn.flowTable[key] = e
|
||||
conn.flowsLock.Unlock()
|
||||
}
|
||||
|
||||
// clean expired flows
|
||||
func (conn *TCPConn) cleaner() {
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
select {
|
||||
case <-conn.die:
|
||||
return
|
||||
case <-ticker.C:
|
||||
conn.flowsLock.Lock()
|
||||
for k, v := range conn.flowTable {
|
||||
if time.Now().Sub(v.ts) > expire {
|
||||
if v.conn != nil {
|
||||
setTTL(v.conn, 64)
|
||||
v.conn.Close()
|
||||
}
|
||||
delete(conn.flowTable, k)
|
||||
}
|
||||
}
|
||||
conn.flowsLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// captureFlow capture every inbound packets based on rules of BPF
|
||||
func (conn *TCPConn) captureFlow(handle *net.IPConn, port int) {
|
||||
buf := make([]byte, 2048)
|
||||
opt := gopacket.DecodeOptions{NoCopy: true, Lazy: true}
|
||||
for {
|
||||
n, addr, err := handle.ReadFromIP(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// try decoding TCP frame from buf[:n]
|
||||
packet := gopacket.NewPacket(buf[:n], layers.LayerTypeTCP, opt)
|
||||
transport := packet.TransportLayer()
|
||||
tcp, ok := transport.(*layers.TCP)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// port filtering
|
||||
if int(tcp.DstPort) != port {
|
||||
continue
|
||||
}
|
||||
|
||||
// address building
|
||||
var src net.TCPAddr
|
||||
src.IP = addr.IP
|
||||
src.Port = int(tcp.SrcPort)
|
||||
|
||||
var orphan bool
|
||||
// flow maintaince
|
||||
conn.lockflow(&src, func(e *tcpFlow) {
|
||||
if e.conn == nil { // make sure it's related to net.TCPConn
|
||||
orphan = true // mark as orphan if it's not related net.TCPConn
|
||||
}
|
||||
|
||||
// to keep track of TCP header related to this source
|
||||
e.ts = time.Now()
|
||||
if tcp.ACK {
|
||||
e.seq = tcp.Ack
|
||||
}
|
||||
if tcp.SYN {
|
||||
e.ack = tcp.Seq + 1
|
||||
}
|
||||
if tcp.PSH {
|
||||
if e.ack == tcp.Seq {
|
||||
e.ack = tcp.Seq + uint32(len(tcp.Payload))
|
||||
}
|
||||
}
|
||||
e.handle = handle
|
||||
})
|
||||
|
||||
// push data if it's not orphan
|
||||
if !orphan && tcp.PSH {
|
||||
payload := make([]byte, len(tcp.Payload))
|
||||
copy(payload, tcp.Payload)
|
||||
select {
|
||||
case conn.chMessage <- message{payload, &src}:
|
||||
case <-conn.die:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReadFrom implements the PacketConn ReadFrom method.
|
||||
func (conn *TCPConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
var timer *time.Timer
|
||||
var deadline <-chan time.Time
|
||||
if d, ok := conn.readDeadline.Load().(time.Time); ok && !d.IsZero() {
|
||||
timer = time.NewTimer(time.Until(d))
|
||||
defer timer.Stop()
|
||||
deadline = timer.C
|
||||
}
|
||||
|
||||
select {
|
||||
case <-deadline:
|
||||
return 0, nil, errTimeout
|
||||
case <-conn.die:
|
||||
return 0, nil, io.EOF
|
||||
case packet := <-conn.chMessage:
|
||||
n = copy(p, packet.bts)
|
||||
return n, packet.addr, nil
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTo implements the PacketConn WriteTo method.
|
||||
func (conn *TCPConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
var deadline <-chan time.Time
|
||||
if d, ok := conn.writeDeadline.Load().(time.Time); ok && !d.IsZero() {
|
||||
timer := time.NewTimer(time.Until(d))
|
||||
defer timer.Stop()
|
||||
deadline = timer.C
|
||||
}
|
||||
|
||||
select {
|
||||
case <-deadline:
|
||||
return 0, errTimeout
|
||||
case <-conn.die:
|
||||
return 0, io.EOF
|
||||
default:
|
||||
raddr, err := net.ResolveTCPAddr("tcp", addr.String())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var lport int
|
||||
if conn.tcpconn != nil {
|
||||
lport = conn.tcpconn.LocalAddr().(*net.TCPAddr).Port
|
||||
} else {
|
||||
lport = conn.listener.Addr().(*net.TCPAddr).Port
|
||||
}
|
||||
|
||||
conn.lockflow(addr, func(e *tcpFlow) {
|
||||
// if the flow doesn't have handle , assume this packet has lost, without notification
|
||||
if e.handle == nil {
|
||||
n = len(p)
|
||||
return
|
||||
}
|
||||
|
||||
// build tcp header with local and remote port
|
||||
e.tcpHeader.SrcPort = layers.TCPPort(lport)
|
||||
e.tcpHeader.DstPort = layers.TCPPort(raddr.Port)
|
||||
binary.Read(rand.Reader, binary.LittleEndian, &e.tcpHeader.Window)
|
||||
e.tcpHeader.Window |= 0x8000 // make sure it's larger than 32768
|
||||
e.tcpHeader.Ack = e.ack
|
||||
e.tcpHeader.Seq = e.seq
|
||||
e.tcpHeader.PSH = true
|
||||
e.tcpHeader.ACK = true
|
||||
|
||||
// build IP header with src & dst ip for TCP checksum
|
||||
if raddr.IP.To4() != nil {
|
||||
ip := &layers.IPv4{
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
SrcIP: e.handle.LocalAddr().(*net.IPAddr).IP.To4(),
|
||||
DstIP: raddr.IP.To4(),
|
||||
}
|
||||
e.tcpHeader.SetNetworkLayerForChecksum(ip)
|
||||
} else {
|
||||
ip := &layers.IPv6{
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
SrcIP: e.handle.LocalAddr().(*net.IPAddr).IP.To16(),
|
||||
DstIP: raddr.IP.To16(),
|
||||
}
|
||||
e.tcpHeader.SetNetworkLayerForChecksum(ip)
|
||||
}
|
||||
|
||||
e.buf.Clear()
|
||||
gopacket.SerializeLayers(e.buf, conn.opts, &e.tcpHeader, gopacket.Payload(p))
|
||||
if conn.tcpconn != nil {
|
||||
_, err = e.handle.Write(e.buf.Bytes())
|
||||
} else {
|
||||
_, err = e.handle.WriteToIP(e.buf.Bytes(), &net.IPAddr{IP: raddr.IP})
|
||||
}
|
||||
// increase seq in flow
|
||||
e.seq += uint32(len(p))
|
||||
n = len(p)
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
func (conn *TCPConn) Close() error {
|
||||
var err error
|
||||
conn.dieOnce.Do(func() {
|
||||
// signal closing
|
||||
close(conn.die)
|
||||
|
||||
// close all established tcp connections
|
||||
if conn.tcpconn != nil { // client
|
||||
setTTL(conn.tcpconn, 64)
|
||||
err = conn.tcpconn.Close()
|
||||
} else if conn.listener != nil {
|
||||
err = conn.listener.Close() // server
|
||||
conn.flowsLock.Lock()
|
||||
for k, v := range conn.flowTable {
|
||||
if v.conn != nil {
|
||||
setTTL(v.conn, 64)
|
||||
v.conn.Close()
|
||||
}
|
||||
delete(conn.flowTable, k)
|
||||
}
|
||||
conn.flowsLock.Unlock()
|
||||
}
|
||||
|
||||
// close handles
|
||||
for k := range conn.handles {
|
||||
conn.handles[k].Close()
|
||||
}
|
||||
|
||||
// delete iptable
|
||||
if conn.iptables != nil {
|
||||
conn.iptables.Delete("filter", "OUTPUT", conn.iprule...)
|
||||
}
|
||||
if conn.ip6tables != nil {
|
||||
conn.ip6tables.Delete("filter", "OUTPUT", conn.ip6rule...)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address.
|
||||
func (conn *TCPConn) LocalAddr() net.Addr {
|
||||
if conn.tcpconn != nil {
|
||||
return conn.tcpconn.LocalAddr()
|
||||
} else if conn.listener != nil {
|
||||
return conn.listener.Addr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDeadline implements the Conn SetDeadline method.
|
||||
func (conn *TCPConn) SetDeadline(t time.Time) error {
|
||||
if err := conn.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := conn.SetWriteDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline implements the Conn SetReadDeadline method.
|
||||
func (conn *TCPConn) SetReadDeadline(t time.Time) error {
|
||||
conn.readDeadline.Store(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline implements the Conn SetWriteDeadline method.
|
||||
func (conn *TCPConn) SetWriteDeadline(t time.Time) error {
|
||||
conn.writeDeadline.Store(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDSCP sets the 6bit DSCP field in IPv4 header, or 8bit Traffic Class in IPv6 header.
|
||||
func (conn *TCPConn) SetDSCP(dscp int) error {
|
||||
for k := range conn.handles {
|
||||
if err := setDSCP(conn.handles[k], dscp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadBuffer sets the size of the operating system's receive buffer associated with the connection.
|
||||
func (conn *TCPConn) SetReadBuffer(bytes int) error {
|
||||
var err error
|
||||
for k := range conn.handles {
|
||||
if err := conn.handles[k].SetReadBuffer(bytes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SetWriteBuffer sets the size of the operating system's transmit buffer associated with the connection.
|
||||
func (conn *TCPConn) SetWriteBuffer(bytes int) error {
|
||||
var err error
|
||||
for k := range conn.handles {
|
||||
if err := conn.handles[k].SetWriteBuffer(bytes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Dial connects to the remote TCP port,
|
||||
// and returns a single packet-oriented connection
|
||||
func Dial(network, address string) (*TCPConn, error) {
|
||||
// remote address resolve
|
||||
raddr, err := net.ResolveTCPAddr(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// AF_INET
|
||||
handle, err := net.DialIP("ip:tcp", nil, &net.IPAddr{IP: raddr.IP})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create an established tcp connection
|
||||
// will hack this tcp connection for packet transmission
|
||||
tcpconn, err := net.DialTCP(network, nil, raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fields
|
||||
conn := new(TCPConn)
|
||||
conn.die = make(chan struct{})
|
||||
conn.flowTable = make(map[string]*tcpFlow)
|
||||
conn.tcpconn = tcpconn
|
||||
conn.chMessage = make(chan message)
|
||||
conn.lockflow(tcpconn.RemoteAddr(), func(e *tcpFlow) { e.conn = tcpconn })
|
||||
conn.handles = append(conn.handles, handle)
|
||||
conn.opts = gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
go conn.captureFlow(handle, tcpconn.LocalAddr().(*net.TCPAddr).Port)
|
||||
go conn.cleaner()
|
||||
|
||||
// iptables
|
||||
err = setTTL(tcpconn, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4); err == nil {
|
||||
rule := []string{"-m", "ttl", "--ttl-eq", "1", "-p", "tcp", "-d", raddr.IP.String(), "--dport", fmt.Sprint(raddr.Port), "-j", "DROP"}
|
||||
if exists, err := ipt.Exists("filter", "OUTPUT", rule...); err == nil {
|
||||
if !exists {
|
||||
if err = ipt.Append("filter", "OUTPUT", rule...); err == nil {
|
||||
conn.iprule = rule
|
||||
conn.iptables = ipt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv6); err == nil {
|
||||
rule := []string{"-m", "hl", "--hl-eq", "1", "-p", "tcp", "-d", raddr.IP.String(), "--dport", fmt.Sprint(raddr.Port), "-j", "DROP"}
|
||||
if exists, err := ipt.Exists("filter", "OUTPUT", rule...); err == nil {
|
||||
if !exists {
|
||||
if err = ipt.Append("filter", "OUTPUT", rule...); err == nil {
|
||||
conn.ip6rule = rule
|
||||
conn.ip6tables = ipt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// discard everything
|
||||
go io.Copy(ioutil.Discard, tcpconn)
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Listen acts like net.ListenTCP,
|
||||
// and returns a single packet-oriented connection
|
||||
func Listen(network, address string) (*TCPConn, error) {
|
||||
// fields
|
||||
conn := new(TCPConn)
|
||||
conn.flowTable = make(map[string]*tcpFlow)
|
||||
conn.die = make(chan struct{})
|
||||
conn.chMessage = make(chan message)
|
||||
conn.opts = gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
|
||||
// resolve address
|
||||
laddr, err := net.ResolveTCPAddr(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// AF_INET
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if laddr.IP == nil || laddr.IP.IsUnspecified() { // if address is not specified, capture on all ifaces
|
||||
var lasterr error
|
||||
for _, iface := range ifaces {
|
||||
if addrs, err := iface.Addrs(); err == nil {
|
||||
for _, addr := range addrs {
|
||||
if ipaddr, ok := addr.(*net.IPNet); ok {
|
||||
if handle, err := net.ListenIP("ip:tcp", &net.IPAddr{IP: ipaddr.IP}); err == nil {
|
||||
conn.handles = append(conn.handles, handle)
|
||||
go conn.captureFlow(handle, laddr.Port)
|
||||
} else {
|
||||
lasterr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(conn.handles) == 0 {
|
||||
return nil, lasterr
|
||||
}
|
||||
} else {
|
||||
if handle, err := net.ListenIP("ip:tcp", &net.IPAddr{IP: laddr.IP}); err == nil {
|
||||
conn.handles = append(conn.handles, handle)
|
||||
go conn.captureFlow(handle, laddr.Port)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// start listening
|
||||
l, err := net.ListenTCP(network, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn.listener = l
|
||||
|
||||
// start cleaner
|
||||
go conn.cleaner()
|
||||
|
||||
// iptables drop packets marked with TTL = 1
|
||||
// TODO: what if iptables is not available, the next hop will send back ICMP Time Exceeded,
|
||||
// is this still an acceptable behavior?
|
||||
if ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4); err == nil {
|
||||
rule := []string{"-m", "ttl", "--ttl-eq", "1", "-p", "tcp", "--sport", fmt.Sprint(laddr.Port), "-j", "DROP"}
|
||||
if exists, err := ipt.Exists("filter", "OUTPUT", rule...); err == nil {
|
||||
if !exists {
|
||||
if err = ipt.Append("filter", "OUTPUT", rule...); err == nil {
|
||||
conn.iprule = rule
|
||||
conn.iptables = ipt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv6); err == nil {
|
||||
rule := []string{"-m", "hl", "--hl-eq", "1", "-p", "tcp", "--sport", fmt.Sprint(laddr.Port), "-j", "DROP"}
|
||||
if exists, err := ipt.Exists("filter", "OUTPUT", rule...); err == nil {
|
||||
if !exists {
|
||||
if err = ipt.Append("filter", "OUTPUT", rule...); err == nil {
|
||||
conn.ip6rule = rule
|
||||
conn.ip6tables = ipt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// discard everything in original connection
|
||||
go func() {
|
||||
for {
|
||||
tcpconn, err := l.AcceptTCP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// if we cannot set TTL = 1, the only thing reasonable is panic
|
||||
if err := setTTL(tcpconn, 1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// record net.Conn
|
||||
conn.lockflow(tcpconn.RemoteAddr(), func(e *tcpFlow) { e.conn = tcpconn })
|
||||
|
||||
// discard everything
|
||||
go io.Copy(ioutil.Discard, tcpconn)
|
||||
}
|
||||
}()
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// setTTL sets the Time-To-Live field on a given connection
|
||||
func setTTL(c *net.TCPConn, ttl int) error {
|
||||
raw, err := c.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addr := c.LocalAddr().(*net.TCPAddr)
|
||||
|
||||
if addr.IP.To4() == nil {
|
||||
raw.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, ttl)
|
||||
})
|
||||
} else {
|
||||
raw.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TTL, ttl)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// setDSCP sets the 6bit DSCP field in IPv4 header, or 8bit Traffic Class in IPv6 header.
|
||||
func setDSCP(c *net.IPConn, dscp int) error {
|
||||
raw, err := c.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addr := c.LocalAddr().(*net.IPAddr)
|
||||
|
||||
if addr.IP.To4() == nil {
|
||||
raw.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, dscp)
|
||||
})
|
||||
} else {
|
||||
raw.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, dscp<<2)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
20
transport/tcpraw/tcp_stub.go
Normal file
20
transport/tcpraw/tcp_stub.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
//go:build !linux || !with_tcpraw
|
||||
|
||||
package tcpraw
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
type TCPConn struct{ *net.UDPConn }
|
||||
|
||||
// Dial connects to the remote TCP port,
|
||||
// and returns a single packet-oriented connection
|
||||
func Dial(network, address string) (*TCPConn, error) {
|
||||
return nil, errors.New("tcpraw is not supported on current os")
|
||||
}
|
||||
|
||||
func Listen(network, address string) (*TCPConn, error) {
|
||||
return nil, errors.New("os not supported")
|
||||
}
|
Loading…
Reference in New Issue
Block a user