Files
umbrix-libcore/config/config.go

531 lines
13 KiB
Go
Raw Normal View History

2024-01-15 17:17:05 +03:30
package config
2023-09-01 14:52:30 +03:30
import (
2023-11-12 12:50:14 +03:30
"bytes"
2023-10-19 19:56:50 +03:30
"encoding/json"
2023-09-01 14:52:30 +03:30
"fmt"
2023-10-19 19:56:50 +03:30
"net"
2023-09-01 14:52:30 +03:30
"net/netip"
2023-10-19 19:56:50 +03:30
"net/url"
"strings"
2023-09-01 14:52:30 +03:30
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
dns "github.com/sagernet/sing-dns"
)
const (
DNSRemoteTag = "dns-remote"
DNSLocalTag = "dns-local"
DNSDirectTag = "dns-direct"
DNSBlockTag = "dns-block"
DNSFakeTag = "dns-fake"
DNSTricksDirectTag = "dns-trick-direct"
OutboundDirectTag = "direct"
OutboundBypassTag = "bypass"
OutboundBlockTag = "block"
OutboundSelectTag = "select"
OutboundURLTestTag = "auto"
OutboundDNSTag = "dns-out"
OutboundDirectFragmentTag = "direct-fragment"
InboundTUNTag = "tun-in"
InboundMixedTag = "mixed-in"
InboundDNSTag = "dns-in"
)
2023-11-12 12:50:14 +03:30
func BuildConfigJson(configOpt ConfigOptions, input option.Options) (string, error) {
2024-01-19 17:55:58 +03:30
options, err := BuildConfig(configOpt, input)
if err != nil {
return "", err
}
2023-11-12 12:50:14 +03:30
var buffer bytes.Buffer
json.NewEncoder(&buffer)
encoder := json.NewEncoder(&buffer)
encoder.SetIndent("", " ")
2024-01-19 17:55:58 +03:30
err = encoder.Encode(options)
2023-11-12 12:50:14 +03:30
if err != nil {
return "", err
}
return buffer.String(), nil
}
2023-10-19 19:56:50 +03:30
// TODO include selectors
2024-02-03 23:12:04 +03:30
func BuildConfig(opt ConfigOptions, input option.Options) (*option.Options, error) {
fmt.Printf("config options: %+v\n", opt)
2023-09-01 14:52:30 +03:30
2023-10-19 19:56:50 +03:30
var options option.Options
directDNSDomains := []string{}
2023-10-20 18:57:23 +03:30
dnsRules := []option.DefaultDNSRule{}
2023-09-01 14:52:30 +03:30
2024-01-01 19:11:08 +03:30
var bind string
2024-02-03 23:12:04 +03:30
if opt.AllowConnectionFromLAN {
2024-01-01 19:11:08 +03:30
bind = "0.0.0.0"
} else {
bind = "127.0.0.1"
}
2024-02-03 23:12:04 +03:30
if opt.EnableClashApi {
2023-09-01 14:52:30 +03:30
options.Experimental = &option.ExperimentalOptions{
ClashAPI: &option.ClashAPIOptions{
2024-02-03 23:12:04 +03:30
ExternalController: fmt.Sprintf("%s:%d", "127.0.0.1", opt.ClashApiPort),
},
2024-01-29 14:21:42 +01:00
// CacheFile: &option.CacheFileOptions{
// Enabled: true,
// Path: "clash.db",
// },
2023-09-01 14:52:30 +03:30
}
}
options.Log = &option.LogOptions{
2024-02-03 23:12:04 +03:30
Level: opt.LogLevel,
2024-01-29 14:21:42 +01:00
// Output: "box.log",
2023-09-01 14:52:30 +03:30
Disabled: false,
2023-10-23 19:22:07 +03:30
Timestamp: true,
2023-09-01 14:52:30 +03:30
DisableColor: true,
}
options.DNS = &option.DNSOptions{
2024-01-30 13:18:47 +01:00
StaticIPs: map[string][]string{
"sky.rethinkdns.com": getIPs([]string{"zula.ir", "www.speedtest.net", "sky.rethinkdns.com"}),
},
2023-09-01 14:52:30 +03:30
DNSClientOptions: option.DNSClientOptions{
2024-02-03 23:12:04 +03:30
IndependentCache: opt.IndependentDNSCache,
2023-09-01 14:52:30 +03:30
},
Final: DNSRemoteTag,
2023-09-01 14:52:30 +03:30
Servers: []option.DNSServerOptions{
{
Tag: DNSRemoteTag,
2024-02-03 23:12:04 +03:30
Address: opt.RemoteDnsAddress,
AddressResolver: DNSDirectTag,
2024-02-03 23:12:04 +03:30
Strategy: opt.RemoteDnsDomainStrategy,
},
{
Tag: DNSTricksDirectTag,
Address: "https://sky.rethinkdns.com/",
// AddressResolver: "dns-local",
2024-02-03 23:12:04 +03:30
Strategy: opt.DirectDnsDomainStrategy,
Detour: OutboundDirectFragmentTag,
2023-09-01 14:52:30 +03:30
},
{
Tag: DNSDirectTag,
2024-02-03 23:12:04 +03:30
Address: opt.DirectDnsAddress,
AddressResolver: DNSLocalTag,
2024-02-03 23:12:04 +03:30
Strategy: opt.DirectDnsDomainStrategy,
Detour: OutboundDirectTag,
2023-09-01 14:52:30 +03:30
},
{
Tag: DNSLocalTag,
2023-09-01 14:52:30 +03:30
Address: "local",
Detour: OutboundDirectTag,
2023-09-01 14:52:30 +03:30
},
{
Tag: DNSBlockTag,
2023-09-01 14:52:30 +03:30
Address: "rcode://success",
},
},
}
var inboundDomainStrategy option.DomainStrategy
2024-02-03 23:12:04 +03:30
if !opt.ResolveDestination {
2023-09-01 14:52:30 +03:30
inboundDomainStrategy = option.DomainStrategy(dns.DomainStrategyAsIS)
} else {
2024-02-03 23:12:04 +03:30
inboundDomainStrategy = opt.IPv6Mode
2023-09-01 14:52:30 +03:30
}
2024-02-03 23:12:04 +03:30
if opt.EnableTun {
if ok, _ := ActivateTunnelService(opt); !ok {
tunInbound := option.Inbound{
Type: C.TypeTun,
Tag: InboundTUNTag,
TunOptions: option.TunInboundOptions{
Stack: opt.TUNStack,
MTU: opt.MTU,
AutoRoute: true,
StrictRoute: opt.StrictRoute,
EndpointIndependentNat: true,
InboundOptions: option.InboundOptions{
SniffEnabled: true,
SniffOverrideDestination: true,
DomainStrategy: inboundDomainStrategy,
},
2023-09-01 14:52:30 +03:30
},
}
switch opt.IPv6Mode {
case option.DomainStrategy(dns.DomainStrategyUseIPv4):
tunInbound.TunOptions.Inet4Address = []netip.Prefix{
netip.MustParsePrefix("172.19.0.1/28"),
}
case option.DomainStrategy(dns.DomainStrategyUseIPv6):
tunInbound.TunOptions.Inet6Address = []netip.Prefix{
netip.MustParsePrefix("fdfe:dcba:9876::1/126"),
}
default:
tunInbound.TunOptions.Inet4Address = []netip.Prefix{
netip.MustParsePrefix("172.19.0.1/28"),
}
tunInbound.TunOptions.Inet6Address = []netip.Prefix{
netip.MustParsePrefix("fdfe:dcba:9876::1/126"),
}
2023-09-01 14:52:30 +03:30
}
options.Inbounds = append(options.Inbounds, tunInbound)
2023-09-01 14:52:30 +03:30
}
}
options.Inbounds = append(
options.Inbounds,
option.Inbound{
Type: C.TypeMixed,
Tag: InboundMixedTag,
2023-09-01 14:52:30 +03:30
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
2024-01-01 19:11:08 +03:30
Listen: option.NewListenAddress(netip.MustParseAddr(bind)),
2024-02-03 23:12:04 +03:30
ListenPort: opt.MixedPort,
2023-09-01 14:52:30 +03:30
InboundOptions: option.InboundOptions{
SniffEnabled: true,
SniffOverrideDestination: true,
DomainStrategy: inboundDomainStrategy,
},
},
2024-02-03 23:12:04 +03:30
SetSystemProxy: opt.SetSystemProxy,
2023-09-01 14:52:30 +03:30
},
},
)
2023-10-19 19:56:50 +03:30
options.Inbounds = append(
options.Inbounds,
2023-09-01 14:52:30 +03:30
option.Inbound{
Type: C.TypeDirect,
Tag: InboundDNSTag,
2023-09-01 14:52:30 +03:30
DirectOptions: option.DirectInboundOptions{
ListenOptions: option.ListenOptions{
2024-01-01 19:11:08 +03:30
Listen: option.NewListenAddress(netip.MustParseAddr(bind)),
2024-02-03 23:12:04 +03:30
ListenPort: opt.LocalDnsPort,
2023-09-01 14:52:30 +03:30
},
2024-01-25 23:59:07 +01:00
OverrideAddress: "1.1.1.1",
2023-09-01 14:52:30 +03:30
OverridePort: 53,
},
},
)
2024-02-03 23:12:04 +03:30
remoteDNSAddress := opt.RemoteDnsAddress
2023-10-19 19:56:50 +03:30
if strings.Contains(remoteDNSAddress, "://") {
remoteDNSAddress = strings.SplitAfter(remoteDNSAddress, "://")[1]
}
parsedUrl, err := url.Parse(fmt.Sprintf("https://%s", remoteDNSAddress))
if err == nil && net.ParseIP(parsedUrl.Host) == nil {
directDNSDomains = append(directDNSDomains, fmt.Sprintf("full:%s", parsedUrl.Host))
//TODO: IS it really needed
2023-10-19 19:56:50 +03:30
}
routeRules := []option.Rule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
Inbound: []string{InboundDNSTag},
Outbound: OutboundDNSTag,
2023-09-01 14:52:30 +03:30
},
2023-10-19 19:56:50 +03:30
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
Port: []uint16{53},
Outbound: OutboundDNSTag,
2023-09-01 14:52:30 +03:30
},
2023-10-19 19:56:50 +03:30
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
ClashMode: "Direct",
Outbound: OutboundDirectTag,
2023-09-01 14:52:30 +03:30
},
2023-10-19 19:56:50 +03:30
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
ClashMode: "Global",
Outbound: OutboundSelectTag,
2023-09-01 14:52:30 +03:30
},
2023-10-19 19:56:50 +03:30
},
}
2024-02-03 23:12:04 +03:30
if opt.BypassLAN {
2023-10-19 19:56:50 +03:30
routeRules = append(
routeRules,
option.Rule{
2023-09-01 14:52:30 +03:30
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultRule{
2023-10-19 19:56:50 +03:30
GeoIP: []string{"private"},
Outbound: OutboundBypassTag,
2023-10-20 18:57:23 +03:30
},
},
)
}
2024-02-03 23:12:04 +03:30
if opt.EnableFakeDNS {
2023-10-26 14:31:25 +03:30
inet4Range := netip.MustParsePrefix("198.18.0.0/15")
inet6Range := netip.MustParsePrefix("fc00::/18")
2023-10-20 18:57:23 +03:30
options.DNS.FakeIP = &option.DNSFakeIPOptions{
Enabled: true,
Inet4Range: &inet4Range,
Inet6Range: &inet6Range,
}
options.DNS.Servers = append(
options.DNS.Servers,
option.DNSServerOptions{
Tag: DNSFakeTag,
2023-10-20 18:57:23 +03:30
Address: "fakeip",
Strategy: option.DomainStrategy(dns.DomainStrategyUseIPv4),
},
)
options.DNS.Rules = append(
options.DNS.Rules,
option.DNSRule{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
Inbound: []string{InboundTUNTag},
Server: DNSFakeTag,
2023-10-20 18:57:23 +03:30
DisableCache: true,
2023-09-01 14:52:30 +03:30
},
},
2023-10-19 19:56:50 +03:30
)
2024-01-25 23:59:07 +01:00
2023-10-19 19:56:50 +03:30
}
2024-02-03 23:12:04 +03:30
for _, rule := range opt.Rules {
2023-10-19 19:56:50 +03:30
routeRule := rule.MakeRule()
switch rule.Outbound {
case "bypass":
routeRule.Outbound = OutboundBypassTag
2023-10-19 19:56:50 +03:30
case "block":
routeRule.Outbound = OutboundBlockTag
2023-10-19 19:56:50 +03:30
case "proxy":
routeRule.Outbound = OutboundDNSTag
2023-10-19 19:56:50 +03:30
}
if routeRule.IsValid() {
routeRules = append(
routeRules,
option.Rule{
Type: C.RuleTypeDefault,
DefaultOptions: routeRule,
2023-09-01 14:52:30 +03:30
},
2023-10-19 19:56:50 +03:30
)
}
dnsRule := rule.MakeDNSRule()
switch rule.Outbound {
case "bypass":
dnsRule.Server = DNSDirectTag
2023-10-19 19:56:50 +03:30
case "block":
dnsRule.Server = DNSBlockTag
2023-10-19 19:56:50 +03:30
dnsRule.DisableCache = true
case "proxy":
2024-02-03 23:12:04 +03:30
if opt.EnableFakeDNS {
2023-10-20 18:57:23 +03:30
fakeDnsRule := dnsRule
fakeDnsRule.Server = DNSFakeTag
fakeDnsRule.Inbound = []string{InboundTUNTag}
2023-10-20 18:57:23 +03:30
dnsRules = append(dnsRules, fakeDnsRule)
}
dnsRule.Server = DNSRemoteTag
2023-10-19 19:56:50 +03:30
}
2023-10-20 18:57:23 +03:30
dnsRules = append(dnsRules, dnsRule)
}
2023-10-19 19:56:50 +03:30
2024-02-03 23:12:04 +03:30
if opt.EnableDNSRouting {
2024-01-01 18:52:00 +03:30
for _, dnsRule := range dnsRules {
if dnsRule.IsValid() {
options.DNS.Rules = append(
options.DNS.Rules,
option.DNSRule{
Type: C.RuleTypeDefault,
DefaultOptions: dnsRule,
},
)
}
2023-10-19 19:56:50 +03:30
}
}
2024-01-26 00:24:24 +01:00
if options.DNS.Rules == nil {
options.DNS.Rules = []option.DNSRule{}
}
var dnsCPttl uint32 = 3000
options.DNS.Rules = append(
options.DNS.Rules,
option.DNSRule{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
Domain: []string{"cp.cloudflare.com"},
Server: DNSRemoteTag,
2024-01-26 00:24:24 +01:00
RewriteTTL: &dnsCPttl,
DisableCache: false,
},
},
)
2023-10-19 19:56:50 +03:30
options.Route = &option.RouteOptions{
Rules: routeRules,
2023-09-01 14:52:30 +03:30
AutoDetectInterface: true,
OverrideAndroidVPN: true,
2023-11-17 19:53:52 +03:30
GeoIP: &option.GeoIPOptions{
2024-02-03 23:12:04 +03:30
Path: opt.GeoIPPath,
2023-11-17 19:53:52 +03:30
},
Geosite: &option.GeositeOptions{
2024-02-03 23:12:04 +03:30
Path: opt.GeoSitePath,
2023-11-17 19:53:52 +03:30
},
2023-09-01 14:52:30 +03:30
}
var outbounds []option.Outbound
var tags []string
for _, out := range input.Outbounds {
2024-02-03 23:12:04 +03:30
outbound, serverDomain, err := patchOutbound(out, opt)
2024-01-19 17:55:58 +03:30
if err != nil {
return nil, err
}
if serverDomain != "" {
directDNSDomains = append(directDNSDomains, serverDomain)
2023-10-19 19:56:50 +03:30
}
out = *outbound
2023-10-19 19:56:50 +03:30
2023-09-01 14:52:30 +03:30
switch out.Type {
case C.TypeDirect, C.TypeBlock, C.TypeDNS:
continue
case C.TypeSelector, C.TypeURLTest:
continue
2024-01-25 18:37:08 +00:00
case C.TypeCustom:
continue
2023-09-01 14:52:30 +03:30
default:
tags = append(tags, out.Tag)
outbounds = append(outbounds, out)
}
}
urlTest := option.Outbound{
Type: C.TypeURLTest,
Tag: OutboundURLTestTag,
2023-09-01 14:52:30 +03:30
URLTestOptions: option.URLTestOutboundOptions{
Outbounds: tags,
2024-02-03 23:12:04 +03:30
URL: opt.ConnectionTestUrl,
Interval: opt.URLTestInterval,
IdleTimeout: opt.URLTestIdleTimeout,
2023-09-01 14:52:30 +03:30
},
}
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...)
options.Outbounds = append(
outbounds,
[]option.Outbound{
{
Tag: OutboundDNSTag,
2023-09-01 14:52:30 +03:30
Type: C.TypeDNS,
},
{
Tag: OutboundDirectTag,
2023-09-01 14:52:30 +03:30
Type: C.TypeDirect,
},
{
Tag: OutboundDirectFragmentTag,
Type: C.TypeDirect,
DirectOptions: option.DirectOutboundOptions{
DialerOptions: option.DialerOptions{
TLSFragment: &option.TLSFragmentOptions{
Enabled: true,
2024-02-03 23:12:04 +03:30
Size: opt.TLSTricks.FragmentSize,
Sleep: opt.TLSTricks.FragmentSleep,
},
},
},
},
2023-10-20 18:57:23 +03:30
{
Tag: OutboundBypassTag,
2023-10-20 18:57:23 +03:30
Type: C.TypeDirect,
},
2023-09-01 14:52:30 +03:30
{
Tag: OutboundBlockTag,
2023-09-01 14:52:30 +03:30
Type: C.TypeBlock,
},
}...,
)
2023-10-19 19:56:50 +03:30
if len(directDNSDomains) > 0 {
trickDnsDomains := []string{}
directDNSDomains = removeDuplicateStr(directDNSDomains)
2024-01-30 13:18:47 +01:00
for _, d := range directDNSDomains {
if isBlockedDomain(d) {
trickDnsDomains = append(trickDnsDomains, d)
}
}
trickDomains := strings.Join(trickDnsDomains, ",")
trickRule := Rule{Domains: trickDomains, Outbound: OutboundBypassTag}
trickDnsRule := trickRule.MakeDNSRule()
trickDnsRule.Server = DNSTricksDirectTag
options.DNS.Rules = append([]option.DNSRule{{Type: C.RuleTypeDefault, DefaultOptions: trickDnsRule}}, options.DNS.Rules...)
domains := strings.Join(directDNSDomains, ",")
directRule := Rule{Domains: domains, Outbound: OutboundBypassTag}
2023-10-19 19:56:50 +03:30
dnsRule := directRule.MakeDNSRule()
dnsRule.Server = DNSDirectTag
2023-10-19 19:56:50 +03:30
options.DNS.Rules = append([]option.DNSRule{{Type: C.RuleTypeDefault, DefaultOptions: dnsRule}}, options.DNS.Rules...)
}
2024-01-19 17:55:58 +03:30
return &options, nil
2023-09-01 14:52:30 +03:30
}
2024-01-30 13:18:47 +01:00
func getIPs(domains []string) []string {
res := []string{}
for _, d := range domains {
ips, err := net.LookupHost(d)
if err != nil {
continue
}
for _, ip := range ips {
if !strings.HasPrefix(ip, "10.") {
res = append(res, ip)
}
}
}
return res
}
func isBlockedDomain(domain string) bool {
if strings.HasPrefix("full:", domain) {
return false
}
ips, err := net.LookupHost(domain)
if err != nil {
// fmt.Println(err)
return true
}
// Print the IP addresses associated with the domain
fmt.Printf("IP addresses for %s:\n", domain)
for _, ip := range ips {
if strings.HasPrefix(ip, "10.") {
return true
}
}
return false
}
2023-09-01 14:52:30 +03:30
2023-10-19 19:56:50 +03:30
func removeDuplicateStr(strSlice []string) []string {
allKeys := make(map[string]bool)
list := []string{}
for _, item := range strSlice {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}