mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-13 20:28:32 +10:00
Compare commits
45 Commits
dev-ndis
...
v1.11.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79a8caed8a | ||
|
|
41f4b71a11 | ||
|
|
eb4a184b7e | ||
|
|
f0f3a45904 | ||
|
|
339e3e6c15 | ||
|
|
f72118135e | ||
|
|
5952c174f7 | ||
|
|
dda692e955 | ||
|
|
f08861185a | ||
|
|
a2b6c367ee | ||
|
|
05338a53eb | ||
|
|
51521653a4 | ||
|
|
b55a18a13f | ||
|
|
6be54ff3eb | ||
|
|
255e591ef7 | ||
|
|
df8a3e912e | ||
|
|
7693e985af | ||
|
|
37f7d9a6fa | ||
|
|
1ec2490a96 | ||
|
|
861cb7fcf3 | ||
|
|
7aa0c572cc | ||
|
|
ccffca9e13 | ||
|
|
bcf9c92793 | ||
|
|
680daeb5f8 | ||
|
|
f9aea332d5 | ||
|
|
a1ded989b7 | ||
|
|
8ef771652c | ||
|
|
e9ed794396 | ||
|
|
feffb897b2 | ||
|
|
dea80da0eb | ||
|
|
606abff177 | ||
|
|
7e21588011 | ||
|
|
abf99a0c89 | ||
|
|
4954d046d2 | ||
|
|
6a62f4c936 | ||
|
|
994b9726db | ||
|
|
ef8e0f5849 | ||
|
|
91b11d5654 | ||
|
|
466171b3cf | ||
|
|
51c0ee6c90 | ||
|
|
2a40003034 | ||
|
|
34442521b4 | ||
|
|
cc773eccbf | ||
|
|
d4b23cc0ab | ||
|
|
e1eeb0d7e0 |
@@ -22,16 +22,6 @@ linters-settings:
|
|||||||
|
|
||||||
run:
|
run:
|
||||||
go: "1.23"
|
go: "1.23"
|
||||||
build-tags:
|
|
||||||
- with_gvisor
|
|
||||||
- with_quic
|
|
||||||
- with_dhcp
|
|
||||||
- with_wireguard
|
|
||||||
- with_ech
|
|
||||||
- with_utls
|
|
||||||
- with_reality_server
|
|
||||||
- with_acme
|
|
||||||
- with_clash_api
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-dirs:
|
exclude-dirs:
|
||||||
|
|||||||
@@ -51,4 +51,5 @@ type NetworkInterface struct {
|
|||||||
DNSServers []string
|
DNSServers []string
|
||||||
Expensive bool
|
Expensive bool
|
||||||
Constrained bool
|
Constrained bool
|
||||||
|
RawNetwork any
|
||||||
}
|
}
|
||||||
|
|||||||
7
box.go
7
box.go
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
"github.com/sagernet/sing-box/adapter/inbound"
|
||||||
"github.com/sagernet/sing-box/adapter/outbound"
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
@@ -85,6 +84,7 @@ func New(options Options) (*Box, error) {
|
|||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
}
|
}
|
||||||
ctx = service.ContextWithDefaultRegistry(ctx)
|
ctx = service.ContextWithDefaultRegistry(ctx)
|
||||||
|
|
||||||
endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx)
|
endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx)
|
||||||
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
|
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
|
||||||
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
||||||
@@ -101,10 +101,7 @@ func New(options Options) (*Box, error) {
|
|||||||
|
|
||||||
ctx = pause.WithDefaultManager(ctx)
|
ctx = pause.WithDefaultManager(ctx)
|
||||||
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
||||||
debugOptions := common.PtrValueOrDefault(experimentalOptions.Debug)
|
applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
|
||||||
applyDebugOptions(debugOptions)
|
|
||||||
ctx = conntrack.ContextWithDefaultTracker(ctx, debugOptions.OOMKiller, uint64(debugOptions.MemoryLimit))
|
|
||||||
|
|
||||||
var needCacheFile bool
|
var needCacheFile bool
|
||||||
var needClashAPI bool
|
var needClashAPI bool
|
||||||
var needV2RayAPI bool
|
var needV2RayAPI bool
|
||||||
|
|||||||
Submodule clients/android updated: e1049099a0...6533b62fa3
Submodule clients/apple updated: 3d889ae017...1ecaff4c90
@@ -21,7 +21,7 @@ func initializeHTTP3Client(instance *box.Box) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
http3Client = &http.Client{
|
http3Client = &http.Client{
|
||||||
Transport: &http3.Transport{
|
Transport: &http3.RoundTripper{
|
||||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||||
destination := M.ParseSocksaddr(addr)
|
destination := M.ParseSocksaddr(addr)
|
||||||
udpConn, dErr := dialer.DialContext(ctx, N.NetworkUDP, destination)
|
udpConn, dErr := dialer.DialContext(ctx, N.NetworkUDP, destination)
|
||||||
|
|||||||
54
common/conntrack/conn.go
Normal file
54
common/conntrack/conn.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package conntrack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Conn struct {
|
||||||
|
net.Conn
|
||||||
|
element *list.Element[io.Closer]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConn(conn net.Conn) (net.Conn, error) {
|
||||||
|
connAccess.Lock()
|
||||||
|
element := openConnection.PushBack(conn)
|
||||||
|
connAccess.Unlock()
|
||||||
|
if KillerEnabled {
|
||||||
|
err := KillerCheck()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Conn{
|
||||||
|
Conn: conn,
|
||||||
|
element: element,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Close() error {
|
||||||
|
if c.element.Value != nil {
|
||||||
|
connAccess.Lock()
|
||||||
|
if c.element.Value != nil {
|
||||||
|
openConnection.Remove(c.element)
|
||||||
|
c.element.Value = nil
|
||||||
|
}
|
||||||
|
connAccess.Unlock()
|
||||||
|
}
|
||||||
|
return c.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) Upstream() any {
|
||||||
|
return c.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) ReaderReplaceable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) WriterReplaceable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package conntrack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ContextWithDefaultTracker(ctx context.Context, killerEnabled bool, memoryLimit uint64) context.Context {
|
|
||||||
if service.FromContext[Tracker](ctx) != nil {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
return service.ContextWith[Tracker](ctx, NewDefaultTracker(killerEnabled, memoryLimit))
|
|
||||||
}
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
package conntrack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
runtimeDebug "runtime/debug"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
"github.com/sagernet/sing/common/memory"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
"github.com/sagernet/sing/common/x/list"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Tracker = (*DefaultTracker)(nil)
|
|
||||||
|
|
||||||
type DefaultTracker struct {
|
|
||||||
connAccess sync.RWMutex
|
|
||||||
connList list.List[net.Conn]
|
|
||||||
connAddress map[netip.AddrPort]netip.AddrPort
|
|
||||||
|
|
||||||
packetConnAccess sync.RWMutex
|
|
||||||
packetConnList list.List[AbstractPacketConn]
|
|
||||||
packetConnAddress map[netip.AddrPort]bool
|
|
||||||
|
|
||||||
pendingAccess sync.RWMutex
|
|
||||||
pendingList list.List[netip.AddrPort]
|
|
||||||
|
|
||||||
killerEnabled bool
|
|
||||||
memoryLimit uint64
|
|
||||||
killerLastCheck time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultTracker(killerEnabled bool, memoryLimit uint64) *DefaultTracker {
|
|
||||||
return &DefaultTracker{
|
|
||||||
connAddress: make(map[netip.AddrPort]netip.AddrPort),
|
|
||||||
packetConnAddress: make(map[netip.AddrPort]bool),
|
|
||||||
killerEnabled: killerEnabled,
|
|
||||||
memoryLimit: memoryLimit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) NewConn(conn net.Conn) (net.Conn, error) {
|
|
||||||
err := t.KillerCheck()
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.connAccess.Lock()
|
|
||||||
element := t.connList.PushBack(conn)
|
|
||||||
t.connAddress[M.AddrPortFromNet(conn.LocalAddr())] = M.AddrPortFromNet(conn.RemoteAddr())
|
|
||||||
t.connAccess.Unlock()
|
|
||||||
return &Conn{
|
|
||||||
Conn: conn,
|
|
||||||
closeFunc: common.OnceFunc(func() {
|
|
||||||
t.removeConn(element)
|
|
||||||
}),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) NewConnEx(conn net.Conn) (N.CloseHandlerFunc, error) {
|
|
||||||
err := t.KillerCheck()
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.connAccess.Lock()
|
|
||||||
element := t.connList.PushBack(conn)
|
|
||||||
t.connAddress[M.AddrPortFromNet(conn.LocalAddr())] = M.AddrPortFromNet(conn.RemoteAddr())
|
|
||||||
t.connAccess.Unlock()
|
|
||||||
return N.OnceClose(func(it error) {
|
|
||||||
t.removeConn(element)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) NewPacketConn(conn net.PacketConn) (net.PacketConn, error) {
|
|
||||||
err := t.KillerCheck()
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.packetConnAccess.Lock()
|
|
||||||
element := t.packetConnList.PushBack(conn)
|
|
||||||
t.packetConnAddress[M.AddrPortFromNet(conn.LocalAddr())] = true
|
|
||||||
t.packetConnAccess.Unlock()
|
|
||||||
return &PacketConn{
|
|
||||||
PacketConn: conn,
|
|
||||||
closeFunc: common.OnceFunc(func() {
|
|
||||||
t.removePacketConn(element)
|
|
||||||
}),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) NewPacketConnEx(conn AbstractPacketConn) (N.CloseHandlerFunc, error) {
|
|
||||||
err := t.KillerCheck()
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.packetConnAccess.Lock()
|
|
||||||
element := t.packetConnList.PushBack(conn)
|
|
||||||
t.packetConnAddress[M.AddrPortFromNet(conn.LocalAddr())] = true
|
|
||||||
t.packetConnAccess.Unlock()
|
|
||||||
return N.OnceClose(func(it error) {
|
|
||||||
t.removePacketConn(element)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) CheckConn(source netip.AddrPort, destination netip.AddrPort) bool {
|
|
||||||
t.connAccess.RLock()
|
|
||||||
defer t.connAccess.RUnlock()
|
|
||||||
return t.connAddress[source] == destination
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) CheckPacketConn(source netip.AddrPort) bool {
|
|
||||||
t.packetConnAccess.RLock()
|
|
||||||
defer t.packetConnAccess.RUnlock()
|
|
||||||
return t.packetConnAddress[source]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) AddPendingDestination(destination netip.AddrPort) func() {
|
|
||||||
t.pendingAccess.Lock()
|
|
||||||
defer t.pendingAccess.Unlock()
|
|
||||||
element := t.pendingList.PushBack(destination)
|
|
||||||
return func() {
|
|
||||||
t.pendingAccess.Lock()
|
|
||||||
defer t.pendingAccess.Unlock()
|
|
||||||
t.pendingList.Remove(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) CheckDestination(destination netip.AddrPort) bool {
|
|
||||||
t.pendingAccess.RLock()
|
|
||||||
defer t.pendingAccess.RUnlock()
|
|
||||||
for element := t.pendingList.Front(); element != nil; element = element.Next() {
|
|
||||||
if element.Value == destination {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) KillerCheck() error {
|
|
||||||
if !t.killerEnabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
nowTime := time.Now()
|
|
||||||
if nowTime.Sub(t.killerLastCheck) < 3*time.Second {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
t.killerLastCheck = nowTime
|
|
||||||
if memory.Total() > t.memoryLimit {
|
|
||||||
t.Close()
|
|
||||||
go func() {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
runtimeDebug.FreeOSMemory()
|
|
||||||
}()
|
|
||||||
return E.New("out of memory")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) Count() int {
|
|
||||||
t.connAccess.RLock()
|
|
||||||
defer t.connAccess.RUnlock()
|
|
||||||
t.packetConnAccess.RLock()
|
|
||||||
defer t.packetConnAccess.RUnlock()
|
|
||||||
return t.connList.Len() + t.packetConnList.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) Close() {
|
|
||||||
t.connAccess.Lock()
|
|
||||||
for element := t.connList.Front(); element != nil; element = element.Next() {
|
|
||||||
element.Value.Close()
|
|
||||||
}
|
|
||||||
t.connList.Init()
|
|
||||||
t.connAccess.Unlock()
|
|
||||||
t.packetConnAccess.Lock()
|
|
||||||
for element := t.packetConnList.Front(); element != nil; element = element.Next() {
|
|
||||||
element.Value.Close()
|
|
||||||
}
|
|
||||||
t.packetConnList.Init()
|
|
||||||
t.packetConnAccess.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) removeConn(element *list.Element[net.Conn]) {
|
|
||||||
t.connAccess.Lock()
|
|
||||||
defer t.connAccess.Unlock()
|
|
||||||
delete(t.connAddress, M.AddrPortFromNet(element.Value.LocalAddr()))
|
|
||||||
t.connList.Remove(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DefaultTracker) removePacketConn(element *list.Element[AbstractPacketConn]) {
|
|
||||||
t.packetConnAccess.Lock()
|
|
||||||
defer t.packetConnAccess.Unlock()
|
|
||||||
delete(t.packetConnAddress, M.AddrPortFromNet(element.Value.LocalAddr()))
|
|
||||||
t.packetConnList.Remove(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conn struct {
|
|
||||||
net.Conn
|
|
||||||
closeFunc func()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) Close() error {
|
|
||||||
c.closeFunc()
|
|
||||||
return c.Conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) Upstream() any {
|
|
||||||
return c.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) ReaderReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) WriterReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
type PacketConn struct {
|
|
||||||
net.PacketConn
|
|
||||||
closeFunc func()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PacketConn) Close() error {
|
|
||||||
c.closeFunc()
|
|
||||||
return c.PacketConn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PacketConn) Upstream() any {
|
|
||||||
return c.PacketConn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PacketConn) ReaderReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PacketConn) WriterReplaceable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
35
common/conntrack/killer.go
Normal file
35
common/conntrack/killer.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package conntrack
|
||||||
|
|
||||||
|
import (
|
||||||
|
runtimeDebug "runtime/debug"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/memory"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
KillerEnabled bool
|
||||||
|
MemoryLimit uint64
|
||||||
|
killerLastCheck time.Time
|
||||||
|
)
|
||||||
|
|
||||||
|
func KillerCheck() error {
|
||||||
|
if !KillerEnabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
nowTime := time.Now()
|
||||||
|
if nowTime.Sub(killerLastCheck) < 3*time.Second {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
killerLastCheck = nowTime
|
||||||
|
if memory.Total() > MemoryLimit {
|
||||||
|
Close()
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
runtimeDebug.FreeOSMemory()
|
||||||
|
}()
|
||||||
|
return E.New("out of memory")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
55
common/conntrack/packet_conn.go
Normal file
55
common/conntrack/packet_conn.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package conntrack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PacketConn struct {
|
||||||
|
net.PacketConn
|
||||||
|
element *list.Element[io.Closer]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPacketConn(conn net.PacketConn) (net.PacketConn, error) {
|
||||||
|
connAccess.Lock()
|
||||||
|
element := openConnection.PushBack(conn)
|
||||||
|
connAccess.Unlock()
|
||||||
|
if KillerEnabled {
|
||||||
|
err := KillerCheck()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &PacketConn{
|
||||||
|
PacketConn: conn,
|
||||||
|
element: element,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PacketConn) Close() error {
|
||||||
|
if c.element.Value != nil {
|
||||||
|
connAccess.Lock()
|
||||||
|
if c.element.Value != nil {
|
||||||
|
openConnection.Remove(c.element)
|
||||||
|
c.element.Value = nil
|
||||||
|
}
|
||||||
|
connAccess.Unlock()
|
||||||
|
}
|
||||||
|
return c.PacketConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PacketConn) Upstream() any {
|
||||||
|
return bufio.NewPacketConn(c.PacketConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PacketConn) ReaderReplaceable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PacketConn) WriterReplaceable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
47
common/conntrack/track.go
Normal file
47
common/conntrack/track.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package conntrack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
connAccess sync.RWMutex
|
||||||
|
openConnection list.List[io.Closer]
|
||||||
|
)
|
||||||
|
|
||||||
|
func Count() int {
|
||||||
|
if !Enabled {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return openConnection.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func List() []io.Closer {
|
||||||
|
if !Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
connAccess.RLock()
|
||||||
|
defer connAccess.RUnlock()
|
||||||
|
connList := make([]io.Closer, 0, openConnection.Len())
|
||||||
|
for element := openConnection.Front(); element != nil; element = element.Next() {
|
||||||
|
connList = append(connList, element.Value)
|
||||||
|
}
|
||||||
|
return connList
|
||||||
|
}
|
||||||
|
|
||||||
|
func Close() {
|
||||||
|
if !Enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
connAccess.Lock()
|
||||||
|
defer connAccess.Unlock()
|
||||||
|
for element := openConnection.Front(); element != nil; element = element.Next() {
|
||||||
|
common.Close(element.Value)
|
||||||
|
element.Value = nil
|
||||||
|
}
|
||||||
|
openConnection.Init()
|
||||||
|
}
|
||||||
5
common/conntrack/track_disable.go
Normal file
5
common/conntrack/track_disable.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !with_conntrack
|
||||||
|
|
||||||
|
package conntrack
|
||||||
|
|
||||||
|
const Enabled = false
|
||||||
5
common/conntrack/track_enable.go
Normal file
5
common/conntrack/track_enable.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build with_conntrack
|
||||||
|
|
||||||
|
package conntrack
|
||||||
|
|
||||||
|
const Enabled = true
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package conntrack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: add to N
|
|
||||||
type AbstractPacketConn interface {
|
|
||||||
Close() error
|
|
||||||
LocalAddr() net.Addr
|
|
||||||
SetDeadline(t time.Time) error
|
|
||||||
SetReadDeadline(t time.Time) error
|
|
||||||
SetWriteDeadline(t time.Time) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tracker interface {
|
|
||||||
NewConn(conn net.Conn) (net.Conn, error)
|
|
||||||
NewPacketConn(conn net.PacketConn) (net.PacketConn, error)
|
|
||||||
NewConnEx(conn net.Conn) (N.CloseHandlerFunc, error)
|
|
||||||
NewPacketConnEx(conn AbstractPacketConn) (N.CloseHandlerFunc, error)
|
|
||||||
CheckConn(source netip.AddrPort, destination netip.AddrPort) bool
|
|
||||||
CheckPacketConn(source netip.AddrPort) bool
|
|
||||||
AddPendingDestination(destination netip.AddrPort) func()
|
|
||||||
CheckDestination(destination netip.AddrPort) bool
|
|
||||||
KillerCheck() error
|
|
||||||
Count() int
|
|
||||||
Close()
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DefaultDialer struct {
|
type DefaultDialer struct {
|
||||||
tracker conntrack.Tracker
|
|
||||||
dialer4 tcpDialer
|
dialer4 tcpDialer
|
||||||
dialer6 tcpDialer
|
dialer6 tcpDialer
|
||||||
udpDialer4 net.Dialer
|
udpDialer4 net.Dialer
|
||||||
@@ -47,7 +46,6 @@ type DefaultDialer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) {
|
func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) {
|
||||||
tracker := service.FromContext[conntrack.Tracker](ctx)
|
|
||||||
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
||||||
platformInterface := service.FromContext[platform.Interface](ctx)
|
platformInterface := service.FromContext[platform.Interface](ctx)
|
||||||
|
|
||||||
@@ -199,7 +197,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &DefaultDialer{
|
return &DefaultDialer{
|
||||||
tracker: tracker,
|
|
||||||
dialer4: tcpDialer4,
|
dialer4: tcpDialer4,
|
||||||
dialer6: tcpDialer6,
|
dialer6: tcpDialer6,
|
||||||
udpDialer4: udpDialer4,
|
udpDialer4: udpDialer4,
|
||||||
@@ -222,26 +219,18 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
|
|||||||
return nil, E.New("invalid address")
|
return nil, E.New("invalid address")
|
||||||
}
|
}
|
||||||
if d.networkStrategy == nil {
|
if d.networkStrategy == nil {
|
||||||
if address.IsFqdn() {
|
|
||||||
return nil, E.New("unexpected domain destination")
|
|
||||||
}
|
|
||||||
// Since pending check is only used by ndis, it is not performed for non-windows connections which are only supported on platform clients
|
|
||||||
if d.tracker != nil {
|
|
||||||
done := d.tracker.AddPendingDestination(address.AddrPort())
|
|
||||||
defer done()
|
|
||||||
}
|
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
if !address.IsIPv6() {
|
if !address.IsIPv6() {
|
||||||
return d.trackConn(d.udpDialer4.DialContext(ctx, network, address.String()))
|
return trackConn(d.udpDialer4.DialContext(ctx, network, address.String()))
|
||||||
} else {
|
} else {
|
||||||
return d.trackConn(d.udpDialer6.DialContext(ctx, network, address.String()))
|
return trackConn(d.udpDialer6.DialContext(ctx, network, address.String()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !address.IsIPv6() {
|
if !address.IsIPv6() {
|
||||||
return d.trackConn(DialSlowContext(&d.dialer4, ctx, network, address))
|
return trackConn(DialSlowContext(&d.dialer4, ctx, network, address))
|
||||||
} else {
|
} else {
|
||||||
return d.trackConn(DialSlowContext(&d.dialer6, ctx, network, address))
|
return trackConn(DialSlowContext(&d.dialer6, ctx, network, address))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return d.DialParallelInterface(ctx, network, address, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
return d.DialParallelInterface(ctx, network, address, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
||||||
@@ -293,17 +282,17 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
|
|||||||
if !fastFallback && !isPrimary {
|
if !fastFallback && !isPrimary {
|
||||||
d.networkLastFallback.Store(time.Now())
|
d.networkLastFallback.Store(time.Now())
|
||||||
}
|
}
|
||||||
return d.trackConn(conn, nil)
|
return trackConn(conn, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if d.networkStrategy == nil {
|
if d.networkStrategy == nil {
|
||||||
if destination.IsIPv6() {
|
if destination.IsIPv6() {
|
||||||
return d.trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6))
|
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6))
|
||||||
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
|
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
|
||||||
return d.trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4))
|
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4))
|
||||||
} else {
|
} else {
|
||||||
return d.trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4))
|
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return d.ListenSerialInterfacePacket(ctx, destination, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
return d.ListenSerialInterfacePacket(ctx, destination, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
||||||
@@ -340,23 +329,23 @@ func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destina
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return d.trackPacketConn(packetConn, nil)
|
return trackPacketConn(packetConn, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) {
|
func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) {
|
||||||
return d.udpListener.ListenPacket(context.Background(), network, address)
|
return d.udpListener.ListenPacket(context.Background(), network, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) trackConn(conn net.Conn, err error) (net.Conn, error) {
|
func trackConn(conn net.Conn, err error) (net.Conn, error) {
|
||||||
if d.tracker == nil || err != nil {
|
if !conntrack.Enabled || err != nil {
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
return d.tracker.NewConn(conn)
|
return conntrack.NewConn(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) trackPacketConn(conn net.PacketConn, err error) (net.PacketConn, error) {
|
func trackPacketConn(conn net.PacketConn, err error) (net.PacketConn, error) {
|
||||||
if err != nil {
|
if !conntrack.Enabled || err != nil {
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
return d.tracker.NewPacketConn(conn)
|
return conntrack.NewPacketConn(conn)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ type echConnWrapper struct {
|
|||||||
|
|
||||||
func (c *echConnWrapper) ConnectionState() tls.ConnectionState {
|
func (c *echConnWrapper) ConnectionState() tls.ConnectionState {
|
||||||
state := c.Conn.ConnectionState()
|
state := c.Conn.ConnectionState()
|
||||||
//nolint:staticcheck
|
|
||||||
return tls.ConnectionState{
|
return tls.ConnectionState{
|
||||||
Version: state.Version,
|
Version: state.Version,
|
||||||
HandshakeComplete: state.HandshakeComplete,
|
HandshakeComplete: state.HandshakeComplete,
|
||||||
|
|||||||
@@ -147,9 +147,6 @@ func echKeygen(version uint16, serverName string, conf []myECHKeyConfig, suite [
|
|||||||
pair.rawConf = b
|
pair.rawConf = b
|
||||||
|
|
||||||
secBuf, err := sec.MarshalBinary()
|
secBuf, err := sec.MarshalBinary()
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "serialize ECH private key")
|
|
||||||
}
|
|
||||||
sk := []byte{}
|
sk := []byte{}
|
||||||
sk = be.AppendUint16(sk, uint16(len(secBuf)))
|
sk = be.AppendUint16(sk, uint16(len(secBuf)))
|
||||||
sk = append(sk, secBuf...)
|
sk = append(sk, secBuf...)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func (c *echClientConfig) DialEarly(ctx context.Context, conn net.PacketConn, ad
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper {
|
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper {
|
||||||
return &http3.Transport{
|
return &http3.RoundTripper{
|
||||||
TLSClientConfig: c.config,
|
TLSClientConfig: c.config,
|
||||||
QUICConfig: quicConfig,
|
QUICConfig: quicConfig,
|
||||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||||
|
|||||||
@@ -174,7 +174,6 @@ type realityConnWrapper struct {
|
|||||||
|
|
||||||
func (c *realityConnWrapper) ConnectionState() ConnectionState {
|
func (c *realityConnWrapper) ConnectionState() ConnectionState {
|
||||||
state := c.Conn.ConnectionState()
|
state := c.Conn.ConnectionState()
|
||||||
//nolint:staticcheck
|
|
||||||
return tls.ConnectionState{
|
return tls.ConnectionState{
|
||||||
Version: state.Version,
|
Version: state.Version,
|
||||||
HandshakeComplete: state.HandshakeComplete,
|
HandshakeComplete: state.HandshakeComplete,
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ type utlsConnWrapper struct {
|
|||||||
|
|
||||||
func (c *utlsConnWrapper) ConnectionState() tls.ConnectionState {
|
func (c *utlsConnWrapper) ConnectionState() tls.ConnectionState {
|
||||||
state := c.Conn.ConnectionState()
|
state := c.Conn.ConnectionState()
|
||||||
//nolint:staticcheck
|
|
||||||
return tls.ConnectionState{
|
return tls.ConnectionState{
|
||||||
Version: state.Version,
|
Version: state.Version,
|
||||||
HandshakeComplete: state.HandshakeComplete,
|
HandshakeComplete: state.HandshakeComplete,
|
||||||
|
|||||||
8
constant/cgo_android_fix.go
Normal file
8
constant/cgo_android_fix.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
//go:build android && debug
|
||||||
|
|
||||||
|
package constant
|
||||||
|
|
||||||
|
// TODO: remove after fixed
|
||||||
|
// https://github.com/golang/go/issues/68760
|
||||||
|
|
||||||
|
const FixAndroidStack = true
|
||||||
5
constant/cgo_android_fix_stub.go
Normal file
5
constant/cgo_android_fix_stub.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !(android && debug)
|
||||||
|
|
||||||
|
package constant
|
||||||
|
|
||||||
|
const FixAndroidStack = false
|
||||||
@@ -23,7 +23,6 @@ const (
|
|||||||
TypeVLESS = "vless"
|
TypeVLESS = "vless"
|
||||||
TypeTUIC = "tuic"
|
TypeTUIC = "tuic"
|
||||||
TypeHysteria2 = "hysteria2"
|
TypeHysteria2 = "hysteria2"
|
||||||
TypeNDIS = "ndis"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -81,8 +80,6 @@ func ProxyDisplayName(proxyType string) string {
|
|||||||
return "Selector"
|
return "Selector"
|
||||||
case TypeURLTest:
|
case TypeURLTest:
|
||||||
return "URLTest"
|
return "URLTest"
|
||||||
case TypeNDIS:
|
|
||||||
return "NDIS"
|
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|||||||
5
debug.go
5
debug.go
@@ -3,6 +3,7 @@ package box
|
|||||||
import (
|
import (
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,5 +26,9 @@ func applyDebugOptions(options option.DebugOptions) {
|
|||||||
}
|
}
|
||||||
if options.MemoryLimit != 0 {
|
if options.MemoryLimit != 0 {
|
||||||
debug.SetMemoryLimit(int64(float64(options.MemoryLimit) / 1.5))
|
debug.SetMemoryLimit(int64(float64(options.MemoryLimit) / 1.5))
|
||||||
|
conntrack.MemoryLimit = uint64(options.MemoryLimit)
|
||||||
|
}
|
||||||
|
if options.OOMKiller != nil {
|
||||||
|
conntrack.KillerEnabled = *options.OOMKiller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,26 +2,6 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 1.11.0-beta.20
|
|
||||||
|
|
||||||
* Hysteria2 `ignore_client_bandwidth` behavior update **1**
|
|
||||||
* Fixes and improvements
|
|
||||||
|
|
||||||
**1**:
|
|
||||||
|
|
||||||
When `up_mbps` and `down_mbps` are set, `ignore_client_bandwidth` instead denies clients from using BBR CC.
|
|
||||||
|
|
||||||
See [Hysteria2](/configuration/inbound/hysteria2/#ignore_client_bandwidth).
|
|
||||||
|
|
||||||
#### 1.11.0-beta.17
|
|
||||||
|
|
||||||
* Add port hopping support for Hysteria2 **1**
|
|
||||||
* Fixes and improvements
|
|
||||||
|
|
||||||
**1**:
|
|
||||||
|
|
||||||
See [Hysteria2](/configuration/outbound/hysteria2/).
|
|
||||||
|
|
||||||
#### 1.11.0-beta.14
|
#### 1.11.0-beta.14
|
||||||
|
|
||||||
* Allow adding route (exclude) address sets to routes **1**
|
* Allow adding route (exclude) address sets to routes **1**
|
||||||
@@ -44,6 +24,10 @@ See [route_address_set](/configuration/inbound/tun/#route_address_set) and
|
|||||||
* Add `rule-set merge` command
|
* Add `rule-set merge` command
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
### 1.10.5
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.11.0-beta.3
|
#### 1.11.0-beta.3
|
||||||
|
|
||||||
* Add more masquerade options for hysteria2 **1**
|
* Add more masquerade options for hysteria2 **1**
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ icon: material/alert-decagram
|
|||||||
!!! quote "Changes in sing-box 1.11.0"
|
!!! quote "Changes in sing-box 1.11.0"
|
||||||
|
|
||||||
:material-alert: [masquerade](#masquerade)
|
:material-alert: [masquerade](#masquerade)
|
||||||
:material-alert: [ignore_client_bandwidth](#ignore_client_bandwidth)
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
@@ -76,13 +75,9 @@ Authentication password
|
|||||||
|
|
||||||
#### ignore_client_bandwidth
|
#### ignore_client_bandwidth
|
||||||
|
|
||||||
*When `up_mbps` and `down_mbps` are not set*:
|
Commands the client to use the BBR flow control algorithm instead of Hysteria CC.
|
||||||
|
|
||||||
Commands clients to use the BBR CC instead of Hysteria CC.
|
Conflict with `up_mbps` and `down_mbps`.
|
||||||
|
|
||||||
*When `up_mbps` and `down_mbps` are set*:
|
|
||||||
|
|
||||||
Deny clients to use the BBR CC.
|
|
||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ icon: material/alert-decagram
|
|||||||
!!! quote "sing-box 1.11.0 中的更改"
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
:material-alert: [masquerade](#masquerade)
|
:material-alert: [masquerade](#masquerade)
|
||||||
:material-alert: [ignore_client_bandwidth](#ignore_client_bandwidth)
|
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
@@ -73,13 +72,9 @@ Hysteria 用户
|
|||||||
|
|
||||||
#### ignore_client_bandwidth
|
#### ignore_client_bandwidth
|
||||||
|
|
||||||
*当 `up_mbps` 和 `down_mbps` 未设定时*:
|
|
||||||
|
|
||||||
命令客户端使用 BBR 拥塞控制算法而不是 Hysteria CC。
|
命令客户端使用 BBR 拥塞控制算法而不是 Hysteria CC。
|
||||||
|
|
||||||
*当 `up_mbps` 和 `down_mbps` 已设定时*:
|
与 `up_mbps` 和 `down_mbps` 冲突。
|
||||||
|
|
||||||
禁止客户端使用 BBR 拥塞控制算法。
|
|
||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.11.0"
|
|
||||||
|
|
||||||
:material-plus: [server_ports](#server_ports)
|
|
||||||
:material-plus: [hop_interval](#hop_interval)
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -16,10 +7,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.1",
|
||||||
"server_port": 1080,
|
"server_port": 1080,
|
||||||
"server_ports": [
|
|
||||||
"2080:3000"
|
|
||||||
],
|
|
||||||
"hop_interval": "",
|
|
||||||
"up_mbps": 100,
|
"up_mbps": 100,
|
||||||
"down_mbps": 100,
|
"down_mbps": 100,
|
||||||
"obfs": {
|
"obfs": {
|
||||||
@@ -35,10 +22,6 @@ icon: material/new-box
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note ""
|
|
||||||
|
|
||||||
You can ignore the JSON Array [] tag when the content is only one item
|
|
||||||
|
|
||||||
!!! warning "Difference from official Hysteria2"
|
!!! warning "Difference from official Hysteria2"
|
||||||
|
|
||||||
The official Hysteria2 supports an authentication method called **userpass**,
|
The official Hysteria2 supports an authentication method called **userpass**,
|
||||||
@@ -61,24 +44,6 @@ The server address.
|
|||||||
|
|
||||||
The server port.
|
The server port.
|
||||||
|
|
||||||
Ignored if `server_ports` is set.
|
|
||||||
|
|
||||||
#### server_ports
|
|
||||||
|
|
||||||
!!! question "Since sing-box 1.11.0"
|
|
||||||
|
|
||||||
Server port range list.
|
|
||||||
|
|
||||||
Conflicts with `server_port`.
|
|
||||||
|
|
||||||
#### hop_interval
|
|
||||||
|
|
||||||
!!! question "Since sing-box 1.11.0"
|
|
||||||
|
|
||||||
Port hopping interval.
|
|
||||||
|
|
||||||
`30s` is used by default.
|
|
||||||
|
|
||||||
#### up_mbps, down_mbps
|
#### up_mbps, down_mbps
|
||||||
|
|
||||||
Max bandwidth, in Mbps.
|
Max bandwidth, in Mbps.
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.11.0 中的更改"
|
|
||||||
|
|
||||||
:material-plus: [server_ports](#server_ports)
|
|
||||||
:material-plus: [hop_interval](#hop_interval)
|
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -16,10 +7,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.1",
|
||||||
"server_port": 1080,
|
"server_port": 1080,
|
||||||
"server_ports": [
|
|
||||||
"2080:3000"
|
|
||||||
],
|
|
||||||
"hop_interval": "",
|
|
||||||
"up_mbps": 100,
|
"up_mbps": 100,
|
||||||
"down_mbps": 100,
|
"down_mbps": 100,
|
||||||
"obfs": {
|
"obfs": {
|
||||||
@@ -35,10 +22,6 @@ icon: material/new-box
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note ""
|
|
||||||
|
|
||||||
当内容只有一项时,可以忽略 JSON 数组 [] 标签
|
|
||||||
|
|
||||||
!!! warning "与官方 Hysteria2 的区别"
|
!!! warning "与官方 Hysteria2 的区别"
|
||||||
|
|
||||||
官方程序支持一种名为 **userpass** 的验证方式,
|
官方程序支持一种名为 **userpass** 的验证方式,
|
||||||
@@ -59,24 +42,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
服务器端口。
|
服务器端口。
|
||||||
|
|
||||||
如果设置了 `server_ports`,则忽略此项。
|
|
||||||
|
|
||||||
#### server_ports
|
|
||||||
|
|
||||||
!!! question "自 sing-box 1.11.0 起"
|
|
||||||
|
|
||||||
服务器端口范围列表。
|
|
||||||
|
|
||||||
与 `server_port` 冲突。
|
|
||||||
|
|
||||||
#### hop_interval
|
|
||||||
|
|
||||||
!!! question "自 sing-box 1.11.0 起"
|
|
||||||
|
|
||||||
端口跳跃间隔。
|
|
||||||
|
|
||||||
默认使用 `30s`。
|
|
||||||
|
|
||||||
#### up_mbps, down_mbps
|
#### up_mbps, down_mbps
|
||||||
|
|
||||||
最大带宽。
|
最大带宽。
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
@@ -113,7 +114,7 @@ func (c *CommandClient) Connect() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if sFixAndroidStack {
|
if C.FixAndroidStack {
|
||||||
go func() {
|
go func() {
|
||||||
c.handler.Connected()
|
c.handler.Connected()
|
||||||
c.handler.InitializeClashMode(newIterator(modeList), currentMode)
|
c.handler.InitializeClashMode(newIterator(modeList), currentMode)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
runtimeDebug "runtime/debug"
|
runtimeDebug "runtime/debug"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *CommandClient) CloseConnections() error {
|
func (c *CommandClient) CloseConnections() error {
|
||||||
@@ -17,7 +19,7 @@ func (c *CommandClient) CloseConnections() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) handleCloseConnections(conn net.Conn) error {
|
func (s *CommandServer) handleCloseConnections(conn net.Conn) error {
|
||||||
tracker.Close()
|
conntrack.Close()
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
runtimeDebug.FreeOSMemory()
|
runtimeDebug.FreeOSMemory()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/memory"
|
"github.com/sagernet/sing/common/memory"
|
||||||
@@ -27,7 +28,7 @@ func (s *CommandServer) readStatus() StatusMessage {
|
|||||||
var message StatusMessage
|
var message StatusMessage
|
||||||
message.Memory = int64(memory.Inuse())
|
message.Memory = int64(memory.Inuse())
|
||||||
message.Goroutines = int32(runtime.NumGoroutine())
|
message.Goroutines = int32(runtime.NumGoroutine())
|
||||||
message.ConnectionsOut = int32(tracker.Count())
|
message.ConnectionsOut = int32(conntrack.Count())
|
||||||
|
|
||||||
if s.service != nil {
|
if s.service != nil {
|
||||||
message.TrafficAvailable = true
|
message.TrafficAvailable = true
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ func (s *platformInterfaceStub) Interfaces() ([]adapter.NetworkInterface, error)
|
|||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *platformInterfaceStub) SetUnderlyingNetworks(networks []adapter.NetworkInterface) error {
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
func (s *platformInterfaceStub) UnderNetworkExtension() bool {
|
func (s *platformInterfaceStub) UnderNetworkExtension() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,21 +7,17 @@ import (
|
|||||||
"github.com/sagernet/sing-box/common/conntrack"
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tracker *conntrack.DefaultTracker
|
|
||||||
|
|
||||||
func SetMemoryLimit(enabled bool) {
|
func SetMemoryLimit(enabled bool) {
|
||||||
if tracker != nil {
|
|
||||||
tracker.Close()
|
|
||||||
}
|
|
||||||
const memoryLimit = 45 * 1024 * 1024
|
const memoryLimit = 45 * 1024 * 1024
|
||||||
const memoryLimitGo = memoryLimit / 1.5
|
const memoryLimitGo = memoryLimit / 1.5
|
||||||
if enabled {
|
if enabled {
|
||||||
runtimeDebug.SetGCPercent(10)
|
runtimeDebug.SetGCPercent(10)
|
||||||
runtimeDebug.SetMemoryLimit(memoryLimitGo)
|
runtimeDebug.SetMemoryLimit(memoryLimitGo)
|
||||||
tracker = conntrack.NewDefaultTracker(true, memoryLimit)
|
conntrack.KillerEnabled = true
|
||||||
|
conntrack.MemoryLimit = memoryLimit
|
||||||
} else {
|
} else {
|
||||||
runtimeDebug.SetGCPercent(100)
|
runtimeDebug.SetGCPercent(100)
|
||||||
runtimeDebug.SetMemoryLimit(math.MaxInt64)
|
runtimeDebug.SetMemoryLimit(math.MaxInt64)
|
||||||
tracker = conntrack.NewDefaultTracker(false, 0)
|
conntrack.KillerEnabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
@@ -55,7 +56,7 @@ func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Eleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
|
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
|
||||||
if sFixAndroidStack {
|
if C.FixAndroidStack {
|
||||||
go m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
|
go m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
|
||||||
} else {
|
} else {
|
||||||
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
|
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type PlatformInterface interface {
|
|||||||
StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
||||||
CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
||||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||||
|
SetUnderlyingNetworks(networks RawNetworkIterator) error
|
||||||
UnderNetworkExtension() bool
|
UnderNetworkExtension() bool
|
||||||
IncludeAllNetworks() bool
|
IncludeAllNetworks() bool
|
||||||
ReadWIFIState() *WIFIState
|
ReadWIFIState() *WIFIState
|
||||||
@@ -51,6 +52,8 @@ type NetworkInterface struct {
|
|||||||
Type int32
|
Type int32
|
||||||
DNSServer StringIterator
|
DNSServer StringIterator
|
||||||
Metered bool
|
Metered bool
|
||||||
|
|
||||||
|
RawNetwork RawNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
type WIFIState struct {
|
type WIFIState struct {
|
||||||
@@ -67,6 +70,11 @@ type NetworkInterfaceIterator interface {
|
|||||||
HasNext() bool
|
HasNext() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RawNetworkIterator interface {
|
||||||
|
Next() RawNetwork
|
||||||
|
HasNext() bool
|
||||||
|
}
|
||||||
|
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
Identifier string
|
Identifier string
|
||||||
TypeName string
|
TypeName string
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type Interface interface {
|
|||||||
UpdateRouteOptions(options *tun.Options, platformOptions option.TunPlatformOptions) error
|
UpdateRouteOptions(options *tun.Options, platformOptions option.TunPlatformOptions) error
|
||||||
CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
|
CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
|
||||||
Interfaces() ([]adapter.NetworkInterface, error)
|
Interfaces() ([]adapter.NetworkInterface, error)
|
||||||
|
SetUnderlyingNetworks(networks []adapter.NetworkInterface) error
|
||||||
UnderNetworkExtension() bool
|
UnderNetworkExtension() bool
|
||||||
IncludeAllNetworks() bool
|
IncludeAllNetworks() bool
|
||||||
ClearDNSCache()
|
ClearDNSCache()
|
||||||
|
|||||||
3
experimental/libbox/raw_network_android.go
Normal file
3
experimental/libbox/raw_network_android.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package libbox
|
||||||
|
|
||||||
|
type RawNetwork interface{}
|
||||||
7
experimental/libbox/raw_network_stub.go
Normal file
7
experimental/libbox/raw_network_stub.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build !android
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
type RawNetwork interface {
|
||||||
|
stub()
|
||||||
|
}
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
@@ -61,7 +60,6 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
|||||||
useProcFS: platformInterface.UseProcFS(),
|
useProcFS: platformInterface.UseProcFS(),
|
||||||
}
|
}
|
||||||
service.MustRegister[platform.Interface](ctx, platformWrapper)
|
service.MustRegister[platform.Interface](ctx, platformWrapper)
|
||||||
service.MustRegister[conntrack.Tracker](ctx, tracker)
|
|
||||||
instance, err := box.New(box.Options{
|
instance, err := box.New(box.Options{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Options: options,
|
Options: options,
|
||||||
@@ -83,7 +81,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Start() error {
|
func (s *BoxService) Start() error {
|
||||||
if sFixAndroidStack {
|
if C.FixAndroidStack {
|
||||||
var err error
|
var err error
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
@@ -222,11 +220,18 @@ func (w *platformInterfaceWrapper) Interfaces() ([]adapter.NetworkInterface, err
|
|||||||
DNSServers: iteratorToArray[string](netInterface.DNSServer),
|
DNSServers: iteratorToArray[string](netInterface.DNSServer),
|
||||||
Expensive: netInterface.Metered || isDefault && w.isExpensive,
|
Expensive: netInterface.Metered || isDefault && w.isExpensive,
|
||||||
Constrained: isDefault && w.isConstrained,
|
Constrained: isDefault && w.isConstrained,
|
||||||
|
RawNetwork: netInterface.RawNetwork,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return interfaces, nil
|
return interfaces, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) SetUnderlyingNetworks(networks []adapter.NetworkInterface) error {
|
||||||
|
return w.iif.SetUnderlyingNetworks(newIterator(common.Map(networks, func(it adapter.NetworkInterface) RawNetwork {
|
||||||
|
return it.RawNetwork.(RawNetwork)
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
|
func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
|
||||||
return w.iif.UnderNetworkExtension()
|
return w.iif.UnderNetworkExtension()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,55 +14,43 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sBasePath string
|
sBasePath string
|
||||||
sWorkingPath string
|
sWorkingPath string
|
||||||
sTempPath string
|
sTempPath string
|
||||||
sUserID int
|
sUserID int
|
||||||
sGroupID int
|
sGroupID int
|
||||||
sTVOS bool
|
sTVOS bool
|
||||||
sFixAndroidStack bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
debug.SetPanicOnFault(true)
|
debug.SetPanicOnFault(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetupOptions struct {
|
func Setup(basePath string, workingPath string, tempPath string, isTVOS bool) {
|
||||||
BasePath string
|
sBasePath = basePath
|
||||||
WorkingPath string
|
sWorkingPath = workingPath
|
||||||
TempPath string
|
sTempPath = tempPath
|
||||||
Username string
|
sUserID = os.Getuid()
|
||||||
IsTVOS bool
|
sGroupID = os.Getgid()
|
||||||
FixAndroidStack bool
|
sTVOS = isTVOS
|
||||||
}
|
|
||||||
|
|
||||||
func Setup(options *SetupOptions) error {
|
|
||||||
sBasePath = options.BasePath
|
|
||||||
sWorkingPath = options.WorkingPath
|
|
||||||
sTempPath = options.TempPath
|
|
||||||
if options.Username != "" {
|
|
||||||
sUser, err := user.Lookup(options.Username)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sUserID, _ = strconv.Atoi(sUser.Uid)
|
|
||||||
sGroupID, _ = strconv.Atoi(sUser.Gid)
|
|
||||||
} else {
|
|
||||||
sUserID = os.Getuid()
|
|
||||||
sGroupID = os.Getgid()
|
|
||||||
}
|
|
||||||
sTVOS = options.IsTVOS
|
|
||||||
|
|
||||||
// TODO: remove after fixed
|
|
||||||
// https://github.com/golang/go/issues/68760
|
|
||||||
sFixAndroidStack = options.FixAndroidStack
|
|
||||||
|
|
||||||
os.MkdirAll(sWorkingPath, 0o777)
|
os.MkdirAll(sWorkingPath, 0o777)
|
||||||
os.MkdirAll(sTempPath, 0o777)
|
os.MkdirAll(sTempPath, 0o777)
|
||||||
if options.Username != "" {
|
}
|
||||||
os.Chown(sWorkingPath, sUserID, sGroupID)
|
|
||||||
os.Chown(sTempPath, sUserID, sGroupID)
|
func SetupWithUsername(basePath string, workingPath string, tempPath string, username string) error {
|
||||||
|
sBasePath = basePath
|
||||||
|
sWorkingPath = workingPath
|
||||||
|
sTempPath = tempPath
|
||||||
|
sUser, err := user.Lookup(username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
sUserID, _ = strconv.Atoi(sUser.Uid)
|
||||||
|
sGroupID, _ = strconv.Atoi(sUser.Gid)
|
||||||
|
os.MkdirAll(sWorkingPath, 0o777)
|
||||||
|
os.MkdirAll(sTempPath, 0o777)
|
||||||
|
os.Chown(sWorkingPath, sUserID, sGroupID)
|
||||||
|
os.Chown(sTempPath, sUserID, sGroupID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
go.mod
15
go.mod
@@ -26,29 +26,28 @@ require (
|
|||||||
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
|
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
|
||||||
github.com/sagernet/quic-go v0.48.2-beta.1
|
github.com/sagernet/quic-go v0.48.2-beta.1
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.6.0-beta.9
|
github.com/sagernet/sing v0.6.0-beta.8
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1
|
github.com/sagernet/sing-dns v0.4.0-beta.1
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1
|
github.com/sagernet/sing-mux v0.3.0-alpha.1
|
||||||
github.com/sagernet/sing-quic v0.4.0-beta.3
|
github.com/sagernet/sing-quic v0.4.0-alpha.4
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||||
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2
|
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2
|
||||||
github.com/sagernet/sing-tun v0.6.0-beta.7
|
github.com/sagernet/sing-tun v0.6.0-beta.7
|
||||||
github.com/sagernet/sing-vmess v0.2.0-beta.2
|
github.com/sagernet/sing-vmess v0.2.0-beta.1
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||||
github.com/sagernet/utls v1.6.7
|
github.com/sagernet/utls v1.6.7
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5
|
github.com/sagernet/wireguard-go v0.0.1-beta.5
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/wiresock/ndisapi-go v0.0.0-20241230094942-3299a7566e08
|
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.29.0
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||||
golang.org/x/mod v0.20.0
|
golang.org/x/mod v0.20.0
|
||||||
golang.org/x/net v0.31.0
|
golang.org/x/net v0.31.0
|
||||||
golang.org/x/sys v0.28.0
|
golang.org/x/sys v0.27.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
google.golang.org/grpc v1.63.2
|
google.golang.org/grpc v1.63.2
|
||||||
google.golang.org/protobuf v1.33.0
|
google.golang.org/protobuf v1.33.0
|
||||||
@@ -93,8 +92,8 @@ require (
|
|||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.20.0 // indirect
|
||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
|
|||||||
31
go.sum
31
go.sum
@@ -119,14 +119,14 @@ github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
|
|||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||||
github.com/sagernet/sing v0.6.0-beta.9 h1:P8lKa5hN53fRNAVCIKy5cWd6/kLO5c4slhdsfehSmHs=
|
github.com/sagernet/sing v0.6.0-beta.8 h1:PoxDdN7y8D4oImT3cQ05Sq1ZYnYsJberkUkIEHIGwWE=
|
||||||
github.com/sagernet/sing v0.6.0-beta.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.0-beta.8/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1 h1:W1XkdhigwxDOMgMDVB+9kdomCpb7ExsZfB4acPcTZFY=
|
github.com/sagernet/sing-dns v0.4.0-beta.1 h1:W1XkdhigwxDOMgMDVB+9kdomCpb7ExsZfB4acPcTZFY=
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8=
|
github.com/sagernet/sing-dns v0.4.0-beta.1/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8=
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE=
|
github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE=
|
||||||
github.com/sagernet/sing-quic v0.4.0-beta.3 h1:cOBjlhVdRZmBm6hIw1GleERpnTSFdBB2htgx5kQ5uqg=
|
github.com/sagernet/sing-quic v0.4.0-alpha.4 h1:P9xAx3nIfcqb9M8jfgs0uLm+VxCcaY++FCqaBfHY3dQ=
|
||||||
github.com/sagernet/sing-quic v0.4.0-beta.3/go.mod h1:1UNObFodd8CnS3aCT53x9cigjPSCl3P//8dfBMCwBDM=
|
github.com/sagernet/sing-quic v0.4.0-alpha.4/go.mod h1:h5RkKTmUhudJKzK7c87FPXD5w1bJjVyxMN9+opZcctA=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||||
@@ -135,8 +135,8 @@ github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjS
|
|||||||
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA=
|
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA=
|
||||||
github.com/sagernet/sing-tun v0.6.0-beta.7 h1:FCSX8oGBqb0H57AAvfGeeH/jMGYWCOg6XWkN/oeES+0=
|
github.com/sagernet/sing-tun v0.6.0-beta.7 h1:FCSX8oGBqb0H57AAvfGeeH/jMGYWCOg6XWkN/oeES+0=
|
||||||
github.com/sagernet/sing-tun v0.6.0-beta.7/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
github.com/sagernet/sing-tun v0.6.0-beta.7/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||||
github.com/sagernet/sing-vmess v0.2.0-beta.2 h1:obAkAL35X7ql4RnGzDg4dBYIRpGXRKqcN4LyLZpZGSs=
|
github.com/sagernet/sing-vmess v0.2.0-beta.1 h1:5sXQ23uwNlZuDvygzi0dFtnG0Csm/SNqTjAHXJkpuj4=
|
||||||
github.com/sagernet/sing-vmess v0.2.0-beta.2/go.mod h1:HGhf9XUdeE2iOWrX0hQNFgXPbKyGlzpeYFyX0c/pykk=
|
github.com/sagernet/sing-vmess v0.2.0-beta.1/go.mod h1:fLyE1emIcvQ5DV8reFWnufquZ7MkCSYM5ThodsR9NrQ=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||||
@@ -158,8 +158,6 @@ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gV
|
|||||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/wiresock/ndisapi-go v0.0.0-20241230094942-3299a7566e08 h1:is+7xN6CAKtgxt3mDSl9OQNvjfi6LggugSP07QhDtws=
|
|
||||||
github.com/wiresock/ndisapi-go v0.0.0-20241230094942-3299a7566e08/go.mod h1:lFE7JYt3LC2UYJ31mRDwl/K35pbtxDnkSDlXrYzgyqg=
|
|
||||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||||
@@ -174,8 +172,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
|||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
@@ -184,8 +182,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -193,15 +191,14 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
//go:build windows && with_gvisor
|
|
||||||
|
|
||||||
package include
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
|
||||||
"github.com/sagernet/sing-box/protocol/ndis"
|
|
||||||
)
|
|
||||||
|
|
||||||
func registerNDISInbound(registry *inbound.Registry) {
|
|
||||||
ndis.RegisterInbound(registry)
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
//go:build windows && !with_gvisor
|
|
||||||
|
|
||||||
package include
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
"github.com/sagernet/sing-tun"
|
|
||||||
)
|
|
||||||
|
|
||||||
func registerNDISInbound(registry *inbound.Registry) {
|
|
||||||
inbound.Register[option.NDISInboundOptions](registry, C.TypeNDIS, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NDISInboundOptions) (adapter.Inbound, error) {
|
|
||||||
return nil, tun.ErrGVisorNotIncluded
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
//go:build !windows
|
|
||||||
|
|
||||||
package include
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func registerNDISInbound(registry *inbound.Registry) {
|
|
||||||
inbound.Register[option.NDISInboundOptions](registry, C.TypeNDIS, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NDISInboundOptions) (adapter.Inbound, error) {
|
|
||||||
return nil, E.New("NDIS is only supported in windows")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -51,7 +51,6 @@ func InboundRegistry() *inbound.Registry {
|
|||||||
|
|
||||||
registerQUICInbounds(registry)
|
registerQUICInbounds(registry)
|
||||||
registerStubForRemovedInbounds(registry)
|
registerStubForRemovedInbounds(registry)
|
||||||
registerNDISInbound(registry)
|
|
||||||
|
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type DebugOptions struct {
|
|||||||
PanicOnFault *bool `json:"panic_on_fault,omitempty"`
|
PanicOnFault *bool `json:"panic_on_fault,omitempty"`
|
||||||
TraceBack string `json:"trace_back,omitempty"`
|
TraceBack string `json:"trace_back,omitempty"`
|
||||||
MemoryLimit MemoryBytes `json:"memory_limit,omitempty"`
|
MemoryLimit MemoryBytes `json:"memory_limit,omitempty"`
|
||||||
OOMKiller bool `json:"oom_killer,omitempty"`
|
OOMKiller *bool `json:"oom_killer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MemoryBytes uint64
|
type MemoryBytes uint64
|
||||||
|
|||||||
@@ -111,13 +111,11 @@ type Hysteria2MasqueradeString struct {
|
|||||||
type Hysteria2OutboundOptions struct {
|
type Hysteria2OutboundOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
ServerOptions
|
ServerOptions
|
||||||
ServerPorts badoption.Listable[string] `json:"server_ports,omitempty"`
|
UpMbps int `json:"up_mbps,omitempty"`
|
||||||
HopInterval badoption.Duration `json:"hop_interval,omitempty"`
|
DownMbps int `json:"down_mbps,omitempty"`
|
||||||
UpMbps int `json:"up_mbps,omitempty"`
|
Obfs *Hysteria2Obfs `json:"obfs,omitempty"`
|
||||||
DownMbps int `json:"down_mbps,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Obfs *Hysteria2Obfs `json:"obfs,omitempty"`
|
Network NetworkList `json:"network,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
Network NetworkList `json:"network,omitempty"`
|
|
||||||
OutboundTLSOptionsContainer
|
OutboundTLSOptionsContainer
|
||||||
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package option
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/json/badoption"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NDISInboundOptions struct {
|
|
||||||
Network NetworkList `json:"network,omitempty"`
|
|
||||||
RouteAddress badoption.Listable[netip.Prefix] `json:"route_address,omitempty"`
|
|
||||||
RouteAddressSet badoption.Listable[string] `json:"route_address_set,omitempty"`
|
|
||||||
RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"route_exclude_address,omitempty"`
|
|
||||||
RouteExcludeAddressSet badoption.Listable[string] `json:"route_exclude_address_set,omitempty"`
|
|
||||||
InterfaceName string `json:"interface_name,omitempty"`
|
|
||||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
|
||||||
}
|
|
||||||
@@ -67,7 +67,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||||||
if len(options.Down) > 0 {
|
if len(options.Down) > 0 {
|
||||||
receiveBps, err = humanize.ParseBytes(options.Down)
|
receiveBps, err = humanize.ParseBytes(options.Down)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "invalid down speed format: ", options.Down)
|
return nil, E.New("invalid down speed format: ", options.Down)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps
|
receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/adapter/outbound"
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
@@ -71,8 +70,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
Logger: logger,
|
Logger: logger,
|
||||||
BrutalDebug: options.BrutalDebug,
|
BrutalDebug: options.BrutalDebug,
|
||||||
ServerAddress: options.ServerOptions.Build(),
|
ServerAddress: options.ServerOptions.Build(),
|
||||||
ServerPorts: options.ServerPorts,
|
|
||||||
HopInterval: time.Duration(options.HopInterval),
|
|
||||||
SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps),
|
SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps),
|
||||||
ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps),
|
ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps),
|
||||||
SalamanderPassword: salamanderPassword,
|
SalamanderPassword: salamanderPassword,
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package ndis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/sagernet/gvisor/pkg/buffer"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
|
||||||
|
|
||||||
"github.com/wiresock/ndisapi-go"
|
|
||||||
"github.com/wiresock/ndisapi-go/driver"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ stack.LinkEndpoint = (*ndisEndpoint)(nil)
|
|
||||||
|
|
||||||
type ndisEndpoint struct {
|
|
||||||
filter *driver.QueuedPacketFilter
|
|
||||||
mtu uint32
|
|
||||||
address tcpip.LinkAddress
|
|
||||||
dispatcher stack.NetworkDispatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) MTU() uint32 {
|
|
||||||
return e.mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) SetMTU(mtu uint32) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) MaxHeaderLength() uint16 {
|
|
||||||
return header.EthernetMinimumSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) LinkAddress() tcpip.LinkAddress {
|
|
||||||
return e.address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
|
||||||
e.dispatcher = dispatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) IsAttached() bool {
|
|
||||||
return e.dispatcher != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) Wait() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) ARPHardwareType() header.ARPHardwareType {
|
|
||||||
return header.ARPHardwareEther
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) AddHeader(pkt *stack.PacketBuffer) {
|
|
||||||
eth := header.Ethernet(pkt.LinkHeader().Push(header.EthernetMinimumSize))
|
|
||||||
fields := header.EthernetFields{
|
|
||||||
SrcAddr: pkt.EgressRoute.LocalLinkAddress,
|
|
||||||
DstAddr: pkt.EgressRoute.RemoteLinkAddress,
|
|
||||||
Type: pkt.NetworkProtocolNumber,
|
|
||||||
}
|
|
||||||
eth.Encode(&fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) ParseHeader(pkt *stack.PacketBuffer) bool {
|
|
||||||
_, ok := pkt.LinkHeader().Consume(header.EthernetMinimumSize)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) Close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) SetOnCloseAction(f func()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
var bufferPool = sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return new(ndisapi.IntermediateBuffer)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ndisEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) {
|
|
||||||
for _, packetBuffer := range list.AsSlice() {
|
|
||||||
ndisBuf := bufferPool.Get().(*ndisapi.IntermediateBuffer)
|
|
||||||
viewList, offset := packetBuffer.AsViewList()
|
|
||||||
var view *buffer.View
|
|
||||||
for view = viewList.Front(); view != nil && offset >= view.Size(); view = view.Next() {
|
|
||||||
offset -= view.Size()
|
|
||||||
}
|
|
||||||
index := copy(ndisBuf.Buffer[:], view.AsSlice()[offset:])
|
|
||||||
for view = view.Next(); view != nil; view = view.Next() {
|
|
||||||
index += copy(ndisBuf.Buffer[index:], view.AsSlice())
|
|
||||||
}
|
|
||||||
ndisBuf.Length = uint32(index)
|
|
||||||
err := e.filter.InsertPacketToMstcp(ndisBuf)
|
|
||||||
bufferPool.Put(ndisBuf)
|
|
||||||
if err != nil {
|
|
||||||
return 0, &tcpip.ErrAborted{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list.Len(), nil
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package ndis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
|
||||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
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/x/list"
|
|
||||||
"github.com/sagernet/sing/service"
|
|
||||||
|
|
||||||
"github.com/wiresock/ndisapi-go"
|
|
||||||
"go4.org/netipx"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RegisterInbound(registry *inbound.Registry) {
|
|
||||||
inbound.Register[option.NDISInboundOptions](registry, C.TypeNDIS, NewInbound)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Inbound struct {
|
|
||||||
inbound.Adapter
|
|
||||||
ctx context.Context
|
|
||||||
router adapter.Router
|
|
||||||
logger log.ContextLogger
|
|
||||||
api *ndisapi.NdisApi
|
|
||||||
tracker conntrack.Tracker
|
|
||||||
routeAddress []netip.Prefix
|
|
||||||
routeExcludeAddress []netip.Prefix
|
|
||||||
routeRuleSet []adapter.RuleSet
|
|
||||||
routeRuleSetCallback []*list.Element[adapter.RuleSetUpdateCallback]
|
|
||||||
routeExcludeRuleSet []adapter.RuleSet
|
|
||||||
routeExcludeRuleSetCallback []*list.Element[adapter.RuleSetUpdateCallback]
|
|
||||||
stack *Stack
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NDISInboundOptions) (adapter.Inbound, error) {
|
|
||||||
api, err := ndisapi.NewNdisApi()
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "create NDIS API")
|
|
||||||
}
|
|
||||||
//if !api.IsDriverLoaded() {
|
|
||||||
// return nil, E.New("missing NDIS driver")
|
|
||||||
//}
|
|
||||||
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
|
||||||
trackerOut := service.FromContext[conntrack.Tracker](ctx)
|
|
||||||
var udpTimeout time.Duration
|
|
||||||
if options.UDPTimeout != 0 {
|
|
||||||
udpTimeout = time.Duration(options.UDPTimeout)
|
|
||||||
} else {
|
|
||||||
udpTimeout = C.UDPTimeout
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
routeRuleSet []adapter.RuleSet
|
|
||||||
routeExcludeRuleSet []adapter.RuleSet
|
|
||||||
)
|
|
||||||
for _, routeAddressSet := range options.RouteAddressSet {
|
|
||||||
ruleSet, loaded := router.RuleSet(routeAddressSet)
|
|
||||||
if !loaded {
|
|
||||||
return nil, E.New("parse route_address_set: rule-set not found: ", routeAddressSet)
|
|
||||||
}
|
|
||||||
ruleSet.IncRef()
|
|
||||||
routeRuleSet = append(routeRuleSet, ruleSet)
|
|
||||||
}
|
|
||||||
for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet {
|
|
||||||
ruleSet, loaded := router.RuleSet(routeExcludeAddressSet)
|
|
||||||
if !loaded {
|
|
||||||
return nil, E.New("parse route_exclude_address_set: rule-set not found: ", routeExcludeAddressSet)
|
|
||||||
}
|
|
||||||
ruleSet.IncRef()
|
|
||||||
routeExcludeRuleSet = append(routeExcludeRuleSet, ruleSet)
|
|
||||||
}
|
|
||||||
trackerIn := conntrack.NewDefaultTracker(false, 0)
|
|
||||||
return &Inbound{
|
|
||||||
Adapter: inbound.NewAdapter(C.TypeNDIS, tag),
|
|
||||||
ctx: ctx,
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
api: api,
|
|
||||||
tracker: trackerIn,
|
|
||||||
routeRuleSet: routeRuleSet,
|
|
||||||
routeExcludeRuleSet: routeExcludeRuleSet,
|
|
||||||
stack: &Stack{
|
|
||||||
ctx: ctx,
|
|
||||||
logger: logger,
|
|
||||||
network: networkManager,
|
|
||||||
trackerIn: trackerIn,
|
|
||||||
trackerOut: trackerOut,
|
|
||||||
api: api,
|
|
||||||
udpTimeout: udpTimeout,
|
|
||||||
routeAddress: options.RouteAddress,
|
|
||||||
routeExcludeAddress: options.RouteExcludeAddress,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Inbound) Start(stage adapter.StartStage) error {
|
|
||||||
switch stage {
|
|
||||||
case adapter.StartStateStart:
|
|
||||||
monitor := taskmonitor.New(t.logger, C.StartTimeout)
|
|
||||||
var (
|
|
||||||
routeAddressSet []*netipx.IPSet
|
|
||||||
routeExcludeAddressSet []*netipx.IPSet
|
|
||||||
)
|
|
||||||
for _, routeRuleSet := range t.routeRuleSet {
|
|
||||||
ipSets := routeRuleSet.ExtractIPSet()
|
|
||||||
if len(ipSets) == 0 {
|
|
||||||
t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeRuleSet.Name())
|
|
||||||
}
|
|
||||||
t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
|
||||||
routeRuleSet.DecRef()
|
|
||||||
routeAddressSet = append(routeAddressSet, ipSets...)
|
|
||||||
}
|
|
||||||
for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
|
|
||||||
ipSets := routeExcludeRuleSet.ExtractIPSet()
|
|
||||||
if len(ipSets) == 0 {
|
|
||||||
t.logger.Warn("route_exclude_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name())
|
|
||||||
}
|
|
||||||
t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
|
||||||
routeExcludeRuleSet.DecRef()
|
|
||||||
routeExcludeAddressSet = append(routeExcludeAddressSet, ipSets...)
|
|
||||||
}
|
|
||||||
t.stack.routeAddressSet = routeAddressSet
|
|
||||||
t.stack.routeExcludeAddressSet = routeExcludeAddressSet
|
|
||||||
monitor.Start("starting NDIS stack")
|
|
||||||
t.stack.handler = t
|
|
||||||
err := t.stack.Start()
|
|
||||||
monitor.Finish()
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "starting NDIS stack")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Inbound) Close() error {
|
|
||||||
if t.api != nil {
|
|
||||||
t.stack.Close()
|
|
||||||
t.api.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Inbound) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
|
||||||
return t.router.PreMatch(adapter.InboundContext{
|
|
||||||
Inbound: t.Tag(),
|
|
||||||
InboundType: C.TypeNDIS,
|
|
||||||
Network: network,
|
|
||||||
Source: source,
|
|
||||||
Destination: destination,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
|
||||||
ctx = log.ContextWithNewID(ctx)
|
|
||||||
var metadata adapter.InboundContext
|
|
||||||
metadata.Inbound = t.Tag()
|
|
||||||
metadata.InboundType = C.TypeNDIS
|
|
||||||
metadata.Source = source
|
|
||||||
metadata.Destination = destination
|
|
||||||
t.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
|
|
||||||
t.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
|
||||||
done, err := t.tracker.NewConnEx(conn)
|
|
||||||
if err != nil {
|
|
||||||
t.logger.ErrorContext(ctx, E.Cause(err, "track inbound connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.router.RouteConnectionEx(ctx, conn, metadata, N.AppendClose(onClose, done))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
|
||||||
ctx = log.ContextWithNewID(ctx)
|
|
||||||
var metadata adapter.InboundContext
|
|
||||||
metadata.Inbound = t.Tag()
|
|
||||||
metadata.InboundType = C.TypeNDIS
|
|
||||||
metadata.Source = source
|
|
||||||
metadata.Destination = destination
|
|
||||||
t.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
|
|
||||||
t.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
|
|
||||||
done, err := t.tracker.NewPacketConnEx(conn)
|
|
||||||
if err != nil {
|
|
||||||
t.logger.ErrorContext(ctx, E.Cause(err, "track inbound connection"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.router.RoutePacketConnectionEx(ctx, conn, metadata, N.AppendClose(onClose, done))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) {
|
|
||||||
t.stack.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
|
|
||||||
t.stack.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
|
|
||||||
}
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package ndis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/netip"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/gvisor/pkg/buffer"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/udp"
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
|
||||||
"github.com/sagernet/sing-tun"
|
|
||||||
"github.com/sagernet/sing/common/control"
|
|
||||||
"github.com/sagernet/sing/common/debug"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
"github.com/sagernet/sing/common/logger"
|
|
||||||
|
|
||||||
"github.com/wiresock/ndisapi-go"
|
|
||||||
"github.com/wiresock/ndisapi-go/driver"
|
|
||||||
"go4.org/netipx"
|
|
||||||
"golang.org/x/net/ipv4"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Stack struct {
|
|
||||||
ctx context.Context
|
|
||||||
logger logger.ContextLogger
|
|
||||||
network adapter.NetworkManager
|
|
||||||
trackerIn conntrack.Tracker
|
|
||||||
trackerOut conntrack.Tracker
|
|
||||||
api *ndisapi.NdisApi
|
|
||||||
handler tun.Handler
|
|
||||||
udpTimeout time.Duration
|
|
||||||
filter *driver.QueuedPacketFilter
|
|
||||||
stack *stack.Stack
|
|
||||||
endpoint *ndisEndpoint
|
|
||||||
routeAddress []netip.Prefix
|
|
||||||
routeExcludeAddress []netip.Prefix
|
|
||||||
routeAddressSet []*netipx.IPSet
|
|
||||||
routeExcludeAddressSet []*netipx.IPSet
|
|
||||||
currentInterface *control.Interface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Start() error {
|
|
||||||
err := s.start(s.network.InterfaceMonitor().DefaultInterface())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.network.InterfaceMonitor().RegisterCallback(s.updateDefaultInterface)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) updateDefaultInterface(defaultInterface *control.Interface, flags int) {
|
|
||||||
if s.currentInterface.Equals(*defaultInterface) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := s.start(defaultInterface)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error(E.Cause(err, "reconfigure NDIS at: ", defaultInterface.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) start(defaultInterface *control.Interface) error {
|
|
||||||
_ = s.Close()
|
|
||||||
adapters, err := s.api.GetTcpipBoundAdaptersInfo()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if defaultInterface != nil {
|
|
||||||
for index := 0; index < int(adapters.AdapterCount); index++ {
|
|
||||||
name := s.api.ConvertWindows2000AdapterName(string(adapters.AdapterNameList[index][:]))
|
|
||||||
if name != defaultInterface.Name {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s.filter, err = driver.NewQueuedPacketFilter(s.api, adapters, nil, s.processOut)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
address := tcpip.LinkAddress(adapters.CurrentAddress[index][:])
|
|
||||||
mtu := uint32(adapters.MTU[index])
|
|
||||||
endpoint := &ndisEndpoint{
|
|
||||||
filter: s.filter,
|
|
||||||
mtu: mtu,
|
|
||||||
address: address,
|
|
||||||
}
|
|
||||||
s.stack, err = tun.NewGVisorStack(endpoint)
|
|
||||||
if err != nil {
|
|
||||||
s.filter = nil
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.stack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(s.ctx, s.stack, s.handler).HandlePacket)
|
|
||||||
s.stack.SetTransportProtocolHandler(udp.ProtocolNumber, tun.NewUDPForwarder(s.ctx, s.stack, s.handler, s.udpTimeout).HandlePacket)
|
|
||||||
err = s.filter.StartFilter(index)
|
|
||||||
if err != nil {
|
|
||||||
s.filter = nil
|
|
||||||
s.stack.Close()
|
|
||||||
s.stack = nil
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.endpoint = endpoint
|
|
||||||
s.logger.Info("started at ", defaultInterface.Name)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.currentInterface = defaultInterface
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Close() error {
|
|
||||||
if s.filter != nil {
|
|
||||||
s.filter.StopFilter()
|
|
||||||
s.filter.Close()
|
|
||||||
s.filter = nil
|
|
||||||
}
|
|
||||||
if s.stack != nil {
|
|
||||||
s.stack.Close()
|
|
||||||
for _, endpoint := range s.stack.CleanupEndpoints() {
|
|
||||||
endpoint.Abort()
|
|
||||||
}
|
|
||||||
s.stack = nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) processOut(handle ndisapi.Handle, packet *ndisapi.IntermediateBuffer) ndisapi.FilterAction {
|
|
||||||
if packet.Length < header.EthernetMinimumSize {
|
|
||||||
return ndisapi.FilterActionPass
|
|
||||||
}
|
|
||||||
if s.endpoint.dispatcher == nil || s.filterPacket(packet.Buffer[:packet.Length]) {
|
|
||||||
return ndisapi.FilterActionPass
|
|
||||||
}
|
|
||||||
packetBuffer := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
|
||||||
Payload: buffer.MakeWithData(packet.Buffer[:packet.Length]),
|
|
||||||
})
|
|
||||||
_, ok := packetBuffer.LinkHeader().Consume(header.EthernetMinimumSize)
|
|
||||||
if !ok {
|
|
||||||
packetBuffer.DecRef()
|
|
||||||
return ndisapi.FilterActionPass
|
|
||||||
}
|
|
||||||
ethHdr := header.Ethernet(packetBuffer.LinkHeader().Slice())
|
|
||||||
destinationAddress := ethHdr.DestinationAddress()
|
|
||||||
if destinationAddress == header.EthernetBroadcastAddress {
|
|
||||||
packetBuffer.PktType = tcpip.PacketBroadcast
|
|
||||||
} else if header.IsMulticastEthernetAddress(destinationAddress) {
|
|
||||||
packetBuffer.PktType = tcpip.PacketMulticast
|
|
||||||
} else if destinationAddress == s.endpoint.address {
|
|
||||||
packetBuffer.PktType = tcpip.PacketHost
|
|
||||||
} else {
|
|
||||||
packetBuffer.PktType = tcpip.PacketOtherHost
|
|
||||||
}
|
|
||||||
s.endpoint.dispatcher.DeliverNetworkPacket(ethHdr.Type(), packetBuffer)
|
|
||||||
packetBuffer.DecRef()
|
|
||||||
return ndisapi.FilterActionDrop
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) filterPacket(packet []byte) bool {
|
|
||||||
var ipHdr header.Network
|
|
||||||
switch header.IPVersion(packet[header.EthernetMinimumSize:]) {
|
|
||||||
case ipv4.Version:
|
|
||||||
ipHdr = header.IPv4(packet[header.EthernetMinimumSize:])
|
|
||||||
case ipv6.Version:
|
|
||||||
ipHdr = header.IPv6(packet[header.EthernetMinimumSize:])
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
sourceAddr := tun.AddrFromAddress(ipHdr.SourceAddress())
|
|
||||||
destinationAddr := tun.AddrFromAddress(ipHdr.DestinationAddress())
|
|
||||||
if !destinationAddr.IsGlobalUnicast() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
transportProtocol tcpip.TransportProtocolNumber
|
|
||||||
transportHdr header.Transport
|
|
||||||
)
|
|
||||||
switch ipHdr.TransportProtocol() {
|
|
||||||
case tcp.ProtocolNumber:
|
|
||||||
transportProtocol = header.TCPProtocolNumber
|
|
||||||
transportHdr = header.TCP(ipHdr.Payload())
|
|
||||||
case udp.ProtocolNumber:
|
|
||||||
transportProtocol = header.UDPProtocolNumber
|
|
||||||
transportHdr = header.UDP(ipHdr.Payload())
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
source := netip.AddrPortFrom(sourceAddr, transportHdr.SourcePort())
|
|
||||||
destination := netip.AddrPortFrom(destinationAddr, transportHdr.DestinationPort())
|
|
||||||
if transportProtocol == header.TCPProtocolNumber {
|
|
||||||
if s.trackerIn.CheckConn(source, destination) {
|
|
||||||
if debug.Enabled {
|
|
||||||
s.logger.Trace("fall exists TCP ", source, " ", destination)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if s.trackerIn.CheckPacketConn(source) {
|
|
||||||
if debug.Enabled {
|
|
||||||
s.logger.Trace("fall exists UDP ", source, " ", destination)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s.routeAddress) > 0 {
|
|
||||||
var match bool
|
|
||||||
for _, route := range s.routeAddress {
|
|
||||||
if route.Contains(destinationAddr) {
|
|
||||||
match = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !match {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s.routeAddressSet) > 0 {
|
|
||||||
var match bool
|
|
||||||
for _, ipSet := range s.routeAddressSet {
|
|
||||||
if ipSet.Contains(destinationAddr) {
|
|
||||||
match = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !match {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s.routeExcludeAddress) > 0 {
|
|
||||||
for _, address := range s.routeExcludeAddress {
|
|
||||||
if address.Contains(destinationAddr) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s.routeExcludeAddressSet) > 0 {
|
|
||||||
for _, ipSet := range s.routeAddressSet {
|
|
||||||
if ipSet.Contains(destinationAddr) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if s.trackerOut.CheckDestination(destination) {
|
|
||||||
if debug.Enabled {
|
|
||||||
s.logger.Trace("passing pending ", source, " ", destination)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if transportProtocol == header.TCPProtocolNumber {
|
|
||||||
if s.trackerOut.CheckConn(source, destination) {
|
|
||||||
if debug.Enabled {
|
|
||||||
s.logger.Trace("passing TCP ", source, " ", destination)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if s.trackerOut.CheckPacketConn(source) {
|
|
||||||
if debug.Enabled {
|
|
||||||
s.logger.Trace("passing UDP ", source, " ", destination)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if debug.Enabled {
|
|
||||||
s.logger.Trace("fall ", source, " ", destination)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -306,6 +306,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
|||||||
t.tunOptions.Name = tun.CalculateInterfaceName("")
|
t.tunOptions.Name = tun.CalculateInterfaceName("")
|
||||||
}
|
}
|
||||||
if t.platformInterface == nil || runtime.GOOS != "android" {
|
if t.platformInterface == nil || runtime.GOOS != "android" {
|
||||||
|
t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
|
||||||
for _, routeRuleSet := range t.routeRuleSet {
|
for _, routeRuleSet := range t.routeRuleSet {
|
||||||
ipSets := routeRuleSet.ExtractIPSet()
|
ipSets := routeRuleSet.ExtractIPSet()
|
||||||
if len(ipSets) == 0 {
|
if len(ipSets) == 0 {
|
||||||
@@ -315,10 +316,11 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
|||||||
routeRuleSet.DecRef()
|
routeRuleSet.DecRef()
|
||||||
t.routeAddressSet = append(t.routeAddressSet, ipSets...)
|
t.routeAddressSet = append(t.routeAddressSet, ipSets...)
|
||||||
}
|
}
|
||||||
|
t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
|
||||||
for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
|
for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
|
||||||
ipSets := routeExcludeRuleSet.ExtractIPSet()
|
ipSets := routeExcludeRuleSet.ExtractIPSet()
|
||||||
if len(ipSets) == 0 {
|
if len(ipSets) == 0 {
|
||||||
t.logger.Warn("route_exclude_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name())
|
t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name())
|
||||||
}
|
}
|
||||||
t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||||
routeExcludeRuleSet.DecRef()
|
routeExcludeRuleSet.DecRef()
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ var _ adapter.NetworkManager = (*NetworkManager)(nil)
|
|||||||
|
|
||||||
type NetworkManager struct {
|
type NetworkManager struct {
|
||||||
logger logger.ContextLogger
|
logger logger.ContextLogger
|
||||||
tracker conntrack.Tracker
|
|
||||||
interfaceFinder *control.DefaultInterfaceFinder
|
interfaceFinder *control.DefaultInterfaceFinder
|
||||||
networkInterfaces atomic.TypedValue[[]adapter.NetworkInterface]
|
networkInterfaces atomic.TypedValue[[]adapter.NetworkInterface]
|
||||||
|
|
||||||
@@ -58,7 +57,6 @@ type NetworkManager struct {
|
|||||||
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) {
|
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) {
|
||||||
nm := &NetworkManager{
|
nm := &NetworkManager{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
tracker: service.FromContext[conntrack.Tracker](ctx),
|
|
||||||
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
||||||
autoDetectInterface: routeOptions.AutoDetectInterface,
|
autoDetectInterface: routeOptions.AutoDetectInterface,
|
||||||
defaultOptions: adapter.NetworkOptions{
|
defaultOptions: adapter.NetworkOptions{
|
||||||
@@ -92,6 +90,9 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
|
|||||||
return nil, E.Cause(err, "create network monitor")
|
return nil, E.Cause(err, "create network monitor")
|
||||||
}
|
}
|
||||||
nm.networkMonitor = networkMonitor
|
nm.networkMonitor = networkMonitor
|
||||||
|
networkMonitor.RegisterCallback(func() {
|
||||||
|
_ = nm.interfaceFinder.Update()
|
||||||
|
})
|
||||||
interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(nm.networkMonitor, logger, tun.DefaultInterfaceMonitorOptions{
|
interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(nm.networkMonitor, logger, tun.DefaultInterfaceMonitorOptions{
|
||||||
InterfaceFinder: nm.interfaceFinder,
|
InterfaceFinder: nm.interfaceFinder,
|
||||||
OverrideAndroidVPN: routeOptions.OverrideAndroidVPN,
|
OverrideAndroidVPN: routeOptions.OverrideAndroidVPN,
|
||||||
@@ -239,6 +240,9 @@ func (r *NetworkManager) UpdateInterfaces() error {
|
|||||||
newInterfaces := common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
|
newInterfaces := common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
|
||||||
return it.Flags&net.FlagUp != 0
|
return it.Flags&net.FlagUp != 0
|
||||||
})
|
})
|
||||||
|
for _, networkInterface := range newInterfaces {
|
||||||
|
networkInterface.RawNetwork = nil
|
||||||
|
}
|
||||||
r.networkInterfaces.Store(newInterfaces)
|
r.networkInterfaces.Store(newInterfaces)
|
||||||
if len(newInterfaces) > 0 && !slices.EqualFunc(oldInterfaces, newInterfaces, func(oldInterface adapter.NetworkInterface, newInterface adapter.NetworkInterface) bool {
|
if len(newInterfaces) > 0 && !slices.EqualFunc(oldInterfaces, newInterfaces, func(oldInterface adapter.NetworkInterface, newInterface adapter.NetworkInterface) bool {
|
||||||
return oldInterface.Interface.Index == newInterface.Interface.Index &&
|
return oldInterface.Interface.Index == newInterface.Interface.Index &&
|
||||||
@@ -259,6 +263,15 @@ func (r *NetworkManager) UpdateInterfaces() error {
|
|||||||
}
|
}
|
||||||
return F.ToString(it.Name, " (", strings.Join(options, ", "), ")")
|
return F.ToString(it.Name, " (", strings.Join(options, ", "), ")")
|
||||||
}), ", "))
|
}), ", "))
|
||||||
|
if C.IsAndroid {
|
||||||
|
err = r.platformInterface.SetUnderlyingNetworks(newInterfaces)
|
||||||
|
if err != nil {
|
||||||
|
r.logger.Error("set underlying networks: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, networkInterface := range interfaces {
|
||||||
|
networkInterface.RawNetwork = nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -357,7 +370,7 @@ func (r *NetworkManager) WIFIState() adapter.WIFIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *NetworkManager) ResetNetwork() {
|
func (r *NetworkManager) ResetNetwork() {
|
||||||
r.tracker.Close()
|
conntrack.Close()
|
||||||
|
|
||||||
for _, endpoint := range r.endpoint.Endpoints() {
|
for _, endpoint := range r.endpoint.Endpoints() {
|
||||||
listener, isListener := endpoint.(adapter.InterfaceUpdateListener)
|
listener, isListener := endpoint.(adapter.InterfaceUpdateListener)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-box/common/sniff"
|
"github.com/sagernet/sing-box/common/sniff"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
@@ -71,10 +72,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
injectable.NewConnectionEx(ctx, conn, metadata, onClose)
|
injectable.NewConnectionEx(ctx, conn, metadata, onClose)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := r.connTracker.KillerCheck()
|
conntrack.KillerCheck()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
metadata.Network = N.NetworkTCP
|
metadata.Network = N.NetworkTCP
|
||||||
switch metadata.Destination.Fqdn {
|
switch metadata.Destination.Fqdn {
|
||||||
case mux.Destination.Fqdn:
|
case mux.Destination.Fqdn:
|
||||||
@@ -192,10 +190,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
|
|||||||
injectable.NewPacketConnectionEx(ctx, conn, metadata, onClose)
|
injectable.NewPacketConnectionEx(ctx, conn, metadata, onClose)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := r.connTracker.KillerCheck()
|
conntrack.KillerCheck()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: move to UoT
|
// TODO: move to UoT
|
||||||
metadata.Network = N.NetworkUDP
|
metadata.Network = N.NetworkUDP
|
||||||
@@ -478,7 +473,7 @@ match:
|
|||||||
}
|
}
|
||||||
if !preMatch && inputPacketConn != nil && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() {
|
if !preMatch && inputPacketConn != nil && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() {
|
||||||
var timeout time.Duration
|
var timeout time.Duration
|
||||||
if metadata.InboundType == C.TypeSOCKS || metadata.InboundType == C.TypeMixed {
|
if metadata.InboundType == C.TypeSOCKS {
|
||||||
timeout = C.TCPTimeout
|
timeout = C.TCPTimeout
|
||||||
}
|
}
|
||||||
newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{Timeout: timeout}, inputConn, inputPacketConn)
|
newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{Timeout: timeout}, inputConn, inputPacketConn)
|
||||||
@@ -577,7 +572,7 @@ func (r *Router) actionSniff(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() {
|
if !metadata.Destination.Addr.IsGlobalUnicast() {
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
}
|
}
|
||||||
if len(packetBuffers) > 0 {
|
if len(packetBuffers) > 0 {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/geoip"
|
"github.com/sagernet/sing-box/common/geoip"
|
||||||
"github.com/sagernet/sing-box/common/geosite"
|
"github.com/sagernet/sing-box/common/geosite"
|
||||||
@@ -39,7 +38,6 @@ type Router struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
logger log.ContextLogger
|
logger log.ContextLogger
|
||||||
dnsLogger log.ContextLogger
|
dnsLogger log.ContextLogger
|
||||||
connTracker conntrack.Tracker
|
|
||||||
inbound adapter.InboundManager
|
inbound adapter.InboundManager
|
||||||
outbound adapter.OutboundManager
|
outbound adapter.OutboundManager
|
||||||
connection adapter.ConnectionManager
|
connection adapter.ConnectionManager
|
||||||
@@ -77,7 +75,6 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.Route
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
logger: logFactory.NewLogger("router"),
|
logger: logFactory.NewLogger("router"),
|
||||||
dnsLogger: logFactory.NewLogger("dns"),
|
dnsLogger: logFactory.NewLogger("dns"),
|
||||||
connTracker: service.FromContext[conntrack.Tracker](ctx),
|
|
||||||
inbound: service.FromContext[adapter.InboundManager](ctx),
|
inbound: service.FromContext[adapter.InboundManager](ctx),
|
||||||
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
||||||
connection: service.FromContext[adapter.ConnectionManager](ctx),
|
connection: service.FromContext[adapter.ConnectionManager](ctx),
|
||||||
|
|||||||
16
test/go.mod
16
test/go.mod
@@ -13,9 +13,9 @@ require (
|
|||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/gofrs/uuid/v5 v5.3.0
|
github.com/gofrs/uuid/v5 v5.3.0
|
||||||
github.com/sagernet/quic-go v0.48.2-beta.1
|
github.com/sagernet/quic-go v0.48.2-beta.1
|
||||||
github.com/sagernet/sing v0.6.0-beta.9
|
github.com/sagernet/sing v0.6.0-beta.5
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1
|
github.com/sagernet/sing-dns v0.4.0-beta.1
|
||||||
github.com/sagernet/sing-quic v0.4.0-beta.3
|
github.com/sagernet/sing-quic v0.4.0-alpha.4
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||||
github.com/spyzhov/ajson v0.9.4
|
github.com/spyzhov/ajson v0.9.4
|
||||||
@@ -85,8 +85,8 @@ require (
|
|||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1 // indirect
|
github.com/sagernet/sing-mux v0.3.0-alpha.1 // indirect
|
||||||
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 // indirect
|
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 // indirect
|
||||||
github.com/sagernet/sing-tun v0.6.0-beta.7 // indirect
|
github.com/sagernet/sing-tun v0.6.0-beta.2 // indirect
|
||||||
github.com/sagernet/sing-vmess v0.2.0-beta.2 // indirect
|
github.com/sagernet/sing-vmess v0.2.0-beta.1 // indirect
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||||
github.com/sagernet/utls v1.6.7 // indirect
|
github.com/sagernet/utls v1.6.7 // indirect
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5 // indirect
|
github.com/sagernet/wireguard-go v0.0.1-beta.5 // indirect
|
||||||
@@ -103,12 +103,12 @@ require (
|
|||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
golang.org/x/crypto v0.29.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||||
golang.org/x/mod v0.20.0 // indirect
|
golang.org/x/mod v0.20.0 // indirect
|
||||||
golang.org/x/sync v0.10.0 // indirect
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.27.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.20.0 // indirect
|
||||||
golang.org/x/time v0.7.0 // indirect
|
golang.org/x/time v0.7.0 // indirect
|
||||||
golang.org/x/tools v0.24.0 // indirect
|
golang.org/x/tools v0.24.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
|
|||||||
36
test/go.sum
36
test/go.sum
@@ -146,24 +146,24 @@ github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
|
|||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||||
github.com/sagernet/sing v0.6.0-beta.9 h1:P8lKa5hN53fRNAVCIKy5cWd6/kLO5c4slhdsfehSmHs=
|
github.com/sagernet/sing v0.6.0-beta.5 h1:RD2j8WmJsvAbbBkAlJWaiYmnd+v/JohBiweoew7kMwo=
|
||||||
github.com/sagernet/sing v0.6.0-beta.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.0-beta.5/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1 h1:W1XkdhigwxDOMgMDVB+9kdomCpb7ExsZfB4acPcTZFY=
|
github.com/sagernet/sing-dns v0.4.0-beta.1 h1:W1XkdhigwxDOMgMDVB+9kdomCpb7ExsZfB4acPcTZFY=
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8=
|
github.com/sagernet/sing-dns v0.4.0-beta.1/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8=
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE=
|
github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE=
|
||||||
github.com/sagernet/sing-quic v0.4.0-beta.3 h1:cOBjlhVdRZmBm6hIw1GleERpnTSFdBB2htgx5kQ5uqg=
|
github.com/sagernet/sing-quic v0.4.0-alpha.4 h1:P9xAx3nIfcqb9M8jfgs0uLm+VxCcaY++FCqaBfHY3dQ=
|
||||||
github.com/sagernet/sing-quic v0.4.0-beta.3/go.mod h1:1UNObFodd8CnS3aCT53x9cigjPSCl3P//8dfBMCwBDM=
|
github.com/sagernet/sing-quic v0.4.0-alpha.4/go.mod h1:h5RkKTmUhudJKzK7c87FPXD5w1bJjVyxMN9+opZcctA=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjSsZtRPxiyLV6jyKg0=
|
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjSsZtRPxiyLV6jyKg0=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA=
|
github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA=
|
||||||
github.com/sagernet/sing-tun v0.6.0-beta.7 h1:FCSX8oGBqb0H57AAvfGeeH/jMGYWCOg6XWkN/oeES+0=
|
github.com/sagernet/sing-tun v0.6.0-beta.2 h1:GK7r2jWKm7RhlJGTq4QadgFcebQia1c3BO3OlYMcQJ0=
|
||||||
github.com/sagernet/sing-tun v0.6.0-beta.7/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
github.com/sagernet/sing-tun v0.6.0-beta.2/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||||
github.com/sagernet/sing-vmess v0.2.0-beta.2 h1:obAkAL35X7ql4RnGzDg4dBYIRpGXRKqcN4LyLZpZGSs=
|
github.com/sagernet/sing-vmess v0.2.0-beta.1 h1:5sXQ23uwNlZuDvygzi0dFtnG0Csm/SNqTjAHXJkpuj4=
|
||||||
github.com/sagernet/sing-vmess v0.2.0-beta.2/go.mod h1:HGhf9XUdeE2iOWrX0hQNFgXPbKyGlzpeYFyX0c/pykk=
|
github.com/sagernet/sing-vmess v0.2.0-beta.1/go.mod h1:fLyE1emIcvQ5DV8reFWnufquZ7MkCSYM5ThodsR9NrQ=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||||
@@ -221,8 +221,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
@@ -240,8 +240,8 @@ golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
|||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -252,16 +252,16 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
@@ -3,36 +3,24 @@ package main
|
|||||||
import (
|
import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-quic/hysteria2"
|
"github.com/sagernet/sing-quic/hysteria2"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
F "github.com/sagernet/sing/common/format"
|
|
||||||
"github.com/sagernet/sing/common/json/badoption"
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHysteria2Self(t *testing.T) {
|
func TestHysteria2Self(t *testing.T) {
|
||||||
t.Run("self", func(t *testing.T) {
|
t.Run("self", func(t *testing.T) {
|
||||||
testHysteria2Self(t, "", false)
|
testHysteria2Self(t, "")
|
||||||
})
|
})
|
||||||
t.Run("self-salamander", func(t *testing.T) {
|
t.Run("self-salamander", func(t *testing.T) {
|
||||||
testHysteria2Self(t, "password", false)
|
testHysteria2Self(t, "password")
|
||||||
})
|
|
||||||
t.Run("self-hop", func(t *testing.T) {
|
|
||||||
testHysteria2Self(t, "", true)
|
|
||||||
})
|
|
||||||
t.Run("self-hop-salamander", func(t *testing.T) {
|
|
||||||
testHysteria2Self(t, "password", true)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHysteria2Hop(t *testing.T) {
|
func testHysteria2Self(t *testing.T, salamanderPassword string) {
|
||||||
testHysteria2Self(t, "password", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testHysteria2Self(t *testing.T, salamanderPassword string, portHop bool) {
|
|
||||||
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||||
var obfs *option.Hysteria2Obfs
|
var obfs *option.Hysteria2Obfs
|
||||||
if salamanderPassword != "" {
|
if salamanderPassword != "" {
|
||||||
@@ -41,14 +29,6 @@ func testHysteria2Self(t *testing.T, salamanderPassword string, portHop bool) {
|
|||||||
Password: salamanderPassword,
|
Password: salamanderPassword,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var (
|
|
||||||
serverPorts []string
|
|
||||||
hopInterval time.Duration
|
|
||||||
)
|
|
||||||
if portHop {
|
|
||||||
serverPorts = []string{F.ToString(serverPort, ":", serverPort)}
|
|
||||||
hopInterval = 5 * time.Second
|
|
||||||
}
|
|
||||||
startInstance(t, option.Options{
|
startInstance(t, option.Options{
|
||||||
Inbounds: []option.Inbound{
|
Inbounds: []option.Inbound{
|
||||||
{
|
{
|
||||||
@@ -97,12 +77,10 @@ func testHysteria2Self(t *testing.T, salamanderPassword string, portHop bool) {
|
|||||||
Server: "127.0.0.1",
|
Server: "127.0.0.1",
|
||||||
ServerPort: serverPort,
|
ServerPort: serverPort,
|
||||||
},
|
},
|
||||||
ServerPorts: serverPorts,
|
UpMbps: 100,
|
||||||
HopInterval: badoption.Duration(hopInterval),
|
DownMbps: 100,
|
||||||
UpMbps: 100,
|
Obfs: obfs,
|
||||||
DownMbps: 100,
|
Password: "password",
|
||||||
Obfs: obfs,
|
|
||||||
Password: "password",
|
|
||||||
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
||||||
TLS: &option.OutboundTLSOptions{
|
TLS: &option.OutboundTLSOptions{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -134,10 +112,6 @@ func testHysteria2Self(t *testing.T, salamanderPassword string, portHop bool) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
testSuitLargeUDP(t, clientPort, testPort)
|
testSuitLargeUDP(t, clientPort, testPort)
|
||||||
if portHop {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
testSuitLargeUDP(t, clientPort, testPort)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHysteria2Inbound(t *testing.T) {
|
func TestHysteria2Inbound(t *testing.T) {
|
||||||
|
|||||||
53
test/wireguard_test.go
Normal file
53
test/wireguard_test.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
|
)
|
||||||
|
|
||||||
|
func _TestWireGuard(t *testing.T) {
|
||||||
|
startDockerContainer(t, DockerOptions{
|
||||||
|
Image: ImageBoringTun,
|
||||||
|
Cap: []string{"MKNOD", "NET_ADMIN", "NET_RAW"},
|
||||||
|
Ports: []uint16{serverPort, testPort},
|
||||||
|
Bind: map[string]string{
|
||||||
|
"wireguard.conf": "/etc/wireguard/wg0.conf",
|
||||||
|
},
|
||||||
|
Cmd: []string{"wg0"},
|
||||||
|
})
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
startInstance(t, option.Options{
|
||||||
|
Inbounds: []option.Inbound{
|
||||||
|
{
|
||||||
|
Type: C.TypeMixed,
|
||||||
|
Options: &option.HTTPMixedInboundOptions{
|
||||||
|
ListenOptions: option.ListenOptions{
|
||||||
|
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||||
|
ListenPort: clientPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Outbounds: []option.Outbound{
|
||||||
|
{
|
||||||
|
Type: C.TypeWireGuard,
|
||||||
|
Options: &option.WireGuardEndpointOptions{
|
||||||
|
ServerOptions: option.ServerOptions{
|
||||||
|
Server: "127.0.0.1",
|
||||||
|
ServerPort: serverPort,
|
||||||
|
},
|
||||||
|
Address: []netip.Prefix{netip.MustParsePrefix("10.0.0.2/32")},
|
||||||
|
PrivateKey: "qGnwlkZljMxeECW8fbwAWdvgntnbK7B8UmMFl3zM0mk=",
|
||||||
|
PeerPublicKey: "QsdcBm+oJw2oNv0cIFXLIq1E850lgTBonup4qnKEQBg=",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
testSuitWg(t, clientPort, testPort)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user