diff --git a/fe-app-tachyon/src/tachyon/types.ts b/fe-app-tachyon/src/tachyon/types.ts index 80f75550..f18e9dc9 100644 --- a/fe-app-tachyon/src/tachyon/types.ts +++ b/fe-app-tachyon/src/tachyon/types.ts @@ -248,6 +248,7 @@ export namespace Tachyon { action?: RuleAction; connection_type?: LegacyConnectionType; proxy_config_type?: ProxyConfigType; + geoip_country?: 'all' | 'non-ru' | 'ru' | 'us' | 'eu' | 'cn'; node?: string; rule_set?: string[]; rule_set_with_subnets?: string[]; diff --git a/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js b/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js index 01904bdf..9a74fe04 100644 --- a/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js +++ b/luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js @@ -8712,6 +8712,24 @@ function createSectionContent(section) { return getRuleResolvedAction(section_id) === "byedpi" ? "1" : "0"; }; + o = section.taboption( + "settings", + form.ListValue, + "geoip_country", + _("GeoIP Country Routing"), + _( + "Select target country or region for this section (e.g. Non-RU for all foreign traffic).", + ), + ); + o.value("all", _("🌐 All Traffic (Default)")); + o.value("non-ru", _("πŸ‡ͺπŸ‡Ί/πŸ‡ΊπŸ‡Έ Non-RU (All Foreign Traffic)")); + o.value("ru", _("πŸ‡·πŸ‡Ί RU Only (Russia)")); + o.value("us", _("πŸ‡ΊπŸ‡Έ US Only (United States)")); + o.value("cn", _("πŸ‡¨πŸ‡³ CN Only (China)")); + o.default = "all"; + o.rmempty = false; + o.modalonly = true; + addTextConditionField(section, { key: "domain_suffix", optionName: "domain", diff --git a/tachyon/files/usr/lib/singbox/generator_routes.uc b/tachyon/files/usr/lib/singbox/generator_routes.uc index ab270e43..aeff5bd3 100644 --- a/tachyon/files/usr/lib/singbox/generator_routes.uc +++ b/tachyon/files/usr/lib/singbox/generator_routes.uc @@ -1182,6 +1182,52 @@ function add_combined_route_for_section(config, section) { if (length(rule_set_tags) > 0) route_rule.rule_set = single_or_array(rule_set_tags); + let geoip_country = option(section, "geoip_country", "all"); + if (geoip_country == "non-ru") { + let ensured_ip = ensure_community_ruleset(config, section_name, "geoip_ru"); + let ensured_site = ensure_community_ruleset(config, section_name, "geosite_ru"); + let geoip_route_rule = { + action: target.action, + inbound: tproxy_inbound_matcher(), + rule_set: [ ensured_ip.tag, ensured_site.tag ], + invert: true + }; + if (target.outbound) + geoip_route_rule.outbound = target.outbound; + push(config.route.rules, geoip_route_rule); + } else if (geoip_country == "ru") { + let ensured_ip = ensure_community_ruleset(config, section_name, "geoip_ru"); + let ensured_site = ensure_community_ruleset(config, section_name, "geosite_ru"); + let geoip_route_rule = { + action: target.action, + inbound: tproxy_inbound_matcher(), + rule_set: [ ensured_ip.tag, ensured_site.tag ] + }; + if (target.outbound) + geoip_route_rule.outbound = target.outbound; + push(config.route.rules, geoip_route_rule); + } else if (geoip_country == "us") { + let ensured_ip = ensure_community_ruleset(config, section_name, "geoip_us"); + let geoip_route_rule = { + action: target.action, + inbound: tproxy_inbound_matcher(), + rule_set: [ ensured_ip.tag ] + }; + if (target.outbound) + geoip_route_rule.outbound = target.outbound; + push(config.route.rules, geoip_route_rule); + } else if (geoip_country == "cn") { + let ensured_ip = ensure_community_ruleset(config, section_name, "geoip_cn"); + let geoip_route_rule = { + action: target.action, + inbound: tproxy_inbound_matcher(), + rule_set: [ ensured_ip.tag ] + }; + if (target.outbound) + geoip_route_rule.outbound = target.outbound; + push(config.route.rules, geoip_route_rule); + } + let has_route_matchers = route_rule.domain != null || route_rule.domain_suffix != null || route_rule.domain_keyword != null || route_rule.domain_regex != null || route_rule.ip_cidr != null || route_rule.port != null || route_rule.port_range != null || diff --git a/tachyon/files/usr/lib/singbox/rulesets.uc b/tachyon/files/usr/lib/singbox/rulesets.uc index 21a108f7..f5907cc0 100644 --- a/tachyon/files/usr/lib/singbox/rulesets.uc +++ b/tachyon/files/usr/lib/singbox/rulesets.uc @@ -4,6 +4,10 @@ const SRS_MAIN_URL = "https://github.com/itdoginfo/allow-domains/releases/latest const SRS_ADS_HAGEZI_PRO_URL = "https://github.com/zxc-rv/ad-filter/releases/latest/download/adlist.srs"; const SRS_SUPERCELL_URL = "https://raw.githubusercontent.com/ushan0v/sing-box-supercell-ruleset/main/supercell.srs"; const SRS_GITHUB_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs"; +const SRS_GEOIP_RU_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/ru.srs"; +const SRS_GEOSITE_RU_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/category-ru.srs"; +const SRS_GEOIP_US_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/us.srs"; +const SRS_GEOIP_CN_URL = "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geoip/cn.srs"; const COMMUNITY_SERVICES = { russia_inside: true, @@ -32,7 +36,11 @@ const COMMUNITY_SERVICES = { roblox: true, ads_hagezi_pro: true, supercell: true, - github: true + github: true, + geoip_ru: true, + geosite_ru: true, + geoip_us: true, + geoip_cn: true }; function as_string(value) { @@ -51,6 +59,14 @@ function community_url(name) { return SRS_SUPERCELL_URL; if (name == "github") return SRS_GITHUB_URL; + if (name == "geoip_ru") + return SRS_GEOIP_RU_URL; + if (name == "geosite_ru") + return SRS_GEOSITE_RU_URL; + if (name == "geoip_us") + return SRS_GEOIP_US_URL; + if (name == "geoip_cn") + return SRS_GEOIP_CN_URL; return SRS_MAIN_URL + "/" + name + ".srs"; }