Add support for rule actions

This commit is contained in:
世界 2024-11-16 20:02:39 +08:00
parent d2f1118c2e
commit 1649ae16e4
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
15 changed files with 317 additions and 312 deletions

View File

@ -5,7 +5,7 @@ import (
"os" "os"
"time" "time"
box "github.com/sagernet/sing-box" "github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/include" "github.com/sagernet/sing-box/include"
_ "github.com/sagernet/sing-box/include" _ "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"

View File

@ -31,7 +31,7 @@ RuleSet generate configuration.
{ {
"type": "github", "type": "github",
"repository": "SagerNet/sing-geosite", "repository": "SagerNet/sing-geosite",
"path": "rule-set", "path": "rule-set/geosite-",
"prefix": "geosite-", "prefix": "geosite-",
"rule_set": [ "rule_set": [
"apple", "apple",
@ -47,7 +47,7 @@ RuleSet generate configuration.
{ {
"type": "github", "type": "github",
"repository": "MetaCubeX/meta-rules-dat", "repository": "MetaCubeX/meta-rules-dat",
"path": "sing/geo/geosite", "path": "sing/geo/geosite/",
"prefix": "geosite-", "prefix": "geosite-",
"rule_set": [ "rule_set": [
"apple", "apple",

View File

@ -11,7 +11,8 @@
"domain_strategy": "", "domain_strategy": "",
"domain_strategy_local": "", "domain_strategy_local": "",
"disable_traffic_bypass": false, "disable_traffic_bypass": false,
"disable_rule_set": false, "disable_sniff": false,
"disable_rule_action": false,
"remote_resolve": false, "remote_resolve": false,
// DNS // DNS
@ -113,9 +114,13 @@ Local sing-box domain strategy.
`prefer_ipv4` is used by default. `prefer_ipv4` is used by default.
#### disable_rule_set #### disable_sniff
Use `geoip` and `geosite` for traffic bypassing instead of rule sets. Don`t generate protocol sniffing options.
#### disable_rule_action
Don`t generate rule action options.
#### disable_traffic_bypass #### disable_traffic_bypass

22
go.mod
View File

@ -11,13 +11,13 @@ require (
github.com/go-chi/render v1.0.3 github.com/go-chi/render v1.0.3
github.com/miekg/dns v1.1.62 github.com/miekg/dns v1.1.62
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f github.com/sagernet/sing v0.6.0-alpha.16
github.com/sagernet/sing-box v1.10.2-0.20241107134520-fead0e42505f github.com/sagernet/sing-box v1.11.0-alpha.17
github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab github.com/sagernet/sing-dns v0.4.0-alpha.2
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
golang.org/x/mod v0.21.0 golang.org/x/mod v0.21.0
golang.org/x/net v0.30.0 golang.org/x/net v0.31.0
) )
require ( require (
@ -68,12 +68,12 @@ require (
github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/sagernet/quic-go v0.48.1-beta.1 // indirect github.com/sagernet/quic-go v0.48.1-beta.1 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec // indirect github.com/sagernet/sing-mux v0.3.0-alpha.1 // indirect
github.com/sagernet/sing-quic v0.3.0-rc.2 // indirect github.com/sagernet/sing-quic v0.4.0-alpha.3 // indirect
github.com/sagernet/sing-shadowsocks v0.2.7 // indirect github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f // indirect github.com/sagernet/sing-tun v0.6.0-alpha.8 // indirect
github.com/sagernet/sing-vmess v0.1.12 // indirect github.com/sagernet/sing-vmess v0.1.12 // indirect
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
github.com/sagernet/utls v1.6.7 // indirect github.com/sagernet/utls v1.6.7 // indirect
@ -91,11 +91,11 @@ require (
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.28.0 // indirect golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/text v0.20.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.24.0 // indirect golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect

48
go.sum
View File

@ -121,24 +121,24 @@ github.com/sagernet/quic-go v0.48.1-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f h1:A6+OeV5P1mok0eEEbLh4PidymZ6VZnTZ2uHwfapXgdU= github.com/sagernet/sing v0.6.0-alpha.16 h1:Ml+nJa8J9d+Svqv2pBvJoet+8PF302Snb6wcMUXaoy4=
github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.6.0-alpha.16/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.2-0.20241107134520-fead0e42505f h1:CkGSNvQvZlzm5VuKmc23DiY2WxxHbp1jYux0fh3xRW4= github.com/sagernet/sing-box v1.11.0-alpha.17 h1:j7+LwRgXvcs1qqmNcj0ckQTzBnEl9FO3eEc5AQOdj3g=
github.com/sagernet/sing-box v1.10.2-0.20241107134520-fead0e42505f/go.mod h1:3Ujxk8+gNR1Kve68iZFjzxDHLGrFODdsvnth8oakrwk= github.com/sagernet/sing-box v1.11.0-alpha.17/go.mod h1:5Gekm6mVOgaL+9JTmNu0vngMuSltxwjLUiHLCQ6gc6w=
github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab h1:djP4EY/KM5T62xscormLflVi7eDlHv6p7md1FHMSArE= github.com/sagernet/sing-dns v0.4.0-alpha.2 h1:0x5WjrO+Ifk9sqJlHRz/tKENHwoEinQ8HQCHAhpJHAQ=
github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M= github.com/sagernet/sing-dns v0.4.0-alpha.2/go.mod h1:ZiXcacKL54jSSYZMbYF3qKNFkkW674Jt+85YCmK64K8=
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48= github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec/go.mod h1:RSwqqHwbtTOX3vs6ms8vMtBGH/0ZNyLm/uwt6TlmR84= github.com/sagernet/sing-mux v0.3.0-alpha.1/go.mod h1:FTcImmdfW38Lz7b+HQ+mxxOth1lz4ao8uEnz+MwIJQE=
github.com/sagernet/sing-quic v0.3.0-rc.2 h1:7vcC4bdS1GBJzHZhfmJiH0CfzQ4mYLUW51Z2RNHcGwc= github.com/sagernet/sing-quic v0.4.0-alpha.3 h1:2svvOqgQCJg7FNrIrLTaRB6oDzXPiIyWIt9csjZxD6Q=
github.com/sagernet/sing-quic v0.3.0-rc.2/go.mod h1:3UOq51WVqzra7eCgod7t4hqnTaOiZzFUci9avMrtOqs= github.com/sagernet/sing-quic v0.4.0-alpha.3/go.mod h1:Fmnpy0XoyYdjJrxNqEyl3LC9uLibMNNbxG7dt6HATY4=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= 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-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f h1:gQwTgN/E4oHe3VlseD3/RhPs866cWcTsPG4dP6a8f8o= github.com/sagernet/sing-tun v0.6.0-alpha.8 h1:HhXyUvXxtaXgT+IILZMq6kbrAyDbUwbN+Df/XxpL7Vo=
github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f/go.mod h1:Ehs5mZ3T8tTgV3H1Tx4Va5ixvyKjTAUPJ3G11dq7B/g= github.com/sagernet/sing-tun v0.6.0-alpha.8/go.mod h1:JkgiLLnQUXln1zLGVoJqUwAulJGT0xoiPU4/pYF1fhU=
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg= github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I= github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
@ -188,18 +188,18 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -210,15 +210,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -36,10 +36,10 @@ func (o *Options) UnmarshalJSONContext(ctx context.Context, content []byte) erro
} }
type User struct { type User struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Profile option.Listable[string] `json:"profile,omitempty"` Profile badoption.Listable[string] `json:"profile,omitempty"`
DefaultProfile string `json:"default_profile,omitempty"` DefaultProfile string `json:"default_profile,omitempty"`
} }
const ( const (
@ -47,24 +47,24 @@ const (
) )
type Subscription struct { type Subscription struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
UserAgent string `json:"user_agent,omitempty"` UserAgent string `json:"user_agent,omitempty"`
UpdateInterval option.Duration `json:"update_interval,omitempty"` UpdateInterval badoption.Duration `json:"update_interval,omitempty"`
Process option.Listable[OutboundProcessOptions] `json:"process,omitempty"` Process badoption.Listable[OutboundProcessOptions] `json:"process,omitempty"`
DeDuplication bool `json:"deduplication,omitempty"` DeDuplication bool `json:"deduplication,omitempty"`
GenerateSelector bool `json:"generate_selector,omitempty"` GenerateSelector bool `json:"generate_selector,omitempty"`
GenerateURLTest bool `json:"generate_urltest,omitempty"` GenerateURLTest bool `json:"generate_urltest,omitempty"`
URLTestTagSuffix string `json:"urltest_suffix,omitempty"` URLTestTagSuffix string `json:"urltest_suffix,omitempty"`
CustomSelector *option.SelectorOutboundOptions `json:"custom_selector,omitempty"` CustomSelector *option.SelectorOutboundOptions `json:"custom_selector,omitempty"`
CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"` CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"`
} }
type OutboundProcessOptions struct { type OutboundProcessOptions struct {
Filter option.Listable[string] `json:"filter,omitempty"` Filter badoption.Listable[string] `json:"filter,omitempty"`
Exclude option.Listable[string] `json:"exclude,omitempty"` Exclude badoption.Listable[string] `json:"exclude,omitempty"`
FilterType option.Listable[string] `json:"filter_type,omitempty"` FilterType badoption.Listable[string] `json:"filter_type,omitempty"`
ExcludeType option.Listable[string] `json:"exclude_type,omitempty"` ExcludeType badoption.Listable[string] `json:"exclude_type,omitempty"`
Invert bool `json:"invert,omitempty"` Invert bool `json:"invert,omitempty"`
Remove bool `json:"remove,omitempty"` Remove bool `json:"remove,omitempty"`
Rename *badjson.TypedMap[string, string] `json:"rename,omitempty"` Rename *badjson.TypedMap[string, string] `json:"rename,omitempty"`
@ -77,6 +77,6 @@ type Profile struct {
Template string `json:"template,omitempty"` Template string `json:"template,omitempty"`
TemplateForPlatform *badjson.TypedMap[string, string] `json:"template_for_platform,omitempty"` TemplateForPlatform *badjson.TypedMap[string, string] `json:"template_for_platform,omitempty"`
TemplateForUserAgent *badjson.TypedMap[string, string] `json:"template_for_user_agent,omitempty"` TemplateForUserAgent *badjson.TypedMap[string, string] `json:"template_for_user_agent,omitempty"`
Outbound option.Listable[string] `json:"outbound,omitempty"` Outbound badoption.Listable[string] `json:"outbound,omitempty"`
Subscription option.Listable[string] `json:"subscription,omitempty"` Subscription badoption.Listable[string] `json:"subscription,omitempty"`
} }

View File

@ -9,6 +9,7 @@ import (
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badjson"
"github.com/sagernet/sing/common/json/badoption"
) )
type _Template struct { type _Template struct {
@ -22,7 +23,8 @@ type _Template struct {
DomainStrategy option.DomainStrategy `json:"domain_strategy,omitempty"` DomainStrategy option.DomainStrategy `json:"domain_strategy,omitempty"`
DomainStrategyLocal option.DomainStrategy `json:"domain_strategy_local,omitempty"` DomainStrategyLocal option.DomainStrategy `json:"domain_strategy_local,omitempty"`
DisableTrafficBypass bool `json:"disable_traffic_bypass,omitempty"` DisableTrafficBypass bool `json:"disable_traffic_bypass,omitempty"`
DisableRuleSet bool `json:"disable_rule_set,omitempty"` DisableSniff bool `json:"disable_sniff,omitempty"`
DisableRuleAction bool `json:"disable_rule_action,omitempty"`
RemoteResolve bool `json:"remote_resolve,omitempty"` RemoteResolve bool `json:"remote_resolve,omitempty"`
// DNS // DNS
@ -53,14 +55,12 @@ type _Template struct {
CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"` CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"`
// Route // Route
DisableDefaultRules bool `json:"disable_default_rules,omitempty"` DisableDefaultRules bool `json:"disable_default_rules,omitempty"`
PreRules []option.Rule `json:"pre_rules,omitempty"` PreRules []option.Rule `json:"pre_rules,omitempty"`
CustomRules []option.Rule `json:"custom_rules,omitempty"` CustomRules []option.Rule `json:"custom_rules,omitempty"`
EnableJSDelivr bool `json:"enable_jsdelivr,omitempty"` EnableJSDelivr bool `json:"enable_jsdelivr,omitempty"`
CustomGeoIP *option.GeoIPOptions `json:"custom_geoip,omitempty"` CustomRuleSet []RuleSet `json:"custom_rule_set,omitempty"`
CustomGeosite *option.GeositeOptions `json:"custom_geosite,omitempty"` PostRuleSet []RuleSet `json:"post_rule_set,omitempty"`
CustomRuleSet []RuleSet `json:"custom_rule_set,omitempty"`
PostRuleSet []RuleSet `json:"post_rule_set,omitempty"`
// Experimental // Experimental
DisableCacheFile bool `json:"disable_cache_file,omitempty"` DisableCacheFile bool `json:"disable_cache_file,omitempty"`
@ -122,10 +122,10 @@ func (r *RuleSet) UnmarshalJSON(content []byte) error {
} }
type GitHubRuleSetOptions struct { type GitHubRuleSetOptions struct {
Repository string `json:"repository,omitempty"` Repository string `json:"repository,omitempty"`
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
Prefix string `json:"prefix,omitempty"` Prefix string `json:"prefix,omitempty"`
RuleSet option.Listable[string] `json:"rule_set,omitempty"` RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
} }
func (t Template) DisableIPv6() bool { func (t Template) DisableIPv6() bool {
@ -137,8 +137,8 @@ type ExtraGroup struct {
Target ExtraGroupTarget `json:"target,omitempty"` Target ExtraGroupTarget `json:"target,omitempty"`
TagPerSubscription string `json:"tag_per_subscription,omitempty"` TagPerSubscription string `json:"tag_per_subscription,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Filter option.Listable[string] `json:"filter,omitempty"` Filter badoption.Listable[string] `json:"filter,omitempty"`
Exclude option.Listable[string] `json:"exclude,omitempty"` Exclude badoption.Listable[string] `json:"exclude,omitempty"`
CustomSelector *option.SelectorOutboundOptions `json:"custom_selector,omitempty"` CustomSelector *option.SelectorOutboundOptions `json:"custom_selector,omitempty"`
CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"` CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"`
} }

View File

@ -138,9 +138,16 @@ func (p *Profile) Render(metadata metadata.Metadata) (*boxOption.Options, error)
outbounds := common.Filter(p.manager.outbounds, func(it []boxOption.Outbound) bool { outbounds := common.Filter(p.manager.outbounds, func(it []boxOption.Outbound) bool {
return common.Contains(p.Outbound, it[0].Tag) return common.Contains(p.Outbound, it[0].Tag)
}) })
subscriptions := common.Filter(p.manager.subscription.Subscriptions(), func(it *subscription.Subscription) bool { var subscriptions []*subscription.Subscription
return common.Contains(p.Subscription, it.Name) for _, subscriptionName := range p.Subscription {
}) subscription := common.Find(p.manager.subscription.Subscriptions(), func(it *subscription.Subscription) bool {
return it.Name == subscriptionName
})
if subscription == nil {
return nil, E.New("render profile[", p.Name, "]: subscription not found: ", subscriptionName)
}
subscriptions = append(subscriptions, subscription)
}
options, err := selectedTemplate.Render(p.manager.ctx, metadata, p.Name, outbounds, subscriptions) options, err := selectedTemplate.Render(p.manager.ctx, metadata, p.Name, outbounds, subscriptions)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -8,6 +8,7 @@ import (
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter"
@ -224,10 +225,10 @@ func clashPluginOptions(plugin string, opts map[string]any) string {
func clashTransport(network string, httpOpts clash_outbound.HTTPOptions, h2Opts clash_outbound.HTTP2Options, grpcOpts clash_outbound.GrpcOptions, wsOpts clash_outbound.WSOptions) *option.V2RayTransportOptions { func clashTransport(network string, httpOpts clash_outbound.HTTPOptions, h2Opts clash_outbound.HTTP2Options, grpcOpts clash_outbound.GrpcOptions, wsOpts clash_outbound.WSOptions) *option.V2RayTransportOptions {
switch network { switch network {
case "http": case "http":
var headers map[string]option.Listable[string] var headers map[string]badoption.Listable[string]
for key, values := range httpOpts.Headers { for key, values := range httpOpts.Headers {
if headers == nil { if headers == nil {
headers = make(map[string]option.Listable[string]) headers = make(map[string]badoption.Listable[string])
} }
headers[key] = values headers[key] = values
} }
@ -255,10 +256,10 @@ func clashTransport(network string, httpOpts clash_outbound.HTTPOptions, h2Opts
}, },
} }
case "ws": case "ws":
var headers map[string]option.Listable[string] var headers map[string]badoption.Listable[string]
for key, value := range wsOpts.Headers { for key, value := range wsOpts.Headers {
if headers == nil { if headers == nil {
headers = make(map[string]option.Listable[string]) headers = make(map[string]badoption.Listable[string])
} }
headers[key] = []string{value} headers[key] = []string{value}
} }

View File

@ -19,8 +19,15 @@ func TestFilter1100(t *testing.T) {
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RuleSet: []string{"test"}, RawDefaultDNSRule: option.RawDefaultDNSRule{
Server: "test", RuleSet: []string{"test"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "test",
},
},
}, },
}, },
}, },
@ -30,8 +37,15 @@ func TestFilter1100(t *testing.T) {
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
RuleSet: []string{"test"}, RawDefaultRule: option.RawDefaultRule{
Outbound: "test", Domain: []string{"example.com"},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: "test",
},
},
}, },
}, },
}, },
@ -61,8 +75,15 @@ func TestFilter1100(t *testing.T) {
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
Domain: []string{"example.com"}, RawDefaultDNSRule: option.RawDefaultDNSRule{
Server: "test", Domain: []string{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "test",
},
},
}, },
}, },
}, },
@ -72,8 +93,15 @@ func TestFilter1100(t *testing.T) {
{ {
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{ DefaultOptions: option.DefaultRule{
Domain: []string{"example.com"}, RawDefaultRule: option.RawDefaultRule{
Outbound: "test", Domain: []string{"example.com"},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: "test",
},
},
}, },
}, },
}, },

View File

@ -167,37 +167,21 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
options.DNS.Rules = append(options.DNS.Rules, t.PreDNSRules...) options.DNS.Rules = append(options.DNS.Rules, t.PreDNSRules...)
if len(t.CustomDNSRules) == 0 { if len(t.CustomDNSRules) == 0 {
if !t.DisableTrafficBypass { if !t.DisableTrafficBypass {
if t.DisableRuleSet || (metadata.Version != nil && metadata.Version.LessThan(semver.ParseVersion("1.8.0-alpha.10"))) {
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{ DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{ RawDefaultDNSRule: option.RawDefaultDNSRule{
Geosite: []string{"geolocation-cn"}, RuleSet: []string{"geosite-geolocation-cn"},
}, },
DNSRuleAction: option.DNSRuleAction{ DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute, Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{ RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag, Server: DNSLocalTag,
},
}, },
}, },
}) },
} else { })
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
RuleSet: []string{"geosite-geolocation-cn"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag,
},
},
},
})
}
if !t.DisableDNSLeak && (metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1"))) { if !t.DisableDNSLeak && (metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1"))) {
options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{ options.DNS.Rules = append(options.DNS.Rules, option.DNSRule{
Type: C.RuleTypeDefault, Type: C.RuleTypeDefault,
@ -224,12 +208,6 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
RawDefaultDNSRule: option.RawDefaultDNSRule{ RawDefaultDNSRule: option.RawDefaultDNSRule{
RuleSet: []string{"geosite-geolocation-!cn"}, RuleSet: []string{"geosite-geolocation-!cn"},
}, },
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSDefaultTag,
},
},
}, },
}, },
{ {
@ -238,12 +216,6 @@ func (t *Template) renderDNS(metadata M.Metadata, options *option.Options) error
RawDefaultDNSRule: option.RawDefaultDNSRule{ RawDefaultDNSRule: option.RawDefaultDNSRule{
RuleSet: []string{"geoip-cn"}, RuleSet: []string{"geoip-cn"},
}, },
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: DNSLocalTag,
},
},
}, },
}, },
}, },

View File

@ -2,7 +2,6 @@ package template
import ( import (
M "github.com/sagernet/serenity/common/metadata" M "github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver"
"github.com/sagernet/serenity/constant" "github.com/sagernet/serenity/constant"
"github.com/sagernet/serenity/option" "github.com/sagernet/serenity/option"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@ -10,87 +9,55 @@ import (
) )
func (t *Template) renderGeoResources(metadata M.Metadata, options *boxOption.Options) { func (t *Template) renderGeoResources(metadata M.Metadata, options *boxOption.Options) {
if t.DisableRuleSet || (metadata.Version != nil && metadata.Version.LessThan(semver.ParseVersion("1.8.0-alpha.10"))) { if len(t.CustomRuleSet) == 0 {
var ( var (
geoipDownloadURL string downloadURL string
geositeDownloadURL string downloadDetour string
downloadDetour string branchSplit string
) )
if t.EnableJSDelivr { if t.EnableJSDelivr {
geoipDownloadURL = "https://testingcf.jsdelivr.net/gh/SagerNet/sing-geoip@release/geoip-cn.db" downloadURL = "https://testingcf.jsdelivr.net/gh/"
geositeDownloadURL = "https://testingcf.jsdelivr.net/gh/SagerNet/sing-geosite@release/geosite-cn.db"
if t.DirectTag != "" { if t.DirectTag != "" {
downloadDetour = t.DirectTag downloadDetour = t.DirectTag
} else { } else {
downloadDetour = DefaultDirectTag downloadDetour = DefaultDirectTag
} }
branchSplit = "@"
} else { } else {
geoipDownloadURL = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip-cn.db" downloadURL = "https://raw.githubusercontent.com/"
geositeDownloadURL = "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite-cn.db" branchSplit = "/"
} }
if t.CustomGeoIP == nil { options.Route.RuleSet = []boxOption.RuleSet{
options.Route.GeoIP = &boxOption.GeoIPOptions{ {
DownloadURL: geoipDownloadURL, Type: C.RuleSetTypeRemote,
DownloadDetour: downloadDetour, Tag: "geoip-cn",
} Format: C.RuleSetFormatBinary,
} RemoteOptions: boxOption.RemoteRuleSet{
if t.CustomGeosite == nil { URL: downloadURL + "SagerNet/sing-geoip" + branchSplit + "rule-set/geoip-cn.srs",
options.Route.Geosite = &boxOption.GeositeOptions{ DownloadDetour: downloadDetour,
DownloadURL: geositeDownloadURL,
DownloadDetour: downloadDetour,
}
}
} else {
if len(t.CustomRuleSet) == 0 {
var (
downloadURL string
downloadDetour string
branchSplit string
)
if t.EnableJSDelivr {
downloadURL = "https://testingcf.jsdelivr.net/gh/"
if t.DirectTag != "" {
downloadDetour = t.DirectTag
} else {
downloadDetour = DefaultDirectTag
}
branchSplit = "@"
} else {
downloadURL = "https://raw.githubusercontent.com/"
branchSplit = "/"
}
options.Route.RuleSet = []boxOption.RuleSet{
{
Type: C.RuleSetTypeRemote,
Tag: "geoip-cn",
Format: C.RuleSetFormatBinary,
RemoteOptions: boxOption.RemoteRuleSet{
URL: downloadURL + "SagerNet/sing-geoip" + branchSplit + "rule-set/geoip-cn.srs",
DownloadDetour: downloadDetour,
},
}, },
{ },
Type: C.RuleSetTypeRemote, {
Tag: "geosite-geolocation-cn", Type: C.RuleSetTypeRemote,
Format: C.RuleSetFormatBinary, Tag: "geosite-geolocation-cn",
RemoteOptions: boxOption.RemoteRuleSet{ Format: C.RuleSetFormatBinary,
URL: downloadURL + "SagerNet/sing-geosite" + branchSplit + "rule-set/geosite-geolocation-cn.srs", RemoteOptions: boxOption.RemoteRuleSet{
DownloadDetour: downloadDetour, URL: downloadURL + "SagerNet/sing-geosite" + branchSplit + "rule-set/geosite-geolocation-cn.srs",
}, DownloadDetour: downloadDetour,
}, },
{ },
Type: C.RuleSetTypeRemote, {
Tag: "geosite-geolocation-!cn", Type: C.RuleSetTypeRemote,
Format: C.RuleSetFormatBinary, Tag: "geosite-geolocation-!cn",
RemoteOptions: boxOption.RemoteRuleSet{ Format: C.RuleSetFormatBinary,
URL: downloadURL + "SagerNet/sing-geosite" + branchSplit + "rule-set/geosite-geolocation-!cn.srs", RemoteOptions: boxOption.RemoteRuleSet{
DownloadDetour: downloadDetour, URL: downloadURL + "SagerNet/sing-geosite" + branchSplit + "rule-set/geosite-geolocation-!cn.srs",
}, DownloadDetour: downloadDetour,
}, },
} },
} }
options.Route.RuleSet = append(options.Route.RuleSet, t.renderRuleSet(t.PostRuleSet)...)
} }
options.Route.RuleSet = append(options.Route.RuleSet, t.renderRuleSet(t.PostRuleSet)...)
} }
func (t *Template) renderRuleSet(ruleSets []option.RuleSet) []boxOption.RuleSet { func (t *Template) renderRuleSet(ruleSets []option.RuleSet) []boxOption.RuleSet {

View File

@ -9,16 +9,14 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json/badjson" "github.com/sagernet/sing/common/json/badjson"
"github.com/sagernet/sing/common/json/badoption"
) )
func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options) error { func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options) error {
options.Inbounds = t.Inbounds options.Inbounds = t.Inbounds
var needSniff bool
if !t.DisableTrafficBypass {
needSniff = true
}
var domainStrategy option.DomainStrategy var domainStrategy option.DomainStrategy
if !t.RemoteResolve { if !t.RemoteResolve {
if t.DomainStrategy != option.DomainStrategy(dns.DomainStrategyAsIS) { if t.DomainStrategy != option.DomainStrategy(dns.DomainStrategyAsIS) {
@ -27,6 +25,7 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
domainStrategy = option.DomainStrategy(dns.DomainStrategyPreferIPv4) domainStrategy = option.DomainStrategy(dns.DomainStrategyPreferIPv4)
} }
} }
disableRuleAction := t.DisableRuleAction || (metadata.Version != nil && metadata.Version.LessThan(semver.ParseVersion("1.11.0-alpha.7")))
autoRedirect := t.AutoRedirect && autoRedirect := t.AutoRedirect &&
!metadata.Platform.IsApple() && !metadata.Platform.IsApple() &&
(metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.10.0-alpha.2"))) (metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.10.0-alpha.2")))
@ -40,9 +39,6 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
tunOptions := &option.TunInboundOptions{ tunOptions := &option.TunInboundOptions{
AutoRoute: true, AutoRoute: true,
Address: address, Address: address,
InboundOptions: option.InboundOptions{
SniffEnabled: needSniff,
},
} }
tunInbound := option.Inbound{ tunInbound := option.Inbound{
Type: C.TypeTun, Type: C.TypeTun,
@ -54,12 +50,17 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
tunOptions.RouteExcludeAddressSet = []string{"geoip-cn"} tunOptions.RouteExcludeAddressSet = []string{"geoip-cn"}
} }
} }
if t.EnableFakeIP {
tunOptions.DomainStrategy = domainStrategy
}
if metadata.Platform == M.PlatformUnknown { if metadata.Platform == M.PlatformUnknown {
tunOptions.StrictRoute = true tunOptions.StrictRoute = true
} }
if disableRuleAction {
tunOptions.InboundOptions = option.InboundOptions{
SniffEnabled: !t.DisableSniff,
}
if t.EnableFakeIP {
tunOptions.DomainStrategy = domainStrategy
}
}
if !t.DisableSystemProxy && metadata.Platform != M.PlatformUnknown { if !t.DisableSystemProxy && metadata.Platform != M.PlatformUnknown {
var httpPort uint16 var httpPort uint16
if t.CustomMixed != nil { if t.CustomMixed != nil {
@ -90,15 +91,17 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
if disableTun || !t.DisableSystemProxy { if disableTun || !t.DisableSystemProxy {
mixedOptions := &option.HTTPMixedInboundOptions{ mixedOptions := &option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.AddrFrom4([4]byte{127, 0, 0, 1})), Listen: common.Ptr(badoption.Addr(netip.AddrFrom4([4]byte{127, 0, 0, 1}))),
ListenPort: DefaultMixedPort, ListenPort: DefaultMixedPort,
InboundOptions: option.InboundOptions{
SniffEnabled: needSniff,
DomainStrategy: domainStrategy,
},
}, },
SetSystemProxy: metadata.Platform == M.PlatformUnknown && disableTun && !t.DisableSystemProxy, SetSystemProxy: metadata.Platform == M.PlatformUnknown && disableTun && !t.DisableSystemProxy,
} }
if disableRuleAction {
mixedOptions.InboundOptions = option.InboundOptions{
SniffEnabled: !t.DisableSniff,
DomainStrategy: domainStrategy,
}
}
mixedInbound := option.Inbound{ mixedInbound := option.Inbound{
Type: C.TypeMixed, Type: C.TypeMixed,
Options: mixedOptions, Options: mixedOptions,

View File

@ -6,6 +6,7 @@ import (
"text/template" "text/template"
M "github.com/sagernet/serenity/common/metadata" M "github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver"
"github.com/sagernet/serenity/option" "github.com/sagernet/serenity/option"
"github.com/sagernet/serenity/subscription" "github.com/sagernet/serenity/subscription"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@ -16,6 +17,7 @@ import (
) )
func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Options, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) error { func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Options, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) error {
disableRuleAction := t.DisableRuleAction || (metadata.Version != nil && metadata.Version.LessThan(semver.ParseVersion("1.11.0-alpha.7")))
defaultTag := t.DefaultTag defaultTag := t.DefaultTag
if defaultTag == "" { if defaultTag == "" {
defaultTag = DefaultDefaultTag defaultTag = DefaultDefaultTag
@ -35,22 +37,26 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Optio
Type: C.TypeDirect, Type: C.TypeDirect,
Options: common.Ptr(common.PtrValueOrDefault(t.CustomDirect)), Options: common.Ptr(common.PtrValueOrDefault(t.CustomDirect)),
}, },
{
Tag: blockTag,
Type: C.TypeBlock,
Options: &boxOption.StubOptions{},
},
{
Tag: DNSTag,
Type: C.TypeDNS,
Options: &boxOption.StubOptions{},
},
{ {
Tag: defaultTag, Tag: defaultTag,
Type: C.TypeSelector, Type: C.TypeSelector,
Options: common.Ptr(common.PtrValueOrDefault(t.CustomSelector)), Options: common.Ptr(common.PtrValueOrDefault(t.CustomSelector)),
}, },
} }
if disableRuleAction {
options.Outbounds = append(options.Outbounds,
boxOption.Outbound{
Tag: blockTag,
Type: C.TypeBlock,
Options: &boxOption.StubOptions{},
},
boxOption.Outbound{
Tag: DNSTag,
Type: C.TypeDNS,
Options: &boxOption.StubOptions{},
},
)
}
urlTestTag := t.URLTestTag urlTestTag := t.URLTestTag
if urlTestTag == "" { if urlTestTag == "" {
urlTestTag = DefaultURLTestTag urlTestTag = DefaultURLTestTag

View File

@ -11,49 +11,90 @@ import (
func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) error { func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) error {
if options.Route == nil { if options.Route == nil {
options.Route = &option.RouteOptions{ options.Route = &option.RouteOptions{
GeoIP: t.CustomGeoIP,
Geosite: t.CustomGeosite,
RuleSet: t.renderRuleSet(t.CustomRuleSet), RuleSet: t.renderRuleSet(t.CustomRuleSet),
} }
} }
if !t.DisableTrafficBypass { if !t.DisableTrafficBypass {
t.renderGeoResources(metadata, options) t.renderGeoResources(metadata, options)
} }
disable18Features := metadata.Version != nil && metadata.Version.LessThan(semver.ParseVersion("1.8.0-alpha.10")) disableRuleAction := t.DisableRuleAction || (metadata.Version != nil && metadata.Version.LessThan(semver.ParseVersion("1.11.0-alpha.7")))
options.Route.Rules = []option.Rule{ if disableRuleAction {
{ options.Route.Rules = []option.Rule{
Type: C.RuleTypeLogical, {
LogicalOptions: option.LogicalRule{ Type: C.RuleTypeLogical,
RawLogicalRule: option.RawLogicalRule{ LogicalOptions: option.LogicalRule{
Mode: C.LogicalTypeOr, RawLogicalRule: option.RawLogicalRule{
Rules: []option.Rule{ Mode: C.LogicalTypeOr,
{ Rules: []option.Rule{
Type: C.RuleTypeDefault, {
DefaultOptions: option.DefaultRule{ Type: C.RuleTypeDefault,
RawDefaultRule: option.RawDefaultRule{ DefaultOptions: option.DefaultRule{
Network: []string{N.NetworkUDP}, RawDefaultRule: option.RawDefaultRule{
Port: []uint16{53}, Network: []string{N.NetworkUDP},
Port: []uint16{53},
},
}, },
}, },
}, {
{ Type: C.RuleTypeDefault,
Type: C.RuleTypeDefault, DefaultOptions: option.DefaultRule{
DefaultOptions: option.DefaultRule{ RawDefaultRule: option.RawDefaultRule{
RawDefaultRule: option.RawDefaultRule{ Protocol: []string{C.ProtocolDNS},
Protocol: []string{C.ProtocolDNS}, },
}, },
}, },
}, },
}, },
}, RuleAction: option.RuleAction{
RuleAction: option.RuleAction{ Action: C.RuleActionTypeRoute,
Action: C.RuleActionTypeRoute, RouteOptions: option.RouteActionOptions{
RouteOptions: option.RouteActionOptions{ Outbound: DNSTag,
Outbound: DNSTag, },
}, },
}, },
}, },
}, }
} else {
options.Route.Rules = []option.Rule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RuleAction: option.RuleAction{
Action: C.RuleActionTypeSniff,
},
},
},
{
Type: C.RuleTypeLogical,
LogicalOptions: option.LogicalRule{
RawLogicalRule: option.RawLogicalRule{
Mode: C.LogicalTypeOr,
Rules: []option.Rule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
Network: []string{N.NetworkUDP},
Port: []uint16{53},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
Protocol: []string{C.ProtocolDNS},
},
},
},
},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeHijackDNS,
},
},
},
}
} }
directTag := t.DirectTag directTag := t.DirectTag
defaultTag := t.DefaultTag defaultTag := t.DefaultTag
@ -63,37 +104,20 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
if defaultTag == "" { if defaultTag == "" {
defaultTag = DefaultDefaultTag defaultTag = DefaultDefaultTag
} }
if disable18Features { options.Route.Rules = append(options.Route.Rules, option.Rule{
options.Route.Rules = append(options.Route.Rules, option.Rule{ Type: C.RuleTypeDefault,
Type: C.RuleTypeDefault, DefaultOptions: option.DefaultRule{
DefaultOptions: option.DefaultRule{ RawDefaultRule: option.RawDefaultRule{
RawDefaultRule: option.RawDefaultRule{ IPIsPrivate: true,
GeoIP: []string{"private"}, },
}, RuleAction: option.RuleAction{
RuleAction: option.RuleAction{ Action: C.RuleActionTypeRoute,
Action: C.RuleActionTypeRoute, RouteOptions: option.RouteActionOptions{
RouteOptions: option.RouteActionOptions{ Outbound: directTag,
Outbound: directTag,
},
}, },
}, },
}) },
} else { })
options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
IPIsPrivate: true,
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag,
},
},
},
})
}
if !t.DisableClashMode { if !t.DisableClashMode {
modeGlobal := t.ClashModeGlobal modeGlobal := t.ClashModeGlobal
modeDirect := t.ClashModeDirect modeDirect := t.ClashModeDirect
@ -131,41 +155,33 @@ func (t *Template) renderRoute(metadata M.Metadata, options *option.Options) err
}, },
}) })
} }
if disableRuleAction {
options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RuleAction: option.RuleAction{
Action: C.RuleActionTypeResolve,
},
},
})
}
options.Route.Rules = append(options.Route.Rules, t.PreRules...) options.Route.Rules = append(options.Route.Rules, t.PreRules...)
if len(t.CustomRules) == 0 { if len(t.CustomRules) == 0 {
if !t.DisableTrafficBypass { if !t.DisableTrafficBypass {
if t.DisableRuleSet || disable18Features { options.Route.Rules = append(options.Route.Rules, option.Rule{
options.Route.Rules = append(options.Route.Rules, option.Rule{ Type: C.RuleTypeDefault,
Type: C.RuleTypeDefault, DefaultOptions: option.DefaultRule{
DefaultOptions: option.DefaultRule{ RawDefaultRule: option.RawDefaultRule{
RawDefaultRule: option.RawDefaultRule{ RuleSet: []string{"geoip-cn", "geosite-geolocation-cn"},
GeoIP: []string{"cn"}, },
Geosite: []string{"geolocation-cn"}, RuleAction: option.RuleAction{
}, Action: C.RuleActionTypeRoute,
RuleAction: option.RuleAction{ RouteOptions: option.RouteActionOptions{
Action: C.RuleActionTypeRoute, Outbound: directTag,
RouteOptions: option.RouteActionOptions{
Outbound: directTag,
},
}, },
}, },
}) },
} else { })
options.Route.Rules = append(options.Route.Rules, option.Rule{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RawDefaultRule: option.RawDefaultRule{
RuleSet: []string{"geoip-cn", "geosite-geolocation-cn"},
},
RuleAction: option.RuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.RouteActionOptions{
Outbound: directTag,
},
},
},
})
}
} }
} else { } else {
options.Route.Rules = append(options.Route.Rules, t.CustomRules...) options.Route.Rules = append(options.Route.Rules, t.CustomRules...)