Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae47deab58 | |||
| c0341118ec | |||
| 116492cb46 | |||
| 2d8d9a1959 |
@@ -16,40 +16,30 @@ import (
|
||||
)
|
||||
|
||||
type LinuxSystemProxy struct {
|
||||
hasGSettings bool
|
||||
kWriteConfigCmd string
|
||||
sudoUser string
|
||||
serverAddr M.Socksaddr
|
||||
supportSOCKS bool
|
||||
isEnabled bool
|
||||
hasGSettings bool
|
||||
hasKWriteConfig5 bool
|
||||
sudoUser string
|
||||
serverAddr M.Socksaddr
|
||||
supportSOCKS bool
|
||||
isEnabled bool
|
||||
}
|
||||
|
||||
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*LinuxSystemProxy, error) {
|
||||
hasGSettings := common.Error(exec.LookPath("gsettings")) == nil
|
||||
kWriteConfigCmds := []string{
|
||||
"kwriteconfig5",
|
||||
"kwriteconfig6",
|
||||
}
|
||||
var kWriteConfigCmd string
|
||||
for _, cmd := range kWriteConfigCmds {
|
||||
if common.Error(exec.LookPath(cmd)) == nil {
|
||||
kWriteConfigCmd = cmd
|
||||
break
|
||||
}
|
||||
}
|
||||
hasKWriteConfig5 := common.Error(exec.LookPath("kwriteconfig5")) == nil
|
||||
var sudoUser string
|
||||
if os.Getuid() == 0 {
|
||||
sudoUser = os.Getenv("SUDO_USER")
|
||||
}
|
||||
if !hasGSettings && kWriteConfigCmd == "" {
|
||||
if !hasGSettings && !hasKWriteConfig5 {
|
||||
return nil, E.New("unsupported desktop environment")
|
||||
}
|
||||
return &LinuxSystemProxy{
|
||||
hasGSettings: hasGSettings,
|
||||
kWriteConfigCmd: kWriteConfigCmd,
|
||||
sudoUser: sudoUser,
|
||||
serverAddr: serverAddr,
|
||||
supportSOCKS: supportSOCKS,
|
||||
hasGSettings: hasGSettings,
|
||||
hasKWriteConfig5: hasKWriteConfig5,
|
||||
sudoUser: sudoUser,
|
||||
serverAddr: serverAddr,
|
||||
supportSOCKS: supportSOCKS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -80,8 +70,8 @@ func (p *LinuxSystemProxy) Enable() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if p.kWriteConfigCmd != "" {
|
||||
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
|
||||
if p.hasKWriteConfig5 {
|
||||
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,7 +83,7 @@ func (p *LinuxSystemProxy) Enable() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
|
||||
err = p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -113,8 +103,8 @@ func (p *LinuxSystemProxy) Disable() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if p.kWriteConfigCmd != "" {
|
||||
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
|
||||
if p.hasKWriteConfig5 {
|
||||
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -160,7 +150,7 @@ func (p *LinuxSystemProxy) setKDEProxy(proxyTypes ...string) error {
|
||||
proxyUrl = "http://" + p.serverAddr.String()
|
||||
}
|
||||
err := p.runAsUser(
|
||||
p.kWriteConfigCmd,
|
||||
"kwriteconfig5",
|
||||
"--file",
|
||||
"kioslaverc",
|
||||
"--group",
|
||||
|
||||
+1
-40
@@ -2,49 +2,10 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.10.0-alpha.6
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.10.0-alpha.5
|
||||
|
||||
* Improve auto-redirect **1**
|
||||
|
||||
**1**:
|
||||
|
||||
nftables support and DNS hijacking has been added.
|
||||
|
||||
Tun inbounds with `auto_route` and `auto_redirect` now works as expected on routers **without intervention**.
|
||||
|
||||
#### 1.10.0-alpha.4
|
||||
|
||||
* Fix auto-redirect **1**
|
||||
* Improve auto-route on linux **2**
|
||||
|
||||
**1**:
|
||||
|
||||
Tun inbounds with `auto_route` and `auto_redirect` now works as expected on routers.
|
||||
|
||||
**2**:
|
||||
|
||||
Tun inbounds with `auto_route` and `strict_route` now works as expected on routers and servers,
|
||||
but the usages of [exclude_interface](/configuration/inbound/tun/#exclude_interface) need to be updated.
|
||||
|
||||
#### 1.10.0-alpha.2
|
||||
|
||||
* Move auto-redirect to Tun **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
Linux support are added.
|
||||
|
||||
See [Tun](/configuration/inbound/tun/#auto_redirect).
|
||||
|
||||
#### 1.10.0-alpha.1
|
||||
|
||||
* Add tailing comma support in JSON configuration
|
||||
* Add simple auto-redirect for Android **1**
|
||||
* Add simple auto redirect for Android **1**
|
||||
* Add BitTorrent sniffer **2**
|
||||
|
||||
**1**:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! question "自 sing-box 1.8.0 起"
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [auto_redirect](#auto_redirect)
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux and macOS.
|
||||
@@ -9,6 +17,11 @@
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
|
||||
"auto_redirect": {
|
||||
"enabled": false,
|
||||
"continue_on_no_permission": false
|
||||
},
|
||||
|
||||
... // Listen Fields
|
||||
}
|
||||
```
|
||||
@@ -16,3 +29,23 @@
|
||||
### Listen Fields
|
||||
|
||||
See [Listen Fields](/configuration/shared/listen/) for details.
|
||||
|
||||
### Fields
|
||||
|
||||
#### `auto_redirect`
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Android.
|
||||
|
||||
Automatically add iptables nat rules to hijack **IPv4 TCP** connections.
|
||||
|
||||
It is expected to run with the Android graphical client (it will attempt to su at runtime).
|
||||
|
||||
#### `auto_redirect.continue_on_no_permission`
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
Ignore errors when the Android device is not rooted or is denied root access.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.10.0 中的更改"
|
||||
|
||||
:material-plus: [auto_redirect](#auto_redirect)
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux 和 macOS。
|
||||
@@ -9,9 +17,35 @@
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
|
||||
"auto_redirect": {
|
||||
"enabled": false,
|
||||
"continue_on_no_permission": false
|
||||
},
|
||||
|
||||
... // 监听字段
|
||||
}
|
||||
```
|
||||
|
||||
### 监听字段
|
||||
|
||||
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||
|
||||
### 字段
|
||||
|
||||
#### `auto_redirect`
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Android。
|
||||
|
||||
自动添加 iptables nat 规则以劫持 **IPv4 TCP** 连接。
|
||||
|
||||
它预计与 Android 图形客户端一起运行(将在运行时尝试 su)。
|
||||
|
||||
#### `auto_redirect.continue_on_no_permission`
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
当 Android 设备未获得 root 权限或 root 访问权限被拒绝时,忽略错误。
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.10.0"
|
||||
|
||||
:material-plus: [auto_redirect](#auto_redirect)
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
|
||||
@@ -33,7 +29,6 @@ icon: material/new-box
|
||||
"gso": false,
|
||||
"auto_route": true,
|
||||
"strict_route": true,
|
||||
"auto_redirect": false,
|
||||
"inet4_route_address": [
|
||||
"0.0.0.0/1",
|
||||
"128.0.0.0/1"
|
||||
@@ -150,10 +145,9 @@ Enforce strict routing rules when `auto_route` is enabled:
|
||||
*In Linux*:
|
||||
|
||||
* Let unsupported network unreachable
|
||||
* Make ICMP traffic route to tun instead of upstream interfaces
|
||||
* Route all connections to tun
|
||||
|
||||
It prevents IP address leaks and makes DNS hijacking work on Android.
|
||||
It prevents address leaks and makes DNS hijacking work on Android.
|
||||
|
||||
*In Windows*:
|
||||
|
||||
@@ -162,25 +156,6 @@ It prevents IP address leaks and makes DNS hijacking work on Android.
|
||||
|
||||
It may prevent some applications (such as VirtualBox) from working properly in certain situations.
|
||||
|
||||
#### auto_redirect
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux.
|
||||
|
||||
Automatically configure iptables/nftables to redirect connections.
|
||||
|
||||
*In Android*:
|
||||
|
||||
Only local connections are forwarded. To share your VPN connection over hotspot or repeater,
|
||||
use [VPNHotspot](https://github.com/Mygod/VPNHotspot).
|
||||
|
||||
*In Linux*:
|
||||
|
||||
`auto_route` with `auto_redirect` now works as expected on routers **without intervention**.
|
||||
|
||||
#### inet4_route_address
|
||||
|
||||
Use custom routes instead of default when `auto_route` is enabled.
|
||||
@@ -239,10 +214,6 @@ Conflict with `exclude_interface`.
|
||||
|
||||
#### exclude_interface
|
||||
|
||||
!!! warning ""
|
||||
|
||||
When `strict_route` enabled, return traffic to excluded interfaces will not be automatically excluded, so add them as well (example: `br-lan` and `pppoe-wan`).
|
||||
|
||||
Exclude interfaces in route.
|
||||
|
||||
Conflict with `include_interface`.
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.10.0 中的更改"
|
||||
|
||||
:material-plus: [auto_redirect](#auto_redirect)
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
|
||||
@@ -33,7 +29,6 @@ icon: material/new-box
|
||||
"gso": false,
|
||||
"auto_route": true,
|
||||
"strict_route": true,
|
||||
"auto_redirect": false,
|
||||
"inet4_route_address": [
|
||||
"0.0.0.0/1",
|
||||
"128.0.0.0/1"
|
||||
@@ -150,10 +145,9 @@ tun 接口的 IPv6 前缀。
|
||||
*在 Linux 中*:
|
||||
|
||||
* 让不支持的网络无法到达
|
||||
* 使 ICMP 流量路由到 tun 而不是上游接口
|
||||
* 将所有连接路由到 tun
|
||||
|
||||
它可以防止 IP 地址泄漏,并使 DNS 劫持在 Android 上工作。
|
||||
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作。
|
||||
|
||||
*在 Windows 中*:
|
||||
|
||||
@@ -163,24 +157,6 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
它可能会使某些应用程序(如 VirtualBox)在某些情况下无法正常工作。
|
||||
|
||||
#### auto_redirect
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux。
|
||||
|
||||
自动配置 iptables 以重定向 TCP 连接。
|
||||
|
||||
*在 Android 中*:
|
||||
|
||||
仅转发本地 IPv4 连接。 要通过热点或中继共享您的 VPN 连接,请使用 [VPNHotspot](https://github.com/Mygod/VPNHotspot)。
|
||||
|
||||
*在 Linux 中*:
|
||||
|
||||
带有 `auto_redirect `的 `auto_route` 现在可以在路由器上按预期工作,**无需干预**。
|
||||
|
||||
#### inet4_route_address
|
||||
|
||||
启用 `auto_route` 时使用自定义路由而不是默认路由。
|
||||
@@ -235,10 +211,6 @@ TCP/IP 栈。
|
||||
|
||||
#### exclude_interface
|
||||
|
||||
!!! warning ""
|
||||
|
||||
当 `strict_route` 启用,到被排除接口的回程流量将不会被自动排除,因此也要添加它们(例:`br-lan` 与 `pppoe-wan`)。
|
||||
|
||||
排除路由的接口。
|
||||
|
||||
与 `include_interface` 冲突。
|
||||
|
||||
@@ -4,6 +4,10 @@ icon: material/arrange-bring-forward
|
||||
|
||||
## 1.9.0
|
||||
|
||||
!!! warning "Unstable"
|
||||
|
||||
This version is still under development, and the following migration guide may be changed in the future.
|
||||
|
||||
### `domain_suffix` behavior update
|
||||
|
||||
For historical reasons, sing-box's `domain_suffix` rule matches literal prefixes instead of the same as other projects.
|
||||
|
||||
@@ -4,6 +4,10 @@ icon: material/arrange-bring-forward
|
||||
|
||||
## 1.9.0
|
||||
|
||||
!!! warning "不稳定的"
|
||||
|
||||
该版本仍在开发中,迁移指南可能将在未来更改。
|
||||
|
||||
### `domain_suffix` 行为更新
|
||||
|
||||
由于历史原因,sing-box 的 `domain_suffix` 规则匹配字面前缀,而不与其他项目相同。
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/process"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
@@ -97,6 +98,14 @@ func (s *platformInterfaceStub) FindProcessInfo(ctx context.Context, network str
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) PerAppProxyList() ([]uint32, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) PerAppProxyMode() int32 {
|
||||
return platform.PerAppProxyModeDisabled
|
||||
}
|
||||
|
||||
type interfaceMonitorStub struct{}
|
||||
|
||||
func (s *interfaceMonitorStub) Start() error {
|
||||
|
||||
@@ -22,6 +22,8 @@ type PlatformInterface interface {
|
||||
IncludeAllNetworks() bool
|
||||
ReadWIFIState() *WIFIState
|
||||
ClearDNSCache()
|
||||
PerAppProxyList() (IntegerIterator, error)
|
||||
PerAppProxyMode() int32
|
||||
}
|
||||
|
||||
type TunInterface interface {
|
||||
@@ -54,6 +56,11 @@ type NetworkInterfaceIterator interface {
|
||||
HasNext() bool
|
||||
}
|
||||
|
||||
type IntegerIterator interface {
|
||||
Next() int32
|
||||
HasNext() bool
|
||||
}
|
||||
|
||||
type OnDemandRule interface {
|
||||
Target() int32
|
||||
DNSSearchDomainMatch() StringIterator
|
||||
|
||||
@@ -11,6 +11,12 @@ import (
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
PerAppProxyModeDisabled int32 = iota
|
||||
PerAppProxyModeExclude
|
||||
PerAppProxyModeInclude
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Initialize(ctx context.Context, router adapter.Router) error
|
||||
UsePlatformAutoDetectInterfaceControl() bool
|
||||
@@ -24,5 +30,7 @@ type Interface interface {
|
||||
IncludeAllNetworks() bool
|
||||
ClearDNSCache()
|
||||
ReadWIFIState() adapter.WIFIState
|
||||
PerAppProxyList() ([]uint32, error)
|
||||
PerAppProxyMode() int32
|
||||
process.Searcher
|
||||
}
|
||||
|
||||
@@ -229,6 +229,18 @@ func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
|
||||
return (adapter.WIFIState)(*wifiState)
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) PerAppProxyList() ([]uint32, error) {
|
||||
uidIterator, err := w.iif.PerAppProxyList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return common.Map(iteratorToArray[int32](uidIterator), func(it int32) uint32 { return uint32(it) }), nil
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) PerAppProxyMode() int32 {
|
||||
return w.iif.PerAppProxyMode()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) DisableColors() bool {
|
||||
return runtime.GOOS != "android"
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ require (
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
||||
github.com/sagernet/quic-go v0.43.1-beta.1
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.5.0-alpha.8
|
||||
github.com/sagernet/sing v0.5.0-alpha.4
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.18
|
||||
github.com/sagernet/sing-mux v0.2.0
|
||||
github.com/sagernet/sing-quic v0.2.0-beta.5
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.5
|
||||
github.com/sagernet/sing-tun v0.3.0-beta.6
|
||||
github.com/sagernet/sing-vmess v0.1.8
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6
|
||||
@@ -65,7 +65,6 @@ require (
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
@@ -73,18 +72,16 @@ require (
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/libdns/libdns v0.2.2 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.2 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
@@ -94,6 +91,7 @@ require (
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.21.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
)
|
||||
|
||||
@@ -40,7 +40,6 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
@@ -58,6 +57,9 @@ github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6K
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ=
|
||||
github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE=
|
||||
github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054=
|
||||
@@ -67,14 +69,12 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
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.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||
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=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
||||
@@ -101,15 +101,13 @@ github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.2 h1:yKqMl4Dpb6nKxAmlE6fXjJRlLO2c1f2wyNFBg4hBr8w=
|
||||
github.com/sagernet/nftables v0.3.0-beta.2/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.43.1-beta.1 h1:alizUjpvWYcz08dBCQsULOd+1xu0o7UtlyYf6SLbRNg=
|
||||
github.com/sagernet/quic-go v0.43.1-beta.1/go.mod h1:BkrQYeop7Jx3hN3TW8/76CXcdhYiNPyYEBL/BVJ1ifc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.5.0-alpha.8 h1:2KtzBvKP6hwknsi/G6H4vRgR4it31HQ6quLb0Woze7c=
|
||||
github.com/sagernet/sing v0.5.0-alpha.8/go.mod h1:Xh4KO9nGdvm4K/LVg9Xn9jSxJdqe9KcXbAzNC1S2qfw=
|
||||
github.com/sagernet/sing v0.5.0-alpha.4 h1:8ljxrEq1BMcDuGe8FxoeUGasPUXQsIywpUusGrlGkQ0=
|
||||
github.com/sagernet/sing v0.5.0-alpha.4/go.mod h1:Xh4KO9nGdvm4K/LVg9Xn9jSxJdqe9KcXbAzNC1S2qfw=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.18 h1:6vzXZThRdA7YUzBOpSbUT48XRumtl/KIpIHFSOP0za8=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.18/go.mod h1:k/dmFcQpg6+m08gC1yQBy+13+QkuLqpKr4bIreq4U24=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
@@ -122,8 +120,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
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.4.0-beta.5 h1:VuTpCPFxBOsWn3ZbTYDEUM/dHhbDBvrViSJOgI8qGAE=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.5/go.mod h1:X9taVYeJXEtK9v6BpS1V/gUXTwY4nQKH4iYDLX1JUXY=
|
||||
github.com/sagernet/sing-tun v0.3.0-beta.6 h1:L11kMrM7UfUW0pzQiU66Fffh4o86KZc1SFGbkYi8Ma8=
|
||||
github.com/sagernet/sing-tun v0.3.0-beta.6/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
|
||||
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-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
@@ -148,8 +146,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA=
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
@@ -178,6 +176,7 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -206,8 +205,9 @@ google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
|
||||
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, o
|
||||
case C.TypeTun:
|
||||
return NewTun(ctx, router, logger, options.Tag, options.TunOptions, platformInterface)
|
||||
case C.TypeRedirect:
|
||||
return NewRedirect(ctx, router, logger, options.Tag, options.RedirectOptions), nil
|
||||
return NewRedirect(ctx, router, logger, options.Tag, options.RedirectOptions, platformInterface)
|
||||
case C.TypeTProxy:
|
||||
return NewTProxy(ctx, router, logger, options.Tag, options.TProxyOptions), nil
|
||||
case C.TypeDirect:
|
||||
|
||||
+157
-3
@@ -2,25 +2,39 @@ package inbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/redir"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type Redirect struct {
|
||||
myInboundAdapter
|
||||
platformInterface platform.Interface
|
||||
autoRedirect option.AutoRedirectOptions
|
||||
needSu bool
|
||||
suPath string
|
||||
}
|
||||
|
||||
func NewRedirect(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.RedirectInboundOptions) *Redirect {
|
||||
func NewRedirect(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.RedirectInboundOptions, platformInterface platform.Interface) (*Redirect, error) {
|
||||
redirect := &Redirect{
|
||||
myInboundAdapter{
|
||||
myInboundAdapter: myInboundAdapter{
|
||||
protocol: C.TypeRedirect,
|
||||
network: []string{N.NetworkTCP},
|
||||
ctx: ctx,
|
||||
@@ -29,9 +43,28 @@ func NewRedirect(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
tag: tag,
|
||||
listenOptions: options.ListenOptions,
|
||||
},
|
||||
platformInterface: platformInterface,
|
||||
autoRedirect: common.PtrValueOrDefault(options.AutoRedirect),
|
||||
}
|
||||
if redirect.autoRedirect.Enabled {
|
||||
if !C.IsAndroid {
|
||||
return nil, E.New("auto redirect is only supported on Android")
|
||||
}
|
||||
userId := os.Getuid()
|
||||
if userId != 0 {
|
||||
suPath, err := exec.LookPath("/bin/su")
|
||||
if err == nil {
|
||||
redirect.needSu = true
|
||||
redirect.suPath = suPath
|
||||
} else if redirect.autoRedirect.ContinueOnNoPermission {
|
||||
redirect.autoRedirect.Enabled = false
|
||||
} else {
|
||||
return nil, E.Extend(E.Cause(err, "root permission is required for auto redirect"), os.Getenv("PATH"))
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect.connHandler = redirect
|
||||
return redirect
|
||||
return redirect, nil
|
||||
}
|
||||
|
||||
func (r *Redirect) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
@@ -42,3 +75,124 @@ func (r *Redirect) NewConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||
metadata.Destination = M.SocksaddrFromNetIP(destination)
|
||||
return r.newConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
func (r *Redirect) Start() error {
|
||||
err := r.myInboundAdapter.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.autoRedirect.Enabled {
|
||||
r.cleanupRedirect()
|
||||
err = r.setupRedirect()
|
||||
if err != nil {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) && exitError.ExitCode() == 13 && r.autoRedirect.ContinueOnNoPermission {
|
||||
r.logger.Error(E.Cause(err, "setup auto redirect"))
|
||||
return nil
|
||||
}
|
||||
r.cleanupRedirect()
|
||||
return E.Cause(err, "setup auto redirect")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Redirect) Close() error {
|
||||
if r.autoRedirect.Enabled {
|
||||
r.cleanupRedirect()
|
||||
}
|
||||
return r.myInboundAdapter.Close()
|
||||
}
|
||||
|
||||
func (r *Redirect) setupRedirect() error {
|
||||
tableName := "sing-box"
|
||||
rules := `
|
||||
set -e -o pipefail
|
||||
iptables -t nat -N sing-box
|
||||
`
|
||||
rules += strings.Join(common.FlatMap(r.router.(adapter.Router).InterfaceFinder().Interfaces(), func(it control.Interface) []string {
|
||||
return common.Map(common.Filter(it.Addresses, func(it netip.Prefix) bool { return it.Addr().Is4() }), func(it netip.Prefix) string {
|
||||
return "iptables -t nat -A " + tableName + " -p tcp -j RETURN -d " + it.String()
|
||||
})
|
||||
}), "\n")
|
||||
var (
|
||||
myUid = uint32(os.Getuid())
|
||||
perAppProxyList []uint32
|
||||
perAppProxyMap = make(map[uint32]bool)
|
||||
perAppProxyMode int32
|
||||
err error
|
||||
)
|
||||
if r.platformInterface != nil {
|
||||
perAppProxyMode = r.platformInterface.PerAppProxyMode()
|
||||
if perAppProxyMode != platform.PerAppProxyModeDisabled {
|
||||
perAppProxyList, err = r.platformInterface.PerAppProxyList()
|
||||
if err != nil {
|
||||
return E.Cause(err, "read per app proxy configuration")
|
||||
}
|
||||
}
|
||||
for _, proxyUID := range perAppProxyList {
|
||||
perAppProxyMap[proxyUID] = true
|
||||
}
|
||||
}
|
||||
excludeUser := func(userID uint32) {
|
||||
if perAppProxyMode != platform.PerAppProxyModeInclude {
|
||||
perAppProxyMap[userID] = false
|
||||
} else {
|
||||
delete(perAppProxyMap, userID)
|
||||
}
|
||||
}
|
||||
excludeUser(myUid)
|
||||
if myUid != 0 && myUid != 2000 {
|
||||
excludeUser(0)
|
||||
}
|
||||
perAppProxyList = perAppProxyList[:0]
|
||||
for uid := range perAppProxyMap {
|
||||
perAppProxyList = append(perAppProxyList, uid)
|
||||
}
|
||||
sort.SliceStable(perAppProxyList, func(i, j int) bool {
|
||||
return perAppProxyList[i] < perAppProxyList[j]
|
||||
})
|
||||
redirectPortStr := F.ToString(M.AddrPortFromNet(r.tcpListener.Addr()).Port())
|
||||
if perAppProxyMode != platform.PerAppProxyModeInclude {
|
||||
rules += "\n" + strings.Join(common.Map(perAppProxyList, func(it uint32) string {
|
||||
return "iptables -t nat -A " + tableName + " -j RETURN -m owner --uid-owner " + F.ToString(it)
|
||||
}), "\n")
|
||||
rules += "\niptables -t nat -A " + tableName + " -p tcp -j REDIRECT --to-ports " + redirectPortStr
|
||||
} else {
|
||||
rules += "\n" + strings.Join(common.Map(perAppProxyList, func(it uint32) string {
|
||||
return "iptables -t nat -A " + tableName + " -p tcp -j REDIRECT --to-ports " + redirectPortStr + " -m owner --uid-owner " + F.ToString(it)
|
||||
}), "\n")
|
||||
}
|
||||
rules += "\niptables -t nat -A OUTPUT -p tcp -j " + tableName
|
||||
for _, ruleLine := range strings.Split(rules, "\n") {
|
||||
ruleLine = strings.TrimSpace(ruleLine)
|
||||
if ruleLine == "" {
|
||||
continue
|
||||
}
|
||||
r.logger.Debug("# ", ruleLine)
|
||||
}
|
||||
return r.runAndroidShell(rules)
|
||||
}
|
||||
|
||||
func (r *Redirect) cleanupRedirect() {
|
||||
_ = r.runAndroidShell(`
|
||||
iptables -t nat -D OUTPUT -p tcp -j sing-box
|
||||
iptables -t nat -F sing-box
|
||||
iptables -t nat -X sing-box
|
||||
`)
|
||||
}
|
||||
|
||||
func (r *Redirect) runAndroidShell(content string) error {
|
||||
var command *exec.Cmd
|
||||
if r.needSu {
|
||||
command = exec.Command(r.suPath, "-c", "sh")
|
||||
} else {
|
||||
command = exec.Command("sh")
|
||||
}
|
||||
command.Stdin = strings.NewReader(content)
|
||||
combinedOutput, err := command.CombinedOutput()
|
||||
if err != nil {
|
||||
return E.Extend(err, string(combinedOutput))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+5
-38
@@ -3,7 +3,6 @@ package inbound
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -38,7 +37,6 @@ type Tun struct {
|
||||
tunStack tun.Stack
|
||||
platformInterface platform.Interface
|
||||
platformOptions option.TunPlatformOptions
|
||||
autoRedirect tun.AutoRedirect
|
||||
}
|
||||
|
||||
func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions, platformInterface platform.Interface) (*Tun, error) {
|
||||
@@ -52,9 +50,9 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
} else {
|
||||
udpTimeout = C.UDPTimeout
|
||||
}
|
||||
var err error
|
||||
includeUID := uidToRange(options.IncludeUID)
|
||||
if len(options.IncludeUIDRange) > 0 {
|
||||
var err error
|
||||
includeUID, err = parseRange(includeUID, options.IncludeUIDRange)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse include_uid_range")
|
||||
@@ -62,13 +60,13 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
}
|
||||
excludeUID := uidToRange(options.ExcludeUID)
|
||||
if len(options.ExcludeUIDRange) > 0 {
|
||||
var err error
|
||||
excludeUID, err = parseRange(excludeUID, options.ExcludeUIDRange)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse exclude_uid_range")
|
||||
}
|
||||
}
|
||||
|
||||
inbound := &Tun{
|
||||
return &Tun{
|
||||
tag: tag,
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
@@ -101,25 +99,7 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
stack: options.Stack,
|
||||
platformInterface: platformInterface,
|
||||
platformOptions: common.PtrValueOrDefault(options.Platform),
|
||||
}
|
||||
if options.AutoRedirect {
|
||||
if !options.AutoRoute {
|
||||
return nil, E.New("`auto_route` is required by `auto_redirect`")
|
||||
}
|
||||
disableNFTables, dErr := strconv.ParseBool(os.Getenv("DISABLE_NFTABLES"))
|
||||
inbound.autoRedirect, err = tun.NewAutoRedirect(tun.AutoRedirectOptions{
|
||||
TunOptions: &inbound.tunOptions,
|
||||
Context: ctx,
|
||||
Handler: inbound,
|
||||
Logger: logger,
|
||||
TableName: "sing-box",
|
||||
DisableNFTables: dErr == nil && disableNFTables,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "initialize auto redirect")
|
||||
}
|
||||
}
|
||||
return inbound, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func uidToRange(uidList option.Listable[uint32]) []ranges.Range[uint32] {
|
||||
@@ -215,14 +195,6 @@ func (t *Tun) Start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.autoRedirect != nil {
|
||||
monitor.Start("initiating auto redirect")
|
||||
err = t.autoRedirect.Start()
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
return E.Cause(err, "auto redirect")
|
||||
}
|
||||
}
|
||||
t.logger.Info("started at ", t.tunOptions.Name)
|
||||
return nil
|
||||
}
|
||||
@@ -231,7 +203,6 @@ func (t *Tun) Close() error {
|
||||
return common.Close(
|
||||
t.tunStack,
|
||||
t.tunIf,
|
||||
t.autoRedirect,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,11 +214,7 @@ func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata
|
||||
metadata.Source = upstreamMetadata.Source
|
||||
metadata.Destination = upstreamMetadata.Destination
|
||||
metadata.InboundOptions = t.inboundOptions
|
||||
if upstreamMetadata.Protocol != "" {
|
||||
t.logger.InfoContext(ctx, "inbound ", upstreamMetadata.Protocol, " connection from ", metadata.Source)
|
||||
} else {
|
||||
t.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
|
||||
}
|
||||
t.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
|
||||
t.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||
err := t.router.RouteConnection(ctx, conn, metadata)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,12 @@ package option
|
||||
|
||||
type RedirectInboundOptions struct {
|
||||
ListenOptions
|
||||
AutoRedirect *AutoRedirectOptions `json:"auto_redirect,omitempty"`
|
||||
}
|
||||
|
||||
type AutoRedirectOptions struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
ContinueOnNoPermission bool `json:"continue_on_no_permission,omitempty"`
|
||||
}
|
||||
|
||||
type TProxyInboundOptions struct {
|
||||
|
||||
@@ -9,7 +9,6 @@ type TunInboundOptions struct {
|
||||
Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"`
|
||||
Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"`
|
||||
AutoRoute bool `json:"auto_route,omitempty"`
|
||||
AutoRedirect bool `json:"auto_redirect,omitempty"`
|
||||
StrictRoute bool `json:"strict_route,omitempty"`
|
||||
Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"`
|
||||
Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user