mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Compare commits
65 Commits
d7a88a2ae3
...
b1f24b0a32
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b1f24b0a32 | ||
![]() |
c1efd5638c | ||
![]() |
064adf66aa | ||
![]() |
6e77b60b6b | ||
![]() |
4972888354 | ||
![]() |
99ea4c7ea9 | ||
![]() |
492e2826ca | ||
![]() |
b0421bdcfc | ||
![]() |
9e8eff51c0 | ||
![]() |
b57274e1ec | ||
![]() |
627bec7266 | ||
![]() |
31116ef3d2 | ||
![]() |
df5baa733d | ||
![]() |
a64c520de2 | ||
![]() |
74bfea713d | ||
![]() |
63f10d37ff | ||
![]() |
8c231fbc38 | ||
![]() |
1cfbee8293 | ||
![]() |
529d41ed6a | ||
![]() |
8af464eb7e | ||
![]() |
3766bbbf9d | ||
![]() |
0d65af5d0a | ||
![]() |
439f3c05ec | ||
![]() |
e3a1e71e4d | ||
![]() |
83c284749e | ||
![]() |
d95fc51be4 | ||
![]() |
6cccfafc10 | ||
![]() |
650e85e684 | ||
![]() |
edfd6fb29d | ||
![]() |
452ca3f5e6 | ||
![]() |
693da37d62 | ||
![]() |
4f902b8507 | ||
![]() |
de9ceb82bb | ||
![]() |
112508ccbb | ||
![]() |
6fb224dd05 | ||
![]() |
683c5b71ed | ||
![]() |
174b857658 | ||
![]() |
5d63c7a0da | ||
![]() |
09f89b4181 | ||
![]() |
c9522fd6d6 | ||
![]() |
9e9886b140 | ||
![]() |
f5dc2ec1dc | ||
![]() |
e0202da833 | ||
![]() |
db01fe90e4 | ||
![]() |
104ea172c0 | ||
![]() |
341958d7c1 | ||
![]() |
05fea2a199 | ||
![]() |
cc294c4616 | ||
![]() |
b99c6a0025 | ||
![]() |
845138a1d8 | ||
![]() |
0645ebe73f | ||
![]() |
1847cb6dfb | ||
![]() |
1dd716453d | ||
![]() |
456eb3dcdc | ||
![]() |
8f9454ce72 | ||
![]() |
3bae0c96bc | ||
![]() |
0153fc7e08 | ||
![]() |
a52ee299e6 | ||
![]() |
bf0e71f32a | ||
![]() |
b2dcb4dc03 | ||
![]() |
221c003ce0 | ||
![]() |
8b7c8dcdb4 | ||
![]() |
360b25e53c | ||
![]() |
6c9e61a0a0 | ||
![]() |
572ee775b1 |
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@ -30,7 +30,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ^1.24.2
|
go-version: ^1.24.2
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v7
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: --timeout=30m
|
args: --timeout=30m
|
||||||
|
@ -24,7 +24,7 @@ type Router interface {
|
|||||||
RuleSet(tag string) (RuleSet, bool)
|
RuleSet(tag string) (RuleSet, bool)
|
||||||
NeedWIFIState() bool
|
NeedWIFIState() bool
|
||||||
Rules() []Rule
|
Rules() []Rule
|
||||||
AppendTracker(tracker ConnectionTracker)
|
SetTracker(tracker ConnectionTracker)
|
||||||
ResetNetwork()
|
ResetNetwork()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
box.go
4
box.go
@ -314,7 +314,7 @@ func New(options Options) (*Box, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "create clash-server")
|
return nil, E.Cause(err, "create clash-server")
|
||||||
}
|
}
|
||||||
router.AppendTracker(clashServer)
|
router.SetTracker(clashServer)
|
||||||
service.MustRegister[adapter.ClashServer](ctx, clashServer)
|
service.MustRegister[adapter.ClashServer](ctx, clashServer)
|
||||||
services = append(services, clashServer)
|
services = append(services, clashServer)
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ func New(options Options) (*Box, error) {
|
|||||||
return nil, E.Cause(err, "create v2ray-server")
|
return nil, E.Cause(err, "create v2ray-server")
|
||||||
}
|
}
|
||||||
if v2rayServer.StatsService() != nil {
|
if v2rayServer.StatsService() != nil {
|
||||||
router.AppendTracker(v2rayServer.StatsService())
|
router.SetTracker(v2rayServer.StatsService())
|
||||||
services = append(services, v2rayServer)
|
services = append(services, v2rayServer)
|
||||||
service.MustRegister[adapter.V2RayServer](ctx, v2rayServer)
|
service.MustRegister[adapter.V2RayServer](ctx, v2rayServer)
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,7 @@ func UTP(_ context.Context, metadata *adapter.InboundContext, packet []byte) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if extension > 0x04 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
var length byte
|
var length byte
|
||||||
err = binary.Read(reader, binary.BigEndian, &length)
|
err = binary.Read(reader, binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -71,19 +71,3 @@ func TestSniffUDPTracker(t *testing.T) {
|
|||||||
require.Equal(t, C.ProtocolBitTorrent, metadata.Protocol)
|
require.Equal(t, C.ProtocolBitTorrent, metadata.Protocol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSniffNotUTP(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
packets := []string{
|
|
||||||
"0102736470696e674958d580121500000000000079aaed6717a39c27b07c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
}
|
|
||||||
for _, pkt := range packets {
|
|
||||||
pkt, err := hex.DecodeString(pkt)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var metadata adapter.InboundContext
|
|
||||||
err = sniff.UTP(context.TODO(), &metadata, pkt)
|
|
||||||
require.Error(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -123,7 +123,6 @@ func (s *STDECHClientConfig) ClientHandshake(ctx context.Context, conn net.Conn)
|
|||||||
if response.Rcode != mDNS.RcodeSuccess {
|
if response.Rcode != mDNS.RcodeSuccess {
|
||||||
return nil, E.Cause(dns.RcodeError(response.Rcode), "fetch ECH config list")
|
return nil, E.Cause(dns.RcodeError(response.Rcode), "fetch ECH config list")
|
||||||
}
|
}
|
||||||
match:
|
|
||||||
for _, rr := range response.Answer {
|
for _, rr := range response.Answer {
|
||||||
switch resource := rr.(type) {
|
switch resource := rr.(type) {
|
||||||
case *mDNS.HTTPS:
|
case *mDNS.HTTPS:
|
||||||
@ -134,15 +133,12 @@ func (s *STDECHClientConfig) ClientHandshake(ctx context.Context, conn net.Conn)
|
|||||||
return nil, E.Cause(err, "decode ECH config")
|
return nil, E.Cause(err, "decode ECH config")
|
||||||
}
|
}
|
||||||
s.config.EncryptedClientHelloConfigList = echConfigList
|
s.config.EncryptedClientHelloConfigList = echConfigList
|
||||||
break match
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(s.config.EncryptedClientHelloConfigList) == 0 {
|
|
||||||
return nil, E.New("no ECH config found in DNS records")
|
return nil, E.New("no ECH config found in DNS records")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
tlsConn, err := s.Client(conn)
|
tlsConn, err := s.Client(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -11,6 +11,7 @@ const (
|
|||||||
ProtocolSSH = "ssh"
|
ProtocolSSH = "ssh"
|
||||||
ProtocolRDP = "rdp"
|
ProtocolRDP = "rdp"
|
||||||
ProtocolNTP = "ntp"
|
ProtocolNTP = "ntp"
|
||||||
|
ProtocolMTProto = "mtproto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -212,8 +212,8 @@ type dnsConnection struct {
|
|||||||
|
|
||||||
func (c *dnsConnection) Close(err error) {
|
func (c *dnsConnection) Close(err error) {
|
||||||
c.closeOnce.Do(func() {
|
c.closeOnce.Do(func() {
|
||||||
c.err = err
|
|
||||||
close(c.done)
|
close(c.done)
|
||||||
|
c.err = err
|
||||||
})
|
})
|
||||||
c.Conn.Close()
|
c.Conn.Close()
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ If enabled in the inbound, the protocol and domain name (if present) of by the c
|
|||||||
|
|
||||||
| QUIC Client | Type |
|
| QUIC Client | Type |
|
||||||
|:------------------------:|:----------:|
|
|:------------------------:|:----------:|
|
||||||
| Chromium/Cronet | `chromium` |
|
| Chromium/Cronet | `chrimium` |
|
||||||
| Safari/Apple Network API | `safari` |
|
| Safari/Apple Network API | `safari` |
|
||||||
| Firefox / uquic firefox | `firefox` |
|
| Firefox / uquic firefox | `firefox` |
|
||||||
| quic-go / uquic chrome | `quic-go` |
|
| quic-go / uquic chrome | `quic-go` |
|
@ -39,7 +39,7 @@ type BoxService struct {
|
|||||||
clashServer adapter.ClashServer
|
clashServer adapter.ClashServer
|
||||||
pauseManager pause.Manager
|
pauseManager pause.Manager
|
||||||
|
|
||||||
iOSPauseFields
|
servicePauseFields
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
|
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
|
||||||
|
@ -1,33 +1,31 @@
|
|||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type iOSPauseFields struct {
|
type servicePauseFields struct {
|
||||||
endPauseTimer *time.Timer
|
pauseAccess sync.Mutex
|
||||||
|
pauseTimer *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Pause() {
|
func (s *BoxService) Pause() {
|
||||||
s.pauseManager.DevicePause()
|
s.pauseAccess.Lock()
|
||||||
if !C.IsIos {
|
defer s.pauseAccess.Unlock()
|
||||||
s.instance.Router().ResetNetwork()
|
if s.pauseTimer != nil {
|
||||||
} else {
|
s.pauseTimer.Stop()
|
||||||
if s.endPauseTimer == nil {
|
|
||||||
s.endPauseTimer = time.AfterFunc(time.Minute, s.pauseManager.DeviceWake)
|
|
||||||
} else {
|
|
||||||
s.endPauseTimer.Reset(time.Minute)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
s.pauseTimer = time.AfterFunc(3*time.Second, s.ResetNetwork)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Wake() {
|
func (s *BoxService) Wake() {
|
||||||
if !C.IsIos {
|
s.pauseAccess.Lock()
|
||||||
s.pauseManager.DeviceWake()
|
defer s.pauseAccess.Unlock()
|
||||||
s.instance.Router().ResetNetwork()
|
if s.pauseTimer != nil {
|
||||||
|
s.pauseTimer.Stop()
|
||||||
}
|
}
|
||||||
|
s.pauseTimer = time.AfterFunc(3*time.Minute, s.ResetNetwork)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) ResetNetwork() {
|
func (s *BoxService) ResetNetwork() {
|
||||||
|
6
go.mod
6
go.mod
@ -9,7 +9,7 @@ require (
|
|||||||
github.com/cretz/bine v0.2.0
|
github.com/cretz/bine v0.2.0
|
||||||
github.com/go-chi/chi/v5 v5.2.1
|
github.com/go-chi/chi/v5 v5.2.1
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
github.com/gofrs/uuid/v5 v5.3.2
|
github.com/gofrs/uuid/v5 v5.3.1
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
|
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
|
||||||
github.com/libdns/alidns v1.0.3
|
github.com/libdns/alidns v1.0.3
|
||||||
github.com/libdns/cloudflare v0.1.1
|
github.com/libdns/cloudflare v0.1.1
|
||||||
@ -26,9 +26,9 @@ require (
|
|||||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
||||||
github.com/sagernet/quic-go v0.49.0-beta.1
|
github.com/sagernet/quic-go v0.49.0-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.6-0.20250406122223-d47540857e58
|
github.com/sagernet/sing v0.6.6-0.20250403102645-159e489fc399
|
||||||
github.com/sagernet/sing-mux v0.3.1
|
github.com/sagernet/sing-mux v0.3.1
|
||||||
github.com/sagernet/sing-quic v0.4.1
|
github.com/sagernet/sing-quic v0.4.1-beta.1
|
||||||
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.1-0.20250316154757-6f9e732e5056
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056
|
||||||
|
12
go.sum
12
go.sum
@ -66,8 +66,8 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
|||||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg=
|
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg=
|
||||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU=
|
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU=
|
||||||
github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0=
|
github.com/gofrs/uuid/v5 v5.3.1 h1:aPx49MwJbekCzOyhZDjJVb0hx3A0KLjlbLx6p2gY0p0=
|
||||||
github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
github.com/gofrs/uuid/v5 v5.3.1/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
@ -178,12 +178,12 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W
|
|||||||
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.6-0.20250406122223-d47540857e58 h1:hq0W1/K6/UOrv+tCm9YrZ/yDFZJlPVtLmBvayuwUxDM=
|
github.com/sagernet/sing v0.6.6-0.20250403102645-159e489fc399 h1:jQ5sGyxICxdPqoakOEE6TbSTYOf/grmt31e/ad749O4=
|
||||||
github.com/sagernet/sing v0.6.6-0.20250406122223-d47540857e58/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.6-0.20250403102645-159e489fc399/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
||||||
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
||||||
github.com/sagernet/sing-quic v0.4.1 h1:pxlMa4efZu/M07RgGagNNDDyl6ZUwpmNUjRTpgHOWK4=
|
github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s=
|
||||||
github.com/sagernet/sing-quic v0.4.1/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY=
|
github.com/sagernet/sing-quic v0.4.1-beta.1/go.mod h1:c+CytOEyeN20KCTFIP8YQUkNDVFLSzjrEPqP7Hlnxys=
|
||||||
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=
|
||||||
|
@ -19,7 +19,6 @@ import (
|
|||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/x/list"
|
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
"github.com/sagernet/sing/service/pause"
|
"github.com/sagernet/sing/service/pause"
|
||||||
)
|
)
|
||||||
@ -28,7 +27,10 @@ func RegisterURLTest(registry *outbound.Registry) {
|
|||||||
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
|
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ adapter.OutboundGroup = (*URLTest)(nil)
|
var (
|
||||||
|
_ adapter.OutboundGroup = (*URLTest)(nil)
|
||||||
|
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
type URLTest struct {
|
type URLTest struct {
|
||||||
outbound.Adapter
|
outbound.Adapter
|
||||||
@ -170,12 +172,15 @@ func (s *URLTest) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
|||||||
s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose)
|
s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *URLTest) InterfaceUpdated() {
|
||||||
|
go s.group.CheckOutbounds(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type URLTestGroup struct {
|
type URLTestGroup struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
outbound adapter.OutboundManager
|
outboundManager adapter.OutboundManager
|
||||||
pause pause.Manager
|
|
||||||
pauseCallback *list.Element[pause.Callback]
|
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
outbounds []adapter.Outbound
|
outbounds []adapter.Outbound
|
||||||
link string
|
link string
|
||||||
@ -184,10 +189,12 @@ type URLTestGroup struct {
|
|||||||
idleTimeout time.Duration
|
idleTimeout time.Duration
|
||||||
history adapter.URLTestHistoryStorage
|
history adapter.URLTestHistoryStorage
|
||||||
checking atomic.Bool
|
checking atomic.Bool
|
||||||
|
pauseManager pause.Manager
|
||||||
selectedOutboundTCP adapter.Outbound
|
selectedOutboundTCP adapter.Outbound
|
||||||
selectedOutboundUDP adapter.Outbound
|
selectedOutboundUDP adapter.Outbound
|
||||||
interruptGroup *interrupt.Group
|
interruptGroup *interrupt.Group
|
||||||
interruptExternalConnections bool
|
interruptExternalConnections bool
|
||||||
|
|
||||||
access sync.Mutex
|
access sync.Mutex
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
close chan struct{}
|
close chan struct{}
|
||||||
@ -218,7 +225,7 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage
|
|||||||
}
|
}
|
||||||
return &URLTestGroup{
|
return &URLTestGroup{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
outbound: outboundManager,
|
outboundManager: outboundManager,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
outbounds: outbounds,
|
outbounds: outbounds,
|
||||||
link: link,
|
link: link,
|
||||||
@ -227,15 +234,13 @@ func NewURLTestGroup(ctx context.Context, outboundManager adapter.OutboundManage
|
|||||||
idleTimeout: idleTimeout,
|
idleTimeout: idleTimeout,
|
||||||
history: history,
|
history: history,
|
||||||
close: make(chan struct{}),
|
close: make(chan struct{}),
|
||||||
pause: service.FromContext[pause.Manager](ctx),
|
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||||
interruptGroup: interrupt.NewGroup(),
|
interruptGroup: interrupt.NewGroup(),
|
||||||
interruptExternalConnections: interruptExternalConnections,
|
interruptExternalConnections: interruptExternalConnections,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) PostStart() {
|
func (g *URLTestGroup) PostStart() {
|
||||||
g.access.Lock()
|
|
||||||
defer g.access.Unlock()
|
|
||||||
g.started = true
|
g.started = true
|
||||||
g.lastActive.Store(time.Now())
|
g.lastActive.Store(time.Now())
|
||||||
go g.CheckOutbounds(false)
|
go g.CheckOutbounds(false)
|
||||||
@ -245,25 +250,24 @@ func (g *URLTestGroup) Touch() {
|
|||||||
if !g.started {
|
if !g.started {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.access.Lock()
|
|
||||||
defer g.access.Unlock()
|
|
||||||
if g.ticker != nil {
|
if g.ticker != nil {
|
||||||
g.lastActive.Store(time.Now())
|
g.lastActive.Store(time.Now())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
g.access.Lock()
|
||||||
|
defer g.access.Unlock()
|
||||||
|
if g.ticker != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
g.ticker = time.NewTicker(g.interval)
|
g.ticker = time.NewTicker(g.interval)
|
||||||
go g.loopCheck()
|
go g.loopCheck()
|
||||||
g.pauseCallback = pause.RegisterTicker(g.pause, g.ticker, g.interval, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *URLTestGroup) Close() error {
|
func (g *URLTestGroup) Close() error {
|
||||||
g.access.Lock()
|
|
||||||
defer g.access.Unlock()
|
|
||||||
if g.ticker == nil {
|
if g.ticker == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
g.ticker.Stop()
|
g.ticker.Stop()
|
||||||
g.pause.UnregisterCallback(g.pauseCallback)
|
|
||||||
close(g.close)
|
close(g.close)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -327,11 +331,10 @@ func (g *URLTestGroup) loopCheck() {
|
|||||||
g.access.Lock()
|
g.access.Lock()
|
||||||
g.ticker.Stop()
|
g.ticker.Stop()
|
||||||
g.ticker = nil
|
g.ticker = nil
|
||||||
g.pause.UnregisterCallback(g.pauseCallback)
|
|
||||||
g.pauseCallback = nil
|
|
||||||
g.access.Unlock()
|
g.access.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
g.pauseManager.WaitActive()
|
||||||
g.CheckOutbounds(false)
|
g.CheckOutbounds(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,7 +367,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
checked[realTag] = true
|
checked[realTag] = true
|
||||||
p, loaded := g.outbound.Outbound(realTag)
|
p, loaded := g.outboundManager.Outbound(realTag)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ func (w *Endpoint) Close() error {
|
|||||||
|
|
||||||
func (w *Endpoint) InterfaceUpdated() {
|
func (w *Endpoint) InterfaceUpdated() {
|
||||||
w.endpoint.BindUpdate()
|
w.endpoint.BindUpdate()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
||||||
|
@ -133,6 +133,7 @@ func (o *Outbound) Close() error {
|
|||||||
|
|
||||||
func (o *Outbound) InterfaceUpdated() {
|
func (o *Outbound) InterfaceUpdated() {
|
||||||
o.endpoint.BindUpdate()
|
o.endpoint.BindUpdate()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
@ -59,6 +59,10 @@ func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
||||||
|
if r.pauseManager.IsDevicePaused() {
|
||||||
|
return E.New("reject connection to ", metadata.Destination, " while device paused")
|
||||||
|
}
|
||||||
|
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if metadata.InboundDetour != "" {
|
if metadata.InboundDetour != "" {
|
||||||
if metadata.LastInbound == metadata.InboundDetour {
|
if metadata.LastInbound == metadata.InboundDetour {
|
||||||
@ -135,8 +139,8 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
for _, buffer := range buffers {
|
for _, buffer := range buffers {
|
||||||
conn = bufio.NewCachedConn(conn, buffer)
|
conn = bufio.NewCachedConn(conn, buffer)
|
||||||
}
|
}
|
||||||
for _, tracker := range r.trackers {
|
if r.tracker != nil {
|
||||||
conn = tracker.RoutedConnection(ctx, conn, metadata, selectedRule, selectedOutbound)
|
conn = r.tracker.RoutedConnection(ctx, conn, metadata, selectedRule, selectedOutbound)
|
||||||
}
|
}
|
||||||
if outboundHandler, isHandler := selectedOutbound.(adapter.ConnectionHandlerEx); isHandler {
|
if outboundHandler, isHandler := selectedOutbound.(adapter.ConnectionHandlerEx); isHandler {
|
||||||
outboundHandler.NewConnectionEx(ctx, conn, metadata, onClose)
|
outboundHandler.NewConnectionEx(ctx, conn, metadata, onClose)
|
||||||
@ -181,6 +185,9 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
||||||
|
if r.pauseManager.IsDevicePaused() {
|
||||||
|
return E.New("reject packet connection to ", metadata.Destination, " while device paused")
|
||||||
|
}
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if metadata.InboundDetour != "" {
|
if metadata.InboundDetour != "" {
|
||||||
if metadata.LastInbound == metadata.InboundDetour {
|
if metadata.LastInbound == metadata.InboundDetour {
|
||||||
@ -250,8 +257,8 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
|
|||||||
conn = bufio.NewCachedPacketConn(conn, buffer.Buffer, buffer.Destination)
|
conn = bufio.NewCachedPacketConn(conn, buffer.Buffer, buffer.Destination)
|
||||||
N.PutPacketBuffer(buffer)
|
N.PutPacketBuffer(buffer)
|
||||||
}
|
}
|
||||||
for _, tracker := range r.trackers {
|
if r.tracker != nil {
|
||||||
conn = tracker.RoutedPacketConnection(ctx, conn, metadata, selectedRule, selectedOutbound)
|
conn = r.tracker.RoutedPacketConnection(ctx, conn, metadata, selectedRule, selectedOutbound)
|
||||||
}
|
}
|
||||||
if metadata.FakeIP {
|
if metadata.FakeIP {
|
||||||
conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination)
|
conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination)
|
||||||
|
@ -36,7 +36,7 @@ type Router struct {
|
|||||||
ruleSetMap map[string]adapter.RuleSet
|
ruleSetMap map[string]adapter.RuleSet
|
||||||
processSearcher process.Searcher
|
processSearcher process.Searcher
|
||||||
pauseManager pause.Manager
|
pauseManager pause.Manager
|
||||||
trackers []adapter.ConnectionTracker
|
tracker adapter.ConnectionTracker
|
||||||
platformInterface platform.Interface
|
platformInterface platform.Interface
|
||||||
needWIFIState bool
|
needWIFIState bool
|
||||||
started bool
|
started bool
|
||||||
@ -203,8 +203,8 @@ func (r *Router) Rules() []adapter.Rule {
|
|||||||
return r.rules
|
return r.rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) AppendTracker(tracker adapter.ConnectionTracker) {
|
func (r *Router) SetTracker(tracker adapter.ConnectionTracker) {
|
||||||
r.trackers = append(r.trackers, tracker)
|
r.tracker = tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) ResetNetwork() {
|
func (r *Router) ResetNetwork() {
|
||||||
|
@ -305,9 +305,6 @@ func (r *RuleActionReject) Error(ctx context.Context) error {
|
|||||||
default:
|
default:
|
||||||
panic(F.ToString("unknown reject method: ", r.Method))
|
panic(F.ToString("unknown reject method: ", r.Method))
|
||||||
}
|
}
|
||||||
if r.NoDrop {
|
|
||||||
return returnErr
|
|
||||||
}
|
|
||||||
r.dropAccess.Lock()
|
r.dropAccess.Lock()
|
||||||
defer r.dropAccess.Unlock()
|
defer r.dropAccess.Unlock()
|
||||||
timeNow := time.Now()
|
timeNow := time.Now()
|
||||||
|
@ -105,7 +105,7 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.lastUpdated.IsZero() {
|
if s.lastUpdated.IsZero() {
|
||||||
err := s.fetch(ctx, startContext)
|
err := s.fetchOnce(ctx, startContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "initial rule-set: ", s.options.Tag)
|
return E.Cause(err, "initial rule-set: ", s.options.Tag)
|
||||||
}
|
}
|
||||||
@ -200,7 +200,7 @@ func (s *RemoteRuleSet) loadBytes(content []byte) error {
|
|||||||
|
|
||||||
func (s *RemoteRuleSet) loopUpdate() {
|
func (s *RemoteRuleSet) loopUpdate() {
|
||||||
if time.Since(s.lastUpdated) > s.updateInterval {
|
if time.Since(s.lastUpdated) > s.updateInterval {
|
||||||
err := s.fetch(s.ctx, nil)
|
err := s.fetchOnce(s.ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
||||||
} else if s.refs.Load() == 0 {
|
} else if s.refs.Load() == 0 {
|
||||||
@ -213,21 +213,18 @@ func (s *RemoteRuleSet) loopUpdate() {
|
|||||||
case <-s.ctx.Done():
|
case <-s.ctx.Done():
|
||||||
return
|
return
|
||||||
case <-s.updateTicker.C:
|
case <-s.updateTicker.C:
|
||||||
s.updateOnce()
|
s.pauseManager.WaitActive()
|
||||||
}
|
err := s.fetchOnce(s.ctx, nil)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RemoteRuleSet) updateOnce() {
|
|
||||||
err := s.fetch(s.ctx, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
|
||||||
} else if s.refs.Load() == 0 {
|
} else if s.refs.Load() == 0 {
|
||||||
s.rules = nil
|
s.rules = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RemoteRuleSet) fetch(ctx context.Context, startContext *adapter.HTTPStartContext) error {
|
func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext *adapter.HTTPStartContext) error {
|
||||||
s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", s.options.RemoteOptions.URL)
|
s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", s.options.RemoteOptions.URL)
|
||||||
var httpClient *http.Client
|
var httpClient *http.Client
|
||||||
if startContext != nil {
|
if startContext != nil {
|
||||||
|
@ -30,7 +30,7 @@ type Endpoint struct {
|
|||||||
allowedAddress []netip.Prefix
|
allowedAddress []netip.Prefix
|
||||||
tunDevice Device
|
tunDevice Device
|
||||||
device *device.Device
|
device *device.Device
|
||||||
pause pause.Manager
|
pauseManager pause.Manager
|
||||||
pauseCallback *list.Element[pause.Callback]
|
pauseCallback *list.Element[pause.Callback]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +187,9 @@ func (e *Endpoint) Start(resolve bool) error {
|
|||||||
return E.Cause(err, "setup wireguard: \n", ipcConf)
|
return E.Cause(err, "setup wireguard: \n", ipcConf)
|
||||||
}
|
}
|
||||||
e.device = wgDevice
|
e.device = wgDevice
|
||||||
e.pause = service.FromContext[pause.Manager](e.options.Context)
|
e.pauseManager = service.FromContext[pause.Manager](e.options.Context)
|
||||||
if e.pause != nil {
|
if e.pauseManager != nil {
|
||||||
e.pauseCallback = e.pause.RegisterCallback(e.onPauseUpdated)
|
e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -217,16 +217,16 @@ func (e *Endpoint) Close() error {
|
|||||||
e.device.Close()
|
e.device.Close()
|
||||||
}
|
}
|
||||||
if e.pauseCallback != nil {
|
if e.pauseCallback != nil {
|
||||||
e.pause.UnregisterCallback(e.pauseCallback)
|
e.pauseManager.UnregisterCallback(e.pauseCallback)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Endpoint) onPauseUpdated(event int) {
|
func (e *Endpoint) onPauseUpdated(event int) {
|
||||||
switch event {
|
switch event {
|
||||||
case pause.EventDevicePaused, pause.EventNetworkPause:
|
case pause.EventDevicePaused:
|
||||||
e.device.Down()
|
e.device.Down()
|
||||||
case pause.EventDeviceWake, pause.EventNetworkWake:
|
case pause.EventDeviceWake:
|
||||||
e.device.Up()
|
e.device.Up()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user