mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-12 18:17:18 +10:00
Compare commits
7 Commits
v1.7.2
...
v1.7.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e48e5a309f | ||
|
|
8060b30e56 | ||
|
|
d7a3d4e493 | ||
|
|
2e051cb456 | ||
|
|
fcba386b4e | ||
|
|
a7f3aabb72 | ||
|
|
4f46b3f0dc |
@@ -43,7 +43,7 @@ type OutboundGroup interface {
|
||||
|
||||
type URLTestGroup interface {
|
||||
OutboundGroup
|
||||
URLTest(ctx context.Context) (map[string]uint16, error)
|
||||
URLTest(ctx context.Context, url string) (map[string]uint16, error)
|
||||
}
|
||||
|
||||
func OutboundTag(detour Outbound) string {
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
|
||||
type Router interface {
|
||||
Service
|
||||
PostStarter
|
||||
|
||||
Outbounds() []Outbound
|
||||
Outbound(tag string) (Outbound, bool)
|
||||
@@ -42,7 +41,6 @@ type Router interface {
|
||||
NetworkMonitor() tun.NetworkUpdateMonitor
|
||||
InterfaceMonitor() tun.DefaultInterfaceMonitor
|
||||
PackageManager() tun.PackageManager
|
||||
WIFIState() WIFIState
|
||||
Rules() []Rule
|
||||
|
||||
ClashServer() ClashServer
|
||||
@@ -80,8 +78,3 @@ type DNSRule interface {
|
||||
type InterfaceUpdateListener interface {
|
||||
InterfaceUpdated()
|
||||
}
|
||||
|
||||
type WIFIState struct {
|
||||
SSID string
|
||||
BSSID string
|
||||
}
|
||||
|
||||
17
box.go
17
box.go
@@ -56,7 +56,7 @@ func New(options Options) (*Box, error) {
|
||||
applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
|
||||
var needClashAPI bool
|
||||
var needV2RayAPI bool
|
||||
if experimentalOptions.ClashAPI != nil || options.PlatformLogWriter != nil {
|
||||
if experimentalOptions.ClashAPI != nil || options.PlatformInterface != nil {
|
||||
needClashAPI = true
|
||||
}
|
||||
if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" {
|
||||
@@ -258,7 +258,7 @@ func (s *Box) start() error {
|
||||
return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
|
||||
}
|
||||
}
|
||||
return s.postStart()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Box) postStart() error {
|
||||
@@ -269,17 +269,16 @@ func (s *Box) postStart() error {
|
||||
return E.Cause(err, "start ", serviceName)
|
||||
}
|
||||
}
|
||||
for _, outbound := range s.outbounds {
|
||||
if lateOutbound, isLateOutbound := outbound.(adapter.PostStarter); isLateOutbound {
|
||||
s.logger.Trace("post-starting outbound/", outbound.Tag())
|
||||
err := lateOutbound.PostStart()
|
||||
for serviceName, service := range s.outbounds {
|
||||
if lateService, isLateService := service.(adapter.PostStarter); isLateService {
|
||||
s.logger.Trace("post-starting ", service)
|
||||
err := lateService.PostStart()
|
||||
if err != nil {
|
||||
return E.Cause(err, "post-start outbound/", outbound.Tag())
|
||||
return E.Cause(err, "post-start ", serviceName)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.logger.Trace("post-starting router")
|
||||
return s.router.PostStart()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Box) Close() error {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/common/bufio/deadline"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -44,7 +45,14 @@ func (d *DetourDialer) DialContext(ctx context.Context, network string, destinat
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dialer.DialContext(ctx, network, destination)
|
||||
conn, err := dialer.DialContext(ctx, network, destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if deadline.NeedAdditionalReadDeadline(conn) {
|
||||
conn = deadline.NewConn(conn)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (d *DetourDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
|
||||
@@ -182,52 +182,11 @@ func QUICClientHello(ctx context.Context, packet []byte) (*adapter.InboundContex
|
||||
break
|
||||
}
|
||||
switch frameType {
|
||||
case 0x00: // PADDING
|
||||
case 0x0:
|
||||
continue
|
||||
case 0x01: // PING
|
||||
case 0x1:
|
||||
continue
|
||||
case 0x02, 0x03: // ACK
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // Largest Acknowledged
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // ACK Delay
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ackRangeCount, err := qtls.ReadUvarint(decryptedReader) // ACK Range Count
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // First ACK Range
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < int(ackRangeCount); i++ {
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // Gap
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // ACK Range Length
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if frameType == 0x03 {
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // ECT0 Count
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // ECT1 Count
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // ECN-CE Count
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case 0x06: // CRYPTO
|
||||
case 0x6:
|
||||
var offset uint64
|
||||
offset, err = qtls.ReadUvarint(decryptedReader)
|
||||
if err != nil {
|
||||
@@ -249,26 +208,8 @@ func QUICClientHello(ctx context.Context, packet []byte) (*adapter.InboundContex
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 0x1c: // CONNECTION_CLOSE
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // Error Code
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = qtls.ReadUvarint(decryptedReader) // Frame Type
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var length uint64
|
||||
length, err = qtls.ReadUvarint(decryptedReader) // Reason Phrase Length
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = decryptedReader.Seek(int64(length), io.SeekCurrent) // Reason Phrase
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, os.ErrInvalid
|
||||
// ignore unknown frame type
|
||||
}
|
||||
}
|
||||
tlsHdr := make([]byte, 5)
|
||||
|
||||
@@ -1,94 +1,4 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
# ChangeLog
|
||||
|
||||
#### 1.7.2
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.7.1
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.7.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
Important changes since 1.6:
|
||||
|
||||
* Add [exclude route support](/configuration/inbound/tun) for TUN inbound
|
||||
* Add `udp_disable_domain_unmapping` [inbound listen option](/configuration/shared/listen) **1**
|
||||
* Add [HTTPUpgrade V2Ray transport](/configuration/shared/v2ray-transport#HTTPUpgrade) support **2**
|
||||
* Migrate multiplex and UoT server to inbound **3**
|
||||
* Add TCP Brutal support for multiplex **4**
|
||||
* Add `wifi_ssid` and `wifi_bssid` route and DNS rules **5**
|
||||
* Update quic-go to v0.40.0
|
||||
* Update gVisor to 20231113.0
|
||||
|
||||
**1**:
|
||||
|
||||
If enabled, for UDP proxy requests addressed to a domain,
|
||||
the original packet address will be sent in the response instead of the mapped domain.
|
||||
|
||||
This option is used for compatibility with clients that
|
||||
do not support receiving UDP packets with domain addresses, such as Surge.
|
||||
|
||||
**2**:
|
||||
|
||||
Introduced in V2Ray 5.10.0.
|
||||
|
||||
The new HTTPUpgrade transport has better performance than WebSocket and is better suited for CDN abuse.
|
||||
|
||||
**3**:
|
||||
|
||||
Starting in 1.7.0, multiplexing support is no longer enabled by default and needs to be turned on explicitly in inbound options.
|
||||
|
||||
**4**
|
||||
|
||||
Hysteria Brutal Congestion Control Algorithm in TCP. A kernel module needs to be installed on the Linux server, see [TCP Brutal](/configuration/shared/tcp-brutal) for details.
|
||||
|
||||
**5**:
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
|
||||
#### 1.7.0-rc.3
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.6.7
|
||||
|
||||
* macOS: Add button for uninstall SystemExtension in the standalone graphical client
|
||||
* Fix missing UDP user context on TUIC/Hysteria2 inbounds
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.7.0-rc.2
|
||||
|
||||
* Fix missing UDP user context on TUIC/Hysteria2 inbounds
|
||||
* macOS: Add button for uninstall SystemExtension in the standalone graphical client
|
||||
|
||||
#### 1.6.6
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.7.0-rc.1
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.7.0-beta.5
|
||||
|
||||
* Update gVisor to 20231113.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.7.0-beta.4
|
||||
|
||||
* Add `wifi_ssid` and `wifi_bssid` route and DNS rules **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
# :material-alert-decagram: ChangeLog
|
||||
|
||||
#### 1.7.0-beta.3
|
||||
|
||||
|
||||
@@ -12,38 +12,28 @@ SFA allows you to run sing-box through ForegroundService or VpnService (when TUN
|
||||
|
||||
SFA provides an unprivileged TUN implementation through Android VpnService.
|
||||
|
||||
| TUN inbound option | Available | Note |
|
||||
|-------------------------------|------------------|--------------------|
|
||||
| `interface_name` | :material-close: | Managed by Android |
|
||||
| `inet4_address` | :material-check: | / |
|
||||
| `inet6_address` | :material-check: | / |
|
||||
| `mtu` | :material-check: | / |
|
||||
| `auto_route` | :material-check: | / |
|
||||
| `strict_route` | :material-close: | Not implemented |
|
||||
| `inet4_route_address` | :material-check: | / |
|
||||
| `inet6_route_address` | :material-check: | / |
|
||||
| `inet4_route_exclude_address` | :material-check: | / |
|
||||
| `inet6_route_exclude_address` | :material-check: | / |
|
||||
| `endpoint_independent_nat` | :material-check: | / |
|
||||
| `stack` | :material-check: | / |
|
||||
| `include_interface` | :material-close: | No permission |
|
||||
| `exclude_interface` | :material-close: | No permission |
|
||||
| `include_uid` | :material-close: | No permission |
|
||||
| `exclude_uid` | :material-close: | No permission |
|
||||
| `include_android_user` | :material-close: | No permission |
|
||||
| `include_package` | :material-check: | / |
|
||||
| `exclude_package` | :material-check: | / |
|
||||
| `platform` | :material-check: | / |
|
||||
|
||||
| Route/DNS rule option | Available | Note |
|
||||
|-----------------------|------------------|-----------------------------------|
|
||||
| `process_name` | :material-close: | No permission |
|
||||
| `process_path` | :material-close: | No permission |
|
||||
| `package_name` | :material-check: | / |
|
||||
| `user` | :material-close: | Use `package_name` instead |
|
||||
| `user_id` | :material-close: | Use `package_name` instead |
|
||||
| `wifi_ssid` | :material-check: | Fine location permission required |
|
||||
| `wifi_bssid` | :material-check: | Fine location permission required |
|
||||
| TUN inbound option | Available | Note |
|
||||
|-------------------------------|-----------|--------------------|
|
||||
| `interface_name` | ✖️ | Managed by Android |
|
||||
| `inet4_address` | ✔️ | / |
|
||||
| `inet6_address` | ✔️ | / |
|
||||
| `mtu` | ✔️ | / |
|
||||
| `auto_route` | ✔️ | / |
|
||||
| `strict_route` | ✖️ | Not implemented |
|
||||
| `inet4_route_address` | ✔️ | / |
|
||||
| `inet6_route_address` | ✔️ | / |
|
||||
| `inet4_route_exclude_address` | ✔️ | / |
|
||||
| `inet6_route_exclude_address` | ✔️ | / |
|
||||
| `endpoint_independent_nat` | ✔️ | / |
|
||||
| `stack` | ✔️ | / |
|
||||
| `include_interface` | ✖️ | No permission |
|
||||
| `exclude_interface` | ✖️ | No permission |
|
||||
| `include_uid` | ✖️ | No permission |
|
||||
| `exclude_uid` | ✖️ | No permission |
|
||||
| `include_android_user` | ✖️ | No permission |
|
||||
| `include_package` | ✔️ | / |
|
||||
| `exclude_package` | ✔️ | / |
|
||||
| `platform` | ✔️ | / |
|
||||
|
||||
### Override
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/android
|
||||
---
|
||||
|
||||
# sing-box for Android
|
||||
# :material-android: sing-box for Android
|
||||
|
||||
SFA allows users to manage and run local or remote sing-box configuration files, and provides
|
||||
platform-specific function implementation, such as TUN transparent proxy implementation.
|
||||
@@ -15,8 +11,8 @@ platform-specific function implementation, such as TUN transparent proxy impleme
|
||||
|
||||
* [Play Store](https://play.google.com/store/apps/details?id=io.nekohasekai.sfa)
|
||||
* [Play Store (Beta)](https://play.google.com/apps/testing/io.nekohasekai.sfa)
|
||||
* [GitHub Releases](https://github.com/SagerNet/sing-box/releases)
|
||||
* [Github Releases](https://github.com/SagerNet/sing-box/releases)
|
||||
|
||||
## :material-source-repository: Source code
|
||||
|
||||
* [GitHub](https://github.com/SagerNet/sing-box-for-android)
|
||||
* [Github](https://github.com/SagerNet/sing-box-for-android)
|
||||
|
||||
@@ -37,16 +37,6 @@ SFI/SFM/SFT provides an unprivileged TUN implementation through NetworkExtension
|
||||
| `exclude_package` | ✖️ | Not implemented |
|
||||
| `platform` | ✔️ | / |
|
||||
|
||||
| Route/DNS rule option | Available | Note |
|
||||
|-----------------------|------------------|-----------------------|
|
||||
| `process_name` | :material-close: | No permission |
|
||||
| `process_path` | :material-close: | No permission |
|
||||
| `package_name` | :material-close: | / |
|
||||
| `user` | :material-close: | No permission |
|
||||
| `user_id` | :material-close: | No permission |
|
||||
| `wifi_ssid` | :material-alert: | Only supported on iOS |
|
||||
| `wifi_bssid` | :material-alert: | Only supported on iOS |
|
||||
|
||||
### Chore
|
||||
|
||||
* Crash logs is located in `Settings` -> `View Service Log`
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/apple
|
||||
---
|
||||
|
||||
# sing-box for Apple platforms
|
||||
# :material-apple: sing-box for Apple platforms
|
||||
|
||||
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
|
||||
platform-specific function implementation, such as TUN transparent proxy implementation.
|
||||
@@ -14,19 +10,9 @@ platform-specific function implementation, such as TUN transparent proxy impleme
|
||||
|
||||
## :material-download: Download
|
||||
|
||||
* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673)
|
||||
* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673)
|
||||
* [TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH)
|
||||
|
||||
## :material-file-download: Download (macOS standalone version)
|
||||
|
||||
* [Homebrew Cask](https://formulae.brew.sh/cask/sfm)
|
||||
|
||||
```bash
|
||||
brew install sfm
|
||||
```
|
||||
|
||||
* [GitHub Releases](https://github.com/SagerNet/sing-box/releases)
|
||||
|
||||
## :material-source-repository: Source code
|
||||
|
||||
* [GitHub](https://github.com/SagerNet/sing-box-for-apple)
|
||||
* [Github](https://github.com/SagerNet/sing-box-for-apple)
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/pencil-ruler
|
||||
---
|
||||
|
||||
# General
|
||||
# :material-pencil-ruler: General
|
||||
|
||||
Describes and explains the functions implemented uniformly by sing-box graphical clients.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Maintained by Project S to provide a unified experience and platform-specific fu
|
||||
|---------------------------------------|-----------------------------------------|
|
||||
| :material-android: Android | [sing-box for Android](./android) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple) |
|
||||
| :material-laptop: Desktop | Working in progress |
|
||||
| TODO | / |
|
||||
|
||||
Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core
|
||||
motivation of the maintainers of such projects is to acquire more users, and even though they provide friendly VPN
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|---------------------------------------|-----------------------------------------|
|
||||
| :material-android: Android | [sing-box for Android](./android) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple) |
|
||||
| :material-laptop: Desktop | 施工中 |
|
||||
| TODO | / |
|
||||
|
||||
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
||||
VPN 客户端功能, 但代码质量很差且包含广告。
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/security
|
||||
---
|
||||
|
||||
# Privacy policy
|
||||
# :material-security: Privacy policy
|
||||
|
||||
sing-box and official graphics clients do not collect or share personal data,
|
||||
and the data generated by the software is always on your device.
|
||||
|
||||
@@ -79,12 +79,6 @@
|
||||
1000
|
||||
],
|
||||
"clash_mode": "direct",
|
||||
"wifi_ssid": [
|
||||
"My WIFI"
|
||||
],
|
||||
"wifi_bssid": [
|
||||
"00:00:00:00:00:00"
|
||||
],
|
||||
"invert": false,
|
||||
"outbound": [
|
||||
"direct"
|
||||
@@ -194,7 +188,7 @@ Match port range.
|
||||
|
||||
#### process_name
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
@@ -202,7 +196,7 @@ Match process name.
|
||||
|
||||
#### process_path
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
@@ -214,7 +208,7 @@ Match android package name.
|
||||
|
||||
#### user
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
@@ -222,7 +216,7 @@ Match user name.
|
||||
|
||||
#### user_id
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
@@ -232,24 +226,6 @@ Match user id.
|
||||
|
||||
Match Clash mode.
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
<!-- md:version 1.7.0-beta.4 -->
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
|
||||
Match WiFi SSID.
|
||||
|
||||
#### wifi_bssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
|
||||
Match WiFi BSSID.
|
||||
|
||||
#### invert
|
||||
|
||||
Invert match result.
|
||||
|
||||
@@ -78,12 +78,6 @@
|
||||
1000
|
||||
],
|
||||
"clash_mode": "direct",
|
||||
"wifi_ssid": [
|
||||
"My WIFI"
|
||||
],
|
||||
"wifi_bssid": [
|
||||
"00:00:00:00:00:00"
|
||||
],
|
||||
"invert": false,
|
||||
"outbound": [
|
||||
"direct"
|
||||
@@ -191,7 +185,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
#### process_name
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
@@ -199,7 +193,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
#### process_path
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
@@ -211,7 +205,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
#### user
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux。
|
||||
|
||||
@@ -219,7 +213,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
#### user_id
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux。
|
||||
|
||||
@@ -229,22 +223,6 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
匹配 Clash 模式。
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
|
||||
匹配 WiFi SSID。
|
||||
|
||||
#### wifi_bssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
|
||||
匹配 WiFi BSSID。
|
||||
|
||||
#### invert
|
||||
|
||||
反选匹配结果。
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
### Clash API Fields
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Clash API is not included by default, see [Installation](./#installation).
|
||||
|
||||
@@ -110,7 +110,7 @@ If not empty, `store_selected` will use a separate store keyed by it.
|
||||
|
||||
### V2Ray API Fields
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
V2Ray API is not included by default, see [Installation](./#installation).
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
### Clash API 字段
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
默认安装不包含 Clash API,参阅 [安装](/zh/#_2)。
|
||||
|
||||
@@ -108,7 +108,7 @@ Clash 中的默认模式,默认使用 `Rule`。
|
||||
|
||||
### V2Ray API 字段
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
默认安装不包含 V2Ray API,参阅 [安装](/zh/#_2)。
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ No authentication required if empty.
|
||||
|
||||
#### set_system_proxy
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Android, Windows, and macOS.
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ HTTP 用户
|
||||
|
||||
#### set_system_proxy
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Android、Windows 和 macOS。
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ No authentication required if empty.
|
||||
|
||||
#### set_system_proxy
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Android, Windows, and macOS.
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ SOCKS 和 HTTP 用户
|
||||
|
||||
#### set_system_proxy
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Android、Windows 和 macOS。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux and macOS.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux 和 macOS。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux。
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
||||
|
||||
#### fallback
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
There is no evidence that GFW detects and blocks Trojan servers based on HTTP responses, and opening the standard http/s port on the server is a much bigger signature.
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
||||
|
||||
#### fallback
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
没有证据表明 GFW 基于 HTTP 响应检测并阻止 Trojan 服务器,并且在服务器上打开标准 http/s 端口是一个更大的特征。
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows and macOS.
|
||||
|
||||
@@ -102,7 +102,7 @@ The maximum transmission unit.
|
||||
|
||||
Set the default route to the Tun.
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
To avoid traffic loopback, set `route.auto_detect_interface` or `route.default_interface` or `outbound.bind_interface`
|
||||
|
||||
@@ -175,7 +175,7 @@ TCP/IP stack.
|
||||
|
||||
#### include_interface
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Interface rules are only supported on Linux and require auto_route.
|
||||
|
||||
@@ -191,7 +191,7 @@ Conflict with `include_interface`.
|
||||
|
||||
#### include_uid
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
UID rules are only supported on Linux and require auto_route.
|
||||
|
||||
@@ -211,7 +211,7 @@ Exclude users in route, but in range.
|
||||
|
||||
#### include_android_user
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Android user and package rules are only supported on Android and require auto_route.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS。
|
||||
|
||||
@@ -102,7 +102,7 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
设置到 Tun 的默认路由。
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
为避免流量环回,请设置 `route.auto_detect_interface` 或 `route.default_interface` 或 `outbound.bind_interface`。
|
||||
|
||||
@@ -171,7 +171,7 @@ TCP/IP 栈。
|
||||
|
||||
#### include_interface
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
接口规则仅在 Linux 下被支持,并且需要 `auto_route`。
|
||||
|
||||
@@ -187,7 +187,7 @@ TCP/IP 栈。
|
||||
|
||||
#### include_uid
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
UID 规则仅在 Linux 下被支持,并且需要 `auto_route`。
|
||||
|
||||
@@ -207,7 +207,7 @@ TCP/IP 栈。
|
||||
|
||||
#### include_android_user
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Android 用户和应用规则仅在 Android 下被支持,并且需要 `auto_route`。
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
The selector can only be controlled through the [Clash API](/configuration/experimental#clash-api-fields) currently.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
选择器目前只能通过 [Clash API](/zh/configuration/experimental#clash-api) 来控制。
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Default outbound tag. the first outbound will be used if empty.
|
||||
|
||||
#### auto_detect_interface
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows and macOS.
|
||||
|
||||
@@ -41,7 +41,7 @@ Takes no effect if `outbound.bind_interface` is set.
|
||||
|
||||
#### override_android_vpn
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Android.
|
||||
|
||||
@@ -49,7 +49,7 @@ Accept Android VPN as upstream NIC when `auto_detect_interface` enabled.
|
||||
|
||||
#### default_interface
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows and macOS.
|
||||
|
||||
@@ -59,7 +59,7 @@ Takes no effect if `auto_detect_interface` is set.
|
||||
|
||||
#### default_mark
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#### auto_detect_interface
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS。
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
#### override_android_vpn
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Android。
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
#### default_interface
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS。
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
#### default_mark
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux。
|
||||
|
||||
|
||||
@@ -83,12 +83,6 @@
|
||||
1000
|
||||
],
|
||||
"clash_mode": "direct",
|
||||
"wifi_ssid": [
|
||||
"My WIFI"
|
||||
],
|
||||
"wifi_bssid": [
|
||||
"00:00:00:00:00:00"
|
||||
],
|
||||
"invert": false,
|
||||
"outbound": "direct"
|
||||
},
|
||||
@@ -196,7 +190,7 @@ Match port range.
|
||||
|
||||
#### process_name
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
@@ -204,7 +198,7 @@ Match process name.
|
||||
|
||||
#### process_path
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
@@ -216,7 +210,7 @@ Match android package name.
|
||||
|
||||
#### user
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
@@ -224,7 +218,7 @@ Match user name.
|
||||
|
||||
#### user_id
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
@@ -234,22 +228,6 @@ Match user id.
|
||||
|
||||
Match Clash mode.
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
|
||||
Match WiFi SSID.
|
||||
|
||||
#### wifi_bssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
|
||||
Match WiFi BSSID.
|
||||
|
||||
#### invert
|
||||
|
||||
Invert match result.
|
||||
|
||||
@@ -81,12 +81,6 @@
|
||||
1000
|
||||
],
|
||||
"clash_mode": "direct",
|
||||
"wifi_ssid": [
|
||||
"My WIFI"
|
||||
],
|
||||
"wifi_bssid": [
|
||||
"00:00:00:00:00:00"
|
||||
],
|
||||
"invert": false,
|
||||
"outbound": "direct"
|
||||
},
|
||||
@@ -194,7 +188,7 @@
|
||||
|
||||
#### process_name
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS。
|
||||
|
||||
@@ -202,7 +196,7 @@
|
||||
|
||||
#### process_path
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
@@ -214,7 +208,7 @@
|
||||
|
||||
#### user
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux.
|
||||
|
||||
@@ -222,7 +216,7 @@
|
||||
|
||||
#### user_id
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux.
|
||||
|
||||
@@ -232,22 +226,6 @@
|
||||
|
||||
匹配 Clash 模式。
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
|
||||
匹配 WiFi SSID。
|
||||
|
||||
#### wifi_bssid
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
|
||||
匹配 WiFi BSSID。
|
||||
|
||||
#### invert
|
||||
|
||||
反选匹配结果。
|
||||
|
||||
@@ -41,7 +41,7 @@ The IPv6 address to bind to.
|
||||
|
||||
#### routing_mark
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
#### routing_mark
|
||||
|
||||
!!! quote ""
|
||||
!!! error ""
|
||||
|
||||
仅支持 Linux。
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/delete-alert
|
||||
---
|
||||
|
||||
# Deprecated Feature List
|
||||
# :material-delete-alert: Deprecated Feature List
|
||||
|
||||
### 1.6.0
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/delete-alert
|
||||
---
|
||||
|
||||
# 废弃功能列表
|
||||
# :material-delete-alert: 废弃功能列表
|
||||
|
||||
### 1.6.0
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/file-code
|
||||
---
|
||||
|
||||
# Build from source
|
||||
# :material-file-code: Build from source
|
||||
|
||||
## :material-graph: Requirements
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/docker
|
||||
---
|
||||
|
||||
# Docker
|
||||
# :material-docker: Docker
|
||||
|
||||
## :material-console: Command
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/package
|
||||
---
|
||||
|
||||
# Package Manager
|
||||
# :material-package: Package Manager
|
||||
|
||||
## :material-download-box: Manual Installation
|
||||
|
||||
@@ -55,36 +51,12 @@ icon: material/package
|
||||
|------------|--------------------|---------------------|------------------------------|---------------------|
|
||||
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
|
||||
|
||||
## :material-book-multiple: Service Management
|
||||
|
||||
For Linux systems with [systemd][systemd], usually the installation already includes a sing-box service,
|
||||
you can manage the service using the following command:
|
||||
|
||||
| Operation | Command |
|
||||
|-----------|-----------------------------------------------|
|
||||
| Enable | `sudo systemctl enable sing-box` |
|
||||
| Disable | `sudo systemctl disable sing-box` |
|
||||
| Start | `sudo systemctl start sing-box` |
|
||||
| Stop | `sudo systemctl stop sing-box` |
|
||||
| Kill | `sudo systemctl kill sing-box` |
|
||||
| Restart | `sudo systemctl restart sing-box` |
|
||||
| Logs | `sudo journalctl -u sing-box --output cat -e` |
|
||||
| New Logs | `sudo journalctl -u sing-box --output cat -f` |
|
||||
|
||||
[alpine]: https://pkgs.alpinelinux.org/packages?name=sing-box
|
||||
|
||||
[aur]: https://aur.archlinux.org/packages/sing-box
|
||||
|
||||
[nixpkgs]: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/tools/networking/sing-box/default.nix
|
||||
|
||||
[termux]: https://github.com/termux/termux-packages/tree/master/packages/sing-box
|
||||
|
||||
[brew]: https://formulae.brew.sh/formula/sing-box
|
||||
|
||||
[choco]: https://chocolatey.org/packages/sing-box
|
||||
|
||||
[scoop]: https://github.com/ScoopInstaller/Main/blob/master/bucket/sing-box.json
|
||||
|
||||
[winget]: https://github.com/microsoft/winget-pkgs/tree/master/manifests/s/SagerNet/sing-box
|
||||
|
||||
[systemd]: https://systemd.io/
|
||||
[winget]: https://github.com/microsoft/winget-pkgs/tree/master/manifests/s/SagerNet/sing-box
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/lightning-bolt
|
||||
---
|
||||
|
||||
# Hysteria 2
|
||||
# :material-lightning-bolt: Hysteria 2
|
||||
|
||||
The most popular Chinese-made simple protocol based on QUIC, the selling point is Brutal,
|
||||
a congestion control algorithm that can resist packet loss by manually specifying the required rate by the user.
|
||||
@@ -17,9 +13,9 @@ a congestion control algorithm that can resist packet loss by manually specifyin
|
||||
|
||||
## :material-text-box-check: Password Generator
|
||||
|
||||
| Generate Password | Action |
|
||||
|----------------------------|-----------------------------------------------------------------|
|
||||
| <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
||||
| Generate Password | Action |
|
||||
|----------------------------|-----------------------------------------------|
|
||||
| <code id="password"><code> | <button onclick="generate()">Refresh</button> |
|
||||
|
||||
<script>
|
||||
function generate() {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/send
|
||||
---
|
||||
|
||||
# Shadowsocks
|
||||
# :material-send: Shadowsocks
|
||||
|
||||
As the most well-known Chinese-made proxy protocol,
|
||||
Shadowsocks exists in multiple versions,
|
||||
@@ -16,9 +12,10 @@ but only AEAD 2022 ciphers TCP with multiplexing is recommended.
|
||||
|
||||
## :material-text-box-check: Password Generator
|
||||
|
||||
| For `2022-blake3-aes-128-gcm` cipher | For other ciphers | Action |
|
||||
|--------------------------------------|-------------------------------|-----------------------------------------------------------------|
|
||||
| <code id="password_16"><code> | <code id="password_32"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
||||
|
||||
| For `2022-blake3-aes-128-gcm` cipher | For other ciphers | Action |
|
||||
|--------------------------------------|-------------------------------|-----------------------------------------------|
|
||||
| <code id="password_16"><code> | <code id="password_32"><code> | <button onclick="generate()">Refresh</button> |
|
||||
|
||||
<script>
|
||||
function generatePassword(element, length) {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/horse
|
||||
---
|
||||
|
||||
# Trojan
|
||||
# :material-horse: Trojan
|
||||
|
||||
As the most commonly used TLS proxy made in China, Trojan can be used in various combinations,
|
||||
but only the combination of uTLS and multiplexing is recommended.
|
||||
@@ -16,9 +12,9 @@ but only the combination of uTLS and multiplexing is recommended.
|
||||
|
||||
## :material-text-box-check: Password Generator
|
||||
|
||||
| Generate Password | Action |
|
||||
|----------------------------|-----------------------------------------------------------------|
|
||||
| <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
||||
| Generate Password | Action |
|
||||
|----------------------------|-----------------------------------------------|
|
||||
| <code id="password"><code> | <button onclick="generate()">Refresh</button> |
|
||||
|
||||
<script>
|
||||
function generate() {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/alpha-t-box
|
||||
---
|
||||
|
||||
# TUIC
|
||||
# :material-alpha-t-box: TUIC
|
||||
|
||||
A recently popular Chinese-made simple protocol based on QUIC, the selling point is the BBR congestion control algorithm.
|
||||
|
||||
@@ -12,13 +8,13 @@ A recently popular Chinese-made simple protocol based on QUIC, the selling point
|
||||
|
||||
| Specification | Binary Characteristics | Active Detect Hiddenness |
|
||||
|-----------------------------------------------------------|------------------------|--------------------------|
|
||||
| [GitHub](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: |
|
||||
| [Github](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: |
|
||||
|
||||
## Password Generator
|
||||
|
||||
| Generated UUID | Generated Password | Action |
|
||||
|------------------------|----------------------------|-----------------------------------------------------------------|
|
||||
| <code id="uuid"><code> | <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
||||
| Generated UUID | Generated Password | Action |
|
||||
|------------------------|----------------------------|-----------------------------------------------|
|
||||
| <code id="uuid"><code> | <code id="password"><code> | <button onclick="generate()">Refresh</button> |
|
||||
|
||||
<script>
|
||||
function generateUUID() {
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
---
|
||||
icon: material/cellphone-link
|
||||
---
|
||||
# :material-cellphone-link: Client
|
||||
|
||||
# Client
|
||||
|
||||
### :material-ray-start: Introduction
|
||||
## :material-ray-start: Introduction
|
||||
|
||||
For a long time, the modern usage and principles of proxy clients
|
||||
for graphical operating systems have not been clearly described.
|
||||
However, we can categorize them into three types:
|
||||
system proxy, firewall redirection, and virtual interface.
|
||||
|
||||
### :material-web-refresh: System Proxy
|
||||
## :material-web-refresh: System Proxy
|
||||
|
||||
Almost all graphical environments support system-level proxies,
|
||||
which are essentially ordinary HTTP proxies that only support TCP.
|
||||
@@ -38,7 +34,7 @@ flowchart LR
|
||||
udp[UDP packet] --> leak
|
||||
```
|
||||
|
||||
### :material-wall-fire: Firewall Redirection
|
||||
## :material-wall-fire: Firewall Redirection
|
||||
|
||||
This type of usage typically relies on the firewall or hook interface provided by the operating system,
|
||||
such as Windows’ WFP, Linux’s redirect, TProxy and eBPF, and macOS’s pf.
|
||||
@@ -46,7 +42,7 @@ Although it is intrusive and cumbersome to configure,
|
||||
it remains popular within the community of amateur proxy open source projects like V2Ray,
|
||||
due to the low technical requirements it imposes on the software.
|
||||
|
||||
### :material-expansion-card: Virtual Interface
|
||||
## :material-expansion-card: Virtual Interface
|
||||
|
||||
All L2/L3 proxies (seriously defined VPNs, such as OpenVPN, WireGuard) are based on virtual network interfaces,
|
||||
which is also the only way for all L4 proxies to work as VPNs on mobile platforms like Android, iOS.
|
||||
@@ -70,7 +66,7 @@ flowchart TB
|
||||
assemble --> conn[TCP and UDP connections]
|
||||
conn --> router[sing-box Router]
|
||||
router --> direct[Direct outbound]
|
||||
router --> proxy[Proxy outbounds]
|
||||
router --> proxy[Proxy outbounds]
|
||||
router -- DNS hijack --> dns_out[DNS outbound]
|
||||
dns_out --> dns_router[DNS router]
|
||||
dns_router --> router
|
||||
@@ -80,346 +76,4 @@ flowchart TB
|
||||
default --> destination[Destination server]
|
||||
default --> proxy_server[Proxy server]
|
||||
proxy_server --> destination
|
||||
```
|
||||
|
||||
## :material-cellphone-link: Examples
|
||||
|
||||
### Basic TUN usage for Chinese users
|
||||
|
||||
=== ":material-numeric-4-box: IPv4 only"
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"auto_route": true,
|
||||
"strict_route": false
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
// ...
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "dns",
|
||||
"tag": "dns-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"outbound": "dns-out"
|
||||
},
|
||||
{
|
||||
"geoip": [
|
||||
"private"
|
||||
],
|
||||
"outbound": "direct"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-numeric-6-box: IPv4 & IPv6"
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"inet6_address": "fdfe:dcba:9876::1/126",
|
||||
"auto_route": true,
|
||||
"strict_route": false
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
// ...
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "dns",
|
||||
"tag": "dns-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"outbound": "dns-out"
|
||||
},
|
||||
{
|
||||
"geoip": [
|
||||
"private"
|
||||
],
|
||||
"outbound": "direct"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-domain-switch: FakeIP"
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
"detour": "direct"
|
||||
},
|
||||
{
|
||||
"tag": "remote",
|
||||
"address": "fakeip"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"query_type": [
|
||||
"A",
|
||||
"AAAA"
|
||||
],
|
||||
"server": "remote"
|
||||
}
|
||||
],
|
||||
"fakeip": {
|
||||
"enabled": true,
|
||||
"inet4_range": "198.18.0.0/15",
|
||||
"inet6_range": "fc00::/18"
|
||||
},
|
||||
"independent_cache": true
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"inet6_address": "fdfe:dcba:9876::1/126",
|
||||
"auto_route": true,
|
||||
"strict_route": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
// ...
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "dns",
|
||||
"tag": "dns-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"outbound": "dns-out"
|
||||
},
|
||||
{
|
||||
"geoip": [
|
||||
"private"
|
||||
],
|
||||
"outbound": "direct"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Traffic bypass usage for Chinese users
|
||||
|
||||
=== ":material-dns: DNS rules"
|
||||
|
||||
!!! info
|
||||
|
||||
DNS rules are optional if FakeIP is used.
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Direct",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Global",
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"geosite": "geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"geosite": [
|
||||
"cn",
|
||||
"category-companies@cn"
|
||||
],
|
||||
}
|
||||
],
|
||||
"server": "local"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-router-network: Route rules"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "or",
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns"
|
||||
},
|
||||
{
|
||||
"port": 53
|
||||
}
|
||||
],
|
||||
"outbound": "dns"
|
||||
},
|
||||
{
|
||||
"geoip": "private",
|
||||
"outbound": "direct"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Direct",
|
||||
"outbound": "direct"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Global",
|
||||
"outbound": "default"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "or",
|
||||
"rules": [
|
||||
{
|
||||
"port": 853
|
||||
},
|
||||
{
|
||||
"network": "udp",
|
||||
"port": 443
|
||||
},
|
||||
{
|
||||
"protocol": "stun"
|
||||
}
|
||||
],
|
||||
"outbound": "block"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"geosite": "geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"geosite": [
|
||||
"cn",
|
||||
"category-companies@cn"
|
||||
],
|
||||
"geoip": "cn"
|
||||
}
|
||||
],
|
||||
"outbound": "direct"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/server
|
||||
---
|
||||
|
||||
# Server
|
||||
# :material-server: Server
|
||||
|
||||
To use sing-box as a proxy protocol server, you pretty much only need to configure the inbound for that protocol.
|
||||
|
||||
|
||||
66
docs/manual/proxy/tun.md
Normal file
66
docs/manual/proxy/tun.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# :material-expansion-card: TUN
|
||||
|
||||
## :material-text-box: Definition
|
||||
|
||||
Refers to TUNnel, a virtual network device supported by the kernel.
|
||||
It’s also used in sing-box to denote the extensive functionality surrounding TUN inbound:
|
||||
including traffic assembly, automatic routing, and network and default interface monitoring.
|
||||
|
||||
The following flow chart describes the minimal TUN-based transparent proxy process in sing-box:
|
||||
|
||||
``` mermaid
|
||||
flowchart LR
|
||||
subgraph inbound [Inbound]
|
||||
direction TB
|
||||
packet[IP Packet]
|
||||
packet --> windows[Windows / macOS]
|
||||
packet --> linux[Linux]
|
||||
tun[TUN interface]
|
||||
windows -. route .-> tun
|
||||
linux -. iproute2 route/rule .-> tun
|
||||
tun --> gvisor[gVisor TUN stack]
|
||||
tun --> system[system TUN stack]
|
||||
assemble([L3 to L4 assemble])
|
||||
gvisor --> assemble
|
||||
system --> assemble
|
||||
assemble --> conn[TCP and UDP connections]
|
||||
conn --> router[sing-box Router]
|
||||
end
|
||||
|
||||
subgraph outbound [Outbound]
|
||||
direction TB
|
||||
direct[Direct outbound]
|
||||
proxy[Proxy outbounds]
|
||||
direct --> adi([auto detect interface])
|
||||
proxy --> adi
|
||||
adi --> default[Default network interface in the system]
|
||||
default --> destination[Destination server]
|
||||
default --> proxy_server[Proxy server]
|
||||
proxy_server --> destination
|
||||
end
|
||||
|
||||
inbound --> outbound
|
||||
```
|
||||
|
||||
## :material-help-box: How to
|
||||
|
||||
A basic TUN-based transparent proxy configuration file includes: an TUN inbound, `route.auto_detect_interface`, like:
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"inet6_address": "fdfe:dcba:9876::1/126",
|
||||
"auto_route": true,
|
||||
"strict_route": true
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
TODO: finish this wiki
|
||||
@@ -1,13 +1,9 @@
|
||||
---
|
||||
icon: material/forum
|
||||
---
|
||||
|
||||
# Support
|
||||
# :material-forum: Support
|
||||
|
||||
| Channel | Link |
|
||||
|:------------------------------|:--------------------------------------------|
|
||||
| Community | https://community.sagernet.org |
|
||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| Github Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| Telegram notification channel | https://t.me/yapnc |
|
||||
| Telegram user group | https://t.me/yapug |
|
||||
| Email | contact@sagernet.org |
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
---
|
||||
icon: material/forum
|
||||
---
|
||||
|
||||
# 支持
|
||||
# :material-forum: 支持
|
||||
|
||||
| 通道 | 链接 |
|
||||
|:--------------|:--------------------------------------------|
|
||||
| 社区 | https://community.sagernet.org |
|
||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| Github Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| Telegram 通知频道 | https://t.me/yapnc |
|
||||
| Telegram 用户组 | https://t.me/yapug |
|
||||
| 邮件 | contact@sagernet.org |
|
||||
|
||||
@@ -83,7 +83,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
var result map[string]uint16
|
||||
if urlTestGroup, isURLTestGroup := group.(adapter.URLTestGroup); isURLTestGroup {
|
||||
result, err = urlTestGroup.URLTest(ctx)
|
||||
result, err = urlTestGroup.URLTest(ctx, url)
|
||||
} else {
|
||||
outbounds := common.FilterNotNil(common.Map(group.All(), func(it string) adapter.Outbound {
|
||||
itOutbound, _ := server.router.Outbound(it)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package cachefile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -14,7 +13,6 @@ import (
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -43,7 +41,7 @@ type CacheFile struct {
|
||||
saveMetadataTimer *time.Timer
|
||||
}
|
||||
|
||||
func Open(ctx context.Context, path string, cacheID string) (*CacheFile, error) {
|
||||
func Open(path string, cacheID string) (*CacheFile, error) {
|
||||
const fileMode = 0o666
|
||||
options := bbolt.Options{Timeout: time.Second}
|
||||
var (
|
||||
@@ -69,10 +67,6 @@ func Open(ctx context.Context, path string, cacheID string) (*CacheFile, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = filemanager.Chown(ctx, path)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "platform chown")
|
||||
}
|
||||
var cacheIDBytes []byte
|
||||
if cacheID != "" {
|
||||
cacheIDBytes = append([]byte{0}, []byte(cacheID)...)
|
||||
|
||||
@@ -148,7 +148,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
|
||||
|
||||
func (s *Server) PreStart() error {
|
||||
if s.cacheFilePath != "" {
|
||||
cacheFile, err := cachefile.Open(s.ctx, s.cacheFilePath, s.cacheID)
|
||||
cacheFile, err := cachefile.Open(s.cacheFilePath, s.cacheID)
|
||||
if err != nil {
|
||||
return E.Cause(err, "open cache file")
|
||||
}
|
||||
|
||||
@@ -70,6 +70,9 @@ func (m *Manager) Snapshot() *Snapshot {
|
||||
return true
|
||||
})
|
||||
|
||||
//if memoryInfo, err := m.process.MemoryInfo(); err == nil {
|
||||
// m.memory = memoryInfo.RSS
|
||||
//} else {
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
m.memory = memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
type StatusMessage struct {
|
||||
Memory int64
|
||||
MemoryInuse int64
|
||||
Goroutines int32
|
||||
ConnectionsIn int32
|
||||
ConnectionsOut int32
|
||||
|
||||
@@ -19,7 +19,6 @@ type PlatformInterface interface {
|
||||
UsePlatformInterfaceGetter() bool
|
||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||
UnderNetworkExtension() bool
|
||||
ReadWIFIState() *WIFIState
|
||||
ClearDNSCache()
|
||||
}
|
||||
|
||||
@@ -39,15 +38,6 @@ type NetworkInterface struct {
|
||||
Addresses StringIterator
|
||||
}
|
||||
|
||||
type WIFIState struct {
|
||||
SSID string
|
||||
BSSID string
|
||||
}
|
||||
|
||||
func NewWIFIState(wifiSSID string, wifiBSSID string) *WIFIState {
|
||||
return &WIFIState{wifiSSID, wifiBSSID}
|
||||
}
|
||||
|
||||
type NetworkInterfaceIterator interface {
|
||||
Next() *NetworkInterface
|
||||
HasNext() bool
|
||||
|
||||
@@ -23,7 +23,6 @@ type Interface interface {
|
||||
Interfaces() ([]NetworkInterface, error)
|
||||
UnderNetworkExtension() bool
|
||||
ClearDNSCache()
|
||||
ReadWIFIState() adapter.WIFIState
|
||||
process.Searcher
|
||||
}
|
||||
|
||||
|
||||
@@ -210,14 +210,6 @@ func (w *platformInterfaceWrapper) ClearDNSCache() {
|
||||
w.iif.ClearDNSCache()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
|
||||
wifiState := w.iif.ReadWIFIState()
|
||||
if wifiState == nil {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
return (adapter.WIFIState)(*wifiState)
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) DisableColors() bool {
|
||||
return runtime.GOOS != "android"
|
||||
}
|
||||
|
||||
24
go.mod
24
go.mod
@@ -12,28 +12,28 @@ require (
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gofrs/uuid/v5 v5.0.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231126010706-b0416c0f187a
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c
|
||||
github.com/libdns/alidns v1.0.3
|
||||
github.com/libdns/cloudflare v0.1.0
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/miekg/dns v1.1.56
|
||||
github.com/ooni/go-libtor v1.1.8
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a
|
||||
github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950
|
||||
github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930
|
||||
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab
|
||||
github.com/sagernet/quic-go v0.40.0
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.2.18-0.20231203085253-0ba5576c7be8
|
||||
github.com/sagernet/sing-dns v0.1.11
|
||||
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c
|
||||
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358
|
||||
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07
|
||||
github.com/sagernet/sing-quic v0.1.5-0.20231123150216-00957d136203
|
||||
github.com/sagernet/sing-quic v0.1.4-0.20231114135334-e2a6aab55cca
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.5
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71
|
||||
github.com/sagernet/sing-tun v0.1.20-0.20231116102736-3fa4ee409a9d
|
||||
github.com/sagernet/sing-vmess v0.1.8
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6
|
||||
@@ -44,9 +44,9 @@ require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.uber.org/zap v1.26.0
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925
|
||||
golang.org/x/crypto v0.16.0
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/sys v0.15.0
|
||||
golang.org/x/crypto v0.15.0
|
||||
golang.org/x/net v0.18.0
|
||||
golang.org/x/sys v0.14.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.59.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
@@ -89,7 +89,7 @@ require (
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.4.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
|
||||
50
go.sum
50
go.sum
@@ -47,8 +47,8 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE
|
||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231126010706-b0416c0f187a h1:biHpNhTkyeXNEzLqTOM6DkIkMedNh/j+ft+POj0Xcko=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231126010706-b0416c0f187a/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
@@ -72,8 +72,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||
@@ -100,8 +100,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||
github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 h1:hUz/2mJLgi7l2H36JGpDY+jou9FmI6kAm0ZkU+xPpgE=
|
||||
github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
||||
github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 h1:dSPgjIw0CT6ISLeEh8Q20dZMBMFCcEceo23+LncRcNQ=
|
||||
github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930/go.mod h1:JpKHkOYgh4wLwrX2BhH3ZIvCvazCkTnPeEcmigZJfHY=
|
||||
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvTfrDD6HhGRybn2lzrhf5vmS+wb4Ho=
|
||||
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.40.0 h1:DvQNPb72lzvNQDe9tcUyHTw8eRv6PLtM2mNYmdlzUMo=
|
||||
@@ -110,22 +110,22 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.2.18-0.20231203085253-0ba5576c7be8 h1:wQuG3Kfob9jppmkamoRmvUE4nwTltxLhDGeeGUD66Dk=
|
||||
github.com/sagernet/sing v0.2.18-0.20231203085253-0ba5576c7be8/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE=
|
||||
github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE=
|
||||
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c h1:uask61Pxc3nGqsOSjqnBKrwfODWRoEa80lXm04LNk0E=
|
||||
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 h1:psJQg/KXVQTupFFR1liaCAucW+NwCDhe1oYfkmz8EJ8=
|
||||
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c=
|
||||
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM=
|
||||
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU=
|
||||
github.com/sagernet/sing-quic v0.1.5-0.20231123150216-00957d136203 h1:e3C94gdfTDal52fk0BS/BRcDeF3USqBr8OjQc7XBk4E=
|
||||
github.com/sagernet/sing-quic v0.1.5-0.20231123150216-00957d136203/go.mod h1:B6OgRz+qLn3N1114dcZVExkdarArtsAX2MgWJIfB72c=
|
||||
github.com/sagernet/sing-quic v0.1.4-0.20231114135334-e2a6aab55cca h1:wGQhe7D8Y4D3lPK8Obtv4IQAvnkEKMMu8Uv/BiYpyWc=
|
||||
github.com/sagernet/sing-quic v0.1.4-0.20231114135334-e2a6aab55cca/go.mod h1:B6OgRz+qLn3N1114dcZVExkdarArtsAX2MgWJIfB72c=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/JtmU+i/YfCYE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.5/go.mod h1:KF65y8lI5PGHyMgRZGYXYsH9ilgRc/yr+NYbSNGuBm4=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 h1:WQi0TwhjbSNFFbxybIgAUSjVvo7uWSsLD28ldoM2avY=
|
||||
github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71/go.mod h1:hyzA4gDWbeg2SXklqPDswBKa//QcjlZqKw9aPcNdQ9A=
|
||||
github.com/sagernet/sing-tun v0.1.20-0.20231116102736-3fa4ee409a9d h1:FlCho4lZEMC6N6dThTVd2rOkWPW0iTqgy7YEAboeyps=
|
||||
github.com/sagernet/sing-tun v0.1.20-0.20231116102736-3fa4ee409a9d/go.mod h1:B1y93eY/4pNklxrstVGFrDrH4dUZAiZFBQ4MFn6HJXA=
|
||||
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
|
||||
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||
@@ -169,16 +169,16 @@ go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0Eq
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -189,16 +189,16 @@ golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.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.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
||||
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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
|
||||
@@ -30,7 +30,6 @@ theme:
|
||||
- navigation.sections
|
||||
- header.autohide
|
||||
- content.code.copy
|
||||
- content.code.select
|
||||
- content.code.annotate
|
||||
nav:
|
||||
- Home:
|
||||
|
||||
@@ -78,8 +78,6 @@ type DefaultRule struct {
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
||||
ClashMode string `json:"clash_mode,omitempty"`
|
||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
Outbound string `json:"outbound,omitempty"`
|
||||
}
|
||||
|
||||
@@ -78,8 +78,6 @@ type DefaultDNSRule struct {
|
||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
||||
Outbound Listable[string] `json:"outbound,omitempty"`
|
||||
ClashMode string `json:"clash_mode,omitempty"`
|
||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
|
||||
@@ -3,6 +3,7 @@ package outbound
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -82,7 +83,7 @@ func (s *URLTest) Start() error {
|
||||
}
|
||||
|
||||
func (s *URLTest) PostStart() error {
|
||||
s.group.PostStart()
|
||||
go s.CheckOutbounds()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -100,8 +101,8 @@ func (s *URLTest) All() []string {
|
||||
return s.tags
|
||||
}
|
||||
|
||||
func (s *URLTest) URLTest(ctx context.Context) (map[string]uint16, error) {
|
||||
return s.group.URLTest(ctx)
|
||||
func (s *URLTest) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
|
||||
return s.group.URLTest(ctx, link)
|
||||
}
|
||||
|
||||
func (s *URLTest) CheckOutbounds() {
|
||||
@@ -109,7 +110,7 @@ func (s *URLTest) CheckOutbounds() {
|
||||
}
|
||||
|
||||
func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
s.group.Touch()
|
||||
s.group.Start()
|
||||
outbound := s.group.Select(network)
|
||||
conn, err := outbound.DialContext(ctx, network, destination)
|
||||
if err == nil {
|
||||
@@ -121,7 +122,7 @@ func (s *URLTest) DialContext(ctx context.Context, network string, destination M
|
||||
}
|
||||
|
||||
func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
s.group.Touch()
|
||||
s.group.Start()
|
||||
outbound := s.group.Select(N.NetworkUDP)
|
||||
conn, err := outbound.ListenPacket(ctx, destination)
|
||||
if err == nil {
|
||||
@@ -163,11 +164,9 @@ type URLTestGroup struct {
|
||||
interruptGroup *interrupt.Group
|
||||
interruptExternalConnections bool
|
||||
|
||||
access sync.Mutex
|
||||
ticker *time.Ticker
|
||||
close chan struct{}
|
||||
started bool
|
||||
lastActive atomic.TypedValue[time.Time]
|
||||
access sync.Mutex
|
||||
ticker *time.Ticker
|
||||
close chan struct{}
|
||||
}
|
||||
|
||||
func NewURLTestGroup(
|
||||
@@ -209,18 +208,8 @@ func NewURLTestGroup(
|
||||
}
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) PostStart() {
|
||||
g.started = true
|
||||
g.lastActive.Store(time.Now())
|
||||
go g.CheckOutbounds(false)
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) Touch() {
|
||||
if !g.started {
|
||||
return
|
||||
}
|
||||
func (g *URLTestGroup) Start() {
|
||||
if g.ticker != nil {
|
||||
g.lastActive.Store(time.Now())
|
||||
return
|
||||
}
|
||||
g.access.Lock()
|
||||
@@ -271,30 +260,51 @@ func (g *URLTestGroup) Select(network string) adapter.Outbound {
|
||||
return minOutbound
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) loopCheck() {
|
||||
if time.Now().Sub(g.lastActive.Load()) > g.interval {
|
||||
g.CheckOutbounds(false)
|
||||
func (g *URLTestGroup) Fallback(used adapter.Outbound) []adapter.Outbound {
|
||||
outbounds := make([]adapter.Outbound, 0, len(g.outbounds)-1)
|
||||
for _, detour := range g.outbounds {
|
||||
if detour != used {
|
||||
outbounds = append(outbounds, detour)
|
||||
}
|
||||
}
|
||||
sort.SliceStable(outbounds, func(i, j int) bool {
|
||||
oi := outbounds[i]
|
||||
oj := outbounds[j]
|
||||
hi := g.history.LoadURLTestHistory(RealTag(oi))
|
||||
if hi == nil {
|
||||
return false
|
||||
}
|
||||
hj := g.history.LoadURLTestHistory(RealTag(oj))
|
||||
if hj == nil {
|
||||
return false
|
||||
}
|
||||
return hi.Delay < hj.Delay
|
||||
})
|
||||
return outbounds
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) loopCheck() {
|
||||
go g.CheckOutbounds(true)
|
||||
for {
|
||||
g.pauseManager.WaitActive()
|
||||
select {
|
||||
case <-g.close:
|
||||
return
|
||||
case <-g.ticker.C:
|
||||
g.CheckOutbounds(false)
|
||||
}
|
||||
g.pauseManager.WaitActive()
|
||||
g.CheckOutbounds(false)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) CheckOutbounds(force bool) {
|
||||
_, _ = g.urlTest(g.ctx, force)
|
||||
_, _ = g.urlTest(g.ctx, g.link, force)
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) URLTest(ctx context.Context) (map[string]uint16, error) {
|
||||
return g.urlTest(ctx, false)
|
||||
func (g *URLTestGroup) URLTest(ctx context.Context, link string) (map[string]uint16, error) {
|
||||
return g.urlTest(ctx, link, false)
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint16, error) {
|
||||
func (g *URLTestGroup) urlTest(ctx context.Context, link string, force bool) (map[string]uint16, error) {
|
||||
result := make(map[string]uint16)
|
||||
if g.checking.Swap(true) {
|
||||
return result, nil
|
||||
@@ -321,7 +331,7 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
|
||||
b.Go(realTag, func() (any, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.TCPTimeout)
|
||||
defer cancel()
|
||||
t, err := urltest.URLTest(ctx, g.link, p)
|
||||
t, err := urltest.URLTest(ctx, link, p)
|
||||
if err != nil {
|
||||
g.logger.Debug("outbound ", tag, " unavailable: ", err)
|
||||
g.history.DeleteURLTestHistory(realTag)
|
||||
|
||||
@@ -86,9 +86,6 @@ type Router struct {
|
||||
clashServer adapter.ClashServer
|
||||
v2rayServer adapter.V2RayServer
|
||||
platformInterface platform.Interface
|
||||
needWIFIState bool
|
||||
wifiState adapter.WIFIState
|
||||
started bool
|
||||
}
|
||||
|
||||
func NewRouter(
|
||||
@@ -119,7 +116,6 @@ func NewRouter(
|
||||
defaultMark: options.DefaultMark,
|
||||
pauseManager: pause.ManagerFromContext(ctx),
|
||||
platformInterface: platformInterface,
|
||||
needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule),
|
||||
}
|
||||
router.dnsClient = dns.NewClient(dns.ClientOptions{
|
||||
DisableCache: dnsOptions.DNSClientOptions.DisableCache,
|
||||
@@ -332,11 +328,6 @@ func NewRouter(
|
||||
service.ContextWith[serviceNTP.TimeService](ctx, timeService)
|
||||
router.timeService = timeService
|
||||
}
|
||||
if platformInterface != nil && router.interfaceMonitor != nil && router.needWIFIState {
|
||||
router.interfaceMonitor.RegisterCallback(func(_ int) {
|
||||
router.updateWIFIState()
|
||||
})
|
||||
}
|
||||
return router, nil
|
||||
}
|
||||
|
||||
@@ -477,9 +468,6 @@ func (r *Router) Start() error {
|
||||
r.geositeCache = nil
|
||||
r.geositeReader = nil
|
||||
}
|
||||
if r.needWIFIState {
|
||||
r.updateWIFIState()
|
||||
}
|
||||
for i, rule := range r.rules {
|
||||
err := rule.Start()
|
||||
if err != nil {
|
||||
@@ -572,11 +560,6 @@ func (r *Router) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Router) PostStart() error {
|
||||
r.started = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Outbound(tag string) (adapter.Outbound, bool) {
|
||||
outbound, loaded := r.outboundByTag[tag]
|
||||
return outbound, loaded
|
||||
@@ -957,10 +940,6 @@ func (r *Router) Rules() []adapter.Rule {
|
||||
return r.rules
|
||||
}
|
||||
|
||||
func (r *Router) WIFIState() adapter.WIFIState {
|
||||
return r.wifiState
|
||||
}
|
||||
|
||||
func (r *Router) NetworkMonitor() tun.NetworkUpdateMonitor {
|
||||
return r.networkMonitor
|
||||
}
|
||||
@@ -1021,11 +1000,8 @@ func (r *Router) notifyNetworkUpdate(event int) {
|
||||
}
|
||||
}
|
||||
|
||||
if !r.started {
|
||||
return
|
||||
}
|
||||
|
||||
_ = r.ResetNetwork()
|
||||
r.ResetNetwork()
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Router) ResetNetwork() error {
|
||||
@@ -1043,14 +1019,3 @@ func (r *Router) ResetNetwork() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) updateWIFIState() {
|
||||
if r.platformInterface == nil {
|
||||
return
|
||||
}
|
||||
state := r.platformInterface.ReadWIFIState()
|
||||
if state != r.wifiState {
|
||||
r.wifiState = state
|
||||
r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,11 +307,3 @@ func isProcessDNSRule(rule option.DefaultDNSRule) bool {
|
||||
func notPrivateNode(code string) bool {
|
||||
return code != "private"
|
||||
}
|
||||
|
||||
func isWIFIRule(rule option.DefaultRule) bool {
|
||||
return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0
|
||||
}
|
||||
|
||||
func isWIFIDNSRule(rule option.DefaultDNSRule) bool {
|
||||
return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0
|
||||
}
|
||||
|
||||
@@ -184,16 +184,6 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.WIFISSID) > 0 {
|
||||
item := NewWIFISSIDItem(router, options.WIFISSID)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.WIFIBSSID) > 0 {
|
||||
item := NewWIFIBSSIDItem(router, options.WIFIBSSID)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -180,16 +180,6 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.WIFISSID) > 0 {
|
||||
item := NewWIFISSIDItem(router, options.WIFISSID)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.WIFIBSSID) > 0 {
|
||||
item := NewWIFIBSSIDItem(router, options.WIFIBSSID)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*WIFIBSSIDItem)(nil)
|
||||
|
||||
type WIFIBSSIDItem struct {
|
||||
bssidList []string
|
||||
bssidMap map[string]bool
|
||||
router adapter.Router
|
||||
}
|
||||
|
||||
func NewWIFIBSSIDItem(router adapter.Router, bssidList []string) *WIFIBSSIDItem {
|
||||
bssidMap := make(map[string]bool)
|
||||
for _, bssid := range bssidList {
|
||||
bssidMap[bssid] = true
|
||||
}
|
||||
return &WIFIBSSIDItem{
|
||||
bssidList,
|
||||
bssidMap,
|
||||
router,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *WIFIBSSIDItem) Match(metadata *adapter.InboundContext) bool {
|
||||
return r.bssidMap[r.router.WIFIState().BSSID]
|
||||
}
|
||||
|
||||
func (r *WIFIBSSIDItem) String() string {
|
||||
if len(r.bssidList) == 1 {
|
||||
return F.ToString("wifi_bssid=", r.bssidList[0])
|
||||
}
|
||||
return F.ToString("wifi_bssid=[", strings.Join(r.bssidList, " "), "]")
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*WIFISSIDItem)(nil)
|
||||
|
||||
type WIFISSIDItem struct {
|
||||
ssidList []string
|
||||
ssidMap map[string]bool
|
||||
router adapter.Router
|
||||
}
|
||||
|
||||
func NewWIFISSIDItem(router adapter.Router, ssidList []string) *WIFISSIDItem {
|
||||
ssidMap := make(map[string]bool)
|
||||
for _, ssid := range ssidList {
|
||||
ssidMap[ssid] = true
|
||||
}
|
||||
return &WIFISSIDItem{
|
||||
ssidList,
|
||||
ssidMap,
|
||||
router,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *WIFISSIDItem) Match(metadata *adapter.InboundContext) bool {
|
||||
return r.ssidMap[r.router.WIFIState().SSID]
|
||||
}
|
||||
|
||||
func (r *WIFISSIDItem) String() string {
|
||||
if len(r.ssidList) == 1 {
|
||||
return F.ToString("wifi_ssid=", r.ssidList[0])
|
||||
}
|
||||
return F.ToString("wifi_ssid=[", strings.Join(r.ssidList, " "), "]")
|
||||
}
|
||||
22
test/go.mod
22
test/go.mod
@@ -11,11 +11,11 @@ require (
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/gofrs/uuid/v5 v5.0.0
|
||||
github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460
|
||||
github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc
|
||||
github.com/sagernet/sing-dns v0.1.11
|
||||
github.com/sagernet/sing-quic v0.1.4
|
||||
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c
|
||||
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358
|
||||
github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.5
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4
|
||||
github.com/spyzhov/ajson v0.9.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.uber.org/goleak v1.3.0
|
||||
@@ -56,7 +56,7 @@ require (
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
github.com/mholt/acmez v1.2.0 // indirect
|
||||
github.com/miekg/dns v1.1.57 // indirect
|
||||
github.com/miekg/dns v1.1.56 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
@@ -72,12 +72,12 @@ require (
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a // indirect
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
|
||||
github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 // indirect
|
||||
github.com/sagernet/sing-tun v0.1.20-0.20231116102736-3fa4ee409a9d // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.8 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect
|
||||
@@ -92,12 +92,12 @@ require (
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect
|
||||
golang.org/x/crypto v0.15.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.4.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
|
||||
46
test/go.sum
46
test/go.sum
@@ -87,8 +87,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
@@ -121,8 +121,8 @@ github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBx
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||
github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 h1:dSPgjIw0CT6ISLeEh8Q20dZMBMFCcEceo23+LncRcNQ=
|
||||
github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930/go.mod h1:JpKHkOYgh4wLwrX2BhH3ZIvCvazCkTnPeEcmigZJfHY=
|
||||
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvTfrDD6HhGRybn2lzrhf5vmS+wb4Ho=
|
||||
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 h1:dAe4OIJAtE0nHOzTHhAReQteh3+sa63rvXbuIpbeOTY=
|
||||
@@ -131,22 +131,22 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc h1:dmU0chO0QrBpARo8sqyOc+mvPLW+qux4ca16kb2WIc8=
|
||||
github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE=
|
||||
github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE=
|
||||
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c h1:uask61Pxc3nGqsOSjqnBKrwfODWRoEa80lXm04LNk0E=
|
||||
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 h1:psJQg/KXVQTupFFR1liaCAucW+NwCDhe1oYfkmz8EJ8=
|
||||
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c=
|
||||
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM=
|
||||
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU=
|
||||
github.com/sagernet/sing-quic v0.1.4 h1:F5KRGXMXKQEmP8VrzVollf9HWcRqggcuG9nRCL+5IJ8=
|
||||
github.com/sagernet/sing-quic v0.1.4/go.mod h1:aXHVP+osF3w5wJzoWZbJSrX3ceJiU9QMd0KPnKV6C/o=
|
||||
github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 h1:V84NPJKirL/oDkvUh9Dor2gMZ+TTNHK3jcedqRkgcQA=
|
||||
github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769/go.mod h1:iggBfFE2ojS2yYQU8Hnrkm029RsHPdYYIKWqeCI64HE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/JtmU+i/YfCYE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.5/go.mod h1:KF65y8lI5PGHyMgRZGYXYsH9ilgRc/yr+NYbSNGuBm4=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 h1:WQi0TwhjbSNFFbxybIgAUSjVvo7uWSsLD28ldoM2avY=
|
||||
github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71/go.mod h1:hyzA4gDWbeg2SXklqPDswBKa//QcjlZqKw9aPcNdQ9A=
|
||||
github.com/sagernet/sing-tun v0.1.20-0.20231116102736-3fa4ee409a9d h1:FlCho4lZEMC6N6dThTVd2rOkWPW0iTqgy7YEAboeyps=
|
||||
github.com/sagernet/sing-tun v0.1.20-0.20231116102736-3fa4ee409a9d/go.mod h1:B1y93eY/4pNklxrstVGFrDrH4dUZAiZFBQ4MFn6HJXA=
|
||||
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
|
||||
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||
@@ -196,12 +196,12 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -213,7 +213,7 @@ golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -236,14 +236,14 @@ 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -74,23 +74,6 @@ func TestShadowsocks2022(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShadowsocks2022EIH(t *testing.T) {
|
||||
for _, method16 := range []string{
|
||||
"2022-blake3-aes-128-gcm",
|
||||
} {
|
||||
t.Run(method16, func(t *testing.T) {
|
||||
testShadowsocks2022EIH(t, method16, mkBase64(t, 16))
|
||||
})
|
||||
}
|
||||
for _, method32 := range []string{
|
||||
"2022-blake3-aes-256-gcm",
|
||||
} {
|
||||
t.Run(method32, func(t *testing.T) {
|
||||
testShadowsocks2022EIH(t, method32, mkBase64(t, 32))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testShadowsocksInboundWithShadowsocksRust(t *testing.T, method string, password string) {
|
||||
startDockerContainer(t, DockerOptions{
|
||||
Image: ImageShadowsocksRustClient,
|
||||
@@ -269,67 +252,6 @@ func TestShadowsocksUoT(t *testing.T) {
|
||||
testSuit(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func testShadowsocks2022EIH(t *testing.T, method string, password string) {
|
||||
startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
MixedOptions: option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: clientPort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeShadowsocks,
|
||||
ShadowsocksOptions: option.ShadowsocksInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Method: method,
|
||||
Password: password,
|
||||
Users: []option.ShadowsocksUser{
|
||||
{
|
||||
Password: password,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeShadowsocks,
|
||||
Tag: "ss-out",
|
||||
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
Method: method,
|
||||
Password: password + ":" + password,
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
DefaultOptions: option.DefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
Outbound: "ss-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
testSuit(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func mkBase64(t *testing.T, length int) string {
|
||||
psk := make([]byte, length)
|
||||
_, err := rand.Read(psk)
|
||||
|
||||
@@ -87,15 +87,9 @@ func (t *Transport) Start() error {
|
||||
}
|
||||
|
||||
func (t *Transport) Reset() {
|
||||
for _, transport := range t.transports {
|
||||
transport.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
for _, transport := range t.transports {
|
||||
transport.Close()
|
||||
}
|
||||
if t.interfaceCallback != nil {
|
||||
t.router.InterfaceMonitor().UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
@@ -272,9 +266,6 @@ func (t *Transport) recreateServers(iface *net.Interface, serverAddrs []netip.Ad
|
||||
}
|
||||
transports = append(transports, serverTransport)
|
||||
}
|
||||
for _, transport := range t.transports {
|
||||
transport.Close()
|
||||
}
|
||||
t.transports = transports
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ import (
|
||||
"github.com/sagernet/sing-box/common/tls"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/sagernet/sing/common/bufio/deadline"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -90,35 +87,18 @@ func (c *Client) dialContext(ctx context.Context, requestURL *url.URL, headers h
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var deadlineConn net.Conn
|
||||
if deadline.NeedAdditionalReadDeadline(conn) {
|
||||
deadlineConn = deadline.NewConn(conn)
|
||||
} else {
|
||||
deadlineConn = conn
|
||||
}
|
||||
err = deadlineConn.SetDeadline(time.Now().Add(C.TCPTimeout))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "set read deadline")
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(C.TCPTimeout))
|
||||
var protocols []string
|
||||
if protocolHeader := headers.Get("Sec-WebSocket-Protocol"); protocolHeader != "" {
|
||||
protocols = []string{protocolHeader}
|
||||
headers.Del("Sec-WebSocket-Protocol")
|
||||
}
|
||||
reader, _, err := ws.Dialer{Header: ws.HandshakeHeaderHTTP(headers), Protocols: protocols}.Upgrade(deadlineConn, requestURL)
|
||||
deadlineConn.SetDeadline(time.Time{})
|
||||
reader, _, err := ws.Dialer{Header: ws.HandshakeHeaderHTTP(headers), Protocols: protocols}.Upgrade(conn, requestURL)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reader != nil {
|
||||
buffer := buf.NewSize(reader.Buffered())
|
||||
_, err = buffer.ReadFullFrom(reader, buffer.Len())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn = bufio.NewCachedConn(conn, buffer)
|
||||
}
|
||||
return NewConn(conn, nil, ws.StateClientSide), nil
|
||||
return NewConn(conn, reader, nil, ws.StateClientSide), nil
|
||||
}
|
||||
|
||||
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package v2raywebsocket
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
@@ -27,13 +28,19 @@ type WebsocketConn struct {
|
||||
remoteAddr net.Addr
|
||||
}
|
||||
|
||||
func NewConn(conn net.Conn, remoteAddr net.Addr, state ws.State) *WebsocketConn {
|
||||
func NewConn(conn net.Conn, br *bufio.Reader, remoteAddr net.Addr, state ws.State) *WebsocketConn {
|
||||
controlHandler := wsutil.ControlFrameHandler(conn, state)
|
||||
var reader io.Reader
|
||||
if br != nil && br.Buffered() > 0 {
|
||||
reader = br
|
||||
} else {
|
||||
reader = conn
|
||||
}
|
||||
return &WebsocketConn{
|
||||
Conn: conn,
|
||||
state: state,
|
||||
reader: &wsutil.Reader{
|
||||
Source: conn,
|
||||
Source: reader,
|
||||
State: state,
|
||||
SkipHeaderCheck: !debug.Enabled,
|
||||
OnIntermediate: controlHandler,
|
||||
|
||||
@@ -88,14 +88,14 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
s.invalidRequest(writer, request, http.StatusBadRequest, E.Cause(err, "decode early data"))
|
||||
return
|
||||
}
|
||||
wsConn, _, _, err := ws.UpgradeHTTP(request, writer)
|
||||
wsConn, reader, _, err := ws.UpgradeHTTP(request, writer)
|
||||
if err != nil {
|
||||
s.invalidRequest(writer, request, 0, E.Cause(err, "upgrade websocket connection"))
|
||||
return
|
||||
}
|
||||
var metadata M.Metadata
|
||||
metadata.Source = sHttp.SourceAddress(request)
|
||||
conn = NewConn(wsConn, metadata.Source.TCPAddr(), ws.StateServerSide)
|
||||
conn = NewConn(wsConn, reader.Reader, metadata.Source.TCPAddr(), ws.StateServerSide)
|
||||
if len(earlyData) > 0 {
|
||||
conn = bufio.NewCachedConn(conn, buf.As(earlyData))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user