mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-06 20:14:10 +08:00
⛄ Sync 2026-07-31 00:26:24
This commit is contained in:
1 parent
47d0743808
commit
b44a4364c4
125 files changed
+3954
-140418
No files matched your search
@@ -0,0 +1,130 @@
|
||||
[
|
||||
{
|
||||
"name": "shadowsocks-basic",
|
||||
"description": "普通 Shadowsocks 节点生成单个 outbound",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"outbounds": ["main-out"],
|
||||
"diagnostics": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadowsocks-shadowtls",
|
||||
"description": "Shadowsocks + ShadowTLS 生成 detour 链路,并隐藏中间层 tag",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"outbounds": ["main-out", "main-out-shadowtls"],
|
||||
"tag_map": true,
|
||||
"diagnostics": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "selector-manual-nodes",
|
||||
"description": "Selector 手选代理节点生成 selector outbound",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"outbound_type": "selector",
|
||||
"diagnostics": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "selector-regex-nodes",
|
||||
"description": "Selector 通过节点正则展开代理节点,并受节点数量上限保护",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"node_filter_limit": 500,
|
||||
"diagnostics": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "selector-references-urltest",
|
||||
"description": "Selector 引用 URLTest 路由节点时补齐实际代理节点依赖",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"outbound_type": "selector",
|
||||
"contains_nested_outbound": true,
|
||||
"diagnostics": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disabled-routing-node",
|
||||
"description": "禁用的 routing_node 不能作为有效路由节点解析,引用时回退到 block-out 并产生 warning",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"route_final": "block-out",
|
||||
"diagnostics": ["warning"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "routing-cycle",
|
||||
"description": "循环引用路由节点应产生 error 诊断且不覆盖旧运行配置",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"diagnostics": ["error"],
|
||||
"write_runtime_config": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "selector-cycle",
|
||||
"description": "Selector 节点列表互相引用时应产生 error 诊断且不覆盖旧运行配置",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"diagnostics": ["error"],
|
||||
"write_runtime_config": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "routing-rule-direct-node",
|
||||
"description": "路由规则直选具体节点时自动补齐该节点 outbound",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"route_rule_outbound": true,
|
||||
"required_outbound": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gfwlist-default-outbound-fallback",
|
||||
"description": "非 custom 模式下 main_node 为空时仍可回退使用 default_outbound 生成运行配置",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"default_outbound_fallback": true,
|
||||
"route_final": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "duplicate-label",
|
||||
"description": "同名 label 通过稳定后缀生成唯一 readable tag",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"unique_tags": true,
|
||||
"tag_map": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "reserved-tag-label",
|
||||
"description": "label 与保留 tag 冲突时生成安全后缀",
|
||||
"generator_fixture": true,
|
||||
"expects": {
|
||||
"unique_tags": true,
|
||||
"reserved_tag_avoided": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unsupported-certificate-pin",
|
||||
"description": "订阅节点包含证书 pin 且 sing-box 不支持时默认跳过节点",
|
||||
"generator_fixture": false,
|
||||
"expects": {
|
||||
"subscription_skip_node": true,
|
||||
"tls_insecure": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "remove-subscription-node-references",
|
||||
"description": "删除订阅节点时清理 main、routing、dns server、dns rule、ruleset 引用",
|
||||
"generator_fixture": false,
|
||||
"expects": {
|
||||
"references_cleaned": true,
|
||||
"uci_commit": true
|
||||
}
|
||||
}
|
||||
]
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const casesPath = path.join(__dirname, 'cases.json');
|
||||
const cases = JSON.parse(fs.readFileSync(casesPath, 'utf8'));
|
||||
const fixturesDir = path.join(__dirname, 'fixtures');
|
||||
const requiredCases = [
|
||||
'shadowsocks-basic',
|
||||
'shadowsocks-shadowtls',
|
||||
'selector-manual-nodes',
|
||||
'selector-regex-nodes',
|
||||
'selector-references-urltest',
|
||||
'disabled-routing-node',
|
||||
'routing-cycle',
|
||||
'selector-cycle',
|
||||
'routing-rule-direct-node',
|
||||
'gfwlist-default-outbound-fallback',
|
||||
'duplicate-label',
|
||||
'reserved-tag-label',
|
||||
'unsupported-certificate-pin',
|
||||
'remove-subscription-node-references'
|
||||
];
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) {
|
||||
console.error(message);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function renameTagValue(value, rename) {
|
||||
if (typeof value === 'string')
|
||||
return Object.prototype.hasOwnProperty.call(rename, value) ? rename[value] : value;
|
||||
|
||||
if (Array.isArray(value))
|
||||
return value.map((item) => (
|
||||
item && typeof item === 'object' && !Array.isArray(item)
|
||||
? renameTags(item, rename)
|
||||
: renameTagValue(item, rename)
|
||||
));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function renameTags(value, rename) {
|
||||
if (Array.isArray(value))
|
||||
return value.map((item) => renameTags(item, rename));
|
||||
|
||||
if (value && typeof value === 'object') {
|
||||
for (const key of Object.keys(value)) {
|
||||
if (['tag', 'outbound', 'outbounds', 'detour', 'default', 'final', 'download_detour'].includes(key))
|
||||
value[key] = renameTagValue(value[key], rename);
|
||||
else
|
||||
value[key] = renameTags(value[key], rename);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
assert(Array.isArray(cases), 'cases.json must contain an array');
|
||||
|
||||
const names = new Set();
|
||||
for (const item of cases) {
|
||||
assert(item && typeof item === 'object', 'each case must be an object');
|
||||
assert(typeof item.name === 'string' && item.name.length > 0, 'case must have a name');
|
||||
assert(!names.has(item.name), `duplicate case name: ${item.name}`);
|
||||
names.add(item.name);
|
||||
assert(typeof item.description === 'string' && item.description.length > 0, `${item.name}: missing description`);
|
||||
assert(item.expects && typeof item.expects === 'object' && !Array.isArray(item.expects), `${item.name}: missing expects object`);
|
||||
|
||||
if (item.generator_fixture) {
|
||||
const fixtureDir = path.join(fixturesDir, item.name);
|
||||
const caseMetaPath = path.join(fixtureDir, 'case.json');
|
||||
const configPath = path.join(fixtureDir, 'homeproxy');
|
||||
const diagnosticsPath = path.join(fixtureDir, 'expected', 'config-diagnostics.json');
|
||||
|
||||
assert(fs.existsSync(configPath), `${item.name}: missing generator fixture homeproxy config`);
|
||||
assert(fs.existsSync(caseMetaPath), `${item.name}: missing generator fixture case.json`);
|
||||
assert(fs.existsSync(diagnosticsPath), `${item.name}: missing expected config diagnostics`);
|
||||
|
||||
if (fs.existsSync(caseMetaPath)) {
|
||||
const meta = JSON.parse(fs.readFileSync(caseMetaPath, 'utf8'));
|
||||
assert(typeof meta.success === 'boolean', `${item.name}: case.json must define boolean success`);
|
||||
if (meta.success)
|
||||
assert(fs.existsSync(path.join(fixtureDir, 'expected', 'sing-box-c.json')), `${item.name}: missing expected sing-box-c.json`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const name of requiredCases)
|
||||
assert(names.has(name), `missing required generator golden case: ${name}`);
|
||||
|
||||
const renameRegression = renameTags({
|
||||
outbounds: [
|
||||
{ type: 'selector', tag: 'Proxy_Selector', outbounds: ['Proxy_Auto', 'direct-out'] },
|
||||
{ type: 'urltest', tag: 'Proxy_Auto', outbounds: ['node-a'] }
|
||||
],
|
||||
route: {
|
||||
final: 'Proxy_Selector',
|
||||
rules: [{ outbound: 'Proxy_Auto' }]
|
||||
}
|
||||
}, {
|
||||
Proxy_Selector: '♻️ 节点选择',
|
||||
Proxy_Auto: 'Proxy_Auto 标签',
|
||||
'node-a': '节点 A'
|
||||
});
|
||||
|
||||
assert(renameRegression.route.final === '♻️ 节点选择', 'rename_tags regression: route.final not renamed');
|
||||
assert(renameRegression.outbounds[0].tag === '♻️ 节点选择', 'rename_tags regression: top-level outbound tag not renamed');
|
||||
assert(renameRegression.outbounds[0].outbounds[0] === 'Proxy_Auto 标签', 'rename_tags regression: selector outbound list not renamed');
|
||||
assert(renameRegression.outbounds[1].tag === 'Proxy_Auto 标签', 'rename_tags regression: nested outbound object not renamed');
|
||||
|
||||
if (!process.exitCode)
|
||||
console.log(`generator golden cases: ${cases.length} ok`);
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"type": "warning",
|
||||
"message": "默认出站 引用了已删除或无效的节点:rn_disabled,已在本次生成中回退为 block-out。",
|
||||
"suggestion": "请进入 LuCI 界面检查路由、DNS、规则集中的出站引用"
|
||||
}
|
||||
]
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "default-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
},
|
||||
{
|
||||
"type": "tproxy",
|
||||
"tag": "tproxy-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5332,
|
||||
"network": "udp",
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "resolve",
|
||||
"server": "default-dns"
|
||||
},
|
||||
"final": "block-out"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'rn_disabled'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_node 'rn_disabled'
|
||||
option enabled '0'
|
||||
option label 'Disabled Selector'
|
||||
option node 'selector'
|
||||
list selector_nodes 'n1'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'Disabled Child'
|
||||
option address 'disabled-child.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'disabled-child-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "main-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "ipv4_only"
|
||||
},
|
||||
"detour": "main-out",
|
||||
"type": "tcp",
|
||||
"server": "223.5.5.5"
|
||||
},
|
||||
{
|
||||
"tag": "china-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
"detour": "direct-out",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-cn",
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-noncn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geoip-cn"
|
||||
}
|
||||
],
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "main-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "urltest",
|
||||
"tag": "main-out",
|
||||
"outbounds": [
|
||||
"Duplicate Label",
|
||||
"Duplicate Label #n2"
|
||||
],
|
||||
"interval": "300s",
|
||||
"tolerance": 50
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Duplicate Label",
|
||||
"routing_mark": 100,
|
||||
"server": "duplicate-a.example",
|
||||
"server_port": 8388,
|
||||
"password": "duplicate-a-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Duplicate Label #n2",
|
||||
"routing_mark": 100,
|
||||
"server": "duplicate-b.example",
|
||||
"server_port": 8389,
|
||||
"password": "duplicate-b-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geoip-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/IPCIDR-CHINA@rule-set/cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-noncn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-!cn.srs",
|
||||
"download_detour": "main-out"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv4"
|
||||
},
|
||||
"final": "main-out"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'bypass_mainland_china'
|
||||
option proxy_mode 'redirect'
|
||||
option ipv6_support '0'
|
||||
option main_node 'urltest'
|
||||
option main_udp_node 'same'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
list main_urltest_nodes 'n1'
|
||||
list main_urltest_nodes 'n2'
|
||||
option main_urltest_interval '300'
|
||||
option main_urltest_tolerance '50'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'Duplicate Label'
|
||||
option address 'duplicate-a.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'duplicate-a-password'
|
||||
|
||||
config node 'n2'
|
||||
option type 'shadowsocks'
|
||||
option label 'Duplicate Label'
|
||||
option address 'duplicate-b.example'
|
||||
option port '8389'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'duplicate-b-password'
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "cfg-Proxy_DNS-dns",
|
||||
"type": "https",
|
||||
"server": "1.1.1.1",
|
||||
"path": "/dns-query",
|
||||
"detour": "Proxy Auto"
|
||||
}
|
||||
],
|
||||
"strategy": "prefer_ipv4",
|
||||
"final": "cfg-Proxy_DNS-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
},
|
||||
{
|
||||
"type": "tproxy",
|
||||
"tag": "tproxy-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5332,
|
||||
"network": "udp",
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Proxy Selector",
|
||||
"outbounds": [
|
||||
"Proxy Auto"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "urltest",
|
||||
"tag": "Proxy Auto",
|
||||
"outbounds": [
|
||||
"Fallback Node"
|
||||
],
|
||||
"url": "https://www.gstatic.com/generate_204",
|
||||
"interval": "300s",
|
||||
"tolerance": 50
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Fallback Node",
|
||||
"routing_mark": 100,
|
||||
"server": "fallback-node.example",
|
||||
"server_port": 8388,
|
||||
"password": "fallback-node-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "resolve",
|
||||
"server": "default-dns"
|
||||
},
|
||||
"final": "Proxy Selector"
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'gfwlist'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '1'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
option main_node 'nil'
|
||||
option main_udp_node 'nil'
|
||||
option dns_server '8.8.8.8'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option dns_port '5333'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'Proxy_Selector'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
option bypass_cn_traffic '0'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option dns_strategy 'prefer_ipv4'
|
||||
option default_server 'Proxy_DNS'
|
||||
|
||||
config dns_server 'Proxy_DNS'
|
||||
option label 'Proxy_DNS'
|
||||
option enabled '1'
|
||||
option type 'https'
|
||||
option server '1.1.1.1'
|
||||
option path '/dns-query'
|
||||
option outbound 'Proxy_Auto'
|
||||
|
||||
config routing_node 'Proxy_Selector'
|
||||
option enabled '1'
|
||||
option label 'Proxy Selector'
|
||||
option node 'selector'
|
||||
list selector_nodes 'Proxy_Auto'
|
||||
|
||||
config routing_node 'Proxy_Auto'
|
||||
option enabled '1'
|
||||
option label 'Proxy Auto'
|
||||
option node 'urltest'
|
||||
list urltest_nodes 'n1'
|
||||
option urltest_url 'https://www.gstatic.com/generate_204'
|
||||
option urltest_interval '300'
|
||||
option urltest_tolerance '50'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'Fallback Node'
|
||||
option address 'fallback-node.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'fallback-node-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "main-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "ipv4_only"
|
||||
},
|
||||
"detour": "main-out",
|
||||
"type": "tcp",
|
||||
"server": "223.5.5.5"
|
||||
},
|
||||
{
|
||||
"tag": "china-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
"detour": "direct-out",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-cn",
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-noncn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geoip-cn"
|
||||
}
|
||||
],
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "main-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "main-out",
|
||||
"routing_mark": 100,
|
||||
"server": "reserved.example",
|
||||
"server_port": 8388,
|
||||
"password": "reserved-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geoip-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/IPCIDR-CHINA@rule-set/cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-noncn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-!cn.srs",
|
||||
"download_detour": "main-out"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv4"
|
||||
},
|
||||
"final": "main-out"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'bypass_mainland_china'
|
||||
option proxy_mode 'redirect'
|
||||
option ipv6_support '0'
|
||||
option main_node 'n1'
|
||||
option main_udp_node 'same'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'direct-out'
|
||||
option address 'reserved.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'reserved-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": false
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"type": "error",
|
||||
"message": "路由节点配置错误:检测到循环引用\n循环路径: rn_b -> rn_a -> rn_b",
|
||||
"suggestion": "进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,检查以下节点的\"出站\"配置,移除循环引用"
|
||||
},
|
||||
{
|
||||
"type": "warning",
|
||||
"message": "路由节点 Cycle A 的节点引用已失效,已在本次生成中临时回退为阻断出站。",
|
||||
"suggestion": "请进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,重新选择有效节点"
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"message": "路由节点配置错误:检测到循环引用\n循环路径: rn_a -> rn_b -> rn_a",
|
||||
"suggestion": "进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,检查以下节点的\"出站\"配置,移除循环引用"
|
||||
},
|
||||
{
|
||||
"type": "warning",
|
||||
"message": "路由节点 Cycle B 的节点引用已失效,已在本次生成中临时回退为阻断出站。",
|
||||
"suggestion": "请进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,重新选择有效节点"
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"message": "路由节点配置错误:检测到循环引用\n循环路径: rn_a -> rn_b -> rn_a",
|
||||
"suggestion": "进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,检查以下节点的\"出站\"配置,移除循环引用"
|
||||
},
|
||||
{
|
||||
"type": "warning",
|
||||
"message": "默认出站 引用了已删除或无效的节点:rn_a,已在本次生成中回退为 block-out。",
|
||||
"suggestion": "请进入 LuCI 界面检查路由、DNS、规则集中的出站引用"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'rn_a'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_node 'rn_a'
|
||||
option enabled '1'
|
||||
option label 'Cycle A'
|
||||
option node 'rn_b'
|
||||
|
||||
config routing_node 'rn_b'
|
||||
option enabled '1'
|
||||
option label 'Cycle B'
|
||||
option node 'rn_a'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "default-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
},
|
||||
{
|
||||
"type": "tproxy",
|
||||
"tag": "tproxy-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5332,
|
||||
"network": "udp",
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Rule Node",
|
||||
"routing_mark": 100,
|
||||
"server": "rule-node.example",
|
||||
"server_port": 8388,
|
||||
"password": "rule-node-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
},
|
||||
{
|
||||
"domain_suffix": [
|
||||
"example.com"
|
||||
],
|
||||
"action": "route",
|
||||
"outbound": "Rule Node"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "resolve",
|
||||
"server": "default-dns"
|
||||
},
|
||||
"final": "direct-out"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'direct-out'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_rule 'rule_node'
|
||||
option enabled '1'
|
||||
option label 'Route To Concrete Node'
|
||||
option action 'route'
|
||||
list domain_suffix 'example.com'
|
||||
option outbound 'n1'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'Rule Node'
|
||||
option address 'rule-node.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'rule-node-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": false
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"type": "error",
|
||||
"message": "路由节点配置错误:Selector Selector A 与 rn_b 形成循环引用。",
|
||||
"suggestion": "进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,检查 Selector 节点列表、默认节点和上游出站配置"
|
||||
},
|
||||
{
|
||||
"type": "warning",
|
||||
"message": "路由节点 Selector A 没有可用节点,已在本次生成中临时回退为阻断出站。",
|
||||
"suggestion": "请手动选择节点,或调整节点正则/排除正则以命中可用节点"
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"message": "路由节点配置错误:Selector Selector B 与 rn_a 形成循环引用。",
|
||||
"suggestion": "进入 LuCI 界面 -> 服务 -> HomeProxy -> 路由节点,检查 Selector 节点列表、默认节点和上游出站配置"
|
||||
},
|
||||
{
|
||||
"type": "warning",
|
||||
"message": "路由节点 Selector B 没有可用节点,已在本次生成中临时回退为阻断出站。",
|
||||
"suggestion": "请手动选择节点,或调整节点正则/排除正则以命中可用节点"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'rn_a'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_node 'rn_a'
|
||||
option enabled '1'
|
||||
option label 'Selector A'
|
||||
option node 'selector'
|
||||
list selector_nodes 'rn_b'
|
||||
option selector_default 'rn_b'
|
||||
|
||||
config routing_node 'rn_b'
|
||||
option enabled '1'
|
||||
option label 'Selector B'
|
||||
option node 'selector'
|
||||
list selector_nodes 'rn_a'
|
||||
option selector_default 'rn_a'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "default-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
},
|
||||
{
|
||||
"type": "tproxy",
|
||||
"tag": "tproxy-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5332,
|
||||
"network": "udp",
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Manual Selector",
|
||||
"outbounds": [
|
||||
"Manual A",
|
||||
"Manual B"
|
||||
],
|
||||
"default": "Manual B"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Manual A",
|
||||
"routing_mark": 100,
|
||||
"server": "manual-a.example",
|
||||
"server_port": 8388,
|
||||
"password": "manual-a-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Manual B",
|
||||
"routing_mark": 100,
|
||||
"server": "manual-b.example",
|
||||
"server_port": 8389,
|
||||
"password": "manual-b-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "resolve",
|
||||
"server": "default-dns"
|
||||
},
|
||||
"final": "Manual Selector"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'rn_selector'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_node 'rn_selector'
|
||||
option enabled '1'
|
||||
option label 'Manual Selector'
|
||||
option node 'selector'
|
||||
list selector_nodes 'n1'
|
||||
list selector_nodes 'n2'
|
||||
option selector_default 'n2'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'Manual A'
|
||||
option address 'manual-a.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'manual-a-password'
|
||||
|
||||
config node 'n2'
|
||||
option type 'shadowsocks'
|
||||
option label 'Manual B'
|
||||
option address 'manual-b.example'
|
||||
option port '8389'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'manual-b-password'
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "default-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
},
|
||||
{
|
||||
"type": "tproxy",
|
||||
"tag": "tproxy-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5332,
|
||||
"network": "udp",
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "urltest",
|
||||
"tag": "URLTest Group",
|
||||
"outbounds": [
|
||||
"URLTest A",
|
||||
"URLTest B"
|
||||
],
|
||||
"url": "https://www.gstatic.com/generate_204",
|
||||
"interval": "300s",
|
||||
"tolerance": 50
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Selector With URLTest",
|
||||
"outbounds": [
|
||||
"URLTest Group",
|
||||
"Selector Direct Node"
|
||||
],
|
||||
"default": "URLTest Group"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "URLTest A",
|
||||
"routing_mark": 100,
|
||||
"server": "urltest-a.example",
|
||||
"server_port": 8388,
|
||||
"password": "urltest-a-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "URLTest B",
|
||||
"routing_mark": 100,
|
||||
"server": "urltest-b.example",
|
||||
"server_port": 8389,
|
||||
"password": "urltest-b-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "Selector Direct Node",
|
||||
"routing_mark": 100,
|
||||
"server": "selector-direct.example",
|
||||
"server_port": 8390,
|
||||
"password": "selector-direct-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "resolve",
|
||||
"server": "default-dns"
|
||||
},
|
||||
"final": "Selector With URLTest"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'rn_selector'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_node 'rn_urltest'
|
||||
option enabled '1'
|
||||
option label 'URLTest Group'
|
||||
option node 'urltest'
|
||||
list urltest_nodes 'n1'
|
||||
list urltest_nodes 'n2'
|
||||
option urltest_url 'https://www.gstatic.com/generate_204'
|
||||
option urltest_interval '300'
|
||||
option urltest_tolerance '50'
|
||||
|
||||
config routing_node 'rn_selector'
|
||||
option enabled '1'
|
||||
option label 'Selector With URLTest'
|
||||
option node 'selector'
|
||||
list selector_nodes 'rn_urltest'
|
||||
list selector_nodes 'n3'
|
||||
option selector_default 'rn_urltest'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'URLTest A'
|
||||
option address 'urltest-a.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'urltest-a-password'
|
||||
|
||||
config node 'n2'
|
||||
option type 'shadowsocks'
|
||||
option label 'URLTest B'
|
||||
option address 'urltest-b.example'
|
||||
option port '8389'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'urltest-b-password'
|
||||
|
||||
config node 'n3'
|
||||
option type 'shadowsocks'
|
||||
option label 'Selector Direct Node'
|
||||
option address 'selector-direct.example'
|
||||
option port '8390'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'selector-direct-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "default-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
},
|
||||
{
|
||||
"type": "tproxy",
|
||||
"tag": "tproxy-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5332,
|
||||
"network": "udp",
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Regex Selector",
|
||||
"outbounds": [
|
||||
"香港 01"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "香港 01",
|
||||
"routing_mark": 100,
|
||||
"server": "hk.example",
|
||||
"server_port": 8388,
|
||||
"password": "hk-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "resolve",
|
||||
"server": "default-dns"
|
||||
},
|
||||
"final": "Regex Selector"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'custom'
|
||||
option proxy_mode 'redirect_tproxy'
|
||||
option ipv6_support '0'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option tproxy_port '5332'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config homeproxy 'dns'
|
||||
option default_strategy 'ipv4_only'
|
||||
option default_server 'default-dns'
|
||||
option disable_cache '0'
|
||||
option disable_cache_expire '0'
|
||||
|
||||
config homeproxy 'routing'
|
||||
option default_outbound 'rn_selector'
|
||||
option default_outbound_dns 'default-dns'
|
||||
option sniff_override '1'
|
||||
|
||||
config routing_node 'rn_selector'
|
||||
option enabled '1'
|
||||
option label 'Regex Selector'
|
||||
option node 'selector'
|
||||
option node_filter '香港|日本'
|
||||
option node_filter_exclude '日本'
|
||||
|
||||
config node 'n_hk'
|
||||
option type 'shadowsocks'
|
||||
option label '香港 01'
|
||||
option address 'hk.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'hk-password'
|
||||
|
||||
config node 'n_jp'
|
||||
option type 'shadowsocks'
|
||||
option label '日本 01'
|
||||
option address 'jp.example'
|
||||
option port '8389'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'jp-password'
|
||||
|
||||
config node 'n_us'
|
||||
option type 'shadowsocks'
|
||||
option label '美国 01'
|
||||
option address 'us.example'
|
||||
option port '8390'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'us-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "main-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "ipv4_only"
|
||||
},
|
||||
"detour": "main-out",
|
||||
"type": "tcp",
|
||||
"server": "223.5.5.5"
|
||||
},
|
||||
{
|
||||
"tag": "china-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
"detour": "direct-out",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-cn",
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-noncn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geoip-cn"
|
||||
}
|
||||
],
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "main-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "main-out",
|
||||
"routing_mark": 100,
|
||||
"server": "ss-basic.example",
|
||||
"server_port": 8388,
|
||||
"password": "basic-password",
|
||||
"method": "2022-blake3-aes-128-gcm"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geoip-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/IPCIDR-CHINA@rule-set/cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-noncn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-!cn.srs",
|
||||
"download_detour": "main-out"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv4"
|
||||
},
|
||||
"final": "main-out"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'bypass_mainland_china'
|
||||
option proxy_mode 'redirect'
|
||||
option ipv6_support '0'
|
||||
option main_node 'n1'
|
||||
option main_udp_node 'same'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'SS Basic'
|
||||
option address 'ss-basic.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'basic-password'
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"items": [
|
||||
]
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"output": "__TEST_ROOT__/var/run/homeproxy/sing-box-c.log",
|
||||
"timestamp": true
|
||||
},
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": "time.apple.com",
|
||||
"detour": "direct-out",
|
||||
"domain_resolver": "default-dns"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "default-dns",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "system-dns",
|
||||
"type": "local",
|
||||
"detour": "direct-out"
|
||||
},
|
||||
{
|
||||
"tag": "main-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "ipv4_only"
|
||||
},
|
||||
"detour": "main-out",
|
||||
"type": "tcp",
|
||||
"server": "223.5.5.5"
|
||||
},
|
||||
{
|
||||
"tag": "china-dns",
|
||||
"domain_resolver": {
|
||||
"server": "default-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
"detour": "direct-out",
|
||||
"type": "udp",
|
||||
"server": "223.5.5.5"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-cn",
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-noncn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geoip-cn"
|
||||
}
|
||||
],
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv6"
|
||||
}
|
||||
],
|
||||
"strategy": "ipv4_only",
|
||||
"final": "main-dns"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5333
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5330,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
"set_system_proxy": false
|
||||
},
|
||||
{
|
||||
"type": "redirect",
|
||||
"tag": "redirect-in",
|
||||
"listen": "::",
|
||||
"listen_port": 5331,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out",
|
||||
"routing_mark": 100
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block-out"
|
||||
},
|
||||
{
|
||||
"type": "shadowtls",
|
||||
"tag": "main-out-shadowtls",
|
||||
"routing_mark": 100,
|
||||
"server": "shadowtls.example",
|
||||
"server_port": 443,
|
||||
"version": 3,
|
||||
"password": "shadowtls-password",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "www.apple.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "main-out",
|
||||
"routing_mark": 100,
|
||||
"server": "ss-shadowtls.example",
|
||||
"server_port": 8388,
|
||||
"password": "ss-password",
|
||||
"method": "2022-blake3-aes-128-gcm",
|
||||
"detour": "main-out-shadowtls"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"inbound": "dns-in",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geoip-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/IPCIDR-CHINA@rule-set/cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-cn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-cn.srs",
|
||||
"download_detour": "main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-noncn",
|
||||
"format": "binary",
|
||||
"url": "https://fastly.jsdelivr.net/gh/1715173329/sing-geosite@rule-set-unstable/geosite-geolocation-!cn.srs",
|
||||
"download_detour": "main-out"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": {
|
||||
"action": "route",
|
||||
"server": "china-dns",
|
||||
"strategy": "prefer_ipv4"
|
||||
},
|
||||
"final": "main-out"
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "__TEST_ROOT__/var/run/homeproxy/cache.db"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
config homeproxy 'config'
|
||||
option routing_mode 'bypass_mainland_china'
|
||||
option proxy_mode 'redirect'
|
||||
option ipv6_support '0'
|
||||
option main_node 'n1'
|
||||
option main_udp_node 'same'
|
||||
option log_level 'warn'
|
||||
option clash_api_enabled '0'
|
||||
|
||||
config homeproxy 'infra'
|
||||
option mixed_port '5330'
|
||||
option redirect_port '5331'
|
||||
option self_mark '100'
|
||||
|
||||
config homeproxy 'control'
|
||||
|
||||
config node 'n1'
|
||||
option type 'shadowsocks'
|
||||
option label 'SS ShadowTLS'
|
||||
option address 'ss-shadowtls.example'
|
||||
option port '8388'
|
||||
option shadowsocks_encrypt_method '2022-blake3-aes-128-gcm'
|
||||
option password 'ss-password'
|
||||
option shadowtls_enabled '1'
|
||||
option shadowtls_address 'shadowtls.example'
|
||||
option shadowtls_port '443'
|
||||
option shadowtls_version '3'
|
||||
option shadowtls_password 'shadowtls-password'
|
||||
option shadowtls_sni 'www.apple.com'
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/ucode
|
||||
'use strict';
|
||||
|
||||
import { readfile, writefile, stat } from 'fs';
|
||||
|
||||
const base_dir = ARGV?.[0] || 'tests/generator-golden';
|
||||
const generator = ARGV?.[1] || '/etc/homeproxy/scripts/generate_client.uc';
|
||||
const module_dir = ARGV?.[2];
|
||||
|
||||
function hasFlag(flag) {
|
||||
const argv = (type(ARGV) === 'array') ? ARGV : [];
|
||||
|
||||
for (let item in argv)
|
||||
if (item === flag)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const update_expected = hasFlag('--update');
|
||||
|
||||
function shellquote(s) {
|
||||
return `'${replace(s, "'", "'\\''")}'`;
|
||||
}
|
||||
|
||||
function fail(message) {
|
||||
warn(message + '\n');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
function path(...parts) {
|
||||
return join('/', parts);
|
||||
}
|
||||
|
||||
function exists(file) {
|
||||
return stat(file)?.type === 'file';
|
||||
}
|
||||
|
||||
function readJson(file, fallback) {
|
||||
if (!exists(file))
|
||||
return fallback;
|
||||
|
||||
return json(readfile(file));
|
||||
}
|
||||
|
||||
function normalize(value, test_root) {
|
||||
let value_type = type(value);
|
||||
|
||||
if (value_type === 'string')
|
||||
return replace(value, test_root, '__TEST_ROOT__');
|
||||
|
||||
if (value_type === 'array') {
|
||||
let result = [];
|
||||
for (let item in value)
|
||||
push(result, normalize(item, test_root));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (value_type === 'object') {
|
||||
let result = {};
|
||||
for (let key in value) {
|
||||
if (key === 'time')
|
||||
continue;
|
||||
result[key] = normalize(value[key], test_root);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function canonical(value) {
|
||||
return sprintf('%.J', value);
|
||||
}
|
||||
|
||||
function compareJson(case_name, label, actual, expected) {
|
||||
if (canonical(actual) === canonical(expected))
|
||||
return;
|
||||
|
||||
warn(sprintf('%s: %s golden mismatch\n', case_name, label));
|
||||
warn('expected:\n' + sprintf('%.J\n', expected));
|
||||
warn('actual:\n' + sprintf('%.J\n', actual));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
function generatorCommand() {
|
||||
if (module_dir && module_dir !== '--update')
|
||||
return sprintf('ucode -S -L %s %s', shellquote(module_dir), shellquote(generator));
|
||||
|
||||
return shellquote(generator);
|
||||
}
|
||||
|
||||
function prepareRoot(case_name, fixture_dir) {
|
||||
const test_root = '/tmp/homeproxy-golden-' + replace(case_name, /[^A-Za-z0-9_-]/g, '_');
|
||||
|
||||
system('rm -rf ' + shellquote(test_root));
|
||||
system('mkdir -p ' +
|
||||
shellquote(path(test_root, 'etc/config')) + ' ' +
|
||||
shellquote(path(test_root, 'etc/homeproxy/resources')) + ' ' +
|
||||
shellquote(path(test_root, 'var/run/homeproxy')));
|
||||
|
||||
writefile(path(test_root, 'etc/config/homeproxy'), readfile(path(fixture_dir, 'homeproxy')));
|
||||
|
||||
const direct_list = path(fixture_dir, 'resources/direct_list.txt'),
|
||||
proxy_list = path(fixture_dir, 'resources/proxy_list.txt');
|
||||
writefile(path(test_root, 'etc/homeproxy/resources/direct_list.txt'), exists(direct_list) ? readfile(direct_list) : '');
|
||||
writefile(path(test_root, 'etc/homeproxy/resources/proxy_list.txt'), exists(proxy_list) ? readfile(proxy_list) : '');
|
||||
|
||||
return test_root;
|
||||
}
|
||||
|
||||
function runCase(item) {
|
||||
const case_name = item.name,
|
||||
fixture_dir = path(base_dir, 'fixtures', case_name),
|
||||
meta = readJson(path(fixture_dir, 'case.json'), null);
|
||||
|
||||
if (!meta)
|
||||
fail(sprintf('%s: missing fixture case.json', case_name));
|
||||
|
||||
const test_root = prepareRoot(case_name, fixture_dir),
|
||||
stdout_path = path(test_root, 'var/run/homeproxy/stdout.log'),
|
||||
stderr_path = path(test_root, 'var/run/homeproxy/stderr.log'),
|
||||
command = sprintf('%s --test-root %s >%s 2>%s',
|
||||
generatorCommand(),
|
||||
shellquote(test_root),
|
||||
shellquote(stdout_path),
|
||||
shellquote(stderr_path)),
|
||||
status = system(command),
|
||||
success = (status === 0);
|
||||
|
||||
if (!!meta.success !== success) {
|
||||
warn(sprintf('%s: expected success=%J, got status=%d\n', case_name, meta.success, status));
|
||||
warn(readfile(stderr_path) || '');
|
||||
system('rm -rf ' + shellquote(test_root));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const actual_config_path = path(test_root, 'var/run/homeproxy/sing-box-c.json'),
|
||||
expected_config_path = path(fixture_dir, 'expected/sing-box-c.json');
|
||||
|
||||
if (meta.success) {
|
||||
if (!exists(actual_config_path))
|
||||
fail(sprintf('%s: generator succeeded but sing-box-c.json is missing', case_name));
|
||||
const actual_config = normalize(json(readfile(actual_config_path)), test_root);
|
||||
|
||||
if (update_expected)
|
||||
writefile(expected_config_path, sprintf('%.J\n', actual_config));
|
||||
else
|
||||
compareJson(case_name, 'sing-box-c.json',
|
||||
actual_config,
|
||||
readJson(expected_config_path, null));
|
||||
}
|
||||
|
||||
const actual_diagnostics = exists(path(test_root, 'var/run/homeproxy/config-diagnostics.json'))
|
||||
? json(readfile(path(test_root, 'var/run/homeproxy/config-diagnostics.json')))
|
||||
: { items: [] };
|
||||
const normalized_diagnostics = normalize(actual_diagnostics, test_root),
|
||||
expected_diagnostics_path = path(fixture_dir, 'expected/config-diagnostics.json');
|
||||
|
||||
if (update_expected)
|
||||
writefile(expected_diagnostics_path, sprintf('%.J\n', normalized_diagnostics));
|
||||
else
|
||||
compareJson(case_name, 'config-diagnostics.json',
|
||||
normalized_diagnostics,
|
||||
readJson(expected_diagnostics_path, { items: [] }));
|
||||
|
||||
system('rm -rf ' + shellquote(test_root));
|
||||
printf('%s ok\n', case_name);
|
||||
}
|
||||
|
||||
const cases = readJson(path(base_dir, 'cases.json'), []);
|
||||
let count = 0;
|
||||
|
||||
for (let item in cases) {
|
||||
if (!item.generator_fixture)
|
||||
continue;
|
||||
|
||||
runCase(item);
|
||||
count++;
|
||||
}
|
||||
|
||||
printf('generator golden fixtures: %d ok\n', count);
|
||||
Reference in new issue
Block a user