Fix geoip geosite & Migrate from block to reject

This commit is contained in:
armv9 2025-02-26 13:24:20 +09:00
parent 0cf1c81933
commit bb53000282
11 changed files with 65 additions and 172 deletions

View File

@ -616,22 +616,27 @@ fun buildConfig(
Toast.LENGTH_LONG
).show()
} else {
// block 改用新的写法
if (ruleObj.outbound == TAG_BLOCK) {
ruleObj.outbound = null
ruleObj.action = "reject"
}
route.rules.add(ruleObj)
route.rule_set.addAll(ruleSets)
}
}
}
// 对 rule_set tag 去重
if (route.rule_set != null) {
route.rule_set = route.rule_set.distinctBy { it.tag }
}
for (freedom in arrayOf(TAG_DIRECT, TAG_BYPASS)) outbounds.add(Outbound().apply {
tag = freedom
type = "direct"
}.asMap())
outbounds.add(Outbound().apply {
tag = TAG_BLOCK
type = "block"
}.asMap())
if (!forTest) {
inbounds.add(0, Inbound_DirectOptions().apply {
type = "direct"
@ -738,7 +743,7 @@ fun buildConfig(
route.rules.add(Rule_DefaultOptions().apply {
ip_cidr = listOf("224.0.0.0/3", "ff00::/8")
source_ip_cidr = listOf("224.0.0.0/3", "ff00::/8")
outbound = TAG_BLOCK
action = "reject"
})
// FakeDNS obj
if (useFakeDns) {

View File

@ -1,38 +0,0 @@
package io.nekohasekai.sagernet.utils
import android.content.Context
import io.nekohasekai.sagernet.ktx.app
import libcore.Libcore
import java.io.File
object GeoipUtils {
/**
* Generate a rule set for a specific country
* @param context the context to use
* @param country the country code to generate the rule set for
* @return the path to the generated rule set
*/
fun generateRuleSet(context: Context = app.applicationContext, country: String): String {
val filesDir = context.getExternalFilesDir(null) ?: context.filesDir
val ruleSetDir = filesDir.resolve("ruleSets")
ruleSetDir.mkdirs()
val output = ruleSetDir.resolve("geoip-$country.srs")
if (output.isFile) {
return output.absolutePath
}
val geositeFile = File(filesDir, "geoip.db")
val geoip = Libcore.newGeoip()
if (!geoip.openGeosite(geositeFile.absolutePath)) {
error("open geoip failed")
}
geoip.convertGeoip(country, output.absolutePath)
return output.absolutePath
}
}

View File

@ -1,33 +0,0 @@
package io.nekohasekai.sagernet.utils
import android.content.Context
import io.nekohasekai.sagernet.ktx.app
import libcore.Geosite
import java.io.File
object GeositeUtils {
/**
* Generate a rule set for a specific geosite code
* @param context the context to use
* @param code the geosite code to generate the rule set for
* @return the path to the generated rule set
*/
fun generateRuleSet(context: Context = app.applicationContext, code: String): String {
val filesDir = context.getExternalFilesDir(null) ?: context.filesDir
val geositeFile = File(filesDir, "geosite.db")
val ruleSetDir = filesDir.resolve("ruleSets")
ruleSetDir.mkdirs()
val output = ruleSetDir.resolve("geosite-$code.srs")
val geosite = Geosite()
if (!geosite.checkGeositeCode(geositeFile.absolutePath, code)) {
error("code $code not found in geosite")
}
geosite.convertGeosite(code, output.absolutePath)
return output.absolutePath
}
}

View File

@ -4374,6 +4374,8 @@ public class SingBoxOptions {
public Boolean invert;
public String action;
public String outbound;
}

View File

@ -1,8 +1,6 @@
package moe.matsuri.nb4a
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.utils.GeoipUtils
import io.nekohasekai.sagernet.utils.GeositeUtils
import moe.matsuri.nb4a.SingBoxOptions.RuleSet
object SingBoxOptionsUtil {
@ -75,23 +73,21 @@ fun SingBoxOptions.DNSRule_DefaultOptions.checkEmpty(): Boolean {
fun generateRuleSet(ruleSetString: List<String>, ruleSet: MutableList<RuleSet>) {
ruleSetString.forEach {
when {
it.startsWith("geoip") -> {
val geoipPath = GeoipUtils.generateRuleSet(country = it.removePrefix("geoip:"))
it.startsWith("geoip:") -> {
ruleSet.add(RuleSet().apply {
type = "local"
tag = it
format = "binary"
path = geoipPath
path = it
})
}
it.startsWith("geosite") -> {
val geositePath = GeositeUtils.generateRuleSet(code = it.removePrefix("geosite:"))
it.startsWith("geosite:") -> {
ruleSet.add(RuleSet().apply {
type = "local"
tag = it
format = "binary"
path = geositePath
path = it
})
}
}

View File

@ -70,7 +70,7 @@
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:text="stun.syncthing.net:3478" />
android:text="stun.voipgate.com:3478" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -1,2 +1,2 @@
export COMMIT_SING_BOX="76802b787333ad72bc1db2de79ea69993b79d892"
export COMMIT_SING_BOX="eb5f8c56b2212a6fda79d5e70659dd9c392c133a"
export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b"

View File

@ -1,34 +1,28 @@
package libcore
import (
"log"
"fmt"
"net"
"os"
"path/filepath"
"strings"
"github.com/oschwald/maxminddb-golang"
"github.com/sagernet/sing-box/common/srs"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/nekoutils"
"github.com/sagernet/sing-box/option"
)
type Geoip struct {
type geoip struct {
geoipReader *maxminddb.Reader
}
func (g *Geoip) OpenGeosite(path string) bool {
func (g *geoip) Open(path string) error {
geoipReader, err := maxminddb.Open(path)
g.geoipReader = geoipReader
if err != nil {
log.Println("failed to open geoip file:", err)
return false
} else {
log.Println("loaded geoip database")
}
return true
return err
}
func (g *Geoip) ConvertGeoip(countryCode, outputPath string) {
func (g *geoip) Rules(countryCode string) ([]option.HeadlessRule, error) {
networks := g.geoipReader.Networks(maxminddb.SkipAliasedNetworks)
countryMap := make(map[string][]*net.IPNet)
var (
@ -39,8 +33,7 @@ func (g *Geoip) ConvertGeoip(countryCode, outputPath string) {
for networks.Next() {
ipNet, err = networks.Network(&nextCountryCode)
if err != nil {
log.Println("failed to get network:", err)
return
return nil, fmt.Errorf("failed to get network: %w", err)
}
countryMap[nextCountryCode] = append(countryMap[nextCountryCode], ipNet)
}
@ -48,8 +41,7 @@ func (g *Geoip) ConvertGeoip(countryCode, outputPath string) {
ipNets := countryMap[strings.ToLower(countryCode)]
if len(ipNets) == 0 {
log.Println("no networks found for country code:", countryCode)
return
return nil, fmt.Errorf("no networks found for country code: %s", countryCode)
}
var headlessRule option.DefaultHeadlessRule
@ -57,24 +49,21 @@ func (g *Geoip) ConvertGeoip(countryCode, outputPath string) {
for _, cidr := range ipNets {
headlessRule.IPCIDR = append(headlessRule.IPCIDR, cidr.String())
}
var plainRuleSet option.PlainRuleSetCompat
plainRuleSet.Version = C.RuleSetVersion1
plainRuleSet.Options.Rules = []option.HeadlessRule{
return []option.HeadlessRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: headlessRule,
},
}, nil
}
outputFile, err := os.Create(outputPath)
rs, _ := plainRuleSet.Upgrade()
err = srs.Write(outputFile, rs, plainRuleSet.Version)
if err != nil {
log.Println("failed to write geosite file:", err)
return
func init() {
nekoutils.GetGeoIPHeadlessRules = func(name string) ([]option.HeadlessRule, error) {
g := new(geoip)
if err := g.Open(filepath.Join(externalAssetsPath, "geoip.db")); err != nil {
return nil, err
}
return g.Rules(name)
}
}
func NewGeoip() *Geoip {
return new(Geoip)
}

View File

@ -1,71 +1,54 @@
package libcore
import (
"log"
"os"
"fmt"
"path/filepath"
"github.com/sagernet/sing-box/common/geosite"
"github.com/sagernet/sing-box/common/srs"
geosites "github.com/sagernet/sing-box/common/geosite"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/nekoutils"
"github.com/sagernet/sing-box/option"
)
type Geosite struct {
geositeReader *geosite.Reader
type geosite struct {
geositeReader *geosites.Reader
}
func (g *Geosite) CheckGeositeCode(path string, code string) bool {
geositeReader, codes, err := geosite.Open(path)
func (g *geosite) Open(path string) error {
geositeReader, _, err := geosites.Open(path)
g.geositeReader = geositeReader
if err != nil {
log.Println("failed to open geosite file:", err)
return false
} else {
log.Println("loaded geosite database: ", len(codes), " codes")
}
sourceSet, err := geositeReader.Read(code)
if err != nil {
log.Println("failed to read geosite code:", code, err)
return false
}
return len(sourceSet) >= 1
return err
}
// ConvertGeosite need to run CheckGeositeCode first
func (g *Geosite) ConvertGeosite(code string, outputPath string) {
func (g *geosite) Rules(code string) ([]option.HeadlessRule, error) {
sourceSet, err := g.geositeReader.Read(code)
if err != nil {
log.Println("failed to read geosite code:", code, err)
return
return nil, fmt.Errorf("failed to read geosite code %s :%w", code, err)
}
var headlessRule option.DefaultHeadlessRule
defaultRule := geosite.Compile(sourceSet)
defaultRule := geosites.Compile(sourceSet)
headlessRule.Domain = defaultRule.Domain
headlessRule.DomainSuffix = defaultRule.DomainSuffix
headlessRule.DomainKeyword = defaultRule.DomainKeyword
headlessRule.DomainRegex = defaultRule.DomainRegex
var plainRuleSet option.PlainRuleSetCompat
plainRuleSet.Version = C.RuleSetVersion1
plainRuleSet.Options.Rules = []option.HeadlessRule{
return []option.HeadlessRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: headlessRule,
},
}, nil
}
outputFile, err := os.Create(outputPath)
rs, _ := plainRuleSet.Upgrade()
err = srs.Write(outputFile, rs, plainRuleSet.Version)
if err != nil {
log.Println("failed to write geosite file:", err)
return
func init() {
nekoutils.GetGeoSiteHeadlessRules = func(name string) ([]option.HeadlessRule, error) {
g := new(geosite)
if err := g.Open(filepath.Join(externalAssetsPath, "geosite.db")); err != nil {
return nil, err
}
return g.Rules(name)
}
}
func newGeosite() *Geosite {
return new(Geosite)
}

View File

@ -19,7 +19,7 @@ require (
require (
github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/anytls/sing-anytls v0.0.2 // indirect
github.com/anytls/sing-anytls v0.0.5 // indirect
github.com/caddyserver/certmagic v0.20.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cretz/bine v0.2.0 // indirect
@ -35,7 +35,6 @@ require (
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.2 // indirect
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
@ -48,7 +47,6 @@ require (
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect
github.com/mholt/acmez v1.2.0 // indirect
github.com/onsi/ginkgo/v2 v2.9.7 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
@ -70,7 +68,6 @@ require (
github.com/sagernet/utls v1.6.7 // indirect
github.com/sagernet/wireguard-go v0.0.1-beta.5 // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.uber.org/multierr v1.11.0 // indirect

View File

@ -2,8 +2,8 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/anytls/sing-anytls v0.0.2 h1:25azSh0o/LMcIkhS4ZutgRTIGwh8O3wuOhsThVM9K9o=
github.com/anytls/sing-anytls v0.0.2/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/anytls/sing-anytls v0.0.5 h1:I1NIh3zKTSXThLG5UgjsOOT/x2DZJqjfBzjuP/wZlDk=
github.com/anytls/sing-anytls v0.0.5/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
@ -41,9 +41,6 @@ github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5X
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4=
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k=
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
@ -76,8 +73,6 @@ github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
@ -134,8 +129,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.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/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
@ -171,7 +164,6 @@ golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=