Fix override logic

This commit is contained in:
problematicconsumer
2023-08-22 00:54:58 +03:30
parent 85efdbb5ff
commit 83d668866e
8 changed files with 351 additions and 198 deletions

View File

@@ -37,8 +37,15 @@ func create(configPath *C.char) *C.char {
if err != nil {
return C.CString(err.Error())
}
overrides := shared.ConfigOverrides{ExcludeTunInbound: true, IncludeMixedInbound: true, IncludeLogOutput: true, LogLevel: "info", IncludeLogTimestamp: false, ClashApiPort: 9090}
options = shared.ApplyOverrides(options, overrides)
overrides := shared.ConfigOverrides{
LogOutput: shared.StringAddr("box.log"),
EnableTun: shared.BoolAddr(false),
SetSystemProxy: shared.BoolAddr(true),
}
template := shared.DefaultTemplate(overrides)
options = shared.ApplyOverrides(template, options, overrides)
shared.SaveCurrentConfig(sWorkingPath, options)
instance, err := NewService(options)
if err != nil {

2
go.mod
View File

@@ -6,6 +6,7 @@ require (
github.com/sagernet/gomobile v0.0.0-20230728014906-3de089147f59
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a
github.com/sagernet/sing-box v1.3.6
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659
github.com/xmdhs/clash2singbox v0.0.0-20230810082059-5054938e1bfd
gopkg.in/yaml.v3 v3.0.1
)
@@ -54,7 +55,6 @@ require (
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/quic-go v0.0.0-20230731012313-1327e4015111 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 // indirect
github.com/sagernet/sing-mux v0.1.3-0.20230803070305-ea4a972acd21 // indirect
github.com/sagernet/sing-shadowsocks v0.2.4 // indirect
github.com/sagernet/sing-shadowsocks2 v0.1.3 // indirect

View File

@@ -1,3 +1,34 @@
// package mobile
// import (
// "encoding/json"
// "os"
// "github.com/hiddify/libcore/shared"
// _ "github.com/sagernet/gomobile/event/key"
// "github.com/sagernet/sing-box/option"
// )
// func Parse(path string) error {
// return shared.ParseConfig(path)
// }
// func ApplyOverrides(path string) (string, error) {
// fileContent, err := os.ReadFile(path)
// if err != nil {
// return "", err
// }
// var options option.Options
// err = options.UnmarshalJSON(fileContent)
// if err != nil {
// return "", err
// }
// overrides := shared.ConfigOverrides{ExcludeTunInbound: false, IncludeMixedInbound: false, IncludeLogOutput: false, LogLevel: "", IncludeLogTimestamp: false, ClashApiPort: 9090}
// options = shared.ApplyOverrides(options, overrides)
// config, err := json.Marshal(options)
// return string(config), err
// }
package mobile
import (
@@ -23,8 +54,13 @@ func ApplyOverrides(path string) (string, error) {
if err != nil {
return "", err
}
overrides := shared.ConfigOverrides{ExcludeTunInbound: false, IncludeMixedInbound: false, IncludeLogOutput: false, LogLevel: "", IncludeLogTimestamp: false, ClashApiPort: 9090}
options = shared.ApplyOverrides(options, overrides)
overrides := shared.ConfigOverrides{
EnableTun: shared.BoolAddr(true),
SetSystemProxy: shared.BoolAddr(false),
LogOutput: shared.StringAddr(""),
}
template := shared.DefaultTemplate(overrides)
options = shared.ApplyOverrides(template, options, overrides)
config, err := json.Marshal(options)
return string(config), err
}

View File

@@ -1,127 +1,8 @@
{
"log": {},
"dns": {
"servers": [
{
"tag": "remote",
"address_resolver": "local",
"address": "tcp://1.1.1.1",
"strategy": "prefer_ipv4",
"detour": "select"
},
{
"tag": "local",
"address": "local",
"detour": "direct"
}
],
"rules": [
{
"clash_mode": "global",
"server": "remote"
},
{
"clash_mode": "direct",
"server": "local"
},
{
"outbound": [
"any"
],
"server": "local"
},
{
"geosite": "ir",
"server": "local"
}
],
"strategy": "ipv4_only"
},
"inbounds": [
{
"type": "tun",
"inet4_address": "172.19.0.1/30",
"sniff": true,
"sniff_override_destination": true,
"domain_strategy": "ipv4_only",
"strict_route": true,
"mtu": 9000,
"endpoint_independent_nat": true,
"auto_route": true
},
{
"type": "socks",
"tag": "socks-in",
"listen": "127.0.0.1",
"sniff": true,
"sniff_override_destination": true,
"domain_strategy": "ipv4_only",
"listen_port": 2333,
"users": []
},
{
"type": "mixed",
"tag": "mixed-in",
"sniff": true,
"sniff_override_destination": true,
"domain_strategy": "ipv4_only",
"listen": "127.0.0.1",
"listen_port": 2334,
"set_system_proxy": true,
"users": []
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
},
{
"type": "dns",
"tag": "dns-out"
}
],
"route": {
"rules": [
{
"geosite": "category-ads-all",
"outbound": "block"
},
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"clash_mode": "direct",
"outbound": "direct"
},
{
"clash_mode": "global",
"outbound": "select"
},
{
"geoip": [
"ir",
"private"
],
"outbound": "direct"
},
{
"geosite": "ir",
"outbound": "direct"
}
],
"auto_detect_interface": true
},
"experimental": {
"clash_api": {
"external_controller": "127.0.0.1:9090",
"store_selected": true,
"secret": ""
}
}
"dns": {},
"inbounds": [],
"outbounds": [],
"route": {},
"experimental": {}
}

22
shared/debug.go Normal file
View File

@@ -0,0 +1,22 @@
package shared
import (
"bytes"
"encoding/json"
"os"
"path/filepath"
"github.com/sagernet/sing-box/option"
)
func SaveCurrentConfig(path string, options option.Options) error {
var buffer bytes.Buffer
json.NewEncoder(&buffer)
encoder := json.NewEncoder(&buffer)
encoder.SetIndent("", " ")
err := encoder.Encode(options)
if err != nil {
return err
}
return os.WriteFile(filepath.Join(path, "current-config.json"), buffer.Bytes(), 0777)
}

View File

@@ -8,91 +8,95 @@ import (
)
type ConfigOverrides struct {
ExcludeTunInbound bool
IncludeMixedInbound bool
IncludeLogOutput bool
IncludeLogTimestamp bool
LogLevel string
ClashApiPort int
ClashApiPort *int `json:"clash-api-port"`
EnableTun *bool `json:"enable-tun"`
SetSystemProxy *bool `json:"set-system-proxy"`
LogLevel *string `json:"log-level"`
LogOutput *string `json:"log-output"`
DNSRemote *string `json:"dns-remote"`
MixedPort *int `json:"mixed-port"`
}
func ApplyOverrides(options option.Options, overrides ConfigOverrides) option.Options {
options.Log = &option.LogOptions{
Disabled: false,
Timestamp: overrides.IncludeLogTimestamp,
DisableColor: true,
}
if overrides.LogLevel != "" {
options.Log.Level = overrides.LogLevel
}
if overrides.IncludeLogOutput {
options.Log.Output = "box.log"
func ApplyOverrides(base option.Options, options option.Options, overrides ConfigOverrides) option.Options {
clashApiPort := pointerOrDefaultInt(overrides.ClashApiPort, 9090)
base.Experimental = &option.ExperimentalOptions{
ClashAPI: &option.ClashAPIOptions{
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", clashApiPort),
StoreSelected: true,
},
}
options.Experimental.ClashAPI = &option.ClashAPIOptions{
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", overrides.ClashApiPort),
StoreSelected: true,
Secret: "",
base.Log = &option.LogOptions{
Level: pointerOrDefaultString(overrides.LogLevel, "info"),
Output: pointerOrDefaultString(overrides.LogOutput, ""),
Disabled: false,
Timestamp: false,
DisableColor: true,
}
var inbounds []option.Inbound
for _, inb := range options.Inbounds {
if overrides.ExcludeTunInbound && inb.Type == C.TypeTun {
continue
}
if overrides.IncludeMixedInbound && inb.Type == C.TypeMixed {
inb.MixedOptions.SetSystemProxy = true
for _, inb := range base.Inbounds {
switch inb.Type {
case C.TypeTun:
if pointerOrDefaultBool(overrides.EnableTun, true) {
inbounds = append(inbounds, inb)
}
default:
inbounds = append(inbounds, inb)
continue
}
inbounds = append(inbounds, inb)
}
options.Inbounds = inbounds
base.Inbounds = inbounds
hasSelector := false
hasUrlTest := false
var selectable []option.Outbound
var urlTests []option.Outbound
var outbounds []option.Outbound
var tags []string
for _, out := range options.Outbounds {
if out.Type == C.TypeSelector {
hasSelector = true
} else if out.Type == C.TypeURLTest {
hasUrlTest = true
urlTests = append(urlTests, out)
}
switch out.Type {
case C.TypeDirect, C.TypeBlock, C.TypeDNS:
continue
case C.TypeSelector, C.TypeURLTest:
continue
default:
tags = append(tags, out.Tag)
}
selectable = append(selectable, out)
}
var generatedUrlTest *option.Outbound
if !hasUrlTest {
var urlSelectOuts []string
for _, out := range selectable {
urlSelectOuts = append(urlSelectOuts, out.Tag)
}
generatedUrlTest = &option.Outbound{Type: C.TypeURLTest, Tag: "urltest", URLTestOptions: option.URLTestOutboundOptions{Outbounds: urlSelectOuts}}
urlTests = append(urlTests, *generatedUrlTest)
}
if !hasSelector {
var selectorOuts []string
for _, out := range selectable {
selectorOuts = append(selectorOuts, out.Tag)
}
for _, out := range urlTests {
selectorOuts = append(selectorOuts, out.Tag)
}
defaultSelector := option.Outbound{Type: C.TypeSelector, Tag: "select", SelectorOptions: option.SelectorOutboundOptions{Outbounds: selectorOuts}}
if generatedUrlTest != nil {
defaultSelector.SelectorOptions.Default = generatedUrlTest.Tag
}
options.Outbounds = append([]option.Outbound{defaultSelector}, options.Outbounds...)
}
if generatedUrlTest != nil {
options.Outbounds = append(options.Outbounds, *generatedUrlTest)
outbounds = append(outbounds, out)
}
return options
urlTest := option.Outbound{
Type: C.TypeURLTest,
Tag: "auto",
URLTestOptions: option.URLTestOutboundOptions{
Outbounds: tags,
},
}
selector := option.Outbound{
Type: C.TypeSelector,
Tag: "select",
SelectorOptions: option.SelectorOutboundOptions{
Outbounds: append([]string{urlTest.Tag}, tags...),
Default: urlTest.Tag,
},
}
outbounds = append([]option.Outbound{selector, urlTest}, outbounds...)
base.Outbounds = append(
outbounds,
[]option.Outbound{
{
Tag: "direct",
Type: C.TypeDirect,
},
{
Tag: "block",
Type: C.TypeBlock,
},
{
Tag: "dns-out",
Type: C.TypeDNS,
},
}...,
)
return base
}

168
shared/template.go Normal file
View File

@@ -0,0 +1,168 @@
package shared
import (
"net/netip"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
dns "github.com/sagernet/sing-dns"
)
func DefaultTemplate(overrides ConfigOverrides) option.Options {
var options option.Options
options.Experimental = &option.ExperimentalOptions{
ClashAPI: &option.ClashAPIOptions{
ExternalController: "127.0.0.1:9090",
StoreSelected: true,
},
}
options.Log = &option.LogOptions{
Level: "warn",
Disabled: false,
Timestamp: false,
DisableColor: true,
}
options.DNS = &option.DNSOptions{
DNSClientOptions: option.DNSClientOptions{
Strategy: option.DomainStrategy(dns.DomainStrategyPreferIPv4),
IndependentCache: true,
},
Servers: []option.DNSServerOptions{
{
Tag: "local",
Address: "local",
Detour: "direct",
},
{
Tag: "dns-remote",
Address: pointerOrDefaultString(overrides.DNSRemote, "tcp://1.1.1.1"),
AddressResolver: "local",
Strategy: option.DomainStrategy(dns.DomainStrategyPreferIPv4),
Detour: "select",
},
},
Rules: []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
ClashMode: "direct",
Server: "local",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
ClashMode: "global",
Server: "dns-remote",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
DomainSuffix: []string{"ir"},
Server: "local",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
Outbound: []string{"any"},
Server: "local",
},
},
},
ReverseMapping: true,
Final: "dns-remote",
}
if pointerOrDefaultBool(overrides.EnableTun, true) {
options.Inbounds = append(
options.Inbounds,
option.Inbound{
Type: C.TypeTun,
Tag: "tun-in",
TunOptions: option.TunInboundOptions{
Inet4Address: []option.ListenPrefix{
option.ListenPrefix(netip.MustParsePrefix("172.19.0.1/30")),
},
MTU: 9000,
AutoRoute: true,
StrictRoute: true,
EndpointIndependentNat: true,
InboundOptions: option.InboundOptions{
SniffEnabled: true,
SniffOverrideDestination: true,
DomainStrategy: option.DomainStrategy(dns.DomainStrategyUseIPv4),
},
},
},
)
}
options.Inbounds = append(
options.Inbounds,
option.Inbound{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.MustParseAddr("127.0.0.1")),
ListenPort: uint16(pointerOrDefaultInt(overrides.MixedPort, 2334)),
InboundOptions: option.InboundOptions{
SniffEnabled: true,
SniffOverrideDestination: true,
DomainStrategy: option.DomainStrategy(dns.DomainStrategyUseIPv4),
},
},
SetSystemProxy: pointerOrDefaultBool(overrides.SetSystemProxy, true),
},
},
)
options.Route = &option.RouteOptions{
Rules: []option.Rule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
Geosite: []string{"category-ads-all"},
Outbound: "block",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
Protocol: []string{"dns"},
Outbound: "dns-out",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
ClashMode: "direct",
Outbound: "direct",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
ClashMode: "global",
Outbound: "select",
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
GeoIP: []string{"ir", "private"},
DomainSuffix: []string{"ir"},
Outbound: "direct",
},
},
},
AutoDetectInterface: true,
OverrideAndroidVPN: true,
}
return options
}

35
shared/utils.go Normal file
View File

@@ -0,0 +1,35 @@
package shared
func StringAddr(b string) *string {
stringVar := b
return &stringVar
}
func BoolAddr(b bool) *bool {
boolVar := b
return &boolVar
}
func pointerOrDefaultString(p *string, def string) string {
if p != nil {
return *p
}
return def
}
func pointerOrDefaultInt(p *int, def int) int {
if p != nil {
return *p
}
return def
}
func pointerOrDefaultBool(p *bool, def bool) bool {
if p != nil {
return *p
}
return def
}