update 2024-11-06 00:26:14
This commit is contained in:
parent
371d3c520b
commit
7b70cb2bf5
|
@ -23,6 +23,7 @@ define Package/luci-app-fchomo/conffiles
|
|||
/etc/fchomo/resources.json
|
||||
/etc/fchomo/geoip.dat
|
||||
/etc/fchomo/geosite.dat
|
||||
/etc/fchomo/asn.mmdb
|
||||
/etc/fchomo/cache.db
|
||||
endef
|
||||
|
||||
|
|
|
@ -132,11 +132,11 @@ return baseclass.extend({
|
|||
['IP-CIDR'],
|
||||
['IP-CIDR6'],
|
||||
['IP-SUFFIX'],
|
||||
//['IP-ASN'],
|
||||
['IP-ASN'],
|
||||
['GEOIP'],
|
||||
|
||||
['SRC-GEOIP'],
|
||||
//['SRC-IP-ASN'],
|
||||
['SRC-IP-ASN'],
|
||||
['SRC-IP-CIDR'],
|
||||
['SRC-IP-SUFFIX'],
|
||||
|
||||
|
@ -158,6 +158,8 @@ return baseclass.extend({
|
|||
//['DSCP'],
|
||||
|
||||
['RULE-SET'],
|
||||
|
||||
['MATCH']
|
||||
],
|
||||
|
||||
rules_logical_type: [
|
||||
|
@ -447,6 +449,23 @@ return baseclass.extend({
|
|||
return this.super('load', section_id);
|
||||
},
|
||||
|
||||
loadSubRuleGroup: function(section_id) {
|
||||
delete this.keylist;
|
||||
delete this.vallist;
|
||||
|
||||
this.value('', _('-- Please choose --'));
|
||||
let groups = {};
|
||||
uci.sections(this.config, 'subrules', (res) => {
|
||||
if (res.enabled !== '0')
|
||||
groups[res.group] = res.group;
|
||||
});
|
||||
Object.keys(groups).forEach((group) => {
|
||||
this.value(group, group);
|
||||
});
|
||||
|
||||
return this.super('load', section_id);
|
||||
},
|
||||
|
||||
renderStatus: function(self, ElId, isRunning, instance, noGlobal) {
|
||||
var visible = isRunning && (isRunning.http || isRunning.https);
|
||||
|
||||
|
|
|
@ -66,7 +66,20 @@ class DNSAddress {
|
|||
class RulesEntry {
|
||||
constructor(entry) {
|
||||
this.input = entry || '';
|
||||
this.rawparams = this.input.split(',');
|
||||
var content = this.input;
|
||||
this.subrule = content.split(',');
|
||||
if (this.subrule.shift() === 'SUB-RULE') {
|
||||
var subrule_payload = this.subrule.join(',').match(/^\(.*\)/);
|
||||
if (subrule_payload) {
|
||||
content = subrule_payload[0].slice(1, -1);
|
||||
this.subrule = this.subrule.pop() || ' ';
|
||||
} else {
|
||||
content = this.subrule.join(',');
|
||||
this.subrule = ' ';
|
||||
}
|
||||
} else
|
||||
this.subrule = false;
|
||||
this.rawparams = content.split(',');
|
||||
this.type = this.rawparams.shift() || '';
|
||||
var logical_payload, rawfactor;
|
||||
(function(rawparams_typecuted) {
|
||||
|
@ -78,6 +91,8 @@ class RulesEntry {
|
|||
rawfactor = this.rawparams.shift() || '';
|
||||
}.call(this, this.rawparams.join(',')));
|
||||
this.detour = this.rawparams.shift() || '';
|
||||
if (this.type === 'MATCH')
|
||||
this.detour = rawfactor;
|
||||
|
||||
this.payload = [];
|
||||
if (logical_payload) { // ꓹ ႇ ❟
|
||||
|
@ -144,9 +159,15 @@ class RulesEntry {
|
|||
} else
|
||||
factor = this.payload[0].factor;
|
||||
|
||||
return [this.type, factor, this.detour].concat(
|
||||
['no-resolve', 'src'].filter(k => this.params[k])
|
||||
).join(',');
|
||||
if (this.subrule) {
|
||||
return 'SUB-RULE,(%s),%s'.format([this.type, factor].join(','), this.subrule);
|
||||
} else
|
||||
if (this.type === 'MATCH') {
|
||||
return [this.type, this.detour].join(',');
|
||||
} else
|
||||
return [this.type, factor, this.detour].concat(
|
||||
['no-resolve', 'src'].filter(k => this.params[k])
|
||||
).join(',');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,18 +244,23 @@ function renderPayload(s, total, uciconfig) {
|
|||
if (n === 0) {
|
||||
o.depends({type: /\bDOMAIN\b/});
|
||||
o.depends({type: /\bGEO(SITE|IP)\b/});
|
||||
o.depends({type: /\bASN\b/});
|
||||
o.depends({type: /\bPROCESS\b/});
|
||||
}
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\bDOMAIN\b/]]));
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\bGEO(SITE|IP)\b/]]));
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\bASN\b/]]));
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\bPROCESS\b/]]));
|
||||
initPayload(o, n, 'factor', uciconfig);
|
||||
|
||||
o = s.option(form.Value, prefix + 'ip', _('Factor') + ` ${n+1}`);
|
||||
o.datatype = 'cidr';
|
||||
if (n === 0)
|
||||
o.depends({type: /\bIP\b/});
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\bIP\b/]]));
|
||||
if (n === 0) {
|
||||
o.depends({type: /\b(CIDR|CIDR6)\b/});
|
||||
o.depends({type: /\bIP-SUFFIX\b/});
|
||||
}
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\b(CIDR|CIDR6)\b/]]));
|
||||
o.depends(Object.fromEntries([[prefix + 'type', /\bIP-SUFFIX\b/]]));
|
||||
initPayload(o, n, 'factor', uciconfig);
|
||||
|
||||
o = s.option(form.Value, prefix + 'port', _('Factor') + ` ${n+1}`);
|
||||
|
@ -266,6 +292,118 @@ function renderPayload(s, total, uciconfig) {
|
|||
}
|
||||
}
|
||||
|
||||
function renderRules(s, uciconfig) {
|
||||
var o;
|
||||
|
||||
o = s.option(form.DummyValue, 'entry', _('Entry'));
|
||||
o.load = function(section_id) {
|
||||
return form.DummyValue.prototype.load.call(this, section_id) || '%s,%s,%s'.format(hm.rules_type[0][0], '', hm.preset_outbound.full[0][0]);
|
||||
}
|
||||
o.write = L.bind(form.AbstractValue.prototype.write, o);
|
||||
o.remove = L.bind(form.AbstractValue.prototype.remove, o);
|
||||
o.editable = true;
|
||||
|
||||
o = s.option(form.ListValue, 'type', _('Type'));
|
||||
o.default = hm.rules_type[0][0];
|
||||
[...hm.rules_type, ...hm.rules_logical_type].forEach((res) => {
|
||||
o.value.apply(o, res);
|
||||
})
|
||||
o.load = function(section_id) {
|
||||
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).type;
|
||||
}
|
||||
o.validate = function(section_id, value) {
|
||||
// params only available for types other than
|
||||
// https://github.com/muink/mihomo/blob/43f21c0b412b7a8701fe7a2ea6510c5b985a53d6/config/config.go#L1050
|
||||
// https://github.com/muink/mihomo/blob/43f21c0b412b7a8701fe7a2ea6510c5b985a53d6/rules/parser.go#L12
|
||||
if (['GEOIP', 'IP-ASN', 'IP-CIDR', 'IP-CIDR6', 'IP-SUFFIX', 'RULE-SET'].includes(value)) {
|
||||
['no-resolve', 'src'].forEach((opt) => {
|
||||
let UIEl = this.section.getUIElement(section_id, opt);
|
||||
UIEl.node.querySelector('input').disabled = null;
|
||||
});
|
||||
} else {
|
||||
['no-resolve', 'src'].forEach((opt) => {
|
||||
let UIEl = this.section.getUIElement(section_id, opt);
|
||||
UIEl.setValue('');
|
||||
UIEl.node.querySelector('input').disabled = 'true';
|
||||
});
|
||||
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setParam('no-resolve').setParam('src').toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
UIEl.setValue(newvalue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
o.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setKey('type', value).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
return UIEl.setValue(newvalue);
|
||||
}
|
||||
o.write = function() {};
|
||||
o.rmempty = false;
|
||||
o.modalonly = true;
|
||||
|
||||
renderPayload(s, Math.max(...Object.values(hm.rules_logical_payload_count)), uciconfig);
|
||||
|
||||
o = s.option(form.ListValue, 'detour', _('Proxy group'));
|
||||
o.load = function(section_id) {
|
||||
hm.loadProxyGroupLabel.call(this, hm.preset_outbound.full, section_id);
|
||||
|
||||
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).detour;
|
||||
}
|
||||
o.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setKey('detour', value).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
return UIEl.setValue(newvalue);
|
||||
}
|
||||
o.write = function() {};
|
||||
//o.depends('SUB-RULE', '0');
|
||||
o.editable = true;
|
||||
|
||||
o = s.option(form.Flag, 'src', _('src'));
|
||||
o.default = o.disabled;
|
||||
o.load = function(section_id) {
|
||||
return strToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getParam('src'));
|
||||
}
|
||||
o.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setParam('src', flagToStr(value)).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
UIEl.setValue(newvalue);
|
||||
}
|
||||
o.write = function() {};
|
||||
o.depends('SUB-RULE', '0');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.option(form.Flag, 'no-resolve', _('no-resolve'));
|
||||
o.default = o.disabled;
|
||||
o.load = function(section_id) {
|
||||
return strToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getParam('no-resolve'));
|
||||
}
|
||||
o.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setParam('no-resolve', flagToStr(value)).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
UIEl.setValue(newvalue);
|
||||
}
|
||||
o.write = function() {};
|
||||
o.depends('SUB-RULE', '0');
|
||||
o.modalonly = true;
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
|
@ -306,8 +444,8 @@ return view.extend({
|
|||
o.inputstyle = 'apply';
|
||||
o.onclick = L.bind(hm.handleReload, o, 'mihomo-c');
|
||||
|
||||
o = s.taboption('group', form.ListValue, 'default_proxy', _('Default outbound'));
|
||||
o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct);
|
||||
o = s.taboption('group', form.Flag, 'client_enabled', _('Enable'));
|
||||
o.default = o.disabled;
|
||||
|
||||
/* Proxy Group */
|
||||
o = s.taboption('group', form.SectionValue, '_group', form.GridSection, 'proxy_group', null);
|
||||
|
@ -521,112 +659,85 @@ return view.extend({
|
|||
so.default = so.enabled;
|
||||
so.editable = true;
|
||||
|
||||
so = ss.option(form.DummyValue, 'entry', _('Entry'));
|
||||
so.load = function(section_id) {
|
||||
return form.DummyValue.prototype.load.call(this, section_id) || '%s,%s,%s'.format(hm.rules_type[0][0], '', hm.preset_outbound.full[0][0]);
|
||||
}
|
||||
so.write = L.bind(form.AbstractValue.prototype.write, so);
|
||||
so.remove = L.bind(form.AbstractValue.prototype.remove, so);
|
||||
so.editable = true;
|
||||
renderRules(ss, data[0]);
|
||||
|
||||
so = ss.option(form.ListValue, 'type', _('Type'));
|
||||
so.default = hm.rules_type[0][0];
|
||||
[...hm.rules_type, ...hm.rules_logical_type].forEach((res) => {
|
||||
so.value.apply(so, res);
|
||||
})
|
||||
so = ss.option(form.Flag, 'SUB-RULE', _('SUB-RULE'));
|
||||
so.default = so.disabled;
|
||||
so.load = function(section_id) {
|
||||
return new RulesEntry(uci.get(data[0], section_id, 'entry')).type;
|
||||
return strToFlag(new RulesEntry(uci.get(data[0], section_id, 'entry')).subrule ? 'true' : 'false');
|
||||
}
|
||||
so.validate = function(section_id, value) {
|
||||
// params only available for types other than
|
||||
// https://github.com/muink/mihomo/blob/43f21c0b412b7a8701fe7a2ea6510c5b985a53d6/config/config.go#L1050
|
||||
// https://github.com/muink/mihomo/blob/43f21c0b412b7a8701fe7a2ea6510c5b985a53d6/rules/parser.go#L12
|
||||
if (['GEOIP', 'IP-ASN', 'IP-CIDR', 'IP-CIDR6', 'IP-SUFFIX', 'RULE-SET'].includes(value)) {
|
||||
this.section.getUIElement(section_id, 'no-resolve').node.querySelector('input').disabled = null;
|
||||
this.section.getUIElement(section_id, 'src').node.querySelector('input').disabled = null;
|
||||
} else {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
value = this.formvalue(section_id);
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setParam('no-resolve').setParam('src').toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
UIEl.setValue(newvalue);
|
||||
|
||||
['no-resolve', 'src'].forEach((opt) => {
|
||||
let UIEl = this.section.getUIElement(section_id, opt);
|
||||
UIEl.setValue('');
|
||||
UIEl.node.querySelector('input').disabled = 'true';
|
||||
});
|
||||
}
|
||||
this.section.getUIElement(section_id, 'detour').node.querySelector('select').disabled = (value === '1') ? 'true' : null;
|
||||
|
||||
return true;
|
||||
}
|
||||
so.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setKey('type', value).toString();
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setKey('subrule', value === '1' ? ' ' : false).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
return UIEl.setValue(newvalue);
|
||||
}
|
||||
so.write = function() {};
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.ListValue, 'sub_rule', _('Sub rule'));
|
||||
so.load = function(section_id) {
|
||||
hm.loadSubRuleGroup.call(this, section_id);
|
||||
|
||||
return new RulesEntry(uci.get(data[0], section_id, 'entry')).subrule || '';
|
||||
}
|
||||
so.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setKey('subrule', value).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
return UIEl.setValue(newvalue);
|
||||
}
|
||||
so.rmempty = false;
|
||||
so.modalonly = true;
|
||||
|
||||
renderPayload(ss, Math.max(...Object.values(hm.rules_logical_payload_count)), data[0]);
|
||||
// dev: Features under development
|
||||
// SUB-RULE
|
||||
|
||||
so = ss.option(form.ListValue, 'detour', _('Proxy group'));
|
||||
so.load = function(section_id) {
|
||||
hm.loadProxyGroupLabel.call(this, hm.preset_outbound.full, section_id);
|
||||
|
||||
return new RulesEntry(uci.get(data[0], section_id, 'entry')).detour;
|
||||
}
|
||||
so.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setKey('detour', value).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
return UIEl.setValue(newvalue);
|
||||
}
|
||||
so.write = function() {};
|
||||
so.editable = true;
|
||||
|
||||
so = ss.option(form.Flag, 'src', _('src'));
|
||||
so.default = so.disabled;
|
||||
so.load = function(section_id) {
|
||||
return strToFlag(new RulesEntry(uci.get(data[0], section_id, 'entry')).getParam('src'));
|
||||
}
|
||||
so.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setParam('src', flagToStr(value)).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
UIEl.setValue(newvalue);
|
||||
}
|
||||
so.write = function() {};
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.Flag, 'no-resolve', _('no-resolve'));
|
||||
so.default = so.disabled;
|
||||
so.load = function(section_id) {
|
||||
return strToFlag(new RulesEntry(uci.get(data[0], section_id, 'entry')).getParam('no-resolve'));
|
||||
}
|
||||
so.onchange = function(ev, section_id, value) {
|
||||
var UIEl = this.section.getUIElement(section_id, 'entry');
|
||||
|
||||
var newvalue = new RulesEntry(UIEl.getValue()).setParam('no-resolve', flagToStr(value)).toString();
|
||||
|
||||
UIEl.node.previousSibling.innerText = newvalue;
|
||||
UIEl.setValue(newvalue);
|
||||
}
|
||||
so.write = function() {};
|
||||
so.depends('SUB-RULE', '1');
|
||||
so.modalonly = true;
|
||||
/* Routing rules END */
|
||||
|
||||
/* Sub rules START */
|
||||
s.tab('subrules', _('Sub rule'));
|
||||
|
||||
/* Sub rules */
|
||||
o = s.taboption('subrules', form.SectionValue, '_subrules', form.GridSection, 'subrules', null);
|
||||
ss = o.subsection;
|
||||
var prefmt = { 'prefix': '', 'suffix': '_subhost' };
|
||||
ss.addremove = true;
|
||||
ss.rowcolors = true;
|
||||
ss.sortable = true;
|
||||
ss.nodescriptions = true;
|
||||
ss.modaltitle = L.bind(hm.loadModalTitle, ss, _('Sub rule'), _('Add a sub rule'));
|
||||
ss.sectiontitle = L.bind(hm.loadDefaultLabel, ss);
|
||||
ss.renderSectionAdd = L.bind(hm.renderSectionAdd, ss, prefmt, false);
|
||||
ss.handleAdd = L.bind(hm.handleAdd, ss, prefmt);
|
||||
|
||||
so = ss.option(form.Value, 'label', _('Label'));
|
||||
so.load = L.bind(hm.loadDefaultLabel, so);
|
||||
so.validate = L.bind(hm.validateUniqueValue, so);
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.Flag, 'enabled', _('Enable'));
|
||||
so.default = so.enabled;
|
||||
so.editable = true;
|
||||
|
||||
so = ss.option(form.Value, 'group', _('Sub rule group'));
|
||||
so.value('sub-rule1');
|
||||
so.rmempty = false;
|
||||
so.validate = L.bind(hm.validateAuthUsername, so);
|
||||
so.editable = true;
|
||||
|
||||
renderRules(ss, data[0]);
|
||||
/* Sub rules END */
|
||||
|
||||
/* DNS settings START */
|
||||
s.tab('dns', _('DNS settings'));
|
||||
|
||||
|
|
|
@ -259,6 +259,9 @@ return view.extend({
|
|||
so = ss.option(form.DummyValue, '_geosite_version', _('GeoSite version'));
|
||||
so.cfgvalue = function() { return renderResVersion.call(this, null, 'geosite') };
|
||||
|
||||
so = ss.option(form.DummyValue, '_asn_version', _('ASN version'));
|
||||
so.cfgvalue = function() { return renderResVersion.call(this, null, 'asn') };
|
||||
|
||||
so = ss.option(form.DummyValue, '_china_ip4_version', _('China IPv4 list version'));
|
||||
so.cfgvalue = function() { return renderResVersion.call(this, null, 'china_ip4') };
|
||||
|
||||
|
|
|
@ -76,6 +76,10 @@ msgstr "API TLS 私钥"
|
|||
msgid "API secret"
|
||||
msgstr "API 令牌"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:262
|
||||
msgid "ASN version"
|
||||
msgstr "ASN 版本"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:562
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:612
|
||||
msgid "Access Control"
|
||||
|
@ -93,6 +97,10 @@ msgstr "新增 DNS 服务器"
|
|||
msgid "Add a Node"
|
||||
msgstr "新增 节点"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:717
|
||||
msgid "Add a sub rule"
|
||||
msgstr "新增 子规则"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:67
|
||||
msgid "Add a provider"
|
||||
msgstr "新增 供应商"
|
||||
|
@ -1519,6 +1527,18 @@ msgstr "堆栈"
|
|||
msgid "Strategy"
|
||||
msgstr "策略"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:646
|
||||
msgid "SUB-RULE"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:664
|
||||
msgid "Sub rule"
|
||||
msgstr "子规则"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:731
|
||||
msgid "Sub rule group"
|
||||
msgstr "子规则组"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/ruleset.js:140
|
||||
msgid "Successfully imported %s rule-set of total %s."
|
||||
msgstr "已成功导入 %s 个规则集 (共 %s 个)。"
|
||||
|
|
|
@ -77,8 +77,8 @@
|
|||
const dnsmasq_hijacked = uci.get('dhcp', '@dnsmasq[0]', 'dns_redirect') || '0',
|
||||
dnsmasq_port = uci.get('dhcp', '@dnsmasq[0]', 'port') || '53';
|
||||
|
||||
let default_proxy, routing_tcpport, routing_udpport, routing_mode, routing_domain;
|
||||
default_proxy = uci.get(cfgname, 'routing', 'default_proxy') || null,
|
||||
let client_enabled, routing_tcpport, routing_udpport, routing_mode, routing_domain;
|
||||
client_enabled = uci.get(cfgname, 'routing', 'client_enabled') || '0',
|
||||
routing_tcpport = uci.get(cfgname, 'routing', 'routing_tcpport') || null;
|
||||
routing_udpport = uci.get(cfgname, 'routing', 'routing_udpport') || null;
|
||||
routing_mode = uci.get(cfgname, 'routing', 'routing_mode') || null;
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
uci.load(cfgname);
|
||||
|
||||
const proxy_mode = uci.get(cfgname, 'inbound', 'proxy_mode') || 'redir_tproxy';
|
||||
let default_proxy, tun_name;
|
||||
let client_enabled, tun_name;
|
||||
if (match(proxy_mode, /tun/)) {
|
||||
default_proxy = uci.get(cfgname, 'routing', 'default_proxy') || null;
|
||||
client_enabled = uci.get(cfgname, 'routing', 'client_enabled') || '0';
|
||||
|
||||
if (default_proxy)
|
||||
if (client_enabled === '1')
|
||||
tun_name = uci.get(cfgname, 'config', 'tun_name') || 'hmtun0';
|
||||
}
|
||||
-%}
|
||||
|
|
|
@ -40,7 +40,8 @@ const ucisniff = 'sniff',
|
|||
ucipgrp = 'proxy_group',
|
||||
uciprov = 'provider',
|
||||
ucirule = 'ruleset',
|
||||
ucirout = 'rules';
|
||||
ucirout = 'rules',
|
||||
ucisubro = 'subrules';
|
||||
|
||||
/* Hardcode options */
|
||||
const common_tcpport = uci.get(uciconf, ucifchm, 'common_tcpport') || '20-21,22,53,80,110,143,443,465,853,873,993,995,8080,8443,9418',
|
||||
|
@ -68,7 +69,7 @@ const listen_interfaces = uci.get(uciconf, uciroute, 'listen_interfaces') || nul
|
|||
lan_proxy_ipv6_ips = uci.get(uciconf, uciroute, 'lan_proxy_ipv6_ips') || null,
|
||||
lan_proxy_mac_addrs = uci.get(uciconf, uciroute, 'lan_proxy_mac_addrs') || null,
|
||||
proxy_router = (uci.get(uciconf, uciroute, 'proxy_router') === '0') ? null : true,
|
||||
default_proxy = uci.get(uciconf, uciroute, 'default_proxy') || null,
|
||||
client_enabled = uci.get(uciconf, uciroute, 'client_enabled') || '0',
|
||||
routing_tcpport = uci.get(uciconf, uciroute, 'routing_tcpport') || null,
|
||||
routing_udpport = uci.get(uciconf, uciroute, 'routing_udpport') || null,
|
||||
routing_mode = uci.get(uciconf, uciroute, 'routing_mode') || null,
|
||||
|
@ -154,6 +155,24 @@ function get_nameserver(cfg, detour) {
|
|||
|
||||
return servers;
|
||||
}
|
||||
|
||||
function parse_entry(cfg) {
|
||||
if (isEmpty(cfg))
|
||||
return null;
|
||||
|
||||
let arr = split(cfg, ',');
|
||||
if (arr[0] === 'MATCH') {
|
||||
arr[1] = get_proxygroup(arr[1]);
|
||||
} else if (arr[0] === 'SUB-RULE') {
|
||||
arr[1] = replace(arr[1], /ꓹ|‚/g, ','); // U+A4F9 | U+201A
|
||||
arr[2] = replace(arr[2], /ꓹ|‚/g, ','); // U+A4F9 | U+201A
|
||||
} else {
|
||||
arr[1] = replace(arr[1], /ꓹ|‚/g, ','); // U+A4F9 | U+201A
|
||||
arr[2] = get_proxygroup(arr[2]);
|
||||
}
|
||||
|
||||
return join(',', arr);
|
||||
}
|
||||
/* Config helper END */
|
||||
|
||||
/* Main */
|
||||
|
@ -529,14 +548,21 @@ uci.foreach(uciconf, ucirout, (cfg) => {
|
|||
if (cfg.enabled === '0')
|
||||
return null;
|
||||
|
||||
push(config.rules, function(arr) {
|
||||
arr[1] = replace(arr[1], /ꓹ|‚/g, ','); // U+A4F9 | U+201A
|
||||
arr[2] = get_proxygroup(arr[2]);
|
||||
return join(',', arr);
|
||||
}(split(cfg.entry, ','))
|
||||
);
|
||||
push(config.rules, parse_entry(cfg.entry));
|
||||
});
|
||||
push(config.rules, 'MATCH,' + get_proxygroup(default_proxy));
|
||||
/* Routing rules END */
|
||||
|
||||
/* Sub rules START */
|
||||
/* Sub rules */
|
||||
config["sub-rules"] = {};
|
||||
uci.foreach(uciconf, ucisubro, (cfg) => {
|
||||
if (cfg.enabled === '0')
|
||||
return null;
|
||||
|
||||
if (!config["sub-rules"][cfg.group])
|
||||
config["sub-rules"][cfg.group] = [];
|
||||
push(config["sub-rules"][cfg.group], parse_entry(cfg.entry));
|
||||
});
|
||||
/* Sub rules END */
|
||||
|
||||
printf('%.J\n', removeBlankAttrs(config));
|
||||
|
|
|
@ -210,7 +210,7 @@ check_list_update() {
|
|||
case "$1" in
|
||||
"ALL")
|
||||
# Since the VER_PATH lock is not designed, parallelism is not currently supported.
|
||||
for _type in geoip geosite china_ip4 china_ip6 gfw_list china_list; do
|
||||
for _type in geoip geosite asn china_ip4 china_ip6 gfw_list china_list; do
|
||||
"$0" "$_type"
|
||||
done
|
||||
# dashboard
|
||||
|
@ -232,6 +232,10 @@ case "$1" in
|
|||
"geosite")
|
||||
check_geodata_update "$1" "Loyalsoldier/v2ray-rules-dat"
|
||||
;;
|
||||
"asn")
|
||||
check_list_update "$1" "Loyalsoldier/geoip" "release" "GeoLite2-ASN.mmdb" &&
|
||||
mv -f "$RESOURCES_DIR/asn.mmdb" "$RESOURCES_DIR/../asn.mmdb"
|
||||
;;
|
||||
"china_ip4")
|
||||
check_list_update "$1" "muink/route-list" "release" "china_ipv4.txt"
|
||||
;;
|
||||
|
@ -245,7 +249,7 @@ case "$1" in
|
|||
check_list_update "$1" "muink/route-list" "release" "china_list2.txt"
|
||||
;;
|
||||
*)
|
||||
echo -e "Usage: $0 <ALL / dashboard / geoip / geosite / china_ip4 / china_ip6 / gfw_list / china_list>"
|
||||
echo -e "Usage: $0 <ALL / dashboard / geoip / geosite / asn / china_ip4 / china_ip6 / gfw_list / china_list>"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -70,19 +70,19 @@ log() {
|
|||
}
|
||||
|
||||
start_service() {
|
||||
local default_proxy server_enabled server_auto_firewall
|
||||
config_get default_proxy "routing" "default_proxy" ""
|
||||
local client_enabled server_enabled server_auto_firewall
|
||||
config_get client_enabled "routing" "client_enabled" "0"
|
||||
config_get_bool server_enabled "routing" "server_enabled" "0"
|
||||
config_get_bool server_auto_firewall "routing" "server_auto_firewall" "0"
|
||||
|
||||
if [ -z "$default_proxy" -a "$server_enabled" = "0" ]; then
|
||||
if [ "$client_enabled" = "0" -a "$server_enabled" = "0" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
|
||||
# Client
|
||||
if [ -n "$default_proxy" ]; then
|
||||
if [ "$client_enabled" = "1" ]; then
|
||||
if [ -z "$1" -o "$1" = "mihomo-c" ]; then
|
||||
# Generate/Validate client config
|
||||
ucode -S "$HM_DIR/scripts/generate_client.uc" 2>>"$LOG_PATH" | yq -Poy | yq \
|
||||
|
@ -317,7 +317,7 @@ start_service() {
|
|||
# Setup firewall
|
||||
utpl -S "$HM_DIR/scripts/firewall_pre.ut" > "$RUN_DIR/fchomo_pre.nft"
|
||||
# Setup Nftables rules
|
||||
if [ -n "$default_proxy" ]; then
|
||||
if [ "$client_enabled" = "1" ]; then
|
||||
[ -z "$1" -o "$1" = "mihomo-c" ] && utpl -S "$HM_DIR/scripts/firewall_post.ut" > "$RUN_DIR/fchomo_post.nft"
|
||||
fi
|
||||
fw4 reload >"/dev/null" 2>&1
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
default_proxy=$(uci -q get fchomo.routing.default_proxy)
|
||||
if [ -n "$default_proxy" ]; then
|
||||
uci -q batch <<-EOF >"/dev/null"
|
||||
delete fchomo.routing.default_proxy
|
||||
set fchomo.routing.client_enabled="1"
|
||||
set fchomo.autogened_final_host="rules"
|
||||
set fchomo.autogened_final_host.label="Auto Generated Final"
|
||||
set fchomo.autogened_final_host.entry="MATCH,$default_proxy"
|
||||
commit fchomo
|
||||
EOF
|
||||
fi
|
||||
|
||||
exit 0
|
|
@ -8,8 +8,8 @@ USE_PROCD=1
|
|||
. "$IPKG_INSTROOT/etc/mihomo/scripts/constants.sh"
|
||||
|
||||
boot() {
|
||||
# init log
|
||||
init_log
|
||||
# prepare log
|
||||
prepare_log
|
||||
# load config
|
||||
config_load mihomo
|
||||
# start delay
|
||||
|
@ -25,8 +25,8 @@ boot() {
|
|||
}
|
||||
|
||||
start_service() {
|
||||
# clear log
|
||||
clear_log
|
||||
# prepare log
|
||||
prepare_log
|
||||
# load config
|
||||
config_load mihomo
|
||||
# check if enabled
|
||||
|
@ -480,15 +480,20 @@ cleanup() {
|
|||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
init_log() {
|
||||
mkdir "$LOG_DIR"
|
||||
touch "$APP_LOG_PATH"
|
||||
touch "$CORE_LOG_PATH"
|
||||
}
|
||||
|
||||
clear_log() {
|
||||
echo -n > "$APP_LOG_PATH"
|
||||
echo -n > "$CORE_LOG_PATH"
|
||||
prepare_log() {
|
||||
if [ ! -d "$LOG_DIR" ]; then
|
||||
mkdir -p "$LOG_DIR"
|
||||
fi
|
||||
if [ ! -f "$APP_LOG_PATH" ]; then
|
||||
touch "$APP_LOG_PATH"
|
||||
else
|
||||
echo -n > "$APP_LOG_PATH"
|
||||
fi
|
||||
if [ ! -f "$CORE_LOG_PATH" ]; then
|
||||
touch "$CORE_LOG_PATH"
|
||||
else
|
||||
echo -n > "$CORE_LOG_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
|
|
Loading…
Reference in New Issue