mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
Compare commits
23 Commits
fafe3847ec
...
v1.12.23
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adbea8b325 | ||
|
|
795eda967b | ||
|
|
f2ec82dd2a | ||
|
|
53853e9ae1 | ||
|
|
e663b7f974 | ||
|
|
f63091d14d | ||
|
|
1c4a01ee90 | ||
|
|
4d7f99310c | ||
|
|
6fc511f56e | ||
|
|
d18d2b352a | ||
|
|
534128bba9 | ||
|
|
736a7368c6 | ||
|
|
e7a9c90213 | ||
|
|
0f3774e501 | ||
|
|
2f8e656522 | ||
|
|
3ba30e3f00 | ||
|
|
f2639a5829 | ||
|
|
69bebbda82 | ||
|
|
00b2c042ee | ||
|
|
d9eb8f3ab6 | ||
|
|
58025a01f8 | ||
|
|
99cad72ea8 | ||
|
|
6e96d620fe |
23
.fpm_pacman
Normal file
23
.fpm_pacman
Normal file
@@ -0,0 +1,23 @@
|
||||
-s dir
|
||||
--name sing-box
|
||||
--category net
|
||||
--license GPL-3.0-or-later
|
||||
--description "The universal proxy platform."
|
||||
--url "https://sing-box.sagernet.org/"
|
||||
--maintainer "nekohasekai <contact-git@sekai.icu>"
|
||||
--config-files etc/sing-box/config.json
|
||||
--after-install release/config/sing-box.postinst
|
||||
|
||||
release/config/config.json=/etc/sing-box/config.json
|
||||
|
||||
release/config/sing-box.service=/usr/lib/systemd/system/sing-box.service
|
||||
release/config/sing-box@.service=/usr/lib/systemd/system/sing-box@.service
|
||||
release/config/sing-box.sysusers=/usr/lib/sysusers.d/sing-box.conf
|
||||
release/config/sing-box.rules=usr/share/polkit-1/rules.d/sing-box.rules
|
||||
release/config/sing-box-split-dns.xml=/usr/share/dbus-1/system.d/sing-box-split-dns.conf
|
||||
|
||||
release/completions/sing-box.bash=/usr/share/bash-completion/completions/sing-box.bash
|
||||
release/completions/sing-box.fish=/usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
release/completions/sing-box.zsh=/usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
LICENSE=/usr/share/licenses/sing-box/LICENSE
|
||||
2
.github/setup_go_for_windows7.sh
vendored
2
.github/setup_go_for_windows7.sh
vendored
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION="1.25.6"
|
||||
VERSION="1.25.7"
|
||||
|
||||
mkdir -p $HOME/go
|
||||
cd $HOME/go
|
||||
|
||||
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Check input version
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |-
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
if: ${{ ! (matrix.legacy_win7 || matrix.legacy_go124) }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Setup Go 1.24
|
||||
if: matrix.legacy_go124
|
||||
uses: actions/setup-go@v5
|
||||
@@ -243,7 +243,7 @@ jobs:
|
||||
sudo gem install fpm
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libarchive-tools
|
||||
cp .fpm_systemd .fpm
|
||||
cp .fpm_pacman .fpm
|
||||
fpm -t pacman \
|
||||
-v "$PKG_VERSION" \
|
||||
-p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.pacman }}.pkg.tar.zst" \
|
||||
@@ -300,7 +300,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -380,7 +380,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -479,7 +479,7 @@ jobs:
|
||||
if: matrix.if
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Set tag
|
||||
if: matrix.if
|
||||
run: |-
|
||||
|
||||
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Check input version
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |-
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.6
|
||||
go-version: ~1.25.7
|
||||
- name: Setup Android NDK
|
||||
if: matrix.os == 'android'
|
||||
uses: nttld/setup-ndk@v1
|
||||
|
||||
Submodule clients/android updated: 39e961fcbc...eb87216961
@@ -88,7 +88,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
||||
|
||||
if networkManager != nil {
|
||||
defaultOptions := networkManager.DefaultOptions()
|
||||
if defaultOptions.BindInterface != "" {
|
||||
if defaultOptions.BindInterface != "" && !disableDefaultBind {
|
||||
bindFunc := control.BindToInterface(networkManager.InterfaceFinder(), defaultOptions.BindInterface, -1)
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
@@ -142,8 +142,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
||||
dialer.Timeout = C.TCPConnectTimeout
|
||||
}
|
||||
// TODO: Add an option to customize the keep alive period
|
||||
dialer.KeepAlive = C.TCPKeepAliveInitial
|
||||
dialer.Control = control.Append(dialer.Control, control.SetKeepAlivePeriod(C.TCPKeepAliveInitial, C.TCPKeepAliveInterval))
|
||||
setKeepAliveConfig(&dialer, C.TCPKeepAliveInitial, C.TCPKeepAliveInterval)
|
||||
var udpFragment bool
|
||||
if options.UDPFragment != nil {
|
||||
udpFragment = *options.UDPFragment
|
||||
|
||||
16
common/dialer/default_go123.go
Normal file
16
common/dialer/default_go123.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build go1.23
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func setKeepAliveConfig(dialer *net.Dialer, idle time.Duration, interval time.Duration) {
|
||||
dialer.KeepAliveConfig = net.KeepAliveConfig{
|
||||
Enable: true,
|
||||
Idle: idle,
|
||||
Interval: interval,
|
||||
}
|
||||
}
|
||||
15
common/dialer/default_nongo123.go
Normal file
15
common/dialer/default_nongo123.go
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build !go1.23
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing/common/control"
|
||||
)
|
||||
|
||||
func setKeepAliveConfig(dialer *net.Dialer, idle time.Duration, interval time.Duration) {
|
||||
dialer.KeepAlive = idle
|
||||
dialer.Control = control.Append(dialer.Control, control.SetKeepAlivePeriod(idle, interval))
|
||||
}
|
||||
@@ -144,7 +144,11 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
if c.cache != nil {
|
||||
cond, loaded := c.cacheLock.LoadOrStore(question, make(chan struct{}))
|
||||
if loaded {
|
||||
<-cond
|
||||
select {
|
||||
case <-cond:
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
} else {
|
||||
defer func() {
|
||||
c.cacheLock.Delete(question)
|
||||
@@ -154,7 +158,11 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
} else if c.transportCache != nil {
|
||||
cond, loaded := c.transportCacheLock.LoadOrStore(question, make(chan struct{}))
|
||||
if loaded {
|
||||
<-cond
|
||||
select {
|
||||
case <-cond:
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
} else {
|
||||
defer func() {
|
||||
c.transportCacheLock.Delete(question)
|
||||
|
||||
@@ -378,9 +378,11 @@ func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQ
|
||||
case *R.RuleActionReject:
|
||||
return nil, &R.RejectedError{Cause: action.Error(ctx)}
|
||||
case *R.RuleActionPredefined:
|
||||
responseAddrs = nil
|
||||
if action.Rcode != mDNS.RcodeSuccess {
|
||||
err = RcodeError(action.Rcode)
|
||||
} else {
|
||||
err = nil
|
||||
for _, answer := range action.Answer {
|
||||
switch record := answer.(type) {
|
||||
case *mDNS.A:
|
||||
|
||||
@@ -2,6 +2,38 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.12.23
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.22
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.21
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.20
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.19
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.18
|
||||
|
||||
* Add fallback routing rule for `auto_redirect` **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
Adds a fallback iproute2 rule checked after system default rules (32766: main, 32767: default),
|
||||
ensuring traffic is routed to the sing-box table when no route is found in system tables.
|
||||
|
||||
The rule index can be customized via `auto_redirect_iproute2_fallback_rule_index` (default: 32768).
|
||||
|
||||
#### 1.12.17
|
||||
|
||||
* Update uTLS to v1.8.2 **1**
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.12.18"
|
||||
|
||||
:material-plus: [auto_redirect_iproute2_fallback_rule_index](#auto_redirect_iproute2_fallback_rule_index)
|
||||
|
||||
!!! quote "Changes in sing-box 1.12.0"
|
||||
|
||||
:material-plus: [loopback_address](#loopback_address)
|
||||
@@ -63,6 +67,7 @@ icon: material/new-box
|
||||
"auto_redirect": true,
|
||||
"auto_redirect_input_mark": "0x2023",
|
||||
"auto_redirect_output_mark": "0x2024",
|
||||
"auto_redirect_iproute2_fallback_rule_index": 32768,
|
||||
"loopback_address": [
|
||||
"10.7.0.1"
|
||||
],
|
||||
@@ -278,6 +283,17 @@ Connection output mark used by `auto_redirect`.
|
||||
|
||||
`0x2024` is used by default.
|
||||
|
||||
#### auto_redirect_iproute2_fallback_rule_index
|
||||
|
||||
!!! question "Since sing-box 1.12.18"
|
||||
|
||||
Linux iproute2 fallback rule index generated by `auto_redirect`.
|
||||
|
||||
This rule is checked after system default rules (32766: main, 32767: default),
|
||||
routing traffic to the sing-box table only when no route is found in system tables.
|
||||
|
||||
`32768` is used by default.
|
||||
|
||||
#### loopback_address
|
||||
|
||||
!!! question "Since sing-box 1.12.0"
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.12.18 中的更改"
|
||||
|
||||
:material-plus: [auto_redirect_iproute2_fallback_rule_index](#auto_redirect_iproute2_fallback_rule_index)
|
||||
|
||||
!!! quote "sing-box 1.12.0 中的更改"
|
||||
|
||||
:material-plus: [loopback_address](#loopback_address)
|
||||
@@ -63,6 +67,7 @@ icon: material/new-box
|
||||
"auto_redirect": true,
|
||||
"auto_redirect_input_mark": "0x2023",
|
||||
"auto_redirect_output_mark": "0x2024",
|
||||
"auto_redirect_iproute2_fallback_rule_index": 32768,
|
||||
"loopback_address": [
|
||||
"10.7.0.1"
|
||||
],
|
||||
@@ -277,6 +282,17 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
默认使用 `0x2024`。
|
||||
|
||||
#### auto_redirect_iproute2_fallback_rule_index
|
||||
|
||||
!!! question "自 sing-box 1.12.18 起"
|
||||
|
||||
`auto_redirect` 生成的 iproute2 回退规则索引。
|
||||
|
||||
此规则在系统默认规则(32766: main,32767: default)之后检查,
|
||||
仅当系统路由表中未找到路由时才将流量路由到 sing-box 路由表。
|
||||
|
||||
默认使用 `32768`。
|
||||
|
||||
#### loopback_address
|
||||
|
||||
!!! question "自 sing-box 1.12.0 起"
|
||||
|
||||
6
go.mod
6
go.mod
@@ -27,13 +27,13 @@ require (
|
||||
github.com/sagernet/gomobile v0.1.8
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
||||
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3
|
||||
github.com/sagernet/sing v0.7.14
|
||||
github.com/sagernet/sing v0.7.18
|
||||
github.com/sagernet/sing-mux v0.3.4
|
||||
github.com/sagernet/sing-quic v0.5.2
|
||||
github.com/sagernet/sing-quic v0.5.3
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
github.com/sagernet/sing-tun v0.7.3
|
||||
github.com/sagernet/sing-tun v0.7.11
|
||||
github.com/sagernet/sing-vmess v0.2.7
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.2
|
||||
|
||||
14
go.sum
14
go.sum
@@ -123,8 +123,6 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 h1:Ui+/2s5Qz0lSnDUBmEL12M5Oi/PzvFxGTNohm8ZcsmE=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4=
|
||||
github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
|
||||
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
||||
@@ -167,20 +165,20 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 h1:ySqffGm82rPqI1TUPqmtHIYd12pfEGScygnOxjTL56w=
|
||||
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/sing v0.7.14 h1:5QQRDCUvYNOMyVp3LuK/hYEBAIv0VsbD3x/l9zH467s=
|
||||
github.com/sagernet/sing v0.7.14/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.18 h1:iZHkaru1/MoHugx3G+9S3WG4owMewKO/KvieE2Pzk4E=
|
||||
github.com/sagernet/sing v0.7.18/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s=
|
||||
github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-quic v0.5.2 h1:I3vlfRImhr0uLwRS3b3ib70RMG9FcXtOKKUDz3eKRWc=
|
||||
github.com/sagernet/sing-quic v0.5.2/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI=
|
||||
github.com/sagernet/sing-quic v0.5.3 h1:K937DKJN98xqyztijRkLJqbBfyV4rEZcYxFyP3EBikU=
|
||||
github.com/sagernet/sing-quic v0.5.3/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.7.3 h1:MFnAir+l24ElEyxdfwtY8mqvUUL9nPnL9TDYLkOmVes=
|
||||
github.com/sagernet/sing-tun v0.7.3/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM=
|
||||
github.com/sagernet/sing-tun v0.7.11 h1:qB7jy8JKqXg73fYBsDkBSy4ulRSbLrFut0e+y+QPhqU=
|
||||
github.com/sagernet/sing-tun v0.7.11/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM=
|
||||
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
|
||||
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
||||
|
||||
@@ -11,33 +11,34 @@ import (
|
||||
)
|
||||
|
||||
type TunInboundOptions struct {
|
||||
InterfaceName string `json:"interface_name,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
Address badoption.Listable[netip.Prefix] `json:"address,omitempty"`
|
||||
AutoRoute bool `json:"auto_route,omitempty"`
|
||||
IPRoute2TableIndex int `json:"iproute2_table_index,omitempty"`
|
||||
IPRoute2RuleIndex int `json:"iproute2_rule_index,omitempty"`
|
||||
AutoRedirect bool `json:"auto_redirect,omitempty"`
|
||||
AutoRedirectInputMark FwMark `json:"auto_redirect_input_mark,omitempty"`
|
||||
AutoRedirectOutputMark FwMark `json:"auto_redirect_output_mark,omitempty"`
|
||||
LoopbackAddress badoption.Listable[netip.Addr] `json:"loopback_address,omitempty"`
|
||||
StrictRoute bool `json:"strict_route,omitempty"`
|
||||
RouteAddress badoption.Listable[netip.Prefix] `json:"route_address,omitempty"`
|
||||
RouteAddressSet badoption.Listable[string] `json:"route_address_set,omitempty"`
|
||||
RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"route_exclude_address,omitempty"`
|
||||
RouteExcludeAddressSet badoption.Listable[string] `json:"route_exclude_address_set,omitempty"`
|
||||
IncludeInterface badoption.Listable[string] `json:"include_interface,omitempty"`
|
||||
ExcludeInterface badoption.Listable[string] `json:"exclude_interface,omitempty"`
|
||||
IncludeUID badoption.Listable[uint32] `json:"include_uid,omitempty"`
|
||||
IncludeUIDRange badoption.Listable[string] `json:"include_uid_range,omitempty"`
|
||||
ExcludeUID badoption.Listable[uint32] `json:"exclude_uid,omitempty"`
|
||||
ExcludeUIDRange badoption.Listable[string] `json:"exclude_uid_range,omitempty"`
|
||||
IncludeAndroidUser badoption.Listable[int] `json:"include_android_user,omitempty"`
|
||||
IncludePackage badoption.Listable[string] `json:"include_package,omitempty"`
|
||||
ExcludePackage badoption.Listable[string] `json:"exclude_package,omitempty"`
|
||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||
Stack string `json:"stack,omitempty"`
|
||||
Platform *TunPlatformOptions `json:"platform,omitempty"`
|
||||
InterfaceName string `json:"interface_name,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
Address badoption.Listable[netip.Prefix] `json:"address,omitempty"`
|
||||
AutoRoute bool `json:"auto_route,omitempty"`
|
||||
IPRoute2TableIndex int `json:"iproute2_table_index,omitempty"`
|
||||
IPRoute2RuleIndex int `json:"iproute2_rule_index,omitempty"`
|
||||
AutoRedirect bool `json:"auto_redirect,omitempty"`
|
||||
AutoRedirectInputMark FwMark `json:"auto_redirect_input_mark,omitempty"`
|
||||
AutoRedirectOutputMark FwMark `json:"auto_redirect_output_mark,omitempty"`
|
||||
AutoRedirectIPRoute2FallbackRuleIndex int `json:"auto_redirect_iproute2_fallback_rule_index,omitempty"`
|
||||
LoopbackAddress badoption.Listable[netip.Addr] `json:"loopback_address,omitempty"`
|
||||
StrictRoute bool `json:"strict_route,omitempty"`
|
||||
RouteAddress badoption.Listable[netip.Prefix] `json:"route_address,omitempty"`
|
||||
RouteAddressSet badoption.Listable[string] `json:"route_address_set,omitempty"`
|
||||
RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"route_exclude_address,omitempty"`
|
||||
RouteExcludeAddressSet badoption.Listable[string] `json:"route_exclude_address_set,omitempty"`
|
||||
IncludeInterface badoption.Listable[string] `json:"include_interface,omitempty"`
|
||||
ExcludeInterface badoption.Listable[string] `json:"exclude_interface,omitempty"`
|
||||
IncludeUID badoption.Listable[uint32] `json:"include_uid,omitempty"`
|
||||
IncludeUIDRange badoption.Listable[string] `json:"include_uid_range,omitempty"`
|
||||
ExcludeUID badoption.Listable[uint32] `json:"exclude_uid,omitempty"`
|
||||
ExcludeUIDRange badoption.Listable[string] `json:"exclude_uid_range,omitempty"`
|
||||
IncludeAndroidUser badoption.Listable[int] `json:"include_android_user,omitempty"`
|
||||
IncludePackage badoption.Listable[string] `json:"include_package,omitempty"`
|
||||
ExcludePackage badoption.Listable[string] `json:"exclude_package,omitempty"`
|
||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||
Stack string `json:"stack,omitempty"`
|
||||
Platform *TunPlatformOptions `json:"platform,omitempty"`
|
||||
InboundOptions
|
||||
|
||||
// Deprecated: removed
|
||||
|
||||
@@ -95,6 +95,7 @@ func (p *paddingConn) writeWithPadding(writer io.Writer, data []byte) (n int, er
|
||||
binary.BigEndian.PutUint16(header, uint16(len(data)))
|
||||
header[2] = byte(paddingSize)
|
||||
common.Must1(buffer.Write(data))
|
||||
buffer.Extend(paddingSize)
|
||||
_, err = writer.Write(buffer.Bytes())
|
||||
if err == nil {
|
||||
n = len(data)
|
||||
|
||||
@@ -174,6 +174,10 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
if ruleIndex == 0 {
|
||||
ruleIndex = tun.DefaultIPRoute2RuleIndex
|
||||
}
|
||||
autoRedirectFallbackRuleIndex := options.AutoRedirectIPRoute2FallbackRuleIndex
|
||||
if autoRedirectFallbackRuleIndex == 0 {
|
||||
autoRedirectFallbackRuleIndex = tun.DefaultIPRoute2AutoRedirectFallbackRuleIndex
|
||||
}
|
||||
inputMark := uint32(options.AutoRedirectInputMark)
|
||||
if inputMark == 0 {
|
||||
inputMark = tun.DefaultAutoRedirectInputMark
|
||||
@@ -192,32 +196,33 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
logger: logger,
|
||||
inboundOptions: options.InboundOptions,
|
||||
tunOptions: tun.Options{
|
||||
Name: options.InterfaceName,
|
||||
MTU: tunMTU,
|
||||
GSO: enableGSO,
|
||||
Inet4Address: inet4Address,
|
||||
Inet6Address: inet6Address,
|
||||
AutoRoute: options.AutoRoute,
|
||||
IPRoute2TableIndex: tableIndex,
|
||||
IPRoute2RuleIndex: ruleIndex,
|
||||
AutoRedirectInputMark: inputMark,
|
||||
AutoRedirectOutputMark: outputMark,
|
||||
Inet4LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is4),
|
||||
Inet6LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is6),
|
||||
StrictRoute: options.StrictRoute,
|
||||
IncludeInterface: options.IncludeInterface,
|
||||
ExcludeInterface: options.ExcludeInterface,
|
||||
Inet4RouteAddress: inet4RouteAddress,
|
||||
Inet6RouteAddress: inet6RouteAddress,
|
||||
Inet4RouteExcludeAddress: inet4RouteExcludeAddress,
|
||||
Inet6RouteExcludeAddress: inet6RouteExcludeAddress,
|
||||
IncludeUID: includeUID,
|
||||
ExcludeUID: excludeUID,
|
||||
IncludeAndroidUser: options.IncludeAndroidUser,
|
||||
IncludePackage: options.IncludePackage,
|
||||
ExcludePackage: options.ExcludePackage,
|
||||
InterfaceMonitor: networkManager.InterfaceMonitor(),
|
||||
EXP_MultiPendingPackets: multiPendingPackets,
|
||||
Name: options.InterfaceName,
|
||||
MTU: tunMTU,
|
||||
GSO: enableGSO,
|
||||
Inet4Address: inet4Address,
|
||||
Inet6Address: inet6Address,
|
||||
AutoRoute: options.AutoRoute,
|
||||
IPRoute2TableIndex: tableIndex,
|
||||
IPRoute2RuleIndex: ruleIndex,
|
||||
IPRoute2AutoRedirectFallbackRuleIndex: autoRedirectFallbackRuleIndex,
|
||||
AutoRedirectInputMark: inputMark,
|
||||
AutoRedirectOutputMark: outputMark,
|
||||
Inet4LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is4),
|
||||
Inet6LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is6),
|
||||
StrictRoute: options.StrictRoute,
|
||||
IncludeInterface: options.IncludeInterface,
|
||||
ExcludeInterface: options.ExcludeInterface,
|
||||
Inet4RouteAddress: inet4RouteAddress,
|
||||
Inet6RouteAddress: inet6RouteAddress,
|
||||
Inet4RouteExcludeAddress: inet4RouteExcludeAddress,
|
||||
Inet6RouteExcludeAddress: inet6RouteExcludeAddress,
|
||||
IncludeUID: includeUID,
|
||||
ExcludeUID: excludeUID,
|
||||
IncludeAndroidUser: options.IncludeAndroidUser,
|
||||
IncludePackage: options.IncludePackage,
|
||||
ExcludePackage: options.ExcludePackage,
|
||||
InterfaceMonitor: networkManager.InterfaceMonitor(),
|
||||
EXP_MultiPendingPackets: multiPendingPackets,
|
||||
},
|
||||
udpTimeout: udpTimeout,
|
||||
stack: options.Stack,
|
||||
@@ -319,7 +324,6 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
t.tunOptions.Name = tun.CalculateInterfaceName("")
|
||||
}
|
||||
if t.platformInterface == nil {
|
||||
t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
|
||||
for _, routeRuleSet := range t.routeRuleSet {
|
||||
ipSets := routeRuleSet.ExtractIPSet()
|
||||
if len(ipSets) == 0 {
|
||||
@@ -331,7 +335,6 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
}
|
||||
}
|
||||
t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
|
||||
for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
|
||||
ipSets := routeExcludeRuleSet.ExtractIPSet()
|
||||
if len(ipSets) == 0 {
|
||||
|
||||
@@ -107,9 +107,7 @@ func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
|
||||
}
|
||||
|
||||
for _, item := range r.items {
|
||||
if _, isRuleSet := item.(*RuleSetItem); !isRuleSet {
|
||||
metadata.DidMatch = true
|
||||
}
|
||||
metadata.DidMatch = true
|
||||
if !item.Match(metadata) {
|
||||
return r.invert
|
||||
}
|
||||
|
||||
157
route/rule/rule_abstract_test.go
Normal file
157
route/rule/rule_abstract_test.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
type fakeRuleSet struct {
|
||||
matched bool
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) Name() string {
|
||||
return "fake-rule-set"
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) StartContext(context.Context, *adapter.HTTPStartContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) PostStart() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) Metadata() adapter.RuleSetMetadata {
|
||||
return adapter.RuleSetMetadata{}
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) ExtractIPSet() []*netipx.IPSet {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) IncRef() {}
|
||||
|
||||
func (f *fakeRuleSet) DecRef() {}
|
||||
|
||||
func (f *fakeRuleSet) Cleanup() {}
|
||||
|
||||
func (f *fakeRuleSet) RegisterCallback(adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) UnregisterCallback(*list.Element[adapter.RuleSetUpdateCallback]) {}
|
||||
|
||||
func (f *fakeRuleSet) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) Match(*adapter.InboundContext) bool {
|
||||
return f.matched
|
||||
}
|
||||
|
||||
func (f *fakeRuleSet) String() string {
|
||||
return "fake-rule-set"
|
||||
}
|
||||
|
||||
type fakeRuleItem struct {
|
||||
matched bool
|
||||
}
|
||||
|
||||
func (f *fakeRuleItem) Match(*adapter.InboundContext) bool {
|
||||
return f.matched
|
||||
}
|
||||
|
||||
func (f *fakeRuleItem) String() string {
|
||||
return "fake-rule-item"
|
||||
}
|
||||
|
||||
func newRuleSetOnlyRule(ruleSetMatched bool, invert bool) *DefaultRule {
|
||||
ruleSetItem := &RuleSetItem{
|
||||
setList: []adapter.RuleSet{&fakeRuleSet{matched: ruleSetMatched}},
|
||||
}
|
||||
return &DefaultRule{
|
||||
abstractDefaultRule: abstractDefaultRule{
|
||||
items: []RuleItem{ruleSetItem},
|
||||
allItems: []RuleItem{ruleSetItem},
|
||||
invert: invert,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newSingleItemRule(matched bool) *DefaultRule {
|
||||
item := &fakeRuleItem{matched: matched}
|
||||
return &DefaultRule{
|
||||
abstractDefaultRule: abstractDefaultRule{
|
||||
items: []RuleItem{item},
|
||||
allItems: []RuleItem{item},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbstractDefaultRule_RuleSetOnly_InvertFalse(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.True(t, newRuleSetOnlyRule(true, false).Match(&adapter.InboundContext{}))
|
||||
require.False(t, newRuleSetOnlyRule(false, false).Match(&adapter.InboundContext{}))
|
||||
}
|
||||
|
||||
func TestAbstractDefaultRule_RuleSetOnly_InvertTrue(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.False(t, newRuleSetOnlyRule(true, true).Match(&adapter.InboundContext{}))
|
||||
require.True(t, newRuleSetOnlyRule(false, true).Match(&adapter.InboundContext{}))
|
||||
}
|
||||
|
||||
func TestAbstractLogicalRule_And_WithRuleSetInvert(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
name string
|
||||
aMatched bool
|
||||
ruleSetBMatch bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "A true B true",
|
||||
aMatched: true,
|
||||
ruleSetBMatch: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "A true B false",
|
||||
aMatched: true,
|
||||
ruleSetBMatch: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "A false B true",
|
||||
aMatched: false,
|
||||
ruleSetBMatch: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "A false B false",
|
||||
aMatched: false,
|
||||
ruleSetBMatch: false,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
logicalRule := &abstractLogicalRule{
|
||||
mode: C.LogicalTypeAnd,
|
||||
rules: []adapter.HeadlessRule{
|
||||
newSingleItemRule(testCase.aMatched),
|
||||
newRuleSetOnlyRule(testCase.ruleSetBMatch, true),
|
||||
},
|
||||
}
|
||||
require.Equal(t, testCase.expected, logicalRule.Match(&adapter.InboundContext{}))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func (w *systemDevice) Start() error {
|
||||
w.options.Logger.Info("started at ", w.options.Name)
|
||||
w.device = tunInterface
|
||||
batchTUN, isBatchTUN := tunInterface.(tun.LinuxTUN)
|
||||
if isBatchTUN {
|
||||
if isBatchTUN && batchTUN.BatchSize() > 1 {
|
||||
w.batchDevice = batchTUN
|
||||
}
|
||||
w.events <- wgTun.EventUp
|
||||
|
||||
Reference in New Issue
Block a user