Compare commits

..

18 Commits

Author SHA1 Message Date
世界
5bd143b9bd documentation: Update changelog 2023-04-16 16:49:02 +08:00
世界
3c10ed3a0c urltest: Start ticker when used 2023-04-16 16:46:08 +08:00
世界
ac508fe472 shadowsocks: Multi-user support for legacy AEAD inbound
Signed-off-by: wwqgtxx <wwqgtxx@gmail.com>
2023-04-16 16:46:08 +08:00
世界
7141ed6e0c Add headers option for HTTP outbound 2023-04-16 16:46:08 +08:00
世界
1574012767 urltest: Recheck after network change 2023-04-16 16:29:52 +08:00
世界
09ee24ce63 Fix wireguard reconnect 2023-04-16 16:29:44 +08:00
世界
2113ade341 Use HTTPS URLTest source 2023-04-16 16:29:44 +08:00
H1JK
1d0e052971 Add BaseContext to http servers 2023-04-16 16:29:44 +08:00
H1JK
0b4d0da1b1 Fix gRPC service name escape 2023-04-16 16:29:44 +08:00
Hellojack
4e7eed989b Remove TLS requirement for gRPC client 2023-04-16 16:29:44 +08:00
世界
0708f871d0 clash-api: Add Clash.Meta APIs 2023-04-16 16:29:38 +08:00
世界
f95c617844 Update to uuid v5 2023-04-16 16:29:36 +08:00
世界
afdd32b656 clash api: download clash-dashboard if external-ui directory is empty 2023-04-16 16:29:34 +08:00
世界
20acbbe68f Fix read deadline implementation 2023-04-16 16:29:32 +08:00
世界
a486add3ec Add multi-peer support for wireguard outbound 2023-04-16 16:29:21 +08:00
世界
a0d27078bd Add fakeip support 2023-04-16 16:29:20 +08:00
世界
afcc8b204f Add L3 routing support 2023-04-16 16:29:20 +08:00
世界
9b762e3c2e Add dns reverse mapping 2023-04-16 16:29:20 +08:00
69 changed files with 503 additions and 1107 deletions

View File

@@ -37,7 +37,6 @@ type Router interface {
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
InterfaceFinder() control.InterfaceFinder
UpdateInterfaces() error
DefaultInterface() string
AutoDetectInterface() bool
AutoDetectInterfaceFunc() control.Func

6
box.go
View File

@@ -133,12 +133,6 @@ func New(options Options) (*Box, error) {
if err != nil {
return nil, err
}
if options.PlatformInterface != nil {
err = options.PlatformInterface.Initialize(ctx, router)
if err != nil {
return nil, E.Cause(err, "initialize platform interface")
}
}
preServices := make(map[string]adapter.Service)
postServices := make(map[string]adapter.Service)
if needClashAPI {

View File

@@ -1,4 +1,4 @@
//go:build go1.20 && !go1.21
//go:build go1.19 && !go1.20
package badtls
@@ -14,60 +14,39 @@ import (
"sync/atomic"
"unsafe"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
aTLS "github.com/sagernet/sing/common/tls"
)
type Conn struct {
*tls.Conn
writer N.ExtendedWriter
isHandshakeComplete *atomic.Bool
activeCall *atomic.Int32
closeNotifySent *bool
version *uint16
rand io.Reader
halfAccess *sync.Mutex
halfError *error
cipher cipher.AEAD
explicitNonceLen int
halfPtr uintptr
halfSeq []byte
halfScratchBuf []byte
writer N.ExtendedWriter
activeCall *int32
closeNotifySent *bool
version *uint16
rand io.Reader
halfAccess *sync.Mutex
halfError *error
cipher cipher.AEAD
explicitNonceLen int
halfPtr uintptr
halfSeq []byte
halfScratchBuf []byte
}
func TryCreate(conn aTLS.Conn) aTLS.Conn {
tlsConn, ok := conn.(*tls.Conn)
if !ok {
return conn
}
badConn, err := Create(tlsConn)
if err != nil {
log.Warn("initialize badtls: ", err)
return conn
}
return badConn
}
func Create(conn *tls.Conn) (aTLS.Conn, error) {
rawConn := reflect.Indirect(reflect.ValueOf(conn))
rawIsHandshakeComplete := rawConn.FieldByName("isHandshakeComplete")
if !rawIsHandshakeComplete.IsValid() || rawIsHandshakeComplete.Kind() != reflect.Struct {
return nil, E.New("badtls: invalid isHandshakeComplete")
}
isHandshakeComplete := (*atomic.Bool)(unsafe.Pointer(rawIsHandshakeComplete.UnsafeAddr()))
if !isHandshakeComplete.Load() {
func Create(conn *tls.Conn) (TLSConn, error) {
if !handshakeComplete(conn) {
return nil, E.New("handshake not finished")
}
rawConn := reflect.Indirect(reflect.ValueOf(conn))
rawActiveCall := rawConn.FieldByName("activeCall")
if !rawActiveCall.IsValid() || rawActiveCall.Kind() != reflect.Struct {
if !rawActiveCall.IsValid() || rawActiveCall.Kind() != reflect.Int32 {
return nil, E.New("badtls: invalid active call")
}
activeCall := (*atomic.Int32)(unsafe.Pointer(rawActiveCall.UnsafeAddr()))
activeCall := (*int32)(unsafe.Pointer(rawActiveCall.UnsafeAddr()))
rawHalfConn := rawConn.FieldByName("out")
if !rawHalfConn.IsValid() || rawHalfConn.Kind() != reflect.Struct {
return nil, E.New("badtls: invalid half conn")
@@ -129,20 +108,19 @@ func Create(conn *tls.Conn) (aTLS.Conn, error) {
}
halfScratchBuf := rawHalfScratchBuf.Bytes()
return &Conn{
Conn: conn,
writer: bufio.NewExtendedWriter(conn.NetConn()),
isHandshakeComplete: isHandshakeComplete,
activeCall: activeCall,
closeNotifySent: closeNotifySent,
version: version,
halfAccess: halfAccess,
halfError: halfError,
cipher: aeadCipher,
explicitNonceLen: explicitNonceLen,
rand: randReader,
halfPtr: rawHalfConn.UnsafeAddr(),
halfSeq: halfSeq,
halfScratchBuf: halfScratchBuf,
Conn: conn,
writer: bufio.NewExtendedWriter(conn.NetConn()),
activeCall: activeCall,
closeNotifySent: closeNotifySent,
version: version,
halfAccess: halfAccess,
halfError: halfError,
cipher: aeadCipher,
explicitNonceLen: explicitNonceLen,
rand: randReader,
halfPtr: rawHalfConn.UnsafeAddr(),
halfSeq: halfSeq,
halfScratchBuf: halfScratchBuf,
}, nil
}
@@ -152,15 +130,15 @@ func (c *Conn) WriteBuffer(buffer *buf.Buffer) error {
return common.Error(c.Write(buffer.Bytes()))
}
for {
x := c.activeCall.Load()
x := atomic.LoadInt32(c.activeCall)
if x&1 != 0 {
return net.ErrClosed
}
if c.activeCall.CompareAndSwap(x, x+2) {
if atomic.CompareAndSwapInt32(c.activeCall, x, x+2) {
break
}
}
defer c.activeCall.Add(-2)
defer atomic.AddInt32(c.activeCall, -2)
c.halfAccess.Lock()
defer c.halfAccess.Unlock()
if err := *c.halfError; err != nil {
@@ -208,7 +186,6 @@ func (c *Conn) WriteBuffer(buffer *buf.Buffer) error {
binary.BigEndian.PutUint16(outBuf[3:], uint16(dataLen+c.explicitNonceLen+c.cipher.Overhead()))
}
incSeq(c.halfPtr)
log.Trace("badtls write ", buffer.Len())
return c.writer.WriteBuffer(buffer)
}

View File

@@ -1,4 +1,4 @@
//go:build !go1.19 || go1.21
//go:build !go1.19 || go1.20
package badtls

13
common/badtls/conn.go Normal file
View File

@@ -0,0 +1,13 @@
package badtls
import (
"context"
"crypto/tls"
"net"
)
type TLSConn interface {
net.Conn
HandshakeContext(ctx context.Context) error
ConnectionState() tls.ConnectionState
}

View File

@@ -1,8 +1,9 @@
//go:build go1.20 && !go.1.21
//go:build go1.19 && !go.1.20
package badtls
import (
"crypto/tls"
"reflect"
_ "unsafe"
)
@@ -15,6 +16,9 @@ const (
//go:linkname errShutdown crypto/tls.errShutdown
var errShutdown error
//go:linkname handshakeComplete crypto/tls.(*Conn).handshakeComplete
func handshakeComplete(conn *tls.Conn) bool
//go:linkname incSeq crypto/tls.(*halfConn).incSeq
func incSeq(conn uintptr)

View File

@@ -7,6 +7,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer/conntrack"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/control"
@@ -16,6 +17,41 @@ import (
"github.com/sagernet/tfo-go"
)
var warnBindInterfaceOnUnsupportedPlatform = warning.New(
func() bool {
return !(C.IsLinux || C.IsWindows || C.IsDarwin)
},
"outbound option `bind_interface` is only supported on Linux and Windows",
)
var warnRoutingMarkOnUnsupportedPlatform = warning.New(
func() bool {
return !C.IsLinux
},
"outbound option `routing_mark` is only supported on Linux",
)
var warnReuseAdderOnUnsupportedPlatform = warning.New(
func() bool {
return !(C.IsDarwin || C.IsDragonfly || C.IsFreebsd || C.IsLinux || C.IsNetbsd || C.IsOpenbsd || C.IsSolaris || C.IsWindows)
},
"outbound option `reuse_addr` is unsupported on current platform",
)
var warnProtectPathOnNonAndroid = warning.New(
func() bool {
return !C.IsAndroid
},
"outbound option `protect_path` is only supported on Android",
)
var warnTFOOnUnsupportedPlatform = warning.New(
func() bool {
return !(C.IsDarwin || C.IsFreebsd || C.IsLinux || C.IsWindows)
},
"outbound option `tcp_fast_open` is unsupported on current platform",
)
type DefaultDialer struct {
dialer4 tfo.Dialer
dialer6 tfo.Dialer
@@ -30,6 +66,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
var dialer net.Dialer
var listener net.ListenConfig
if options.BindInterface != "" {
warnBindInterfaceOnUnsupportedPlatform.Check()
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc)
@@ -43,6 +80,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
listener.Control = control.Append(listener.Control, bindFunc)
}
if options.RoutingMark != 0 {
warnRoutingMarkOnUnsupportedPlatform.Check()
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
} else if router.DefaultMark() != 0 {
@@ -50,9 +88,11 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
}
if options.ReuseAddr {
warnReuseAdderOnUnsupportedPlatform.Check()
listener.Control = control.Append(listener.Control, control.ReuseAddr())
}
if options.ProtectPath != "" {
warnProtectPathOnNonAndroid.Check()
dialer.Control = control.Append(dialer.Control, control.ProtectPath(options.ProtectPath))
listener.Control = control.Append(listener.Control, control.ProtectPath(options.ProtectPath))
}
@@ -61,6 +101,9 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
} else {
dialer.Timeout = C.TCPTimeout
}
if options.TCPFastOpen {
warnTFOOnUnsupportedPlatform.Check()
}
var udpFragment bool
if options.UDPFragment != nil {
udpFragment = *options.UDPFragment

View File

@@ -11,6 +11,7 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -68,7 +69,7 @@ func (c *Client) DialContext(ctx context.Context, network string, destination M.
if err != nil {
return nil, err
}
return bufio.NewUnbindPacketConn(&ClientPacketConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: destination}), nil
return bufio.NewBindPacketConn(deadline.NewPacketConn(bufio.NewNetPacketConn(&ClientPacketConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: destination})), destination), nil
default:
return nil, E.Extend(N.ErrUnknownNetwork, network)
}
@@ -79,7 +80,7 @@ func (c *Client) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
if err != nil {
return nil, err
}
return &ClientPacketAddrConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: destination}, nil
return deadline.NewPacketConn(&ClientPacketAddrConn{ExtendedConn: bufio.NewExtendedConn(stream), destination: destination}), nil
}
func (c *Client) openStream() (net.Conn, error) {
@@ -249,10 +250,6 @@ func (c *ClientConn) WriterReplaceable() bool {
return c.requestWrite
}
func (c *ClientConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *ClientConn) Upstream() any {
return c.Conn
}
@@ -381,10 +378,6 @@ func (c *ClientPacketConn) RemoteAddr() net.Addr {
return c.destination.UDPAddr()
}
func (c *ClientPacketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *ClientPacketConn) Upstream() any {
return c.ExtendedConn
}
@@ -526,10 +519,6 @@ func (c *ClientPacketAddrConn) FrontHeadroom() int {
return 2 + M.MaxSocksaddrLength
}
func (c *ClientPacketAddrConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *ClientPacketAddrConn) Upstream() any {
return c.ExtendedConn
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -67,7 +68,7 @@ func newConnection(ctx context.Context, router adapter.Router, errorHandler E.Ha
logger.InfoContext(ctx, "inbound multiplex packet connection")
packetConn = &ServerPacketAddrConn{ExtendedConn: bufio.NewExtendedConn(stream)}
}
hErr := router.RoutePacketConnection(ctx, packetConn, metadata)
hErr := router.RoutePacketConnection(ctx, deadline.NewPacketConn(bufio.NewNetPacketConn(packetConn)), metadata)
stream.Close()
if hErr != nil {
errorHandler.NewError(ctx, hErr)
@@ -131,10 +132,6 @@ func (c *ServerConn) FrontHeadroom() int {
return 0
}
func (c *ServerConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *ServerConn) Upstream() any {
return c.ExtendedConn
}
@@ -187,10 +184,6 @@ func (c *ServerPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksad
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *ServerPacketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *ServerPacketConn) Upstream() any {
return c.ExtendedConn
}
@@ -253,10 +246,6 @@ func (c *ServerPacketAddrConn) WritePacket(buffer *buf.Buffer, destination M.Soc
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *ServerPacketAddrConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *ServerPacketAddrConn) Upstream() any {
return c.ExtendedConn
}

View File

@@ -7,7 +7,6 @@ import (
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/protocol/http"
)
@@ -16,5 +15,5 @@ func HTTPHost(ctx context.Context, reader io.Reader) (*adapter.InboundContext, e
if err != nil {
return nil, err
}
return &adapter.InboundContext{Protocol: C.ProtocolHTTP, Domain: M.ParseSocksaddr(request.Host).AddrString()}, nil
return &adapter.InboundContext{Protocol: C.ProtocolHTTP, Domain: request.Host}, nil
}

View File

@@ -1,27 +0,0 @@
package sniff_test
import (
"context"
"strings"
"testing"
"github.com/sagernet/sing-box/common/sniff"
"github.com/stretchr/testify/require"
)
func TestSniffHTTP1(t *testing.T) {
t.Parallel()
pkt := "GET / HTTP/1.1\r\nHost: www.google.com\r\nAccept: */*\r\n\r\n"
metadata, err := sniff.HTTPHost(context.Background(), strings.NewReader(pkt))
require.NoError(t, err)
require.Equal(t, metadata.Domain, "www.google.com")
}
func TestSniffHTTP1WithPort(t *testing.T) {
t.Parallel()
pkt := "GET / HTTP/1.1\r\nHost: www.gov.cn:8080\r\nAccept: */*\r\n\r\n"
metadata, err := sniff.HTTPHost(context.Background(), strings.NewReader(pkt))
require.NoError(t, err)
require.Equal(t, metadata.Domain, "www.gov.cn")
}

View File

@@ -125,7 +125,7 @@ func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn
hello.SessionId[0] = 1
hello.SessionId[1] = 8
hello.SessionId[2] = 1
hello.SessionId[2] = 0
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
copy(hello.SessionId[8:], e.shortID[:])

31
common/warning/warning.go Normal file
View File

@@ -0,0 +1,31 @@
package warning
import (
"sync"
"github.com/sagernet/sing-box/log"
)
type Warning struct {
logger log.Logger
check CheckFunc
message string
checkOnce sync.Once
}
type CheckFunc = func() bool
func New(checkFunc CheckFunc, message string) Warning {
return Warning{
check: checkFunc,
message: message,
}
}
func (w *Warning) Check() {
w.checkOnce.Do(func() {
if w.check() {
log.Warn(w.message)
}
})
}

View File

@@ -1,14 +1,3 @@
#### 1.3-beta8
* Fix `system` tun stack for ios
* Fix network monitor for android/ios
* Update VLESS and XUDP protocol **1**
* Fixes and improvements
*1:
As in Xray, this is an incompatible update for XUDP in VLESS if vision flow is enabled.
#### 1.3-beta7
* Add `path` and `headers` options for HTTP outbound

View File

@@ -12,6 +12,5 @@ Experimental Android client for sing-box.
#### Note
* User Agent in remote profile request is `SFA/$version ($version_code; sing-box $sing_box_version)`
* The working directory is located at `/sdcard/Android/data/io.nekohasekai.sfa/files` (External files directory)
* Crash logs is located in `$working_directory/stderr.log`
* Working directory is at `/sdcard/Android/data/io.nekohasekai.sfa/files` (External files directory)
* User Agent is `SFA/$version ($version_code; sing-box $sing_box_version)` in the remote profile request

View File

@@ -12,6 +12,5 @@
#### 注意事项
* 远程配置文件请求中的 User Agent 为 `SFA/$version ($version_code; sing-box $sing_box_version)`
* 工作目录位于 `/sdcard/Android/data/io.nekohasekai.sfa/files` (外部文件目录)
* 崩溃日志位于 `$working_directory/stderr.log`
* 远程配置文件请求中的 User Agent 为 `SFA/$version ($version_code; sing-box $sing_box_version)`

View File

@@ -13,8 +13,8 @@ Experimental iOS client for sing-box.
#### Note
* User Agent in remote profile request is `SFA/$version ($version_code; sing-box $sing_box_version)`
* Crash logs is located in `Settings` -> `View Service Log`
* `system` tun stack not working on iOS
* User Agent is `SFI/$version ($version_code; sing-box $sing_box_version)` in the remote profile request
#### Privacy policy

View File

@@ -13,8 +13,8 @@
#### 注意事项
* `system` tun stack 在 iOS 不工作
* 远程配置文件请求中的 User Agent 为 `SFI/$version ($version_code; sing-box $sing_box_version)`
* 崩溃日志位于 `设置` -> `查看服务日志`
#### 隐私政策

View File

@@ -29,19 +29,3 @@ func (i *iterator[T]) Next() T {
func (i *iterator[T]) HasNext() bool {
return len(i.values) > 0
}
type abstractIterator[T any] interface {
Next() T
HasNext() bool
}
func iteratorToArray[T any](iterator abstractIterator[T]) []T {
if iterator == nil {
return nil
}
var values []T
for iterator.HasNext() {
values = append(values, iterator.Next())
}
return values
}

View File

@@ -1,183 +0,0 @@
package libbox
import (
"context"
"net"
"net/netip"
"sync"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/x/list"
)
var (
_ tun.DefaultInterfaceMonitor = (*platformDefaultInterfaceMonitor)(nil)
_ InterfaceUpdateListener = (*platformDefaultInterfaceMonitor)(nil)
)
type platformDefaultInterfaceMonitor struct {
*platformInterfaceWrapper
errorHandler E.Handler
networkAddresses []networkAddress
defaultInterfaceName string
defaultInterfaceIndex int
element *list.Element[tun.NetworkUpdateCallback]
access sync.Mutex
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
}
type networkAddress struct {
interfaceName string
interfaceIndex int
addresses []netip.Prefix
}
func (m *platformDefaultInterfaceMonitor) Start() error {
return m.iif.StartDefaultInterfaceMonitor(m)
}
func (m *platformDefaultInterfaceMonitor) Close() error {
return m.iif.CloseDefaultInterfaceMonitor(m)
}
func (m *platformDefaultInterfaceMonitor) DefaultInterfaceName(destination netip.Addr) string {
for _, address := range m.networkAddresses {
for _, prefix := range address.addresses {
if prefix.Contains(destination) {
return address.interfaceName
}
}
}
return m.defaultInterfaceName
}
func (m *platformDefaultInterfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
for _, address := range m.networkAddresses {
for _, prefix := range address.addresses {
if prefix.Contains(destination) {
return address.interfaceIndex
}
}
}
return m.defaultInterfaceIndex
}
func (m *platformDefaultInterfaceMonitor) OverrideAndroidVPN() bool {
return false
}
func (m *platformDefaultInterfaceMonitor) AndroidVPNEnabled() bool {
return false
}
func (m *platformDefaultInterfaceMonitor) RegisterCallback(callback tun.DefaultInterfaceUpdateCallback) *list.Element[tun.DefaultInterfaceUpdateCallback] {
m.access.Lock()
defer m.access.Unlock()
return m.callbacks.PushBack(callback)
}
func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
m.access.Lock()
defer m.access.Unlock()
m.callbacks.Remove(element)
}
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32) {
var err error
if m.iif.UsePlatformInterfaceGetter() {
err = m.updateInterfacesPlatform()
} else {
err = m.updateInterfaces()
}
if err == nil {
err = m.router.UpdateInterfaces()
}
if err != nil {
m.errorHandler.NewError(context.Background(), E.Cause(err, "update interfaces"))
}
interfaceIndex := int(interfaceIndex32)
if interfaceName == "" {
for _, netIf := range m.networkAddresses {
if netIf.interfaceIndex == interfaceIndex {
interfaceName = netIf.interfaceName
break
}
}
} else if interfaceIndex == -1 {
for _, netIf := range m.networkAddresses {
if netIf.interfaceName == interfaceName {
interfaceIndex = netIf.interfaceIndex
break
}
}
}
if interfaceName == "" {
m.errorHandler.NewError(context.Background(), E.New("invalid interface name for ", interfaceIndex))
return
} else if interfaceIndex == -1 {
m.errorHandler.NewError(context.Background(), E.New("invalid interface index for ", interfaceName))
return
}
if m.defaultInterfaceName == interfaceName && m.defaultInterfaceIndex == interfaceIndex {
return
}
m.defaultInterfaceName = interfaceName
m.defaultInterfaceIndex = interfaceIndex
m.access.Lock()
callbacks := m.callbacks.Array()
m.access.Unlock()
for _, callback := range callbacks {
err = callback(tun.EventInterfaceUpdate)
if err != nil {
m.errorHandler.NewError(context.Background(), err)
}
}
}
func (m *platformDefaultInterfaceMonitor) updateInterfaces() error {
interfaces, err := net.Interfaces()
if err != nil {
return err
}
var addresses []networkAddress
for _, iif := range interfaces {
var netAddresses []net.Addr
netAddresses, err = iif.Addrs()
if err != nil {
return err
}
var address networkAddress
address.interfaceName = iif.Name
address.interfaceIndex = iif.Index
address.addresses = common.Map(common.FilterIsInstance(netAddresses, func(it net.Addr) (*net.IPNet, bool) {
value, loaded := it.(*net.IPNet)
return value, loaded
}), func(it *net.IPNet) netip.Prefix {
bits, _ := it.Mask.Size()
return netip.PrefixFrom(M.AddrFromIP(it.IP), bits)
})
addresses = append(addresses, address)
}
m.networkAddresses = addresses
return nil
}
func (m *platformDefaultInterfaceMonitor) updateInterfacesPlatform() error {
interfaces, err := m.Interfaces()
if err != nil {
return err
}
var addresses []networkAddress
for _, iif := range interfaces {
var address networkAddress
address.interfaceName = iif.Name
address.interfaceIndex = iif.Index
// address.addresses = common.Map(iif.Addresses, netip.MustParsePrefix)
addresses = append(addresses, address)
}
m.networkAddresses = addresses
return nil
}

View File

@@ -1,8 +1,6 @@
package libbox
import (
"github.com/sagernet/sing-box/option"
)
import "github.com/sagernet/sing-box/option"
type PlatformInterface interface {
AutoDetectInterfaceControl(fd int32) error
@@ -12,11 +10,6 @@ type PlatformInterface interface {
FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
PackageNameByUid(uid int32) (string, error)
UIDByPackageName(packageName string) (int32, error)
UsePlatformDefaultInterfaceMonitor() bool
StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
UsePlatformInterfaceGetter() bool
GetInterfaces() (NetworkInterfaceIterator, error)
}
type TunInterface interface {
@@ -24,19 +17,8 @@ type TunInterface interface {
Close() error
}
type InterfaceUpdateListener interface {
UpdateDefaultInterface(interfaceName string, interfaceIndex int32)
}
type NetworkInterface struct {
Index int32
MTU int32
Name string
Addresses StringIterator
}
type NetworkInterfaceIterator interface {
Next() *NetworkInterface
type OnDemandRuleIterator interface {
Next() OnDemandRule
HasNext() bool
}
@@ -49,11 +31,6 @@ type OnDemandRule interface {
ProbeURL() string
}
type OnDemandRuleIterator interface {
Next() OnDemandRule
HasNext() bool
}
type onDemandRule struct {
option.OnDemandRule
}

View File

@@ -1,33 +1,17 @@
package platform
import (
"context"
"io"
"net/netip"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
)
type Interface interface {
Initialize(ctx context.Context, router adapter.Router) error
AutoDetectInterfaceControl() control.Func
OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
UsePlatformDefaultInterfaceMonitor() bool
CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor
UsePlatformInterfaceGetter() bool
Interfaces() ([]NetworkInterface, error)
OpenTun(options tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
process.Searcher
io.Writer
}
type NetworkInterface struct {
Index int
MTU int
Name string
Addresses []netip.Prefix
}

View File

@@ -6,13 +6,11 @@ import (
"syscall"
"github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
"github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
@@ -33,7 +31,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
instance, err := box.New(box.Options{
Context: ctx,
Options: options,
PlatformInterface: &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()},
PlatformInterface: &platformInterfaceWrapper{platformInterface, platformInterface.UseProcFS()},
})
if err != nil {
cancel()
@@ -60,12 +58,6 @@ var _ platform.Interface = (*platformInterfaceWrapper)(nil)
type platformInterfaceWrapper struct {
iif PlatformInterface
useProcFS bool
router adapter.Router
}
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
w.router = router
return nil
}
func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
@@ -76,7 +68,7 @@ func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
}
}
func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
func (w *platformInterfaceWrapper) OpenTun(options tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
return nil, E.New("android: unsupported uid options")
}
@@ -87,16 +79,12 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions
if err != nil {
return nil, err
}
options.Name, err = getTunnelName(tunFd)
if err != nil {
return nil, E.Cause(err, "query tun name")
}
dupFd, err := dup(int(tunFd))
if err != nil {
return nil, E.Cause(err, "dup tun file descriptor")
}
options.FileDescriptor = dupFd
return tun.New(*options)
return tun.New(options)
}
func (w *platformInterfaceWrapper) Write(p []byte) (n int, err error) {
@@ -130,36 +118,3 @@ func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network
packageName, _ := w.iif.PackageNameByUid(uid)
return &process.Info{UserId: uid, PackageName: packageName}, nil
}
func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
return w.iif.UsePlatformDefaultInterfaceMonitor()
}
func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor {
return &platformDefaultInterfaceMonitor{
platformInterfaceWrapper: w,
errorHandler: errorHandler,
defaultInterfaceIndex: -1,
}
}
func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
return w.iif.UsePlatformInterfaceGetter()
}
func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, error) {
interfaceIterator, err := w.iif.GetInterfaces()
if err != nil {
return nil, err
}
var interfaces []platform.NetworkInterface
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
interfaces = append(interfaces, platform.NetworkInterface{
Index: int(netInterface.Index),
MTU: int(netInterface.MTU),
Name: netInterface.Name,
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
})
}
return interfaces, nil
}

View File

@@ -59,7 +59,7 @@ func mapRoutePrefix(prefixes []netip.Prefix) RoutePrefixIterator {
var _ TunOptions = (*tunOptions)(nil)
type tunOptions struct {
*tun.Options
tun.Options
option.TunPlatformOptions
}

View File

@@ -1,11 +0,0 @@
package libbox
import "golang.org/x/sys/unix"
func getTunnelName(fd int32) (string, error) {
return unix.GetsockoptString(
int(fd),
2, /* #define SYSPROTO_CONTROL 2 */
2, /* #define UTUN_OPT_IFNAME 2 */
)
}

View File

@@ -1,26 +0,0 @@
package libbox
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
const ifReqSize = unix.IFNAMSIZ + 64
func getTunnelName(fd int32) (string, error) {
var ifr [ifReqSize]byte
var errno syscall.Errno
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.TUNGETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return "", fmt.Errorf("failed to get name of TUN device: %w", errno)
}
return unix.ByteSliceToString(ifr[:]), nil
}

View File

@@ -1,9 +0,0 @@
//go:build !(darwin || linux)
package libbox
import "os"
func getTunnelName(fd int32) (string, error) {
return "", os.ErrInvalid
}

12
go.mod
View File

@@ -25,12 +25,12 @@ require (
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.2.4-0.20230418095640-3b5e6c1812d3
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3
github.com/sagernet/sing v0.2.3
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc
github.com/sagernet/sing-shadowsocks v0.2.1
github.com/sagernet/sing-shadowtls v0.1.1
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
github.com/sagernet/sing-vmess v0.1.4
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2

24
go.sum
View File

@@ -111,18 +111,18 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
github.com/sagernet/sing v0.2.4-0.20230418095640-3b5e6c1812d3 h1:dkH6SEs3yZlUjSXUAn64LUlFAfAgJqiThaWiBKWJ0Q0=
github.com/sagernet/sing v0.2.4-0.20230418095640-3b5e6c1812d3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 h1:UDSeJZ2xB3dj1lySnM5LpF48dGlphGstw2BqtkJwcZI=
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322/go.mod h1:2wjxSr1Gbecq9A0ESA9cnR399tQTcpCZEOGytekb+qI=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d h1:UUxtLujzp5jmtOXqXpSOGvHwHSZcBveKVDzRJ4GlnFU=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d/go.mod h1:Co3PJXcaZoLwHGBfT0rbSnn9C7ywc41zVYWtDeoeI/Q=
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 h1:aPb0T2HQRTG2t7fEwLvFLZSXmhmnBh+SMs2NufhmrsI=
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302/go.mod h1:bvcVzlf9q9dgxt8qKluW+zOXCFoN1+SpBG3sHTq8/9Q=
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U=
github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk=
github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
github.com/sagernet/sing-shadowsocks v0.2.1 h1:FvdLQOqpvxHBJUcUe4fvgiYP2XLLwH5i1DtXQviVEPw=
github.com/sagernet/sing-shadowsocks v0.2.1/go.mod h1:T/OgurSjsAe+Ug3+6PprXjmgHFmJidjOvQcjXGTKb3I=
github.com/sagernet/sing-shadowtls v0.1.1 h1:Gf8YD/4zCjfM9xxVzI0QVYAnjMCtsDHcIp84CUdY3VA=
github.com/sagernet/sing-shadowtls v0.1.1/go.mod h1:espnHDPRQeG95ZoU3xfHDFnc6Nt4GvbbuPV2okN+x/E=
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab h1:a9oeWuPBuIZ70qMhIIH6RrYhp886xN9jJIwsuu4ZFUo=
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab/go.mod h1:4YxIDEkkCjGXDOTMPw1SXpLmCQUFAWuaQN250oo+928=
github.com/sagernet/sing-vmess v0.1.4 h1:aZ03KgmR9COPitVqo8NTPHeaHmbJYDZ8mkumnUV4oGQ=
github.com/sagernet/sing-vmess v0.1.4/go.mod h1:NensKZJDgfPsUf3TzFD8kTuzI3CQfN1Tj3Eygti5Isg=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=

View File

@@ -53,7 +53,7 @@ func NewDirect(ctx context.Context, router adapter.Router, logger log.ContextLog
} else {
udpTimeout = int64(C.UDPTimeout.Seconds())
}
inbound.udpNat = udpnat.New[netip.AddrPort](ctx, udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
inbound.udpNat = udpnat.New[netip.AddrPort](udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
inbound.connHandler = inbound
inbound.packetHandler = inbound
inbound.packetUpstream = inbound.udpNat

View File

@@ -609,10 +609,6 @@ func (c *naiveH2Conn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *naiveH2Conn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *naiveH2Conn) UpstreamReader() any {
return c.reader
}

View File

@@ -64,11 +64,11 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
var err error
switch {
case options.Method == shadowsocks.MethodNone:
inbound.service = shadowsocks.NewNoneService(ctx, options.UDPTimeout, inbound.upstreamContextHandler())
inbound.service = shadowsocks.NewNoneService(options.UDPTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead.List, options.Method):
inbound.service, err = shadowaead.NewService(ctx, options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead_2022.List, options.Method):
inbound.service, err = shadowaead_2022.NewServiceWithPassword(ctx, options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc())
inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc())
default:
err = E.New("unsupported method: ", options.Method)
}

View File

@@ -57,7 +57,6 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
)
if common.Contains(shadowaead_2022.List, options.Method) {
service, err = shadowaead_2022.NewMultiServiceWithPassword[int](
ctx,
options.Method,
options.Password,
udpTimeout,
@@ -66,7 +65,6 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
)
} else if common.Contains(shadowaead.List, options.Method) {
service, err = shadowaead.NewMultiService[int](
ctx,
options.Method,
udpTimeout,
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))

View File

@@ -50,7 +50,6 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.
udpTimeout = int64(C.UDPTimeout.Seconds())
}
service, err := shadowaead_2022.NewRelayServiceWithPassword[int](
ctx,
options.Method,
options.Password,
udpTimeout,

View File

@@ -45,7 +45,7 @@ func NewTProxy(ctx context.Context, router adapter.Router, logger log.ContextLog
}
tproxy.connHandler = tproxy
tproxy.oobPacketHandler = tproxy
tproxy.udpNat = udpnat.New[netip.AddrPort](ctx, udpTimeout, tproxy.upstreamContextHandler())
tproxy.udpNat = udpnat.New[netip.AddrPort](udpTimeout, tproxy.upstreamContextHandler())
tproxy.packetUpstream = tproxy.udpNat
return tproxy
}

View File

@@ -152,7 +152,7 @@ func (t *Tun) Start() error {
)
t.logger.Trace("opening interface")
if t.platformInterface != nil {
tunInterface, err = t.platformInterface.OpenTun(&t.tunOptions, t.platformOptions)
tunInterface, err = t.platformInterface.OpenTun(t.tunOptions, t.platformOptions)
} else {
tunInterface, err = tun.New(t.tunOptions)
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/sagernet/sing-vmess/packetaddr"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
M "github.com/sagernet/sing/common/metadata"
@@ -171,7 +172,7 @@ func (h *VLESS) newPacketConnection(ctx context.Context, conn N.PacketConn, meta
}
if metadata.Destination.Fqdn == packetaddr.SeqPacketMagicAddress {
metadata.Destination = M.Socksaddr{}
conn = packetaddr.NewConn(conn.(vmess.PacketConn), metadata.Destination)
conn = deadline.NewPacketConn(packetaddr.NewConn(conn.(vmess.PacketConn), metadata.Destination))
h.logger.InfoContext(ctx, "[", user, "] inbound packet addr connection")
} else {
h.logger.InfoContext(ctx, "[", user, "] inbound packet connection to ", metadata.Destination)

View File

@@ -15,6 +15,7 @@ import (
"github.com/sagernet/sing-vmess/packetaddr"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
M "github.com/sagernet/sing/common/metadata"
@@ -179,7 +180,7 @@ func (h *VMess) newPacketConnection(ctx context.Context, conn N.PacketConn, meta
}
if metadata.Destination.Fqdn == packetaddr.SeqPacketMagicAddress {
metadata.Destination = M.Socksaddr{}
conn = packetaddr.NewConn(conn.(vmess.PacketConn), metadata.Destination)
conn = deadline.NewPacketConn(packetaddr.NewConn(conn.(vmess.PacketConn), metadata.Destination))
h.logger.InfoContext(ctx, "[", user, "] inbound packet addr connection")
} else {
h.logger.InfoContext(ctx, "[", user, "] inbound packet connection to ", metadata.Destination)

View File

@@ -13,7 +13,6 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/batch"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
@@ -73,7 +72,7 @@ func (s *URLTest) Start() error {
outbounds = append(outbounds, detour)
}
s.group = NewURLTestGroup(s.ctx, s.router, s.logger, outbounds, s.link, s.interval, s.tolerance)
go s.group.CheckOutbounds(false)
go s.group.CheckOutbounds()
return nil
}
@@ -128,7 +127,7 @@ func (s *URLTest) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
}
func (s *URLTest) InterfaceUpdated() error {
go s.group.CheckOutbounds(true)
go s.group.CheckOutbounds()
return nil
}
@@ -141,7 +140,6 @@ type URLTestGroup struct {
interval time.Duration
tolerance uint16
history *urltest.HistoryStorage
checking atomic.Bool
access sync.Mutex
ticker *time.Ticker
@@ -250,33 +248,25 @@ func (g *URLTestGroup) Fallback(used adapter.Outbound) []adapter.Outbound {
}
func (g *URLTestGroup) loopCheck() {
go g.CheckOutbounds(true)
go g.CheckOutbounds()
for {
select {
case <-g.close:
return
case <-g.ticker.C:
g.CheckOutbounds(false)
g.CheckOutbounds()
}
}
}
func (g *URLTestGroup) CheckOutbounds(force bool) {
_, _ = g.urlTest(g.ctx, g.link, force)
func (g *URLTestGroup) CheckOutbounds() {
_, _ = g.URLTest(g.ctx, g.link)
}
func (g *URLTestGroup) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
return g.urlTest(ctx, link, false)
}
func (g *URLTestGroup) urlTest(ctx context.Context, link string, force bool) (map[string]uint16, error) {
result := make(map[string]uint16)
if g.checking.Swap(true) {
return result, nil
}
defer g.checking.Store(false)
b, _ := batch.New(ctx, batch.WithConcurrencyNum[any](10))
checked := make(map[string]bool)
result := make(map[string]uint16)
var resultAccess sync.Mutex
for _, detour := range g.outbounds {
tag := detour.Tag()
@@ -285,7 +275,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, link string, force bool) (ma
continue
}
history := g.history.LoadURLTestHistory(realTag)
if !force && history != nil && time.Now().Sub(history.Time) < g.interval {
if history != nil && time.Now().Sub(history.Time) < g.interval {
continue
}
checked[realTag] = true

View File

@@ -9,7 +9,7 @@ import (
var _ control.InterfaceFinder = (*myInterfaceFinder)(nil)
type myInterfaceFinder struct {
interfaces []net.Interface
ifs []net.Interface
}
func (f *myInterfaceFinder) update() error {
@@ -17,16 +17,12 @@ func (f *myInterfaceFinder) update() error {
if err != nil {
return err
}
f.interfaces = ifs
f.ifs = ifs
return nil
}
func (f *myInterfaceFinder) updateInterfaces(interfaces []net.Interface) {
f.interfaces = interfaces
}
func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex int, err error) {
for _, netInterface := range f.interfaces {
for _, netInterface := range f.ifs {
if netInterface.Name == name {
return netInterface.Index, nil
}
@@ -40,7 +36,7 @@ func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex in
}
func (f *myInterfaceFinder) InterfaceNameByIndex(index int) (interfaceName string, err error) {
for _, netInterface := range f.interfaces {
for _, netInterface := range f.ifs {
if netInterface.Index == index {
return netInterface.Name, nil
}

View File

@@ -12,12 +12,12 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/dialer/conntrack"
"github.com/sagernet/sing-box/common/geoip"
"github.com/sagernet/sing-box/common/geosite"
"github.com/sagernet/sing-box/common/mux"
"github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/common/sniff"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/log"
@@ -31,7 +31,6 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
@@ -40,6 +39,27 @@ import (
"github.com/sagernet/sing/common/uot"
)
var warnDefaultInterfaceOnUnsupportedPlatform = warning.New(
func() bool {
return !(C.IsLinux || C.IsWindows || C.IsDarwin)
},
"route option `default_mark` is only supported on Linux and Windows",
)
var warnDefaultMarkOnNonLinux = warning.New(
func() bool {
return !C.IsLinux
},
"route option `default_mark` is only supported on Linux",
)
var warnFindProcessOnUnsupportedPlatform = warning.New(
func() bool {
return !(C.IsLinux || C.IsWindows || C.IsDarwin)
},
"route option `find_process` is only supported on Linux, Windows, and macOS",
)
var _ adapter.Router = (*Router)(nil)
type Router struct {
@@ -93,6 +113,16 @@ func NewRouter(
inbounds []option.Inbound,
platformInterface platform.Interface,
) (*Router, error) {
if options.DefaultInterface != "" {
warnDefaultInterfaceOnUnsupportedPlatform.Check()
}
if options.DefaultMark != 0 {
warnDefaultMarkOnNonLinux.Check()
}
if options.FindProcess {
warnFindProcessOnUnsupportedPlatform.Check()
}
router := &Router{
ctx: ctx,
logger: logFactory.NewLogger("router"),
@@ -113,7 +143,7 @@ func NewRouter(
defaultMark: options.DefaultMark,
platformInterface: platformInterface,
}
router.dnsClient = dns.NewClient(ctx, dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire, router.dnsLogger)
router.dnsClient = dns.NewClient(dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire, router.dnsLogger)
for i, ruleOptions := range options.Rules {
routeRule, err := NewRule(router, router.logger, ruleOptions)
if err != nil {
@@ -259,36 +289,29 @@ func NewRouter(
router.fakeIPStore = fakeip.NewStore(router, inet4Range, inet6Range)
}
usePlatformDefaultInterfaceMonitor := platformInterface != nil && platformInterface.UsePlatformDefaultInterfaceMonitor()
needInterfaceMonitor := options.AutoDetectInterface || common.Any(inbounds, func(inbound option.Inbound) bool {
needInterfaceMonitor := platformInterface == nil && (options.AutoDetectInterface || common.Any(inbounds, func(inbound option.Inbound) bool {
return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || inbound.TunOptions.AutoRoute
})
}))
if needInterfaceMonitor {
if !usePlatformDefaultInterfaceMonitor {
networkMonitor, err := tun.NewNetworkUpdateMonitor(router)
if err != os.ErrInvalid {
if err != nil {
return nil, err
}
router.networkMonitor = networkMonitor
networkMonitor.RegisterCallback(router.interfaceFinder.update)
interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, tun.DefaultInterfaceMonitorOptions{
OverrideAndroidVPN: options.OverrideAndroidVPN,
})
if err != nil {
return nil, E.New("auto_detect_interface unsupported on current platform")
}
interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
router.interfaceMonitor = interfaceMonitor
}
} else {
interfaceMonitor := platformInterface.CreateDefaultInterfaceMonitor(router)
interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
router.interfaceMonitor = interfaceMonitor
networkMonitor, err := tun.NewNetworkUpdateMonitor(router)
if err == nil {
router.networkMonitor = networkMonitor
networkMonitor.RegisterCallback(router.interfaceFinder.update)
}
}
if router.networkMonitor != nil && needInterfaceMonitor {
interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, tun.DefaultInterfaceMonitorOptions{
OverrideAndroidVPN: options.OverrideAndroidVPN,
})
if err != nil {
return nil, E.New("auto_detect_interface unsupported on current platform")
}
interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
router.interfaceMonitor = interfaceMonitor
}
needFindProcess := hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess
needPackageManager := C.IsAndroid && platformInterface == nil && (needFindProcess || common.Any(inbounds, func(inbound option.Inbound) bool {
return len(inbound.TunOptions.IncludePackage) > 0 || len(inbound.TunOptions.ExcludePackage) > 0
@@ -634,10 +657,6 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
}
if deadline.NeedAdditionalReadDeadline(conn) {
conn = deadline.NewConn(conn)
}
if metadata.InboundOptions.SniffEnabled {
buffer := buf.NewPacket()
buffer.FullReset()
@@ -743,11 +762,6 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
}
// Currently we don't have deadline usages for UDP connections
/*if deadline.NeedAdditionalReadDeadline(conn) {
conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
}*/
if metadata.InboundOptions.SniffEnabled {
buffer := buf.NewPacket()
buffer.FullReset()
@@ -872,25 +886,6 @@ func (r *Router) InterfaceFinder() control.InterfaceFinder {
return &r.interfaceFinder
}
func (r *Router) UpdateInterfaces() error {
if r.platformInterface == nil || !r.platformInterface.UsePlatformInterfaceGetter() {
return r.interfaceFinder.update()
} else {
interfaces, err := r.platformInterface.Interfaces()
if err != nil {
return err
}
r.interfaceFinder.updateInterfaces(common.Map(interfaces, func(it platform.NetworkInterface) net.Interface {
return net.Interface{
Name: it.Name,
Index: it.Index,
MTU: it.MTU,
}
}))
return nil
}
}
func (r *Router) AutoDetectInterface() bool {
return r.autoDetectInterface
}
@@ -975,7 +970,7 @@ func (r *Router) NewError(ctx context.Context, err error) {
}
func (r *Router) notifyNetworkUpdate(int) error {
if C.IsAndroid && r.platformInterface == nil {
if C.IsAndroid {
var vpnStatus string
if r.interfaceMonitor.AndroidVPNEnabled() {
vpnStatus = "enabled"
@@ -987,10 +982,6 @@ func (r *Router) notifyNetworkUpdate(int) error {
r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()))
}
if conntrack.Enabled {
conntrack.Close()
}
for _, outbound := range r.outbounds {
listener, isListener := outbound.(adapter.InterfaceUpdateListener)
if isListener {

View File

@@ -4,6 +4,13 @@ import (
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
)
var warnPackageNameOnNonAndroid = warning.New(
func() bool { return !C.IsAndroid },
"rule item `package_name` is only supported on Android",
)
var _ RuleItem = (*PackageNameItem)(nil)
@@ -14,6 +21,7 @@ type PackageNameItem struct {
}
func NewPackageNameItem(packageNameList []string) *PackageNameItem {
warnPackageNameOnNonAndroid.Check()
rule := &PackageNameItem{
packageNames: packageNameList,
packageMap: make(map[string]bool),

View File

@@ -5,6 +5,13 @@ import (
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
)
var warnProcessNameOnNonSupportedPlatform = warning.New(
func() bool { return !(C.IsLinux || C.IsWindows || C.IsDarwin) },
"rule item `process_name` is only supported on Linux, Windows and macOS",
)
var _ RuleItem = (*ProcessItem)(nil)
@@ -15,6 +22,7 @@ type ProcessItem struct {
}
func NewProcessItem(processNameList []string) *ProcessItem {
warnProcessNameOnNonSupportedPlatform.Check()
rule := &ProcessItem{
processes: processNameList,
processMap: make(map[string]bool),

View File

@@ -4,6 +4,13 @@ import (
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
)
var warnProcessPathOnNonSupportedPlatform = warning.New(
func() bool { return !(C.IsLinux || C.IsWindows || C.IsDarwin) },
"rule item `process_path` is only supported on Linux, Windows and macOS",
)
var _ RuleItem = (*ProcessPathItem)(nil)
@@ -14,6 +21,7 @@ type ProcessPathItem struct {
}
func NewProcessPathItem(processNameList []string) *ProcessPathItem {
warnProcessPathOnNonSupportedPlatform.Check()
rule := &ProcessPathItem{
processes: processNameList,
processMap: make(map[string]bool),

View File

@@ -4,9 +4,16 @@ import (
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
F "github.com/sagernet/sing/common/format"
)
var warnUserOnNonLinux = warning.New(
func() bool { return !C.IsLinux },
"rule item `user` is only supported on Linux",
)
var _ RuleItem = (*UserItem)(nil)
type UserItem struct {
@@ -15,6 +22,7 @@ type UserItem struct {
}
func NewUserItem(users []string) *UserItem {
warnUserOnNonLinux.Check()
userMap := make(map[string]bool)
for _, protocol := range users {
userMap[protocol] = true

View File

@@ -4,9 +4,16 @@ import (
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/warning"
C "github.com/sagernet/sing-box/constant"
F "github.com/sagernet/sing/common/format"
)
var warnUserIDOnNonLinux = warning.New(
func() bool { return !C.IsLinux },
"rule item `user_id` is only supported on Linux",
)
var _ RuleItem = (*UserIdItem)(nil)
type UserIdItem struct {
@@ -15,6 +22,7 @@ type UserIdItem struct {
}
func NewUserIDItem(userIdList []int32) *UserIdItem {
warnUserIDOnNonLinux.Check()
rule := &UserIdItem{
userIds: userIdList,
userIdMap: make(map[int32]bool),

View File

@@ -7,20 +7,20 @@ require github.com/sagernet/sing-box v0.0.0
replace github.com/sagernet/sing-box => ../
require (
github.com/docker/docker v20.10.18+incompatible
github.com/docker/docker v23.0.3+incompatible
github.com/docker/go-connections v0.4.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d
github.com/spyzhov/ajson v0.7.1
github.com/gofrs/uuid/v5 v5.0.0
github.com/sagernet/sing v0.2.2
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4
github.com/spyzhov/ajson v0.8.0
github.com/stretchr/testify v1.8.2
go.uber.org/goleak v1.2.0
go.uber.org/goleak v1.2.1
golang.org/x/net v0.9.0
)
require (
berty.tech/go-libtor v1.0.385 // indirect
github.com/Dreamacro/clash v1.15.0 // indirect
github.com/Dreamacro/clash v1.14.0 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
@@ -36,7 +36,6 @@ require (
github.com/go-chi/cors v1.2.1 // indirect
github.com/go-chi/render v1.0.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/gofrs/uuid/v5 v5.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
@@ -71,16 +70,15 @@ require (
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 // indirect
github.com/sagernet/sing-shadowtls v0.1.0 // indirect
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 // indirect
github.com/sagernet/sing-vmess v0.1.3 // indirect
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440 // indirect
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 // indirect
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab // indirect
github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 // indirect
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
go.etcd.io/bbolt v1.3.7 // indirect

View File

@@ -1,8 +1,8 @@
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Dreamacro/clash v1.15.0 h1:mlpD950VEggXZBNahV66hyKDRxcczkj3vymoAt78KyE=
github.com/Dreamacro/clash v1.15.0/go.mod h1:WNH69bN11LiAdgdSr4hpkEuXVMfBbWyhEKMCTx9BtNE=
github.com/Dreamacro/clash v1.14.0 h1:ehJ/C/1m9LEjmME72WSE/Y2YqbR3Q54AbjqiRCvtyW4=
github.com/Dreamacro/clash v1.14.0/go.mod h1:ia2CU7V713H1QdCqMwOLK9U9V5Ay8X0voj3yQr2tk+I=
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
@@ -25,8 +25,8 @@ 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=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfemfitN7pbsp26WSc=
github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho=
github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
@@ -43,8 +43,6 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -128,18 +126,18 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31 h1:qgq8jeY/rbnY9NwYXByO//AP0ByIxnsKUxQx1tOB3W0=
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 h1:UDSeJZ2xB3dj1lySnM5LpF48dGlphGstw2BqtkJwcZI=
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322/go.mod h1:2wjxSr1Gbecq9A0ESA9cnR399tQTcpCZEOGytekb+qI=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d h1:UUxtLujzp5jmtOXqXpSOGvHwHSZcBveKVDzRJ4GlnFU=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d/go.mod h1:Co3PJXcaZoLwHGBfT0rbSnn9C7ywc41zVYWtDeoeI/Q=
github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 h1:aPb0T2HQRTG2t7fEwLvFLZSXmhmnBh+SMs2NufhmrsI=
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302/go.mod h1:bvcVzlf9q9dgxt8qKluW+zOXCFoN1+SpBG3sHTq8/9Q=
github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
github.com/sagernet/sing v0.2.2 h1:qfEdSLuwFgIIkeLOcwVQkVDzKLHtclXb93Ql0zZA+aE=
github.com/sagernet/sing v0.2.2/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440 h1:VH8/BcOVuApHtS+vKP+khxlGRcXH7KKhgkTDtNynqSQ=
github.com/sagernet/sing-dns v0.1.5-0.20230408004833-5adaf486d440/go.mod h1:69PNSHyEmXdjf6C+bXBOdr2GQnPeEyWjIzo/MV8gmz8=
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4 h1:mKpXBBnAhTy9/CvDKqt5cN78LKX8cVUqjoWEXI/g0No=
github.com/sagernet/sing-shadowsocks v0.2.1-0.20230408141421-e40d6a4e42d4/go.mod h1:NFEROpOEiLG+lEoSPNpSL2yDyXx6q0OJvwWnEAd40cI=
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc=
github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U=
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab h1:a9oeWuPBuIZ70qMhIIH6RrYhp886xN9jJIwsuu4ZFUo=
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab/go.mod h1:4YxIDEkkCjGXDOTMPw1SXpLmCQUFAWuaQN250oo+928=
github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 h1:ZArINfN+zcHMdZCeRFOm4rO3SWyvYuLg3VhWcA5zonc=
github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7/go.mod h1:A9iGfwYmAEmVg8bavkqQ7Hx7nr9Pc2oWMYDwbLIBDjY=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
@@ -151,10 +149,8 @@ github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spyzhov/ajson v0.7.1 h1:1MDIlPc6x0zjNtpa7tDzRAyFAvRX+X8ZsvtYz5lZg6A=
github.com/spyzhov/ajson v0.7.1/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
github.com/spyzhov/ajson v0.8.0 h1:sFXyMbi4Y/BKjrsfkUZHSjA2JM1184enheSjjoT/zCc=
github.com/spyzhov/ajson v0.8.0/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -178,8 +174,8 @@ go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
@@ -195,7 +191,6 @@ golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -230,7 +225,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/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-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@@ -141,95 +141,6 @@ func TestVLESSVisionReality(t *testing.T) {
testSuit(t, clientPort, testPort)
}
func TestVLESSVisionRealityPlain(t *testing.T) {
userUUID := newUUID()
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: clientPort,
},
},
},
{
Type: C.TypeVLESS,
VLESSOptions: option.VLESSInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: serverPort,
},
Users: []option.VLESSUser{
{
Name: "sekai",
UUID: userUUID.String(),
Flow: vless.FlowVision,
},
},
TLS: &option.InboundTLSOptions{
Enabled: true,
ServerName: "google.com",
Reality: &option.InboundRealityOptions{
Enabled: true,
Handshake: option.InboundRealityHandshakeOptions{
ServerOptions: option.ServerOptions{
Server: "google.com",
ServerPort: 443,
},
},
ShortID: []string{"0123456789abcdef"},
PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc",
},
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeDirect,
},
{
Type: C.TypeVLESS,
Tag: "vless-out",
VLESSOptions: option.VLESSOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
UUID: userUUID.String(),
Flow: vless.FlowVision,
TLS: &option.OutboundTLSOptions{
Enabled: true,
ServerName: "google.com",
Reality: &option.OutboundRealityOptions{
Enabled: true,
ShortID: "0123456789abcdef",
PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0",
},
UTLS: &option.OutboundUTLSOptions{
Enabled: true,
},
},
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"},
Outbound: "vless-out",
},
},
},
},
})
testSuit(t, clientPort, testPort)
}
func TestVLESSRealityTransport(t *testing.T) {
t.Run("grpc", func(t *testing.T) {
testVLESSRealityTransport(t, &option.V2RayTransportOptions{
@@ -249,6 +160,8 @@ func TestVLESSRealityTransport(t *testing.T) {
}
func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOptions) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
userUUID := newUUID()
startInstance(t, option.Options{
Inbounds: []option.Inbound{
@@ -293,11 +206,52 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
Transport: transport,
},
},
{
Type: C.TypeTrojan,
Tag: "trojan",
TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
ListenPort: otherPort,
},
Users: []option.TrojanUser{
{
Name: "sekai",
Password: userUUID.String(),
},
},
TLS: &option.InboundTLSOptions{
Enabled: true,
ServerName: "example.org",
CertificatePath: certPem,
KeyPath: keyPem,
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeDirect,
},
{
Type: C.TypeTrojan,
Tag: "trojan-out",
TrojanOptions: option.TrojanOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: otherPort,
},
Password: userUUID.String(),
TLS: &option.OutboundTLSOptions{
Enabled: true,
ServerName: "example.org",
CertificatePath: certPem,
},
DialerOptions: option.DialerOptions{
Detour: "vless-out",
},
},
},
{
Type: C.TypeVLESS,
Tag: "vless-out",
@@ -328,7 +282,7 @@ func testVLESSRealityTransport(t *testing.T, transport *option.V2RayTransportOpt
{
DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"},
Outbound: "vless-out",
Outbound: "trojan-out",
},
},
},

View File

@@ -1,59 +0,0 @@
package main
import (
"context"
"net"
"testing"
"time"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/udpnat"
)
func TestUDPNatClose(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
connCtx, connCancel := common.ContextWithCancelCause(context.Background())
defer connCancel(net.ErrClosed)
service := udpnat.New[int](ctx, 1, &testUDPNatCloseHandler{connCancel})
service.NewPacket(ctx, 0, buf.As([]byte("Hello")), M.Metadata{}, func(natConn N.PacketConn) N.PacketWriter {
return &testPacketWriter{}
})
select {
case <-connCtx.Done():
if E.IsClosed(connCtx.Err()) {
t.Fatal(E.New("conn closed unexpectedly: ", connCtx.Err()))
}
case <-time.After(2 * time.Second):
t.Fatal("conn not closed")
}
}
type testUDPNatCloseHandler struct {
done common.ContextCancelCauseFunc
}
func (h *testUDPNatCloseHandler) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
for {
buffer := buf.NewPacket()
_, err := conn.ReadPacket(buffer)
buffer.Release()
if err != nil {
h.done(err)
return err
}
}
}
func (h *testUDPNatCloseHandler) NewError(ctx context.Context, err error) {
}
type testPacketWriter struct{}
func (t *testPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
return nil
}

View File

@@ -119,7 +119,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
func (t *Transport) fetchInterface() (*net.Interface, error) {
interfaceName := t.interfaceName
if t.autoInterface {
if t.router.InterfaceMonitor() == nil {
if t.router.NetworkMonitor() == nil {
return nil, E.New("missing monitor for auto DHCP, set route.auto_detect_interface")
}
interfaceName = t.router.InterfaceMonitor().DefaultInterfaceName(netip.Addr{})

View File

@@ -535,10 +535,6 @@ func (c *PacketConn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *PacketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *PacketConn) Read(b []byte) (n int, err error) {
return 0, os.ErrInvalid
}

View File

@@ -4,6 +4,8 @@ import (
"context"
"net"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/rw"
@@ -53,7 +55,7 @@ func newMuxConnection0(ctx context.Context, stream net.Conn, metadata M.Metadata
case CommandTCP:
return handler.NewConnection(ctx, stream, metadata)
case CommandUDP:
return handler.NewPacketConnection(ctx, &PacketConn{stream}, metadata)
return handler.NewPacketConnection(ctx, deadline.NewPacketConn(bufio.NewNetPacketConn(&PacketConn{stream})), metadata)
default:
return E.New("unknown command ", command)
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -106,7 +107,7 @@ func (s *Service[K]) NewConnection(ctx context.Context, conn net.Conn, metadata
case CommandTCP:
return s.handler.NewConnection(ctx, conn, metadata)
case CommandUDP:
return s.handler.NewPacketConnection(ctx, &PacketConn{conn}, metadata)
return s.handler.NewPacketConnection(ctx, deadline.NewPacketConn(bufio.NewNetPacketConn(&PacketConn{conn})), metadata)
// case CommandMux:
default:
return HandleMuxConnection(ctx, conn, metadata, s.handler)
@@ -136,11 +137,3 @@ func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) er
func (c *PacketConn) FrontHeadroom() int {
return M.MaxSocksaddrLength + 4
}
func (c *PacketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *PacketConn) Upstream() any {
return c.Conn
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio/deadline"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -109,5 +110,5 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
cancel(err)
return nil, err
}
return NewGRPCConn(stream, cancel), nil
return deadline.NewConn(NewGRPCConn(stream, cancel)), nil
}

View File

@@ -81,10 +81,6 @@ func (c *GRPCConn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *GRPCConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *GRPCConn) Upstream() any {
return c.GunService
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio/deadline"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -66,7 +67,7 @@ func (s *Server) Tun(server GunService_TunServer) error {
}
}
}
go s.handler.NewConnection(ctx, conn, metadata)
go s.handler.NewConnection(ctx, deadline.NewConn(conn), metadata)
<-ctx.Done()
return nil
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/v2rayhttp"
"github.com/sagernet/sing/common/bufio/deadline"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -92,7 +93,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
conn.setup(nil, err)
}
}()
return conn, nil
return deadline.NewConn(conn), nil
}
func (c *Client) Close() error {

View File

@@ -156,7 +156,3 @@ func (c *GunConn) SetReadDeadline(t time.Time) error {
func (c *GunConn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *GunConn) NeedAdditionalReadDeadline() bool {
return true
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/v2rayhttp"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -81,7 +82,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
var metadata M.Metadata
metadata.Source = sHttp.SourceAddress(request)
conn := v2rayhttp.NewHTTP2Wrapper(newGunConn(request.Body, writer, writer.(http.Flusher)))
s.handler.NewConnection(request.Context(), conn, metadata)
s.handler.NewConnection(request.Context(), deadline.NewConn(conn), metadata)
conn.CloseWrapper()
}

View File

@@ -182,21 +182,32 @@ func (c *HTTP2Conn) RemoteAddr() net.Addr {
}
func (c *HTTP2Conn) SetDeadline(t time.Time) error {
if responseWriter, loaded := c.writer.(interface {
SetWriteDeadline(time.Time) error
}); loaded {
return responseWriter.SetWriteDeadline(t)
}
return os.ErrInvalid
}
func (c *HTTP2Conn) SetReadDeadline(t time.Time) error {
if responseWriter, loaded := c.writer.(interface {
SetReadDeadline(time.Time) error
}); loaded {
return responseWriter.SetReadDeadline(t)
}
return os.ErrInvalid
}
func (c *HTTP2Conn) SetWriteDeadline(t time.Time) error {
if responseWriter, loaded := c.writer.(interface {
SetWriteDeadline(time.Time) error
}); loaded {
return responseWriter.SetWriteDeadline(t)
}
return os.ErrInvalid
}
func (c *HTTP2Conn) NeedAdditionalReadDeadline() bool {
return true
}
type ServerHTTPConn struct {
HTTP2Conn
flusher http.Flusher

View File

@@ -10,6 +10,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -78,11 +79,11 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
if c.maxEarlyData <= 0 {
conn, response, err := c.dialer.DialContext(ctx, c.uri, c.headers)
if err == nil {
return &WebsocketConn{Conn: conn, Writer: NewWriter(conn, false)}, nil
return deadline.NewConn(&WebsocketConn{Conn: conn, Writer: NewWriter(conn, false)}), nil
}
return nil, wrapDialError(response, err)
} else {
return &EarlyWebsocketConn{Client: c, ctx: ctx, create: make(chan struct{})}, nil
return deadline.NewConn(&EarlyWebsocketConn{Client: c, ctx: ctx, create: make(chan struct{})}), nil
}
}

View File

@@ -77,10 +77,6 @@ func (c *WebsocketConn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *WebsocketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *WebsocketConn) Upstream() any {
return c.Conn.NetConn()
}
@@ -218,10 +214,6 @@ func (c *EarlyWebsocketConn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *EarlyWebsocketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *EarlyWebsocketConn) Upstream() any {
return common.PtrOrNil(c.conn)
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -107,7 +108,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
if len(earlyData) > 0 {
conn = bufio.NewCachedConn(conn, buf.As(earlyData))
}
s.handler.NewConnection(request.Context(), conn, metadata)
s.handler.NewConnection(request.Context(), deadline.NewConn(conn), metadata)
}
func (s *Server) fallbackRequest(ctx context.Context, writer http.ResponseWriter, request *http.Request, statusCode int, err error) {

View File

@@ -9,6 +9,7 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
@@ -36,156 +37,105 @@ func NewClient(userId string, flow string, logger logger.Logger) (*Client, error
return &Client{user, flow, logger}, nil
}
func (c *Client) prepareConn(conn net.Conn, tlsConn net.Conn) (net.Conn, error) {
func (c *Client) prepareConn(conn net.Conn) (net.Conn, error) {
if c.flow == FlowVision {
protocolConn, err := NewVisionConn(conn, tlsConn, c.key, c.logger)
vConn, err := NewVisionConn(conn, c.key, c.logger)
if err != nil {
return nil, E.Cause(err, "initialize vision")
}
conn = protocolConn
conn = vConn
}
return conn, nil
}
func (c *Client) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
vConn, err := c.prepareConn(conn)
if err != nil {
return nil, err
}
return protocolConn, common.Error(remoteConn.Write(nil))
serverConn := &Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow}
return deadline.NewConn(serverConn), common.Error(serverConn.Write(nil))
}
func (c *Client) DialEarlyConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) {
return c.prepareConn(NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow), conn)
vConn, err := c.prepareConn(conn)
if err != nil {
return nil, err
}
return deadline.NewConn(&Conn{Conn: conn, protocolConn: vConn, key: c.key, command: vmess.CommandTCP, destination: destination, flow: c.flow}), nil
}
func (c *Client) DialPacketConn(conn net.Conn, destination M.Socksaddr) (*PacketConn, error) {
func (c *Client) DialPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
serverConn := &PacketConn{Conn: conn, key: c.key, destination: destination, flow: c.flow}
return serverConn, common.Error(serverConn.Write(nil))
return bufio.NewBindPacketConn(deadline.NewPacketConn(bufio.NewPacketConn(serverConn)), destination), common.Error(serverConn.Write(nil))
}
func (c *Client) DialEarlyPacketConn(conn net.Conn, destination M.Socksaddr) (*PacketConn, error) {
return &PacketConn{Conn: conn, key: c.key, destination: destination, flow: c.flow}, nil
func (c *Client) DialEarlyPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
return bufio.NewBindPacketConn(deadline.NewPacketConn(bufio.NewPacketConn(&PacketConn{Conn: conn, key: c.key, destination: destination, flow: c.flow})), destination), nil
}
func (c *Client) DialXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
remoteConn := NewConn(conn, c.key, vmess.CommandTCP, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
serverConn := &Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow}
err := common.Error(serverConn.Write(nil))
if err != nil {
return nil, err
}
return vmess.NewXUDPConn(protocolConn, destination), common.Error(remoteConn.Write(nil))
return bufio.NewBindPacketConn(deadline.NewPacketConn(vmess.NewXUDPConn(serverConn, destination)), destination), nil
}
func (c *Client) DialEarlyXUDPPacketConn(conn net.Conn, destination M.Socksaddr) (vmess.PacketConn, error) {
remoteConn := NewConn(conn, c.key, vmess.CommandMux, destination, c.flow)
protocolConn, err := c.prepareConn(remoteConn, conn)
if err != nil {
return nil, err
}
return vmess.NewXUDPConn(protocolConn, destination), common.Error(remoteConn.Write(nil))
return bufio.NewBindPacketConn(deadline.NewPacketConn(vmess.NewXUDPConn(&Conn{Conn: conn, protocolConn: conn, key: c.key, command: vmess.CommandMux, destination: destination, flow: c.flow}, destination)), destination), nil
}
var (
_ N.EarlyConn = (*Conn)(nil)
_ N.VectorisedWriter = (*Conn)(nil)
)
var _ N.EarlyConn = (*Conn)(nil)
type Conn struct {
N.ExtendedConn
writer N.VectorisedWriter
request Request
net.Conn
protocolConn net.Conn
key [16]byte
command byte
destination M.Socksaddr
flow string
requestWritten bool
responseRead bool
}
func NewConn(conn net.Conn, uuid [16]byte, command byte, destination M.Socksaddr, flow string) *Conn {
return &Conn{
ExtendedConn: bufio.NewExtendedConn(conn),
writer: bufio.NewVectorisedWriter(conn),
request: Request{
UUID: uuid,
Command: command,
Destination: destination,
Flow: flow,
},
}
}
func (c *Conn) Read(b []byte) (n int, err error) {
if !c.responseRead {
err = ReadResponse(c.ExtendedConn)
if err != nil {
return
}
c.responseRead = true
}
return c.ExtendedConn.Read(b)
}
func (c *Conn) ReadBuffer(buffer *buf.Buffer) error {
if !c.responseRead {
err := ReadResponse(c.ExtendedConn)
if err != nil {
return err
}
c.responseRead = true
}
return c.ExtendedConn.ReadBuffer(buffer)
}
func (c *Conn) Write(b []byte) (n int, err error) {
if !c.requestWritten {
err = WriteRequest(c.ExtendedConn, c.request, b)
if err == nil {
n = len(b)
}
c.requestWritten = true
return
}
return c.ExtendedConn.Write(b)
}
func (c *Conn) WriteBuffer(buffer *buf.Buffer) error {
if !c.requestWritten {
EncodeRequest(c.request, buf.With(buffer.ExtendHeader(RequestLen(c.request))))
c.requestWritten = true
}
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *Conn) WriteVectorised(buffers []*buf.Buffer) error {
if !c.requestWritten {
buffer := buf.NewSize(RequestLen(c.request))
EncodeRequest(c.request, buffer)
c.requestWritten = true
return c.writer.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...))
}
return c.writer.WriteVectorised(buffers)
}
func (c *Conn) ReaderReplaceable() bool {
return c.responseRead
}
func (c *Conn) WriterReplaceable() bool {
return c.requestWritten
}
func (c *Conn) NeedHandshake() bool {
return !c.requestWritten
}
func (c *Conn) FrontHeadroom() int {
if c.requestWritten {
return 0
func (c *Conn) Read(b []byte) (n int, err error) {
if !c.responseRead {
err = ReadResponse(c.Conn)
if err != nil {
return
}
c.responseRead = true
}
return RequestLen(c.request)
return c.protocolConn.Read(b)
}
func (c *Conn) Write(b []byte) (n int, err error) {
if !c.requestWritten {
request := Request{c.key, c.command, c.destination, c.flow}
if c.protocolConn != nil {
err = WriteRequest(c.Conn, request, nil)
} else {
err = WriteRequest(c.Conn, request, b)
}
if err == nil {
n = len(b)
}
c.requestWritten = true
if c.protocolConn == nil {
return
}
}
return c.protocolConn.Write(b)
}
func (c *Conn) Upstream() any {
return c.ExtendedConn
return c.Conn
}
type PacketConn struct {
@@ -264,10 +214,6 @@ func (c *PacketConn) FrontHeadroom() int {
return 2
}
func (c *PacketConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *PacketConn) Upstream() any {
return c.Conn
}

View File

@@ -11,12 +11,10 @@ var (
tlsClientHandShakeStart = []byte{0x16, 0x03}
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
)
const (
commandPaddingContinue byte = iota
commandPaddingEnd
commandPaddingDirect
commandPaddingContinue byte = 0
commandPaddingEnd byte = 1
commandPaddingDirect byte = 2
)
var tls13CipherSuiteDic = map[uint16]string{

View File

@@ -128,7 +128,7 @@ func WriteRequest(writer io.Writer, request Request, payload []byte) error {
requestLen += 1 // protobuf length
var addonsLen int
if request.Flow != "" {
if request.Command == vmess.CommandTCP && request.Flow != "" {
addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(len(request.Flow)))
addonsLen += len(request.Flow)
@@ -165,62 +165,6 @@ func WriteRequest(writer io.Writer, request Request, payload []byte) error {
return common.Error(writer.Write(buffer.Bytes()))
}
func EncodeRequest(request Request, buffer *buf.Buffer) {
var requestLen int
requestLen += 1 // version
requestLen += 16 // uuid
requestLen += 1 // protobuf length
var addonsLen int
if request.Flow != "" {
addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(len(request.Flow)))
addonsLen += len(request.Flow)
requestLen += addonsLen
}
requestLen += 1 // command
if request.Command != vmess.CommandMux {
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
}
common.Must(
buffer.WriteByte(Version),
common.Error(buffer.Write(request.UUID[:])),
buffer.WriteByte(byte(addonsLen)),
)
if addonsLen > 0 {
common.Must(buffer.WriteByte(10))
binary.PutUvarint(buffer.Extend(UvarintLen(uint64(len(request.Flow)))), uint64(len(request.Flow)))
common.Must(common.Error(buffer.Write([]byte(request.Flow))))
}
common.Must(
buffer.WriteByte(request.Command),
)
if request.Command != vmess.CommandMux {
common.Must(vmess.AddressSerializer.WriteAddrPort(buffer, request.Destination))
}
}
func RequestLen(request Request) int {
var requestLen int
requestLen += 1 // version
requestLen += 16 // uuid
requestLen += 1 // protobuf length
var addonsLen int
if request.Flow != "" {
addonsLen += 1 // protobuf header
addonsLen += UvarintLen(uint64(len(request.Flow)))
addonsLen += len(request.Flow)
requestLen += addonsLen
}
requestLen += 1 // command
if request.Command != vmess.CommandMux {
requestLen += vmess.AddressSerializer.AddrPortLen(request.Destination)
}
return requestLen
}
func WritePacketRequest(writer io.Writer, request Request, payload []byte) error {
var requestLen int
requestLen += 1 // version

View File

@@ -10,6 +10,7 @@ import (
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
@@ -68,32 +69,30 @@ func (s *Service[T]) NewConnection(ctx context.Context, conn net.Conn, metadata
metadata.Destination = request.Destination
userFlow := s.userFlow[user]
if request.Flow == FlowVision && request.Command == vmess.NetworkUDP {
return E.New(FlowVision, " flow does not support UDP")
} else if request.Flow != userFlow {
return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
var responseWriter io.Writer
if request.Command == vmess.CommandTCP {
if request.Flow != userFlow {
return E.New("flow mismatch: expected ", flowName(userFlow), ", but got ", flowName(request.Flow))
}
switch userFlow {
case "":
case FlowVision:
responseWriter = conn
conn, err = NewVisionConn(conn, request.UUID, s.logger)
if err != nil {
return E.Cause(err, "initialize vision")
}
}
}
if request.Command == vmess.CommandUDP {
return s.handler.NewPacketConnection(ctx, &serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}, metadata)
}
responseConn := &serverConn{ExtendedConn: bufio.NewExtendedConn(conn), writer: bufio.NewVectorisedWriter(conn)}
switch userFlow {
case FlowVision:
conn, err = NewVisionConn(responseConn, conn, request.UUID, s.logger)
if err != nil {
return E.Cause(err, "initialize vision")
}
case "":
conn = responseConn
default:
return E.New("unknown flow: ", userFlow)
}
switch request.Command {
case vmess.CommandTCP:
return s.handler.NewConnection(ctx, conn, metadata)
return s.handler.NewConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, metadata)
case vmess.CommandUDP:
return s.handler.NewPacketConnection(ctx, deadline.NewPacketConn(&serverPacketConn{ExtendedConn: bufio.NewExtendedConn(conn), destination: request.Destination}), metadata)
case vmess.CommandMux:
return vmess.HandleMuxConnection(ctx, conn, s.handler)
return vmess.HandleMuxConnection(ctx, &serverConn{Conn: conn, responseWriter: responseWriter}, s.handler)
default:
return E.New("unknown command: ", request.Command)
}
@@ -106,70 +105,34 @@ func flowName(value string) string {
return value
}
var _ N.VectorisedWriter = (*serverConn)(nil)
type serverConn struct {
N.ExtendedConn
writer N.VectorisedWriter
net.Conn
responseWriter io.Writer
responseWritten bool
}
func (c *serverConn) Read(b []byte) (n int, err error) {
return c.ExtendedConn.Read(b)
return c.Conn.Read(b)
}
func (c *serverConn) Write(b []byte) (n int, err error) {
if !c.responseWritten {
_, err = bufio.WriteVectorised(c.writer, [][]byte{{Version, 0}, b})
if err == nil {
n = len(b)
if c.responseWriter == nil {
_, err = bufio.WriteVectorised(bufio.NewVectorisedWriter(c.Conn), [][]byte{{Version, 0}, b})
if err == nil {
n = len(b)
}
c.responseWritten = true
return
} else {
_, err = c.responseWriter.Write([]byte{Version, 0})
if err != nil {
return
}
c.responseWritten = true
}
c.responseWritten = true
return
}
return c.ExtendedConn.Write(b)
}
func (c *serverConn) WriteBuffer(buffer *buf.Buffer) error {
if !c.responseWritten {
header := buffer.ExtendHeader(2)
header[0] = Version
header[1] = 0
c.responseWritten = true
}
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *serverConn) WriteVectorised(buffers []*buf.Buffer) error {
if !c.responseWritten {
err := c.writer.WriteVectorised(append([]*buf.Buffer{buf.As([]byte{Version, 0})}, buffers...))
c.responseWritten = true
return err
}
return c.writer.WriteVectorised(buffers)
}
func (c *serverConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *serverConn) FrontHeadroom() int {
if c.responseWritten {
return 0
}
return 2
}
func (c *serverConn) ReaderReplaceable() bool {
return true
}
func (c *serverConn) WriterReplaceable() bool {
return c.responseWritten
}
func (c *serverConn) Upstream() any {
return c.ExtendedConn
return c.Conn.Write(b)
}
type serverPacketConn struct {

View File

@@ -56,12 +56,12 @@ type VisionConn struct {
withinPaddingBuffers bool
remainingContent int
remainingPadding int
currentCommand byte
currentCommand int
directRead bool
remainingReader io.Reader
}
func NewVisionConn(conn net.Conn, tlsConn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) {
func NewVisionConn(conn net.Conn, userUUID [16]byte, logger logger.Logger) (*VisionConn, error) {
var (
loaded bool
reflectType reflect.Type
@@ -69,7 +69,7 @@ func NewVisionConn(conn net.Conn, tlsConn net.Conn, userUUID [16]byte, logger lo
netConn net.Conn
)
for _, tlsCreator := range tlsRegistry {
loaded, netConn, reflectType, reflectPointer = tlsCreator(tlsConn)
loaded, netConn, reflectType, reflectPointer = tlsCreator(conn)
if loaded {
break
}
@@ -103,7 +103,6 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
if c.remainingReader != nil {
n, err = c.remainingReader.Read(p)
if err == io.EOF {
err = nil
c.remainingReader = nil
}
if n > 0 {
@@ -114,7 +113,6 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
return c.netConn.Read(p)
}
var bufferBytes []byte
var chunkBuffer *buf.Buffer
if len(p) > xrayChunkSize {
n, err = c.Conn.Read(p)
if err != nil {
@@ -122,26 +120,21 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
}
bufferBytes = p[:n]
} else {
chunkBuffer, err = c.reader.ReadChunk()
buffer, err := c.reader.ReadChunk()
if err != nil {
return 0, err
}
bufferBytes = chunkBuffer.Bytes()
defer buffer.FullReset()
bufferBytes = buffer.Bytes()
}
if c.withinPaddingBuffers || c.numberOfPacketToFilter > 0 {
buffers := c.unPadding(bufferBytes)
if chunkBuffer != nil {
buffers = common.Map(buffers, func(it *buf.Buffer) *buf.Buffer {
return it.ToOwned()
})
chunkBuffer.FullReset()
}
if c.remainingContent == 0 && c.remainingPadding == 0 {
if c.currentCommand == commandPaddingEnd {
if c.currentCommand == 1 {
c.withinPaddingBuffers = false
c.remainingContent = -1
c.remainingPadding = -1
} else if c.currentCommand == commandPaddingDirect {
} else if c.currentCommand == 2 {
c.withinPaddingBuffers = false
c.directRead = true
@@ -149,17 +142,17 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
if err != nil {
return 0, err
}
buffers = append(buffers, buf.As(inputBuffer))
buffers = append(buffers, inputBuffer)
rawInputBuffer, err := io.ReadAll(c.rawInput)
if err != nil {
return 0, err
}
buffers = append(buffers, buf.As(rawInputBuffer))
buffers = append(buffers, rawInputBuffer)
c.logger.Trace("XtlsRead readV")
} else if c.currentCommand == commandPaddingContinue {
} else if c.currentCommand == 0 {
c.withinPaddingBuffers = true
} else {
return 0, E.New("unknown command ", c.currentCommand)
@@ -170,18 +163,14 @@ func (c *VisionConn) Read(p []byte) (n int, err error) {
c.withinPaddingBuffers = false
}
if c.numberOfPacketToFilter > 0 {
c.filterTLS(buf.ToSliceMulti(buffers))
c.filterTLS(buffers)
}
c.remainingReader = io.MultiReader(common.Map(buffers, func(it *buf.Buffer) io.Reader { return it })...)
c.remainingReader = io.MultiReader(common.Map(buffers, func(it []byte) io.Reader { return bytes.NewReader(it) })...)
return c.Read(p)
} else {
if c.numberOfPacketToFilter > 0 {
c.filterTLS([][]byte{bufferBytes})
}
if chunkBuffer != nil {
n = copy(p, bufferBytes)
chunkBuffer.Advance(n)
}
return
}
}
@@ -321,7 +310,7 @@ func (c *VisionConn) padding(buffer *buf.Buffer, command byte) *buf.Buffer {
return newBuffer
}
func (c *VisionConn) unPadding(buffer []byte) []*buf.Buffer {
func (c *VisionConn) unPadding(buffer []byte) [][]byte {
var bufferIndex int
if c.remainingContent == -1 && c.remainingPadding == -1 {
if len(buffer) >= 21 && bytes.Equal(c.userUUID[:], buffer[:16]) {
@@ -332,17 +321,17 @@ func (c *VisionConn) unPadding(buffer []byte) []*buf.Buffer {
}
}
if c.remainingContent == -1 && c.remainingPadding == -1 {
return []*buf.Buffer{buf.As(buffer)}
return [][]byte{buffer}
}
var buffers []*buf.Buffer
var buffers [][]byte
for bufferIndex < len(buffer) {
if c.remainingContent <= 0 && c.remainingPadding <= 0 {
if c.currentCommand == 1 {
buffers = append(buffers, buf.As(buffer[bufferIndex:]))
buffers = append(buffers, buffer[bufferIndex:])
break
} else {
paddingInfo := buffer[bufferIndex : bufferIndex+5]
c.currentCommand = paddingInfo[0]
c.currentCommand = int(paddingInfo[0])
c.remainingContent = int(paddingInfo[1])<<8 | int(paddingInfo[2])
c.remainingPadding = int(paddingInfo[3])<<8 | int(paddingInfo[4])
bufferIndex += 5
@@ -353,7 +342,7 @@ func (c *VisionConn) unPadding(buffer []byte) []*buf.Buffer {
if end > len(buffer)-bufferIndex {
end = len(buffer) - bufferIndex
}
buffers = append(buffers, buf.As(buffer[bufferIndex:bufferIndex+end]))
buffers = append(buffers, buffer[bufferIndex:bufferIndex+end])
c.remainingContent -= end
bufferIndex += end
} else {
@@ -371,10 +360,6 @@ func (c *VisionConn) unPadding(buffer []byte) []*buf.Buffer {
return buffers
}
func (c *VisionConn) NeedAdditionalReadDeadline() bool {
return true
}
func (c *VisionConn) Upstream() any {
return c.Conn
}