Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

适配 sing-box 1.11 新版配置 #88

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 118 additions & 104 deletions src/SingboxConfigBuilder.js
Original file line number Diff line number Diff line change
@@ -1,104 +1,118 @@
import { SING_BOX_CONFIG, generateRuleSets, generateRules, getOutbounds, PREDEFINED_RULE_SETS} from './config.js';
import { BaseConfigBuilder } from './BaseConfigBuilder.js';
import { DeepCopy } from './utils.js';

export class ConfigBuilder extends BaseConfigBuilder {
constructor(inputString, selectedRules, customRules, pin, baseConfig) {
if (baseConfig === undefined) {
baseConfig = SING_BOX_CONFIG
}
super(inputString, baseConfig);
this.selectedRules = selectedRules;
this.customRules = customRules;
this.pin = pin;
}

addCustomItems(customItems) {
const validItems = customItems.filter(item => item != null);
this.config.outbounds.push(...validItems);
}

addSelectors() {
let outbounds;
if (typeof this.selectedRules === 'string' && PREDEFINED_RULE_SETS[this.selectedRules]) {
outbounds = getOutbounds(PREDEFINED_RULE_SETS[this.selectedRules]);
} else if(this.selectedRules && Object.keys(this.selectedRules).length > 0) {
outbounds = getOutbounds(this.selectedRules);
} else {
outbounds = getOutbounds(PREDEFINED_RULE_SETS.minimal);
}

const proxyList = this.config.outbounds.filter(outbound => outbound?.server != undefined).map(outbound => outbound.tag);

this.config.outbounds.unshift({
type: "urltest",
tag: "⚡ 自动选择",
outbounds: DeepCopy(proxyList),
});

proxyList.unshift('DIRECT', 'REJECT', '⚡ 自动选择');
outbounds.unshift('🚀 节点选择','GLOBAL');

outbounds.forEach(outbound => {
if (outbound !== '🚀 节点选择') {
this.config.outbounds.push({
type: "selector",
tag: outbound,
outbounds: ['🚀 节点选择', ...proxyList]
});
} else {
this.config.outbounds.unshift({
type: "selector",
tag: outbound,
outbounds: proxyList
});
}
});

if (Array.isArray(this.customRules)) {
this.customRules.forEach(rule => {
this.config.outbounds.push({
type: "selector",
tag: rule.name,
outbounds: ['🚀 节点选择', ...proxyList]
});
});
}

this.config.outbounds.push({
type: "selector",
tag: "🐟 漏网之鱼",
outbounds: ['🚀 节点选择', ...proxyList]
});
}

formatConfig() {
const rules = generateRules(this.selectedRules, this.customRules, this.pin);
const { site_rule_sets, ip_rule_sets } = generateRuleSets(this.selectedRules,this.customRules);

this.config.route.rule_set = [...site_rule_sets, ...ip_rule_sets];

this.config.route.rules = rules.map(rule => ({
rule_set: [
...(rule.site_rules.length > 0 && rule.site_rules[0] !== '' ? rule.site_rules : []),
...(rule.ip_rules.filter(ip => ip.trim() !== '').map(ip => `${ip}-ip`))
],
domain_suffix: rule.domain_suffix,
domain_keyword: rule.domain_keyword,
ip_cidr: rule.ip_cidr,
protocol: rule.protocol,
outbound: rule.outbound
}));
// Add any default rules that should always be present
this.config.route.rules.unshift(
{ protocol: 'dns', outbound: 'dns-out' },
{ clash_mode: 'direct', outbound: 'DIRECT' },
{ clash_mode: 'global', outbound: 'GLOBAL' }
);

this.config.route.auto_detect_interface = true;
this.config.route.final = '🐟 漏网之鱼';

return this.config;
}
}
import { SING_BOX_CONFIG, generateRuleSets, generateRules, getOutbounds, PREDEFINED_RULE_SETS} from './config.js';
import { BaseConfigBuilder } from './BaseConfigBuilder.js';
import { DeepCopy } from './utils.js';

export class ConfigBuilder extends BaseConfigBuilder {
constructor(inputString, selectedRules, customRules, pin, baseConfig) {
if (baseConfig === undefined) {
baseConfig = SING_BOX_CONFIG
}
super(inputString, baseConfig);
this.selectedRules = selectedRules;
this.customRules = customRules;
this.pin = pin;
}

addCustomItems(customItems) {
const validItems = customItems.filter(item => item != null);
this.config.outbounds.push(...validItems);
}

addSelectors() {
let outbounds;
if (typeof this.selectedRules === 'string' && PREDEFINED_RULE_SETS[this.selectedRules]) {
outbounds = getOutbounds(PREDEFINED_RULE_SETS[this.selectedRules]);
} else if(this.selectedRules && Object.keys(this.selectedRules).length > 0) {
outbounds = getOutbounds(this.selectedRules);
} else {
outbounds = getOutbounds(PREDEFINED_RULE_SETS.minimal);
}

const proxyList = this.config.outbounds.filter(outbound => outbound?.server != undefined).map(outbound => outbound.tag);

this.config.outbounds.unshift({
type: "urltest",
tag: "⚡ 自动选择",
outbounds: DeepCopy(proxyList),
});

proxyList.unshift('⚡ 自动选择', 'DIRECT');
outbounds.unshift('🚀 节点选择','GLOBAL');

outbounds.forEach(outbound => {
if (outbound === '🔒 国内服务' || outbound === '🏠 私有网络') {
this.config.outbounds.push({
type: "selector",
tag: outbound,
outbounds: ['DIRECT', '🚀 节点选择'] // DIRECT 优先
});
} else if (outbound !== '🚀 节点选择') {
this.config.outbounds.push({
type: "selector",
tag: outbound,
outbounds: ['🚀 节点选择', ...proxyList]
});
} else {
this.config.outbounds.unshift({
type: "selector",
tag: outbound,
outbounds: proxyList
});
}
});

if (Array.isArray(this.customRules)) {
this.customRules.forEach(rule => {
this.config.outbounds.push({
type: "selector",
tag: rule.name,
outbounds: ['DIRECT', '🚀 节点选择'] // DIRECT 优先
});
});
}

this.config.outbounds.push({
type: "selector",
tag: "🐟 漏网之鱼",
outbounds: ['🚀 节点选择', ...proxyList]
});
}

formatConfig() {
const rules = generateRules(this.selectedRules, this.customRules, this.pin);
const { site_rule_sets, ip_rule_sets } = generateRuleSets(this.selectedRules,this.customRules);

this.config.route.rule_set = [...site_rule_sets, ...ip_rule_sets];

this.config.route.rules = rules.map(rule => ({
rule_set: [
...(rule.site_rules.length > 0 && rule.site_rules[0] !== '' ? rule.site_rules : []),
...(rule.ip_rules.filter(ip => ip.trim() !== '').map(ip => `${ip}-ip`))
],
domain_suffix: rule.domain_suffix,
domain_keyword: rule.domain_keyword,
ip_cidr: rule.ip_cidr,
protocol: rule.protocol,
outbound: rule.outbound
}));
// Add any default rules that should always be present
this.config.route.rules.unshift(
{ action: 'sniff' },
{ type:'logical',mode:'or',rules:[{protocol:'dns'},{port:53}],action:'hijack-dns' },
{ ip_is_private:true,outbound:'DIRECT' },
{ "clash_mode":"Ad-block","rule_set":"category-ads-all","action":"reject","method":"default" },
{ clash_mode: 'Globl', outbound: 'GLOBAL' }
);
//漏网域名解析为 IP ,若为国内 IP 则走直连
this.config.route.rules.push(
{ action: "resolve" },
{ rule_set: "cn-ip", outbound: "DIRECT" }
);


this.config.route.auto_detect_interface = true;
this.config.route.final = '🐟 漏网之鱼';

return this.config;
}
}
68 changes: 28 additions & 40 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -4,12 +4,7 @@ export const IP_RULE_SET_BASE_URL = 'https://raw.githubusercontent.com/lyc8503/s
export const CUSTOM_RULES = [];
// Unified rule structure
export const UNIFIED_RULES = [
{
name: 'Ad Block',
outbound: '🛑 广告拦截',
site_rules: ['category-ads-all'],
ip_rules: []
},

{
name: 'AI Services',
outbound: '💬 AI 服务',
@@ -246,6 +241,16 @@ export function generateRuleSets(selectedRules = [], customRules = []) {
download_detour: '⚡ 自动选择'
}));


// 添加 ad 规则集
site_rule_sets.push({
tag: 'category-ads-all',
type: 'remote',
format: 'binary',
url: `${SITE_RULE_SET_BASE_URL}geosite-category-ads-all.srs`,
download_detour: '⚡ 自动选择'
});

if(!selectedRules.includes('Non-China')){
site_rule_sets.push({
tag: 'geolocation-!cn',
@@ -311,14 +316,6 @@ export const SING_BOX_CONFIG = {
address: "223.5.5.5",
detour: "DIRECT"
},
{
tag: "dns_success",
address: "rcode://success"
},
{
tag: "dns_refused",
address: "rcode://refused"
},
{
tag: "dns_fakeip",
address: "fakeip"
@@ -328,34 +325,22 @@ export const SING_BOX_CONFIG = {
{
outbound: "any",
server: "dns_resolver"
},
{
rule_set: "geolocation-cn",
server: "dns_direct"
},
{
rule_set: "geolocation-!cn",
query_type: [
"A",
"AAAA"
],
rewrite_ttl: 1,
server: "dns_fakeip"
},
{
rule_set: "geolocation-!cn",
query_type: [
"CNAME"
],
server: "dns_proxy"
},
{
query_type: [
"A",
"AAAA",
"CNAME"
],
invert: true,
server: "dns_refused",
disable_cache: true
}
],
final: "dns_direct",
strategy: "ipv4_only",
final: "dns_proxy",
independent_cache: true,
fakeip: {
enabled: true,
@@ -371,13 +356,10 @@ export const SING_BOX_CONFIG = {
detour: 'DIRECT'
},
inbounds: [
{ type: 'mixed', tag: 'mixed-in', listen: '0.0.0.0', listen_port: 2080 },
{ type: 'tun', tag: 'tun-in', address: '172.19.0.1/30', auto_route: true, strict_route: true, stack: 'mixed', sniff: true }
{"type":"mixed","tag":"mixed-in","listen":"0.0.0.0","listen_port":8888},{"type":"tun","tag":"tun-in","mtu":9000,"address":"172.18.0.1/30","auto_route":true,"strict_route":true,"stack":"mixed","platform":{"http_proxy":{"enabled":true,"server":"127.0.0.1","server_port":8888}}}
],
outbounds: [
{ type: 'direct', tag: 'DIRECT' },
{ type: 'block', tag: 'REJECT' },
{ type: 'dns', tag: 'dns-out' }
{ type: 'direct', tag: 'DIRECT' }
],
route : {
"rule_set": [
@@ -398,13 +380,19 @@ export const SING_BOX_CONFIG = {
experimental: {
cache_file: {
enabled: true,
path: 'cache000.db',
store_fakeip: true
},
clash_api: {
external_controller: '127.0.0.1:9090',
external_ui: 'dashboard'
}
}
},
log: {
disabled: false,
level: "error",
output: "",
}
};

export const CLASH_CONFIG = {
@@ -439,4 +427,4 @@ export const CLASH_CONFIG = {
},
proxies: [],
'proxy-groups': [],
};
};
Loading