Add support for inline rule-sets

This commit is contained in:
世界 2024-07-06 08:09:19 +08:00
parent 29ba67b745
commit d7af8bd589
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
14 changed files with 337 additions and 253 deletions

View File

@ -110,7 +110,7 @@ func readConfigAndMerge() (option.Options, error) {
}
var mergedMessage json.RawMessage
for _, options := range optionsList {
mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage)
mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage, false)
if err != nil {
return option.Options{}, E.Cause(err, "merge config at ", options.path)
}

21
go.mod
View File

@ -7,12 +7,13 @@ require (
github.com/go-chi/chi/v5 v5.0.12
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.3
github.com/miekg/dns v1.1.59
github.com/miekg/dns v1.1.61
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/sing v0.5.0-alpha.10.0.20240615025518-3de31664ce39
github.com/sagernet/sing-box v1.10.0-alpha.13
github.com/sagernet/sing-dns v0.3.0-beta.5
github.com/sagernet/sing v0.5.0-alpha.12
github.com/sagernet/sing-box v1.10.0-alpha.19
github.com/sagernet/sing-dns v0.3.0-beta.10
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.9.0
golang.org/x/mod v0.18.0
golang.org/x/net v0.26.0
)
@ -25,6 +26,7 @@ require (
github.com/caddyserver/certmagic v0.20.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cretz/bine v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect
@ -55,21 +57,22 @@ require (
github.com/oschwald/geoip2-golang v1.9.0 // indirect
github.com/oschwald/maxminddb-golang v1.12.0 // 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/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect
github.com/sagernet/fswatch v0.1.1 // indirect
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/sagernet/quic-go v0.45.0-beta.2 // indirect
github.com/sagernet/quic-go v0.45.1-beta.2 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-mux v0.2.0 // indirect
github.com/sagernet/sing-quic v0.2.0-beta.9 // indirect
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect
github.com/sagernet/sing-quic v0.2.0-beta.12 // indirect
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240616073727-85f5f2dd587d // indirect
github.com/sagernet/sing-vmess v0.1.8 // indirect
github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d // indirect
github.com/sagernet/sing-vmess v0.1.11 // indirect
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 // indirect
github.com/sagernet/utls v1.5.4 // indirect

55
go.sum
View File

@ -67,6 +67,8 @@ 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/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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=
@ -82,8 +84,10 @@ 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/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
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=
@ -107,49 +111,37 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY=
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
github.com/sagernet/nftables v0.3.0-beta.4/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/quic-go v0.45.0-beta.2 h1:nWq9KJTR+cGU8UU4E20XNjdM6QgbLkBgpq+NCExg5RY=
github.com/sagernet/quic-go v0.45.0-beta.2/go.mod h1:rs3XCo3SQ2sB96NtaKnEyq+ZkyaKWL51BvIW3veaiWw=
github.com/sagernet/quic-go v0.45.1-beta.2 h1:zkEeCbhdFFkrxKcuIRBtXNKci/1t2J/39QSG/sPvlmc=
github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX7DeW7BslzLO6N/xI=
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.10 h1:kuHl10gpjbKQAdQfyogQU3u0CVnpqC3wrAHe/+BFaXc=
github.com/sagernet/sing v0.5.0-alpha.10/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.5.0-alpha.10.0.20240615025518-3de31664ce39 h1:Q1Hlje8FURQLHyDq8V2myk/YG+0RPdcnTRZ7Of9/iv8=
github.com/sagernet/sing v0.5.0-alpha.10.0.20240615025518-3de31664ce39/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.0-alpha.7 h1:J3osMCs6ODluRnLfDmoFut9rCpJe/32K9ChpDjG99WI=
github.com/sagernet/sing-box v1.10.0-alpha.7/go.mod h1:fccWloAcFMMFqwYitclTwgUFXJSkC9fNmtbBL6AUhoc=
github.com/sagernet/sing-box v1.10.0-alpha.13 h1:Pmw0U9vB0BYqg5J41KjEzoW93GzpyFdFHp1hg+FxNTE=
github.com/sagernet/sing-box v1.10.0-alpha.13/go.mod h1:xrhprxb5867wn85fGfXcTbrFs2dcatQv/WUvgIudMQQ=
github.com/sagernet/sing-dns v0.3.0-beta.1 h1:ZARhK79eWYckWcGtYBLIT68LnwfbdE2EojkpIpoPGlc=
github.com/sagernet/sing-dns v0.3.0-beta.1/go.mod h1:k/dmFcQpg6+m08gC1yQBy+13+QkuLqpKr4bIreq4U24=
github.com/sagernet/sing-dns v0.3.0-beta.5 h1:lX+wfnBVaOlSd7+GBgb431Tt/gmYwJXSHvS1HutfnD4=
github.com/sagernet/sing-dns v0.3.0-beta.5/go.mod h1:qeO/lOUK/c3Zczp5a1VO13fbmolaM8xGKCUXtaX0/NQ=
github.com/sagernet/sing v0.5.0-alpha.12 h1:pjffG3SUpuF9PLDCqPO2fOAUozXItIBmnMVTKQ/QMhM=
github.com/sagernet/sing v0.5.0-alpha.12/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.0-alpha.19 h1:nsl5T5MAemZdHpsOd10WyTArMsg7QGrNiY1wEsj/ZBM=
github.com/sagernet/sing-box v1.10.0-alpha.19/go.mod h1:LjkcUc0igCyGrX3Ac1JPq2UzUYFQyfCr69f0e0oTOa8=
github.com/sagernet/sing-dns v0.3.0-beta.10 h1:Js61EjQXVpcu2VDegWEQTH1isCcVwJju8WEHYgG4tQ0=
github.com/sagernet/sing-dns v0.3.0-beta.10/go.mod h1:nXE6EYMXahB5DV3AcXYbFfuorqF7tbQ86kxweSxRKM4=
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
github.com/sagernet/sing-quic v0.2.0-beta.5 h1:ceKFLd1iS5AtM+pScKmcDp5k7R6WgYIe8vl6nB0aVsE=
github.com/sagernet/sing-quic v0.2.0-beta.5/go.mod h1:lfad61lScAZhAxZ0DHZWvEIcAaT38O6zPTR4vLsHeP0=
github.com/sagernet/sing-quic v0.2.0-beta.9 h1:gfqUwVgKA6APwFOPhwge9VrPZ0XQtmuXF8hbbIVZML8=
github.com/sagernet/sing-quic v0.2.0-beta.9/go.mod h1:hb6RwYy9Js0gZi80zlTBWABMOIvJDv46K5yak/pbZ4w=
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY=
github.com/sagernet/sing-quic v0.2.0-beta.12/go.mod h1:YVpLfVi8BvYM7NMrjmnvcRm3E8iMETf1gFQmTQDN9jI=
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-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.9.0.20240616071054-61dfac626b74 h1:GcPy5uRjdIdjMvAlx4ZESq2K+9vZNnQpTSPRMXdsHfY=
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240616071054-61dfac626b74/go.mod h1:YgaSM4cm+YIn6erBZN/eF+sW7I27BfBt91EWGo53MME=
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240616073727-85f5f2dd587d h1:ppBKR8H4x64nbtselcGdGOrIMJUIXQL135s5tNUcQMQ=
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240616073727-85f5f2dd587d/go.mod h1:YgaSM4cm+YIn6erBZN/eF+sW7I27BfBt91EWGo53MME=
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/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d h1:2nBM9W9fOCM45hjlu1Fh9qyzBCgKEkq+SOuRCbCCs7c=
github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d/go.mod h1:81JwnnYw8X9W9XvmZetSTTiPgIE3SbAbnc+EHKwPJ5U=
github.com/sagernet/sing-vmess v0.1.11 h1:Kq20MJOBrZzxyHko+/fPHuTszYxe41ClbiNt0TTaqP4=
github.com/sagernet/sing-vmess v0.1.11/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/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI=
@ -244,8 +236,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.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -5,12 +5,16 @@ import (
boxOption "github.com/sagernet/sing-box/option"
)
type OptionsFilter func(metadata metadata.Metadata, options *boxOption.Options)
type OptionsFilter func(metadata metadata.Metadata, options *boxOption.Options) error
var filters []OptionsFilter
func Filter(metadata metadata.Metadata, options *boxOption.Options) {
func Filter(metadata metadata.Metadata, options *boxOption.Options) error {
for _, filter := range filters {
filter(metadata, options)
err := filter(metadata, options)
if err != nil {
return err
}
}
return nil
}

View File

@ -8,57 +8,207 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson"
)
func init() {
filters = append(filters, filter1100)
}
func filter1100(metadata metadata.Metadata, options *option.Options) {
if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.10.0-alpha.13")) {
return
func filter1100(metadata metadata.Metadata, options *option.Options) error {
if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.10.0-alpha.19")) {
return nil
}
newInbounds := make([]option.Inbound, 0, len(options.Inbounds))
for _, inbound := range options.Inbounds {
if inbound.Type == C.TypeTun {
inbound.TunOptions.AutoRedirect = false
inbound.TunOptions.RouteAddressSet = nil
inbound.TunOptions.RouteExcludeAddressSet = nil
//nolint:staticcheck
//goland:noinspection GoDeprecation
if len(inbound.TunOptions.Address) > 0 {
inbound.TunOptions.Inet4Address = append(inbound.TunOptions.Inet4Address, common.Filter(inbound.TunOptions.Address, func(it netip.Prefix) bool {
return it.Addr().Is4()
})...)
inbound.TunOptions.Inet6Address = append(inbound.TunOptions.Inet6Address, common.Filter(inbound.TunOptions.Address, func(it netip.Prefix) bool {
return it.Addr().Is6()
})...)
inbound.TunOptions.Address = nil
}
//nolint:staticcheck
//goland:noinspection GoDeprecation
if len(inbound.TunOptions.RouteAddress) > 0 {
inbound.TunOptions.Inet4RouteAddress = append(inbound.TunOptions.Inet4RouteAddress, common.Filter(inbound.TunOptions.RouteAddress, func(it netip.Prefix) bool {
return it.Addr().Is4()
})...)
inbound.TunOptions.Inet6RouteAddress = append(inbound.TunOptions.Inet6RouteAddress, common.Filter(inbound.TunOptions.RouteAddress, func(it netip.Prefix) bool {
return it.Addr().Is6()
})...)
inbound.TunOptions.RouteAddress = nil
}
//nolint:staticcheck
//goland:noinspection GoDeprecation
if len(inbound.TunOptions.RouteExcludeAddress) > 0 {
inbound.TunOptions.Inet4RouteExcludeAddress = append(inbound.TunOptions.Inet4RouteExcludeAddress, common.Filter(inbound.TunOptions.RouteExcludeAddress, func(it netip.Prefix) bool {
return it.Addr().Is4()
})...)
inbound.TunOptions.Inet6RouteExcludeAddress = append(inbound.TunOptions.Inet6RouteExcludeAddress, common.Filter(inbound.TunOptions.RouteExcludeAddress, func(it netip.Prefix) bool {
return it.Addr().Is6()
})...)
inbound.TunOptions.RouteExcludeAddress = nil
}
var newRuleSets []option.RuleSet
var inlineRuleSets []option.RuleSet
for _, ruleSet := range options.Route.RuleSet {
if ruleSet.Type == C.RuleSetTypeInline {
inlineRuleSets = append(inlineRuleSets, ruleSet)
} else {
newRuleSets = append(newRuleSets, ruleSet)
}
newInbounds = append(newInbounds, inbound)
}
options.Inbounds = newInbounds
options.Route.RuleSet = newRuleSets
if len(inlineRuleSets) > 0 {
var (
currentRules []option.Rule
newRules []option.Rule
)
currentRules = options.Route.Rules
for _, inlineRuleSet := range inlineRuleSets {
for i, rule := range currentRules {
newRuleItems, err := expandInlineRule(inlineRuleSet, rule)
if err != nil {
return E.Cause(err, "expand rule[", i, "]")
}
newRules = append(newRules, newRuleItems...)
}
currentRules = newRules
newRules = newRules[:0]
}
options.Route.Rules = currentRules
var (
currentDNSRules []option.DNSRule
newDNSRules []option.DNSRule
)
currentDNSRules = options.DNS.Rules
for _, inlineRuleSet := range inlineRuleSets {
for i, rule := range currentDNSRules {
newRuleItems, err := expandInlineDNSRule(inlineRuleSet, rule)
if err != nil {
return E.Cause(err, "expand dns rule[", i, "]")
}
newDNSRules = append(newDNSRules, newRuleItems...)
}
currentDNSRules = newDNSRules
newDNSRules = newDNSRules[:0]
}
options.DNS.Rules = currentDNSRules
}
options.Route.Rules = common.Filter(options.Route.Rules, filter1100Rule)
options.DNS.Rules = common.Filter(options.DNS.Rules, filter1100DNSRule)
if metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.10.0-alpha.13")) {
return nil
}
if len(options.Inbounds) > 0 {
newInbounds := make([]option.Inbound, 0, len(options.Inbounds))
for _, inbound := range options.Inbounds {
if inbound.Type == C.TypeTun {
inbound.TunOptions.AutoRedirect = false
inbound.TunOptions.RouteAddressSet = nil
inbound.TunOptions.RouteExcludeAddressSet = nil
//nolint:staticcheck
//goland:noinspection GoDeprecation
if len(inbound.TunOptions.Address) > 0 {
inbound.TunOptions.Inet4Address = append(inbound.TunOptions.Inet4Address, common.Filter(inbound.TunOptions.Address, func(it netip.Prefix) bool {
return it.Addr().Is4()
})...)
inbound.TunOptions.Inet6Address = append(inbound.TunOptions.Inet6Address, common.Filter(inbound.TunOptions.Address, func(it netip.Prefix) bool {
return it.Addr().Is6()
})...)
inbound.TunOptions.Address = nil
}
//nolint:staticcheck
//goland:noinspection GoDeprecation
if len(inbound.TunOptions.RouteAddress) > 0 {
inbound.TunOptions.Inet4RouteAddress = append(inbound.TunOptions.Inet4RouteAddress, common.Filter(inbound.TunOptions.RouteAddress, func(it netip.Prefix) bool {
return it.Addr().Is4()
})...)
inbound.TunOptions.Inet6RouteAddress = append(inbound.TunOptions.Inet6RouteAddress, common.Filter(inbound.TunOptions.RouteAddress, func(it netip.Prefix) bool {
return it.Addr().Is6()
})...)
inbound.TunOptions.RouteAddress = nil
}
//nolint:staticcheck
//goland:noinspection GoDeprecation
if len(inbound.TunOptions.RouteExcludeAddress) > 0 {
inbound.TunOptions.Inet4RouteExcludeAddress = append(inbound.TunOptions.Inet4RouteExcludeAddress, common.Filter(inbound.TunOptions.RouteExcludeAddress, func(it netip.Prefix) bool {
return it.Addr().Is4()
})...)
inbound.TunOptions.Inet6RouteExcludeAddress = append(inbound.TunOptions.Inet6RouteExcludeAddress, common.Filter(inbound.TunOptions.RouteExcludeAddress, func(it netip.Prefix) bool {
return it.Addr().Is6()
})...)
inbound.TunOptions.RouteExcludeAddress = nil
}
}
newInbounds = append(newInbounds, inbound)
}
options.Inbounds = newInbounds
}
return nil
}
func expandInlineRule(ruleSet option.RuleSet, rule option.Rule) ([]option.Rule, error) {
var (
newRules []option.Rule
err error
)
if rule.Type == C.RuleTypeLogical {
for i := range rule.LogicalOptions.Rules {
newRules, err = expandInlineRule(ruleSet, rule.LogicalOptions.Rules[i])
if err != nil {
return nil, E.Cause(err, "[", i, "]")
}
newRules = append(newRules, newRules...)
}
rule.LogicalOptions.Rules = newRules
return []option.Rule{rule}, nil
}
if !common.Contains(rule.DefaultOptions.RuleSet, ruleSet.Tag) {
return []option.Rule{rule}, nil
}
rule.DefaultOptions.RuleSet = common.Filter(rule.DefaultOptions.RuleSet, func(it string) bool {
return it != ruleSet.Tag
})
for i, hRule := range ruleSet.InlineOptions.Rules {
var (
rawRule json.RawMessage
newRule option.Rule
)
rawRule, err = json.Marshal(hRule)
if err != nil {
return nil, E.Cause(err, "marshal inline rule ", ruleSet.Tag, "[", i, "]")
}
newRule, err = badjson.MergeFromSource(rawRule, rule, false)
if err != nil {
return nil, E.Cause(err, "merge inline rule ", ruleSet.Tag, "[", i, "]")
}
newRules = append(newRules, newRule)
}
return newRules, nil
}
func expandInlineDNSRule(ruleSet option.RuleSet, rule option.DNSRule) ([]option.DNSRule, error) {
var (
newRules []option.DNSRule
err error
)
if rule.Type == C.RuleTypeLogical {
for i := range rule.LogicalOptions.Rules {
newRules, err = expandInlineDNSRule(ruleSet, rule.LogicalOptions.Rules[i])
if err != nil {
return nil, E.Cause(err, "[", i, "]")
}
newRules = append(newRules, newRules...)
}
rule.LogicalOptions.Rules = newRules
return []option.DNSRule{rule}, nil
}
if !common.Contains(rule.DefaultOptions.RuleSet, ruleSet.Tag) {
return []option.DNSRule{rule}, nil
}
rule.DefaultOptions.RuleSet = common.Filter(rule.DefaultOptions.RuleSet, func(it string) bool {
return it != ruleSet.Tag
})
for i, hRule := range ruleSet.InlineOptions.Rules {
var (
rawRule json.RawMessage
newRule option.DNSRule
)
rawRule, err = json.Marshal(hRule)
if err != nil {
return nil, E.Cause(err, "marshal inline rule ", ruleSet.Tag, "[", i, "]")
}
newRule, err = badjson.MergeFromSource(rawRule, rule, false)
if err != nil {
return nil, E.Cause(err, "merge inline rule ", ruleSet.Tag, "[", i, "]")
}
newRules = append(newRules, newRule)
}
return newRules, nil
}
func filter1100Rule(it option.Rule) bool {
return !hasRule([]option.Rule{it}, func(it option.DefaultRule) bool {
return it.RuleSetIPCIDRMatchSource
})
}
func filter1100DNSRule(it option.DNSRule) bool {
return !hasDNSRule([]option.DNSRule{it}, func(it option.DefaultDNSRule) bool {
return it.RuleSetIPCIDRMatchSource || it.RuleSetIPCIDRAcceptEmpty
})
}

View File

@ -1,92 +0,0 @@
package filter
import (
"github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
)
func init() {
filters = append(filters, filter170)
}
func filter170(metadata metadata.Metadata, options *option.Options) {
if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.Version{Major: 1, Minor: 7}) {
return
}
newInbounds := make([]option.Inbound, 0, len(options.Inbounds))
for _, inbound := range options.Inbounds {
switch inbound.Type {
case C.TypeTun:
inbound.TunOptions = filter170Tun(inbound.TunOptions)
inbound.TunOptions.InboundOptions = filter170InboundOptions(inbound.TunOptions.InboundOptions)
case C.TypeRedirect:
inbound.RedirectOptions.InboundOptions = filter170InboundOptions(inbound.RedirectOptions.InboundOptions)
case C.TypeTProxy:
inbound.TProxyOptions.InboundOptions = filter170InboundOptions(inbound.TProxyOptions.InboundOptions)
case C.TypeDirect:
inbound.DirectOptions.InboundOptions = filter170InboundOptions(inbound.DirectOptions.InboundOptions)
case C.TypeSOCKS:
inbound.SocksOptions.InboundOptions = filter170InboundOptions(inbound.SocksOptions.InboundOptions)
case C.TypeHTTP:
inbound.HTTPOptions.InboundOptions = filter170InboundOptions(inbound.HTTPOptions.InboundOptions)
case C.TypeMixed:
inbound.MixedOptions.InboundOptions = filter170InboundOptions(inbound.MixedOptions.InboundOptions)
case C.TypeShadowsocks:
inbound.ShadowsocksOptions.InboundOptions = filter170InboundOptions(inbound.ShadowsocksOptions.InboundOptions)
inbound.ShadowsocksOptions.Multiplex = nil
case C.TypeVMess:
inbound.VMessOptions.InboundOptions = filter170InboundOptions(inbound.VMessOptions.InboundOptions)
inbound.VMessOptions.Multiplex = nil
case C.TypeTrojan:
inbound.TrojanOptions.InboundOptions = filter170InboundOptions(inbound.TrojanOptions.InboundOptions)
inbound.TrojanOptions.Multiplex = nil
case C.TypeNaive:
inbound.NaiveOptions.InboundOptions = filter170InboundOptions(inbound.NaiveOptions.InboundOptions)
case C.TypeHysteria:
inbound.HysteriaOptions.InboundOptions = filter170InboundOptions(inbound.HysteriaOptions.InboundOptions)
case C.TypeShadowTLS:
inbound.ShadowTLSOptions.InboundOptions = filter170InboundOptions(inbound.ShadowTLSOptions.InboundOptions)
case C.TypeVLESS:
inbound.VLESSOptions.InboundOptions = filter170InboundOptions(inbound.VLESSOptions.InboundOptions)
inbound.VLESSOptions.Multiplex = nil
case C.TypeTUIC:
inbound.TUICOptions.InboundOptions = filter170InboundOptions(inbound.TUICOptions.InboundOptions)
case C.TypeHysteria2:
inbound.Hysteria2Options.InboundOptions = filter170InboundOptions(inbound.Hysteria2Options.InboundOptions)
default:
continue
}
newInbounds = append(newInbounds, inbound)
}
options.Inbounds = newInbounds
if options.Route != nil {
options.Route.Rules = common.Filter(options.Route.Rules, filter170Rule)
}
if options.DNS != nil {
options.DNS.Rules = common.Filter(options.DNS.Rules, filter170DNSRule)
}
}
//nolint:staticcheck
//goland:noinspection GoDeprecation
func filter170Tun(options option.TunInboundOptions) option.TunInboundOptions {
options.Inet4RouteExcludeAddress = nil
options.Inet6RouteExcludeAddress = nil
return options
}
func filter170InboundOptions(options option.InboundOptions) option.InboundOptions {
options.UDPDisableDomainUnmapping = false
return options
}
func filter170Rule(it option.Rule) bool {
return !hasRule([]option.Rule{it}, isWIFIRule)
}
func filter170DNSRule(it option.DNSRule) bool {
return !hasDNSRule([]option.DNSRule{it}, isWIFIDNSRule)
}

View File

@ -1,58 +0,0 @@
package filter
import (
"github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
)
func init() {
filters = append(filters, filter180)
}
func filter180(metadata metadata.Metadata, options *option.Options) {
if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.8.0-alpha.10")) {
return
}
for index, outbound := range options.Outbounds {
switch outbound.Type {
case C.TypeURLTest:
options.Outbounds[index].URLTestOptions = filter180a10URLTest(outbound.URLTestOptions)
}
}
if metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.8.0-alpha.5")) {
return
}
options.Route.RuleSet = nil
if options.Route != nil {
options.Route.Rules = common.Filter(options.Route.Rules, filter180Rule)
}
if options.DNS != nil {
options.DNS.Rules = common.Filter(options.DNS.Rules, filter180DNSRule)
}
if metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.8.0-alpha.1")) {
return
}
if options.Route != nil {
options.Route.Rules = common.Filter(options.Route.Rules, filter180a5Rule)
}
}
func filter180Rule(it option.Rule) bool {
return !hasRule([]option.Rule{it}, isRuleSetRule)
}
func filter180DNSRule(it option.DNSRule) bool {
return !hasDNSRule([]option.DNSRule{it}, isRuleSetDNSRule)
}
func filter180a5Rule(it option.Rule) bool {
return !hasRule([]option.Rule{it}, isIPIsPrivateRule)
}
func filter180a10URLTest(options option.URLTestOutboundOptions) option.URLTestOutboundOptions {
options.IdleTimeout = 0
return options
}

View File

@ -12,16 +12,16 @@ func init() {
filters = append(filters, filter190)
}
func filter190(metadata metadata.Metadata, options *option.Options) {
func filter190(metadata metadata.Metadata, options *option.Options) error {
if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.1")) {
return
return nil
}
if options.DNS == nil || len(options.DNS.Rules) == 0 {
return
return nil
}
options.DNS.Rules = common.Filter(options.DNS.Rules, filter190DNSRule)
if metadata.Version == nil || metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.9.0-alpha.10")) {
return
return nil
}
for _, inbound := range options.Inbounds {
switch inbound.Type {
@ -36,12 +36,11 @@ func filter190(metadata metadata.Metadata, options *option.Options) {
}
}
}
return nil
}
func filter190DNSRule(it option.DNSRule) bool {
return !hasDNSRule([]option.DNSRule{it}, isAddressFilterRule)
}
func isAddressFilterRule(it option.DefaultDNSRule) bool {
return len(it.GeoIP) > 0 || len(it.IPCIDR) > 0 || it.IPIsPrivate
return !hasDNSRule([]option.DNSRule{it}, func(it option.DefaultDNSRule) bool {
return len(it.GeoIP) > 0 || len(it.IPCIDR) > 0 || it.IPIsPrivate
})
}

View File

@ -11,7 +11,7 @@ func init() {
filters = append(filters, filterNullGroupReference)
}
func filterNullGroupReference(metadata M.Metadata, options *option.Options) {
func filterNullGroupReference(metadata M.Metadata, options *option.Options) error {
outboundTags := common.Map(options.Outbounds, func(it option.Outbound) string {
return it.Tag
})
@ -30,4 +30,5 @@ func filterNullGroupReference(metadata M.Metadata, options *option.Options) {
}
options.Outbounds[i] = outbound
}
return nil
}

View File

@ -0,0 +1,81 @@
package filter
import (
"testing"
"github.com/sagernet/serenity/common/metadata"
"github.com/sagernet/serenity/common/semver"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/stretchr/testify/require"
)
func TestFilter1100(t *testing.T) {
options := &option.Options{
DNS: &option.DNSOptions{
Rules: []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RuleSet: []string{"test"},
Server: "test",
},
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
RuleSet: []string{"test"},
Outbound: "test",
},
},
},
RuleSet: []option.RuleSet{
{
Type: C.RuleSetTypeInline,
Tag: "test",
InlineOptions: option.PlainRuleSet{
Rules: []option.HeadlessRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultHeadlessRule{
Domain: []string{"example.com"},
},
},
},
},
},
},
},
}
err := filter1100(metadata.Metadata{Version: &semver.Version{Major: 1, Minor: 9, Patch: 3}}, options)
require.NoError(t, err)
require.Equal(t, options, &option.Options{
DNS: &option.DNSOptions{
Rules: []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
Domain: []string{"example.com"},
Server: "test",
},
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
Domain: []string{"example.com"},
Outbound: "test",
},
},
},
},
})
}

View File

@ -41,7 +41,7 @@ func extendTemplate(rawTemplates []option.Template, root, current option.Templat
}
next = newNext
}
newRawTemplate, err := badjson.MergeJSON(next.RawMessage, current.RawMessage)
newRawTemplate, err := badjson.MergeJSON(next.RawMessage, current.RawMessage, true)
if err != nil {
return option.Template{}, E.Cause(err, "initialize template[", current.Name, "]: merge extended template: ", current.Extend)
}

View File

@ -37,7 +37,7 @@ func (t *Template) renderExperimental(metadata M.Metadata, options *option.Optio
}
if t.CustomClashAPI != nil {
newClashOptions, err := badjson.MergeFromDestination(options.Experimental.ClashAPI, t.CustomClashAPI.Message)
newClashOptions, err := badjson.MergeFromDestination(options.Experimental.ClashAPI, t.CustomClashAPI.Message, true)
if err != nil {
return err
}

View File

@ -77,7 +77,7 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
}
}
if t.CustomTUN != nil {
newTUNOptions, err := badjson.MergeFromDestination(tunInbound.TunOptions, t.CustomTUN.Message)
newTUNOptions, err := badjson.MergeFromDestination(tunInbound.TunOptions, t.CustomTUN.Message, true)
if err != nil {
return E.Cause(err, "merge custom tun options")
}
@ -101,7 +101,7 @@ func (t *Template) renderInbounds(metadata M.Metadata, options *option.Options)
},
}
if t.CustomMixed != nil {
newMixedOptions, err := badjson.MergeFromDestination(mixedInbound.MixedOptions, t.CustomMixed.Message)
newMixedOptions, err := badjson.MergeFromDestination(mixedInbound.MixedOptions, t.CustomMixed.Message, true)
if err != nil {
return E.Cause(err, "merge custom mixed options")
}

View File

@ -62,6 +62,9 @@ func (t *Template) Render(metadata M.Metadata, profileName string, outbounds [][
if err != nil {
return nil, E.Cause(err, "render experimental")
}
filter.Filter(metadata, &options)
err = filter.Filter(metadata, &options)
if err != nil {
return nil, E.Cause(err, "filter options")
}
return &options, nil
}