🌈 Sync 2024-09-06 00:19:59

This commit is contained in:
github-actions[bot] 2024-09-06 00:19:59 +08:00
parent 1ef28a654a
commit cefd5f478f
10 changed files with 234 additions and 630 deletions

View File

@ -7,50 +7,7 @@
'require rpc';
'require poll';
'require tools.widgets as widgets';
'require tools.mihomo as mihomo'
const convertBackends = [
'https://api.dler.io/sub',
'https://sub.id9.cc/sub',
'https://sub.xeton.dev/sub',
'http://127.0.0.1:25500/sub',
];
const convertTemplates = [
{ name: 'ACL4SSR', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR.ini' },
{ name: 'ACL4SSR_AdblockPlus', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_AdblockPlus.ini' },
{ name: 'ACL4SSR_BackCN', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_BackCN.ini' },
{ name: 'ACL4SSR_Mini', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Mini.ini' },
{ name: 'ACL4SSR_Mini_Fallback', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Mini_Fallback.ini' },
{ name: 'ACL4SSR_Mini_MultiMode', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Mini_MultiMode.ini' },
{ name: 'ACL4SSR_Mini_NoAuto', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Mini_NoAuto.ini' },
{ name: 'ACL4SSR_NoApple', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_NoApple.ini' },
{ name: 'ACL4SSR_NoAuto', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_NoAuto.ini' },
{ name: 'ACL4SSR_NoAuto_NoApple', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_NoAuto_NoApple.ini' },
{ name: 'ACL4SSR_NoAuto_NoApple_NoMicrosoft', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_NoAuto_NoApple_NoMicrosoft.ini' },
{ name: 'ACL4SSR_NoMicrosoft', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_NoMicrosoft.ini' },
{ name: 'ACL4SSR_Online', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini' },
{ name: 'ACL4SSR_Online_AdblockPlus', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_AdblockPlus.ini' },
{ name: 'ACL4SSR_Online_Full', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full.ini' },
{ name: 'ACL4SSR_Online_Full_AdblockPlus', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_AdblockPlus.ini' },
{ name: 'ACL4SSR_Online_Full_Google', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_Google.ini' },
{ name: 'ACL4SSR_Online_Full_MultiMode', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_MultiMode.ini' },
{ name: 'ACL4SSR_Online_Full_Netflix', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_Netflix.ini' },
{ name: 'ACL4SSR_Online_Full_NoAuto', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_NoAuto.ini' },
{ name: 'ACL4SSR_Online_Mini', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini.ini' },
{ name: 'ACL4SSR_Online_Mini_AdblockPlus', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_AdblockPlus.ini' },
{ name: 'ACL4SSR_Online_Mini_Ai', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_Ai.ini' },
{ name: 'ACL4SSR_Online_Mini_Fallback', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_Fallback.ini' },
{ name: 'ACL4SSR_Online_Mini_MultiCountry', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_MultiCountry.ini' },
{ name: 'ACL4SSR_Online_Mini_MultiMode', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_MultiMode.ini' },
{ name: 'ACL4SSR_Online_Mini_NoAuto', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_NoAuto.ini' },
{ name: 'ACL4SSR_Online_MultiCountry', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_MultiCountry.ini' },
{ name: 'ACL4SSR_Online_NoAuto', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_NoAuto.ini' },
{ name: 'ACL4SSR_Online_NoReject', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_NoReject.ini' },
{ name: 'ACL4SSR_WithChinaIp', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_WithChinaIp.ini' },
{ name: 'ACL4SSR_WithChinaIp_WithGFW', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_WithChinaIp_WithGFW.ini' },
{ name: 'ACL4SSR_WithGFW', url: 'https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_WithGFW.ini' },
];
'require tools.mihomo as mihomo';
function renderStatus(running) {
return updateStatus(E('input', { id: 'core_status', style: 'border: unset; font-style: italic; font-weight: bold;', readonly: '' }), running);
@ -115,14 +72,14 @@ return view.extend({
o = s.option(form.Button, 'reload', '-');
o.inputstyle = 'action';
o.inputtitle = _('Reload');
o.inputtitle = _('Reload Service');
o.onclick = function () {
return mihomo.reload();
};
o = s.option(form.Button, 'restart', '-');
o.inputstyle = 'negative';
o.inputtitle = _('Restart');
o.inputtitle = _('Restart Service');
o.onclick = function () {
return mihomo.restart();
};
@ -153,7 +110,7 @@ return view.extend({
o.rmempty = false;
o.depends('scheduled_restart', '1');
o = s.option(form.Value, 'profile', _('Choose Profile'));
o = s.option(form.ListValue, 'profile', _('Choose Profile'));
o.rmempty = false;
for (const profile of profiles) {
@ -183,8 +140,12 @@ return view.extend({
o = s.taboption('transparent_proxy', form.Flag, 'transparent_proxy', _('Enable'));
o.rmempty = false;
o = s.taboption('transparent_proxy', form.ListValue, 'transparent_proxy_mode', _('Mode'));
o.rmempty = false;
o = s.taboption('transparent_proxy', form.ListValue, 'tcp_transparent_proxy_mode', _('TCP Proxy Mode'));
o.value('redirect', _('Redirect Mode'));
o.value('tproxy', _('TPROXY Mode'));
o.value('tun', _('TUN Mode'));
o = s.taboption('transparent_proxy', form.ListValue, 'udp_transparent_proxy_mode', _('UDP Proxy Mode'));
o.value('tproxy', _('TPROXY Mode'));
o.value('tun', _('TUN Mode'));
@ -209,7 +170,6 @@ return view.extend({
s.tab('access_control', _('Access Control'));
o = s.taboption('access_control', form.ListValue, 'access_control_mode', _('Mode'));
o.rmempty = false;
o.value('all', _('All Mode'));
o.value('allow', _('Allow Mode'));
o.value('block', _('Block Mode'));
@ -261,103 +221,35 @@ return view.extend({
o = s.taboption('bypass', form.Value, 'acl_tcp_dport', _('Destination TCP Port to Proxy'));
o.rmempty = false;
o.value('1-65535', _('All Port'));
o.value('0-65535', _('All Port'));
o.value('21 22 80 110 143 194 443 465 993 995 8080 8443', _('Commonly Used Port'));
o = s.taboption('bypass', form.Value, 'acl_udp_dport', _('Destination UDP Port to Proxy'));
o.rmempty = false;
o.value('1-65535', _('All Port'));
o.value('0-65535', _('All Port'));
o.value('123 443 8443', _('Commonly Used Port'));
s = m.section(form.GridSection, 'subscription', _('Subscription Config'));
s = m.section(form.TableSection, 'subscription', _('Subscription Config'));
s.addremove = true;
s.anonymous = true;
s.tab('subscription', _('Subscription Config'));
o = s.taboption('subscription', form.Value, 'name', _('Subscription Name'));
o = s.option(form.Value, 'name', _('Subscription Name'));
o.rmempty = false;
o.width = '10%';
o.width = '15%';
o = s.taboption('subscription', form.Value, 'url', _('Subscription Url'));
o = s.option(form.Value, 'url', _('Subscription Url'));
o.rmempty = false;
o = s.taboption('subscription', form.Value, 'user_agent', _('User Agent'));
o = s.option(form.Value, 'user_agent', _('User Agent'));
o.default = 'mihomo';
o.rmempty = false;
o.modalonly = true;
o.width = '15%';
o.value('mihomo');
o.value('clash.meta');
o.value('clash');
s.tab('convert', _('Convert Config'));
o = s.taboption('convert', form.Flag, 'convert', _('Enable'));
o.modalonly = true;
o.rmempty = false;
o = s.taboption('convert', form.Value, 'convert_backend', _('Backend'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends('convert', '1');
for (const backend of convertBackends) {
o.value(backend);
}
o = s.taboption('convert', form.Value, 'convert_template', _('Template'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends('convert', '1');
for (const template of convertTemplates) {
o.value(template.url, template.name);
}
o = s.taboption('convert', form.Flag, 'convert_advanced', _('Advanced Config'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends('convert', '1');
o = s.taboption('convert', form.Value, 'convert_include', _('Include'));
o.modalonly = true;
o.retain = true;
o.depends({ 'convert': '1', 'convert_advanced': '1' });
o = s.taboption('convert', form.Value, 'convert_exclude', _('Exclude'));
o.modalonly = true;
o.retain = true;
o.depends({ 'convert': '1', 'convert_advanced': '1' });
o = s.taboption('convert', form.Flag, 'convert_udp', _('UDP'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends({ 'convert': '1', 'convert_advanced': '1' });
o = s.taboption('convert', form.Flag, 'convert_emoji', _('Use Emoji'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends({ 'convert': '1', 'convert_advanced': '1' });
o = s.taboption('convert', form.Flag, 'convert_insert_node_type', _('Insert Node Type'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends({ 'convert': '1', 'convert_advanced': '1' });
o = s.taboption('convert', form.Flag, 'convert_expand', _('Expand Ruleset'));
o.modalonly = true;
o.retain = true;
o.rmempty = false;
o.depends({ 'convert': '1', 'convert_advanced': '1' });
s = m.section(form.NamedSection, 'mixin', 'mixin', _('Mixin Config'));
s.tab('general', _('General Config'));
o = s.taboption('general', form.ListValue, 'log_level', _('Log Level'));
@ -384,15 +276,13 @@ return view.extend({
o = s.taboption('general', form.Flag, 'ipv6', _('IPv6'));
o.rmempty = false;
o = s.taboption('general', form.Flag, 'unify_delay', _('Unify Delay'));
o.rmempty = false;
o = s.taboption('general', form.Flag, 'tcp_concurrent', _('TCP Concurrent'));
o.rmempty = false;
o = s.taboption('general', form.Value, 'tcp_keep_alive_idle', _('TCP Keep Alive Idle'));
o.datatype = 'integer';
o.placeholder = '600';
o = s.taboption('general', form.Value, 'tcp_keep_alive_interval', _('TCP Keep Alive Interval'));
o.datatype = 'integer';
o.placeholder = '600';
o.placeholder = '15';
s.tab('external_control', _('External Control Config'));
@ -505,11 +395,19 @@ return view.extend({
o.retain = true;
o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' });
o = s.taboption('dns', form.ListValue, 'fake_ip_filter_mode', _('Fake-IP Filter Mode'))
o.value('blacklist', _('Block Mode'));
o.value('whitelist', _('Allow Mode'));
o.depends({ 'dns_mode': 'fake-ip', 'fake_ip_filter': '1' });
o = s.taboption('dns', form.Flag, 'fake_ip_cache', _('Fake-IP Cache'));
o.retain = true;
o.rmempty = false;
o.depends('dns_mode', 'fake-ip');
o = s.taboption('dns', form.Flag, 'dns_respect_rules', _('Respect Rules'));
o.rmempty = false;
o = s.taboption('dns', form.Flag, 'dns_ipv6', _('IPv6'));
o.rmempty = false;
@ -551,36 +449,14 @@ return view.extend({
so.rmempty = false;
so = o.subsection.option(form.ListValue, 'type', _('Type'));
so.readonly = true;
so.value('default-nameserver');
so.value('proxy-server-nameserver');
so.value('nameserver');
so.value('fallback');
so.readonly = true;
so = o.subsection.option(form.DynamicList, 'nameserver', _('Nameserver'));
o = s.taboption('dns', form.Flag, 'dns_fallback_filter', _('Overwrite Fallback Filter'));
o.rmempty = false;
o = s.taboption('dns', form.SectionValue, '_dns_fallback_filters', form.TableSection, 'fallback_filter', _('Edit Fallback Filters'));
o.retain = true;
o.depends('dns_fallback_filter', '1');
o.subsection.anonymous = true;
o.subsection.addremove = false;
so = o.subsection.option(form.Flag, 'enabled', _('Enable'));
so.rmempty = false;
so = o.subsection.option(form.ListValue, 'type', _('Type'));
so.value('geoip-code', _('GeoIP'));
so.value('geosite', _('GeoSite'));
so.value('ipcidr', _('IPCIDR'));
so.value('domain_name', _('Domain Name'));
so.readonly = true;
so = o.subsection.option(form.DynamicList, 'value', _('Value'));
o = s.taboption('dns', form.Flag, 'dns_nameserver_policy', _('Overwrite Nameserver Policy'));
o.rmempty = false;
@ -599,44 +475,6 @@ return view.extend({
so = o.subsection.option(form.DynamicList, 'nameserver', _('Nameserver'));
s.tab('sniffer', _('Sniffer Config'));
o = s.taboption('sniffer', form.Flag, 'sniffer', _('Enable'));
o.rmempty = false;
o = s.taboption('sniffer', form.Flag, 'sniff_dns_mapping', _('Sniff Redir-Host'));
o.rmempty = false;
o = s.taboption('sniffer', form.Flag, 'sniff_pure_ip', _('Sniff Pure IP'));
o.rmempty = false;
o = s.taboption('sniffer', form.Flag, 'sniffer_overwrite_dest', _('Overwrite Destination'));
o.rmempty = false;
o = s.taboption('sniffer', form.DynamicList, 'sniffer_force_domain_name', _('Force Sniff Domain Name'));
o = s.taboption('sniffer', form.DynamicList, 'sniffer_ignore_domain_name', _('Ignore Sniff Domain Name'));
o = s.taboption('sniffer', form.SectionValue, '_sniffer_sniffs', form.TableSection, 'sniff', _('Sniff By Protocol'));
o.subsection.anonymous = true;
o.subsection.addremove = false;
so = o.subsection.option(form.Flag, 'enabled', _('Enable'));
so.rmempty = false;
so = o.subsection.option(form.ListValue, 'protocol', _('Protocol'));
so.value('HTTP');
so.value('TLS');
so.value('QUIC');
so.readonly = true;
so = o.subsection.option(form.DynamicList, 'port', _('Port'));
so.datatype = 'portrange';
so = o.subsection.option(form.Flag, 'overwrite_dest', _('Overwrite Destination'));
so.rmempty = false;
s.tab('geox', _('GeoX Config'));
o = s.taboption('geox', form.ListValue, 'geoip_format', _('GeoIP Format'));

View File

@ -28,11 +28,11 @@ msgstr "运行中"
msgid "Not Running"
msgstr "未在运行"
msgid "Reload"
msgstr "重新加载"
msgid "Reload Service"
msgstr "重载服务"
msgid "Restart"
msgstr "重启"
msgid "Restart Service"
msgstr "重启服务"
msgid "Update Dashboard"
msgstr "更新面板"
@ -94,6 +94,15 @@ msgstr "代理配置"
msgid "Transparent Proxy"
msgstr "透明代理"
msgid "TCP Proxy Mode"
msgstr "TCP 代理模式"
msgid "UDP Proxy Mode"
msgstr "UDP 代理模式"
msgid "Redirect Mode"
msgstr "Redirect 模式"
msgid "TPROXY Mode"
msgstr "TPROXY 模式"
@ -148,12 +157,6 @@ msgstr "全部端口"
msgid "Commonly Used Port"
msgstr "常用端口"
msgid "WAN Interfaces"
msgstr "WAN 接口"
msgid "WAN6 Interfaces"
msgstr "WAN6 接口"
msgid "Subscription Config"
msgstr "订阅配置"
@ -163,39 +166,9 @@ msgstr "订阅名称"
msgid "Subscription Url"
msgstr "订阅链接"
msgid "Convert Config"
msgstr "订阅转换配置"
msgid "User Agent"
msgstr "用户代理UA"
msgid "Backend"
msgstr "后端地址"
msgid "Template"
msgstr "模板"
msgid "Advanced Config"
msgstr "进阶配置"
msgid "Include"
msgstr "包含节点"
msgid "Exclude"
msgstr "排除节点"
msgid "UDP"
msgstr "UDP"
msgid "Use Emoji"
msgstr "使用 Emoji"
msgid "Insert Node Type"
msgstr "插入节点类型"
msgid "Expand Ruleset"
msgstr "展开规则集"
msgid "Mixin Config"
msgstr "混入配置"
@ -220,11 +193,8 @@ msgstr "匹配进程"
msgid "Outbound Interface"
msgstr "出站接口"
msgid "Unify Delay"
msgstr "统一延迟"
msgid "TCP Concurrent"
msgstr "TCP 并发"
msgid "TCP Keep Alive Idle"
msgstr "TCP Keep Alive 空闲"
msgid "TCP Keep Alive Interval"
msgstr "TCP Keep Alive 间隔"
@ -325,9 +295,15 @@ msgstr "覆盖 Fake-IP 过滤列表"
msgid "Edit Fake-IP Filters"
msgstr "编辑 Fake-IP 过滤列表"
msgid "Fake-IP Filter Mode"
msgstr "Fake-IP 过滤模式"
msgid "Fake-IP Cache"
msgstr "Fake-IP 缓存"
msgid "Respect Rules"
msgstr "遵循分流规则"
msgid "Use System Hosts"
msgstr "使用系统的 Hosts"
@ -367,27 +343,6 @@ msgstr "编辑 DNS 服务器查询策略"
msgid "Matcher"
msgstr "匹配"
msgid "Sniffer Config"
msgstr "嗅探器配置"
msgid "Sniff Redir-Host"
msgstr "嗅探 Redir-Host 流量"
msgid "Sniff Pure IP"
msgstr "嗅探纯IP连接"
msgid "Overwrite Destination"
msgstr "将嗅探结果作为连接的目标"
msgid "Force Sniff Domain Name"
msgstr "强制嗅探的域名"
msgid "Ignore Sniff Domain Name"
msgstr "忽略嗅探的域名"
msgid "Sniff By Protocol"
msgstr "按协议嗅探"
msgid "GeoX Config"
msgstr "GeoX 配置"

View File

@ -1,12 +1,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=mihomo
PKG_RELEASE:=48
PKG_RELEASE:=49
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
PKG_SOURCE_DATE:=2024-09-01
PKG_SOURCE_VERSION:=802267fb5b0a17bf7915b78abbb80afa407d8815
PKG_SOURCE_DATE:=2024-09-03
PKG_SOURCE_VERSION:=faaa90f8a621499ba86f8734a05bb80edb38ada9
PKG_MIRROR_HASH:=skip
PKG_LICENSE:=MIT
@ -31,7 +31,7 @@ define Package/mihomo
CATEGORY:=Network
TITLE:=A rule based proxy in Go.
URL:=https://wiki.metacubex.one
DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle +curl +yq firewall4 +kmod-nft-tproxy +ip-full +kmod-tun
DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle +curl +yq firewall4 +kmod-nft-tproxy +ip-full +kmod-tun +procd-ujail
USERID:=mihomo=7890:mihomo=7890
endef

View File

@ -2,6 +2,7 @@
"permitted": [
"CAP_FOWNER",
"CAP_DAC_OVERRIDE",
"CAP_DAC_READ_SEARCH",
"CAP_SYS_PTRACE",
"CAP_NET_ADMIN",
"CAP_NET_BIND_SERVICE",
@ -10,6 +11,7 @@
"effective": [
"CAP_FOWNER",
"CAP_DAC_OVERRIDE",
"CAP_DAC_READ_SEARCH",
"CAP_SYS_PTRACE",
"CAP_NET_ADMIN",
"CAP_NET_BIND_SERVICE",
@ -18,6 +20,7 @@
"bounding": [
"CAP_FOWNER",
"CAP_DAC_OVERRIDE",
"CAP_DAC_READ_SEARCH",
"CAP_SYS_PTRACE",
"CAP_NET_ADMIN",
"CAP_NET_BIND_SERVICE",
@ -26,6 +29,7 @@
"inheritable": [
"CAP_FOWNER",
"CAP_DAC_OVERRIDE",
"CAP_DAC_READ_SEARCH",
"CAP_SYS_PTRACE",
"CAP_NET_ADMIN",
"CAP_NET_BIND_SERVICE",
@ -34,6 +38,7 @@
"ambient": [
"CAP_FOWNER",
"CAP_DAC_OVERRIDE",
"CAP_DAC_READ_SEARCH",
"CAP_SYS_PTRACE",
"CAP_NET_ADMIN",
"CAP_NET_BIND_SERVICE",

View File

@ -11,7 +11,8 @@ config config 'config'
config proxy 'proxy'
option 'transparent_proxy' '1'
option 'transparent_proxy_mode' 'tproxy'
option 'tcp_transparent_proxy_mode' 'tproxy'
option 'udp_transparent_proxy_mode' 'tproxy'
option 'ipv4_dns_hijack' '1'
option 'ipv6_dns_hijack' '1'
option 'ipv4_proxy' '1'
@ -23,23 +24,13 @@ config proxy 'proxy'
option 'acl_ip6' ''
option 'acl_mac' ''
option 'bypass_china_mainland_ip' '0'
option 'acl_tcp_dport' '1-65535'
option 'acl_udp_dport' '1-65535'
option 'acl_tcp_dport' '0-65535'
option 'acl_udp_dport' '0-65535'
config subscription 'subscription'
option 'name' 'default'
option 'url' 'http://example.com/default.yaml'
option 'user_agent' 'mihomo'
option 'convert' '0'
option 'convert_backend' ''
option 'convert_template' ''
option 'convert_advanced' '0'
option 'convert_include' ''
option 'convert_exclude' ''
option 'convert_udp' '0'
option 'convert_emoji' '0'
option 'convert_insert_node_type' '0'
option 'convert_expand' '0'
config mixin 'mixin'
option 'log_level' 'info'
@ -47,9 +38,8 @@ config mixin 'mixin'
option 'match_process' 'off'
option 'outbound_interface' ''
option 'ipv6' '0'
option 'unify_delay' '1'
option 'tcp_concurrent' '1'
option 'tcp_keep_alive_interval' '600'
option 'tcp_keep_alive_idle' '600'
option 'tcp_keep_alive_interval' '15'
option 'ui_name' 'metacubexd'
option 'ui_url' 'https://mirror.ghproxy.com/https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip'
option 'api_port' '9090'
@ -74,19 +64,13 @@ config mixin 'mixin'
list 'fake_ip_filters' '+.lan'
list 'fake_ip_filters' '+.local'
option 'fake_ip_cache' '1'
option 'respect_rules' '1'
option 'dns_ipv6' '0'
option 'dns_system_hosts' '0'
option 'dns_hosts' '0'
option 'hosts' '0'
option 'dns_nameserver' '0'
option 'dns_fallback_filter' '0'
option 'dns_nameserver_policy' '0'
option 'sniffer' '0'
option 'sniff_dns_mapping' '1'
option 'sniff_pure_ip' '1'
option 'sniffer_overwrite_dest' '1'
option 'sniffer_force_domain_name' ''
option 'sniffer_ignore_domain_name' ''
option 'geoip_format' 'dat'
option 'geodata_loader' 'memconservative'
option 'geosite_url' 'https://mirror.ghproxy.com/https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat'
@ -131,24 +115,6 @@ config nameserver
list 'nameserver' 'https://dns.cloudflare.com/dns-query'
list 'nameserver' 'https://dns.google/dns-query'
config fallback_filter
option 'enabled' '1'
option 'type' 'geoip-code'
list 'value' 'CN'
config fallback_filter
option 'enabled' '1'
option 'type' 'geosite'
list 'value' 'GFW'
config fallback_filter
option 'enabled' '0'
option 'type' 'ipcidr'
config fallback_filter
option 'enabled' '0'
option 'type' 'domain_name'
config nameserver_policy
option 'enabled' '1'
option 'matcher' 'geosite:cn,private'
@ -161,27 +127,6 @@ config nameserver_policy
list 'nameserver' 'https://dns.cloudflare.com/dns-query'
list 'nameserver' 'https://dns.google/dns-query'
config sniff
option 'enabled' '1'
option 'protocol' 'HTTP'
list 'port' '80'
list 'port' '8080-8880'
option 'overwrite_dest' '1'
config sniff
option 'enabled' '1'
option 'protocol' 'TLS'
list 'port' '443'
list 'port' '8443'
option 'overwrite_dest' '1'
config sniff
option 'enabled' '1'
option 'protocol' 'QUIC'
list 'port' '443'
list 'port' '8443'
option 'overwrite_dest' '1'
config editor 'editor'
config log 'log'

View File

@ -25,37 +25,40 @@ start_service() {
# get config
## app config
local scheduled_restart cron_expression profile mixin test_profile fast_reload
config_get scheduled_restart "config" "scheduled_restart"
config_get_bool scheduled_restart "config" "scheduled_restart" 0
config_get cron_expression "config" "cron_expression"
config_get profile "config" "profile"
config_get_bool mixin "config" "mixin" 0
config_get_bool test_profile "config" "test_profile" 0
config_get_bool fast_reload "config" "fast_reload" 0
## proxy config
local transparent_proxy transparent_proxy_mode ipv4_dns_hijack ipv6_dns_hijack ipv4_proxy ipv6_proxy router_proxy lan_proxy access_control_mode bypass_china_mainland_ip acl_tcp_dport acl_udp_dport
### transparent proxy
local transparent_proxy tcp_transparent_proxy_mode udp_transparent_proxy_mode ipv4_dns_hijack ipv6_dns_hijack ipv4_proxy ipv6_proxy router_proxy lan_proxy
config_get_bool transparent_proxy "proxy" "transparent_proxy" 0
config_get transparent_proxy_mode "proxy" "transparent_proxy_mode"
config_get tcp_transparent_proxy_mode "proxy" "tcp_transparent_proxy_mode" "tproxy"
config_get udp_transparent_proxy_mode "proxy" "udp_transparent_proxy_mode" "tproxy"
config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0
config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0
config_get_bool ipv4_proxy "proxy" "ipv4_proxy" 0
config_get_bool ipv6_proxy "proxy" "ipv6_proxy" 0
config_get_bool router_proxy "proxy" "router_proxy" 0
config_get_bool lan_proxy "proxy" "lan_proxy" 0
### access control
local access_control_mode bypass_china_mainland_ip acl_tcp_dport acl_udp_dport
config_get access_control_mode "proxy" "access_control_mode"
config_get_bool bypass_china_mainland_ip "proxy" "bypass_china_mainland_ip" 0
config_get acl_tcp_dport "proxy" "acl_tcp_dport" "1-65535"
config_get acl_udp_dport "proxy" "acl_udp_dport" "1-65535"
config_get acl_tcp_dport "proxy" "acl_tcp_dport" "0-65535"
config_get acl_udp_dport "proxy" "acl_udp_dport" "0-65535"
## mixin config
### general
local mode match_process outbound_interface ipv6 unify_delay tcp_concurrent tcp_keep_alive_interval log_level
config_get mode "mixin" "mode"
config_get match_process "mixin" "match_process"
local mode match_process outbound_interface ipv6 tcp_keep_alive_idle tcp_keep_alive_interval log_level
config_get mode "mixin" "mode" "rule"
config_get match_process "mixin" "match_process" "off"
config_get outbound_interface "mixin" "outbound_interface"
config_get_bool ipv6 "mixin" "ipv6" 0
config_get_bool unify_delay "mixin" "unify_delay" 0
config_get_bool tcp_concurrent "mixin" "tcp_concurrent" 0
config_get tcp_keep_alive_interval "mixin" "tcp_keep_alive_interval" 600
config_get log_level "mixin" "log_level"
config_get tcp_keep_alive_idle "mixin" "tcp_keep_alive_idle" 600
config_get tcp_keep_alive_interval "mixin" "tcp_keep_alive_interval" 15
config_get log_level "mixin" "log_level" "info"
### external control
local ui_name ui_url api_port api_secret selection_cache
config_get ui_name "mixin" "ui_name"
@ -74,41 +77,45 @@ start_service() {
config_get_bool authentication "mixin" "authentication" 0
### tun
local tun_stack tun_mtu tun_gso tun_gso_max_size tun_endpoint_independent_nat
config_get tun_stack "mixin" "tun_stack"
config_get tun_stack "mixin" "tun_stack" "system"
config_get tun_mtu "mixin" "tun_mtu" "9000"
config_get_bool tun_gso "mixin" "tun_gso" 0
config_get tun_gso_max_size "mixin" "tun_gso_max_size" "65536"
config_get_bool tun_endpoint_independent_nat "mixin" "tun_endpoint_independent_nat" 0
### dns
local dns_port dns_mode fake_ip_range fake_ip_filter fake_ip_cache dns_ipv6 dns_system_hosts dns_hosts hosts dns_nameserver dns_fallback_filter dns_nameserver_policy
local dns_port dns_mode fake_ip_range fake_ip_filter fake_ip_filter_mode fake_ip_cache dns_respect_rules dns_ipv6 dns_system_hosts dns_hosts hosts dns_nameserver dns_nameserver_policy
config_get dns_port "mixin" "dns_port" "1053"
config_get dns_mode "mixin" "dns_mode"
config_get dns_mode "mixin" "dns_mode" "redir-host"
config_get fake_ip_range "mixin" "fake_ip_range" "198.18.0.1/16"
config_get_bool fake_ip_filter "mixin" "fake_ip_filter" 0
config_get fake_ip_filter_mode "mixin" "fake_ip_filter_mode" "blacklist"
config_get_bool fake_ip_cache "mixin" "fake_ip_cache" 0
config_get_bool dns_respect_rules "mixin" "dns_respect_rules" 0
config_get_bool dns_ipv6 "mixin" "dns_ipv6" 0
config_get_bool dns_system_hosts "mixin" "dns_system_hosts" 0
config_get_bool dns_hosts "mixin" "dns_hosts" 0
config_get_bool hosts "mixin" "hosts" 0
config_get_bool dns_nameserver "mixin" "dns_nameserver" 0
config_get_bool dns_fallback_filter "mixin" "dns_fallback_filter" 0
config_get_bool dns_nameserver_policy "mixin" "dns_nameserver_policy" 0
### sniffer
local sniffer sniff_dns_mapping sniff_pure_ip sniffer_overwrite_dest
config_get_bool sniffer "mixin" "sniffer" 0
config_get_bool sniff_dns_mapping "mixin" "sniff_dns_mapping" 0
config_get_bool sniff_pure_ip "mixin" "sniff_pure_ip" 0
config_get_bool sniffer_overwrite_dest "mixin" "sniffer_overwrite_dest" 0
### geox
local geoip_format geodata_loader geosite_url geoip_mmdb_url geoip_dat_url geoip_asn_url geox_auto_update geox_update_interval
config_get geoip_format "mixin" "geoip_format"
config_get geodata_loader "mixin" "geodata_loader"
config_get geoip_format "mixin" "geoip_format" "mmdb"
config_get geodata_loader "mixin" "geodata_loader" "memconservative"
config_get geosite_url "mixin" "geosite_url"
config_get geoip_mmdb_url "mixin" "geoip_mmdb_url"
config_get geoip_dat_url "mixin" "geoip_dat_url"
config_get geoip_asn_url "mixin" "geoip_asn_url"
config_get_bool geox_auto_update "mixin" "geox_auto_update" 0
config_get geox_update_interval "mixin" "geox_update_interval" "24"
# prepare
local tproxy_enable; tproxy_enable=0
if [[ "$tcp_transparent_proxy_mode" == "tproxy" || "$udp_transparent_proxy_mode" == "tproxy" ]]; then
tproxy_enable=1
fi
local tun_enable; tun_enable=0
if [[ "$tcp_transparent_proxy_mode" == "tun" || "$udp_transparent_proxy_mode" == "tun" ]]; then
tun_enable=1
fi
# get profile
if [[ "$profile" == "file:"* ]]; then
local profile_name; profile_name=$(basename "${profile/file:/}")
@ -116,53 +123,19 @@ start_service() {
log "Use Profile: $profile_name"
elif [[ "$profile" == "subscription:"* ]]; then
local subscription_section; subscription_section="${profile/subscription:/}"
# subscription
local subscription_name subscription_url subscription_user_agent
config_get subscription_name "$subscription_section" "name"
config_get subscription_url "$subscription_section" "url"
config_get subscription_user_agent "$subscription_section" "user_agent"
# convert
local subscription_convert subscription_convert_backend subscription_convert_template
config_get_bool subscription_convert "$subscription_section" "convert" 0
config_get subscription_convert_backend "$subscription_section" "convert_backend"
config_get subscription_convert_template "$subscription_section" "convert_template"
# convert advanced
local subscription_convert_advanced subscription_convert_include subscription_convert_exclude subscription_convert_udp subscription_convert_emoji subscription_convert_insert_node_type subscription_convert_expand
config_get_bool subscription_convert_advanced "$subscription_section" "convert_advanced" 0
config_get subscription_convert_include "$subscription_section" "convert_include"
config_get subscription_convert_exclude "$subscription_section" "convert_exclude"
config_get_bool subscription_convert_udp "$subscription_section" "convert_udp" 0
config_get_bool subscription_convert_emoji "$subscription_section" "convert_emoji" 0
config_get_bool subscription_convert_insert_node_type "$subscription_section" "convert_insert_node_type" 0
config_get_bool subscription_convert_expand "$subscription_section" "convert_expand" 0
# generate url
local url
if [ "$subscription_convert" == 0 ]; then
url="$subscription_url"
else
url="$subscription_convert_backend?target=clash&url=$(echo -n "$subscription_url" | yq -M -o uri)"
if [ -n "$subscription_convert_template" ]; then
url="$url&config=$(echo -n "$subscription_convert_template" | yq -M -o uri)"
fi
if [ "$subscription_convert_advanced" == 1 ]; then
if [ -n "$subscription_convert_include" ]; then
url="$url&include=$(echo -n "$subscription_convert_include" | yq -M -o uri)"
fi
if [ -n "$subscription_convert_exclude" ]; then
url="$url&exclude=$(echo -n "$subscription_convert_exclude" | yq -M -o uri)"
fi
url="$url&udp=$([ "$subscription_convert_udp" == 1 ] && echo -n "true" || echo -n "false")"
url="$url&emoji=$([ "$subscription_convert_emoji" == 1 ] && echo -n "true" || echo -n "false")"
url="$url&append_type=$([ "$subscription_convert_insert_node_type" == 1 ] && echo -n "true" || echo -n "false")"
url="$url&expand=$([ "$subscription_convert_expand" == 1 ] && echo -n "true" || echo -n "false")"
fi
curl -s --connect-timeout 15 --retry 3 -o "$RUN_PROFILE_PATH" -L -H "User-Agent: $subscription_user_agent" "$subscription_url"
if [ "$?" != 0 ]; then
log "Subscription download failed."
log "Exiting..."
return
fi
curl -s -o "$RUN_PROFILE_PATH" -L -H "User-Agent: $subscription_user_agent" "$url"
log "Use Subscription: $subscription_name"
elif [[ "$profile" == "http:"* || "$profile" == "https:"* ]]; then
local url; url=$profile
curl -s -o "$RUN_PROFILE_PATH" -L -H "User-Agent: mihomo clash.meta clash" "$url"
log "Use Url: $url"
else
return
fi
# mixin
if [ "$mixin" == 0 ]; then
@ -171,35 +144,33 @@ start_service() {
log_level="$log_level" ipv6="$ipv6" \
ui_path="ui" ui_name="$ui_name" ui_url="$ui_url" api_listen="0.0.0.0:$api_port" api_secret="$api_secret" \
http_port="$http_port" socks_port="$socks_port" mixed_port="$mixed_port" redir_port="$redir_port" tproxy_port="$tproxy_port" \
tun_stack="$tun_stack" tun_device="$TUN_DEVICE" tun_mtu="$tun_mtu" tun_gso="$tun_gso" tun_gso_max_size="$tun_gso_max_size" tun_endpoint_independent_nat="$tun_endpoint_independent_nat" \
tun_enable="$tun_enable" tun_stack="$tun_stack" tun_device="$TUN_DEVICE" tun_mtu="$tun_mtu" tun_gso="$tun_gso" tun_gso_max_size="$tun_gso_max_size" tun_endpoint_independent_nat="$tun_endpoint_independent_nat" \
dns_enable="true" dns_listen="0.0.0.0:$dns_port" \
yq -M -i '
.log-level = env(log_level) | .ipv6 = env(ipv6) == 1 |
.external-ui = env(ui_path) | .external-ui-name = env(ui_name) | .external-ui-url = env(ui_url) | .external-controller = env(api_listen) | .secret = env(api_secret) |
.port = env(http_port) | .socks-port = env(socks_port) | .mixed-port = env(mixed_port) | .redir-port = env(redir_port) | .tproxy-port = env(tproxy_port) |
.tun.stack = env(tun_stack) | .tun.device = env(tun_device) | .tun.mtu = env(tun_mtu) | .tun.gso = env(tun_gso) == 1 | .tun.gso-max-size = env(tun_gso_max_size) | .tun.endpoint-independent-nat = env(tun_endpoint_independent_nat) == 1 |
.tun.enable = env(tun_enable) == 1 | .tun.stack = env(tun_stack) | .tun.device = env(tun_device) | .tun.mtu = env(tun_mtu) | .tun.gso = env(tun_gso) == 1 | .tun.gso-max-size = env(tun_gso_max_size) | .tun.endpoint-independent-nat = env(tun_endpoint_independent_nat) == 1 |
.dns.enable = env(dns_enable) | .dns.listen = env(dns_listen)
' "$RUN_PROFILE_PATH"
else
log "Mixin is enabled, mixin all config."
# do mixin
log_level="$log_level" mode="$mode" match_process="$match_process" unify_delay="$unify_delay" tcp_concurrent="$tcp_concurrent" tcp_keep_alive_interval="$tcp_keep_alive_interval" ipv6="$ipv6" \
log_level="$log_level" mode="$mode" match_process="$match_process" tcp_keep_alive_idle="$tcp_keep_alive_idle" tcp_keep_alive_interval="$tcp_keep_alive_interval" ipv6="$ipv6" \
ui_path="ui" ui_name="$ui_name" ui_url="$ui_url" api_listen="0.0.0.0:$api_port" api_secret="$api_secret" selection_cache="$selection_cache" \
allow_lan="$allow_lan" http_port="$http_port" socks_port="$socks_port" mixed_port="$mixed_port" redir_port="$redir_port" tproxy_port="$tproxy_port" \
tun_stack="$tun_stack" tun_device="$TUN_DEVICE" tun_mtu="$tun_mtu" tun_gso="$tun_gso" tun_gso_max_size="$tun_gso_max_size" tun_endpoint_independent_nat="$tun_endpoint_independent_nat" \
tun_enable="$tun_enable" tun_stack="$tun_stack" tun_device="$TUN_DEVICE" tun_mtu="$tun_mtu" tun_gso="$tun_gso" tun_gso_max_size="$tun_gso_max_size" tun_endpoint_independent_nat="$tun_endpoint_independent_nat" \
dns_enable="true" dns_listen="0.0.0.0:$dns_port" dns_mode="$dns_mode" fake_ip_range="$fake_ip_range" fake_ip_cache="$fake_ip_cache" \
dns_ipv6="$dns_ipv6" dns_system_hosts="$dns_system_hosts" dns_hosts="$dns_hosts" \
sniffer="$sniffer" sniff_dns_mapping="$sniff_dns_mapping" sniff_pure_ip="$sniff_pure_ip" sniffer_overwrite_dest="$sniffer_overwrite_dest" \
dns_respect_rules="$dns_respect_rules" dns_ipv6="$dns_ipv6" dns_system_hosts="$dns_system_hosts" dns_hosts="$dns_hosts" \
geoip_format="$geoip_format" geodata_loader="$geodata_loader" geosite_url="$geosite_url" geoip_mmdb_url="$geoip_mmdb_url" geoip_dat_url="$geoip_dat_url" geoip_asn_url="$geoip_asn_url" \
geox_auto_update="$geox_auto_update" geox_update_interval="$geox_update_interval" \
yq -M -i '
.log-level = env(log_level) | .mode = env(mode) | .find-process-mode = env(match_process) | .unified-delay = env(unify_delay) == 1 | .tcp-concurrent = env(tcp_concurrent) == 1 | .keep-alive-interval = env(tcp_keep_alive_interval) | .ipv6 = env(ipv6) == 1 |
.log-level = env(log_level) | .mode = env(mode) | .find-process-mode = env(match_process) | .keep-alive-idle = env(tcp_keep_alive_idle) | .keep-alive-interval = env(tcp_keep_alive_interval) | .ipv6 = env(ipv6) == 1 |
.external-ui = env(ui_path) | .external-ui-name = env(ui_name) | .external-ui-url = env(ui_url) | .external-controller = env(api_listen) | .secret = env(api_secret) | .profile.store-selected = env(selection_cache) == 1 |
.allow-lan = env(allow_lan) == 1 | .port = env(http_port) | .socks-port = env(socks_port) | .mixed-port = env(mixed_port) | .redir-port = env(redir_port) | .tproxy-port = env(tproxy_port) |
.tun.stack = env(tun_stack) | .tun.device = env(tun_device) | .tun.mtu = env(tun_mtu) | .tun.gso = env(tun_gso) == 1 | .tun.gso-max-size = env(tun_gso_max_size) | .tun.endpoint-independent-nat = env(tun_endpoint_independent_nat) == 1 |
.tun.enable = env(tun_enable) == 1 | .tun.stack = env(tun_stack) | .tun.device = env(tun_device) | .tun.mtu = env(tun_mtu) | .tun.gso = env(tun_gso) == 1 | .tun.gso-max-size = env(tun_gso_max_size) | .tun.endpoint-independent-nat = env(tun_endpoint_independent_nat) == 1 |
.dns.enable = env(dns_enable) | .dns.listen = env(dns_listen) | .dns.enhanced-mode = env(dns_mode) | .dns.fake-ip-range = env(fake_ip_range) | .profile.store-fake-ip = env(fake_ip_cache) == 1 |
.dns.ipv6 = env(dns_ipv6) == 1 | .dns.use-system-hosts = env(dns_system_hosts) == 1 | .dns.use-hosts = env(dns_hosts) == 1 |
.sniffer.enable = env(sniffer) == 1 | .sniffer.force-dns-mapping = env(sniff_dns_mapping) == 1 | .sniffer.parse-pure-ip = env(sniff_pure_ip) == 1 | .sniffer.override-destination = env(sniffer_overwrite_dest) == 1 |
.dns.respect-rules = env(dns_respect_rules) == 1 | .dns.ipv6 = env(dns_ipv6) == 1 | .dns.use-system-hosts = env(dns_system_hosts) == 1 | .dns.use-hosts = env(dns_hosts) == 1 |
.geodata-mode = env(geoip_format) == "dat" | .geodata-loader = env(geodata_loader) | .geox-url.geosite = env(geosite_url) | .geox-url.mmdb = env(geoip_mmdb_url) | .geox-url.geoip = env(geoip_dat_url) | .geox-url.asn = env(geoip_asn_url) |
.geo-auto-update = env(geox_auto_update) == 1 | .geo-update-interval = env(geox_update_interval)
' "$RUN_PROFILE_PATH"
@ -209,7 +180,8 @@ start_service() {
config_foreach mixin_authentications "authentication"
fi
if [ "$fake_ip_filter" == 1 ]; then
yq -M -i 'del(.dns.fake-ip-filter)' "$RUN_PROFILE_PATH"
fake_ip_filter_mode="$fake_ip_filter_mode" \
yq -M -i 'del(.dns.fake-ip-filter) | .dns.fake-ip-filter-mode = env(fake_ip_filter_mode)' "$RUN_PROFILE_PATH"
config_list_foreach "mixin" "fake_ip_filters" mixin_fake_ip_filters
fi
if [ "$hosts" == 1 ]; then
@ -220,29 +192,17 @@ start_service() {
yq -M -i 'del(.dns.default-nameserver) | del(.dns.proxy-server-nameserver) | del(.dns.nameserver) | del(.dns.fallback)' "$RUN_PROFILE_PATH"
config_foreach mixin_nameservers "nameserver"
fi
if [ "$dns_fallback_filter" == 1 ]; then
yq -M -i '.dns.fallback-filter.geoip = true | del(.dns.fallback-filter.geoip-code) | del(.dns.fallback-filter.geosite) | del(.dns.fallback-filter.ipcidr) | del(.dns.fallback-filter.domain)' "$RUN_PROFILE_PATH"
config_foreach mixin_fallback_filters "fallback_filter"
fi
if [ "$dns_nameserver_policy" == 1 ]; then
yq -M -i 'del(.dns.nameserver-policy)' "$RUN_PROFILE_PATH"
config_foreach mixin_nameserver_policies "nameserver_policy"
fi
if [ "$sniffer" == 1 ]; then
yq -M -i 'del(.sniffer.force-domain) | del(.sniffer.skip-domain) | del(.sniffer.sniff)' "$RUN_PROFILE_PATH"
config_list_foreach "mixin" "sniffer_force_domain_name" mixin_sniffer_domain_name "force-domain"
config_list_foreach "mixin" "sniffer_ignore_domain_name" mixin_sniffer_domain_name "skip-domain"
config_foreach mixin_sniffs "sniff"
fi
# mixin file
if [ -s "$MIXIN_FILE_PATH" ]; then
yq ea -M -i '. as $item ireduce ({}; . * $item ) | ... comments=""' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH"
fi
fi
if [ "$transparent_proxy_mode" == "tproxy" ]; then
yq -M -i '.tun.enable = false' "$RUN_PROFILE_PATH"
elif [ "$transparent_proxy_mode" == "tun" ]; then
yq -M -i '.tun.enable = true | .tun.auto-route = false | .tun.auto-redirect = false | .tun.auto-detect-interface = false' "$RUN_PROFILE_PATH"
if [ "$tun_enable" == 1 ]; then
yq -M -i '.tun.auto-route = false | .tun.auto-redirect = false | .tun.auto-detect-interface = false | .tun.dns-hijack = []' "$RUN_PROFILE_PATH"
fi
if [ -n "$outbound_interface" ]; then
local outbound_device
@ -275,9 +235,11 @@ start_service() {
procd_set_param user "$MIHOMO_USER"
procd_set_param group "$MIHOMO_GROUP"
procd_add_jail_mount "$PROG" /etc/TZ /etc/localtime /etc/hosts /etc/ssl/certs /proc
procd_add_jail mihomo requirejail procfs
procd_add_jail_mount "$PROG" /etc/TZ /etc/localtime /etc/hosts /etc/ssl/certs
procd_add_jail_mount_rw "$RUN_DIR" /dev/net
procd_set_param capabilities /etc/capabilities/mihomo.json
procd_set_param no_new_privs 1
procd_close_instance
# transparent proxy
@ -285,33 +247,47 @@ start_service() {
log "Transparent Proxy is enabled."
log "Transparent Proxy: Start hijack."
# prepare
if [ "$transparent_proxy_mode" == "tproxy" ]; then
log "Transparent Proxy: Using TPROXY mode."
if [ "$ipv4_proxy" == 1 ]; then
ip route add local default dev lo table "$ROUTE_TABLE"
ip rule add pref "$RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" table "$ROUTE_TABLE"
fi
if [ "$ipv6_proxy" == 1 ]; then
ip -6 route add local default dev lo table "$ROUTE_TABLE"
ip -6 rule add pref "$RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" table "$ROUTE_TABLE"
fi
elif [ "$transparent_proxy_mode" == "tun" ]; then
log "Transparent Proxy: Using TUN mode."
if [ "$tproxy_enable" == 1 ]; then
ip route add local default dev lo table "$TPROXY_ROUTE_TABLE"
fi
if [ "$tun_enable" == 1 ]; then
ip tuntap add dev "$TUN_DEVICE" mode tun vnet_hdr
ip link set "$TUN_DEVICE" up
ip route add unicast default dev $TUN_DEVICE table "$TUN_ROUTE_TABLE"
$TUN_SH
fi
local tcp_route_table
if [ "$tcp_transparent_proxy_mode" == "tproxy" ]; then
tcp_route_table="$TPROXY_ROUTE_TABLE"
elif [ "$tcp_transparent_proxy_mode" == "tun" ]; then
tcp_route_table="$TUN_ROUTE_TABLE"
fi
if [ -n "$tcp_route_table" ]; then
if [ "$ipv4_proxy" == 1 ]; then
ip route add unicast default dev "$TUN_DEVICE" table "$ROUTE_TABLE"
ip rule add pref "$RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" table "$ROUTE_TABLE"
ip rule add pref "$TCP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto tcp table "$tcp_route_table"
fi
if [ "$ipv6_proxy" == 1 ]; then
ip -6 route add unicast default dev "$TUN_DEVICE" table "$ROUTE_TABLE"
ip -6 rule add pref "$RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" table "$ROUTE_TABLE"
ip -6 rule add pref "$TCP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto tcp table "$tcp_route_table"
fi
fi
nft -f "$HIJACK_NFT" -D FW_MARK="$FW_MARK" -D FW_MARK_MASK="$FW_MARK_MASK" -D TUN_DEVICE="$TUN_DEVICE" -D MIHOMO_USER="$MIHOMO_USER" -D TPROXY_PORT="$tproxy_port" -D DNS_PORT="$dns_port"
local udp_route_table
if [ "$udp_transparent_proxy_mode" == "tproxy" ]; then
udp_route_table="$TPROXY_ROUTE_TABLE"
elif [ "$udp_transparent_proxy_mode" == "tun" ]; then
udp_route_table="$TUN_ROUTE_TABLE"
fi
if [ -n "$udp_route_table" ]; then
if [ "$ipv4_proxy" == 1 ]; then
ip rule add pref "$UDP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto udp table "$udp_route_table"
fi
if [ "$ipv6_proxy" == 1 ]; then
ip -6 rule add pref "$UDP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto udp table "$udp_route_table"
fi
fi
nft -f "$HIJACK_NFT" -D FW_MARK="$FW_MARK" -D FW_MARK_MASK="$FW_MARK_MASK" -D MIHOMO_USER="$MIHOMO_USER" -D TUN_DEVICE="$TUN_DEVICE" -D DNS_PORT="$dns_port" -D REDIR_PORT="$redir_port" -D TPROXY_PORT="$tproxy_port"
nft -f "$RESERVED_IP_NFT"
nft -f "$RESERVED_IP6_NFT"
nft add element inet "$FW_TABLE" fake_ip \{ "$fake_ip_range" \}
# dns hijack
if [ "$ipv4_dns_hijack" == 1 ]; then
log "Transparent Proxy: IPv4 DNS Hijack is enabled, IPv4 dns request will redirect to the core."
@ -343,7 +319,6 @@ start_service() {
# destination port to proxy
log "Transparent Proxy: Destination TCP Port to Proxy: $acl_tcp_dport."
log "Transparent Proxy: Destination UDP Port to Proxy: $acl_udp_dport."
nft add element inet "$FW_TABLE" fake_ip \{ "$fake_ip_range" \}
local acl_dport
for acl_dport in $acl_tcp_dport; do
nft add element inet "$FW_TABLE" acl_dport \{ "tcp" . "$acl_dport" \}
@ -354,8 +329,13 @@ start_service() {
# router proxy
if [ "$router_proxy" == 1 ]; then
log "Transparent Proxy: Router Proxy is enabled, set proxy for router."
nft add rule inet "$FW_TABLE" nat_output jump router_dns_hijack
nft add rule inet "$FW_TABLE" mangle_output jump router_reroute
nft insert rule inet "$FW_TABLE" nat_output jump router_dns_hijack
if [ "$tcp_transparent_proxy_mode" == "redirect" ]; then
nft add rule inet "$FW_TABLE" nat_output meta l4proto tcp jump router_redirect
else
nft add rule inet "$FW_TABLE" mangle_output meta l4proto tcp jump router_reroute
fi
nft add rule inet "$FW_TABLE" mangle_output meta l4proto udp jump router_reroute
fi
# lan proxy
if [ "$lan_proxy" == 1 ]; then
@ -371,8 +351,13 @@ start_service() {
config_list_foreach "proxy" "acl_ip" add_acl_ip
config_list_foreach "proxy" "acl_ip6" add_acl_ip6
config_list_foreach "proxy" "acl_mac" add_acl_mac
nft add rule inet "$FW_TABLE" dstnat jump "${access_control_mode}_dns_hijack"
nft add rule inet "$FW_TABLE" mangle_prerouting jump "${access_control_mode}_${transparent_proxy_mode}"
nft insert rule inet "$FW_TABLE" dstnat jump "${access_control_mode}_dns_hijack"
if [ "$tcp_transparent_proxy_mode" == "redirect" ]; then
nft add rule inet "$FW_TABLE" dstnat meta l4proto tcp jump "${access_control_mode}_redirect"
else
nft add rule inet "$FW_TABLE" mangle_prerouting meta l4proto tcp jump "${access_control_mode}_${tcp_transparent_proxy_mode}"
fi
nft add rule inet "$FW_TABLE" mangle_prerouting meta l4proto udp jump "${access_control_mode}_${udp_transparent_proxy_mode}"
fi
fi
# cron
@ -398,12 +383,24 @@ service_triggers() {
}
cleanup() {
# delete hijack
ip rule del table "$ROUTE_TABLE" > /dev/null 2>&1
ip route flush table "$ROUTE_TABLE" > /dev/null 2>&1
ip -6 rule del table "$ROUTE_TABLE" > /dev/null 2>&1
ip -6 route flush table "$ROUTE_TABLE" > /dev/null 2>&1
# delete routing policy
ip rule del ipproto tcp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip rule del ipproto udp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip rule del ipproto tcp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
ip rule del ipproto udp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
ip -6 rule del ipproto tcp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -6 rule del ipproto udp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -6 rule del ipproto tcp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
ip -6 rule del ipproto udp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
# delete routing table
ip route flush table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
ip -6 route flush table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -6 route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
# delete tun
ip link set "$TUN_DEVICE" down
ip tuntap del dev "$TUN_DEVICE" mode tun > /dev/null 2>&1
# delete hijack
nft delete table inet "$FW_TABLE" > /dev/null 2>&1
local handles handle
handles=$(nft --json list table inet fw4 | yq '.nftables[] | select(has("rule")) | .rule | select(.family == "inet" and .table == "fw4" and .chain == "input" and .expr[0].match.right == "tun") | .handle')
@ -483,24 +480,6 @@ mixin_nameserver() {
nameserver="$1" type="$2" yq -M -i '.dns.[env(type)] += [env(nameserver)]' "$RUN_PROFILE_PATH"
}
mixin_fallback_filters() {
local section="$1"
local enabled
config_get_bool enabled "$section" "enabled" 0
config_get type "$section" "type"
if [ "$enabled" == 0 ]; then
return
fi
config_list_foreach "$section" "value" mixin_fallback_filter "$type"
}
mixin_fallback_filter() {
value="$1" type="$2" yq -M -i '.dns.fallback-filter.[env(type)] += [env(value)]' "$RUN_PROFILE_PATH"
}
mixin_nameserver_policies() {
local section="$1"
@ -519,30 +498,6 @@ mixin_nameserver_policy() {
nameserver="$1" matcher="$2" yq -M -i '.dns.nameserver-policy.[env(matcher)] += [env(nameserver)]' "$RUN_PROFILE_PATH"
}
mixin_sniffer_domain_name() {
domain_name="$1" type="$2" yq -M -i '.sniffer.[env(type)] += [env(domain_name)]' "$RUN_PROFILE_PATH"
}
mixin_sniffs() {
local section="$1"
local enabled protocol overwrite_dest
config_get_bool enabled "$section" "enabled" 0
config_get protocol "$section" "protocol"
config_get_bool overwrite_dest "$section" "overwrite_dest" 0
if [ "$enabled" == 0 ]; then
return
fi
protocol="$protocol" overwrite_dest="$overwrite_dest" yq -M -i '.sniffer.sniff.[env(protocol)].override-destination = env(overwrite_dest) == 1' "$RUN_PROFILE_PATH"
config_list_foreach "$section" "port" mixin_sniff "$protocol"
}
mixin_sniff() {
port="$1" protocol="$2" yq -M -i '.sniffer.sniff.[env(protocol)].ports += [env(port)]' "$RUN_PROFILE_PATH"
}
add_acl_ip() {
nft add element inet "$FW_TABLE" acl_ip \{ "$1" \}
}

View File

@ -83,6 +83,23 @@ table inet mihomo {
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter redirect to :$DNS_PORT
}
chain all_redirect {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } counter redirect to :$REDIR_PORT
}
chain allow_redirect {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip saddr @acl_ip counter redirect to :$REDIR_PORT
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip6 saddr @acl_ip6 counter redirect to :$REDIR_PORT
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ether saddr @acl_mac counter redirect to :$REDIR_PORT
}
chain block_redirect {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip saddr @acl_ip counter return
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip6 saddr @acl_ip6 counter return
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ether saddr @acl_mac counter return
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } counter redirect to :$REDIR_PORT
}
chain all_tproxy {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK tproxy to :$TPROXY_PORT counter accept
}
@ -117,16 +134,37 @@ table inet mihomo {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK counter
}
chain router_redirect {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } counter redirect to :$REDIR_PORT
}
chain router_reroute {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK counter accept
}
chain dstnat {
type nat hook prerouting priority dstnat + 1; policy accept;
fib daddr type local counter return
ct direction reply counter return
ip daddr @reserved_ip counter return
ip6 daddr @reserved_ip6 counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta l4proto . th dport != @acl_dport ip daddr != @fake_ip counter return
meta nfproto ipv6 meta l4proto . th dport != @acl_dport counter return
}
chain nat_output {
type nat hook output priority filter; policy accept;
meta skuid $MIHOMO_USER counter return
fib daddr type local counter return
ct direction reply counter return
ip daddr @reserved_ip counter return
ip6 daddr @reserved_ip6 counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta l4proto . th dport != @acl_dport ip daddr != @fake_ip counter return
meta nfproto ipv6 meta l4proto . th dport != @acl_dport counter return
}
chain mangle_prerouting {

View File

@ -1,15 +1,17 @@
#!/bin/sh
# permission
MIHOMO_USER="root"
MIHOMO_USER="mihomo"
MIHOMO_GROUP="mihomo"
# routing
FW_TABLE="mihomo"
FW_MARK="0x80"
FW_MARK_MASK="0xFF"
RULE_PREF="1024"
ROUTE_TABLE="80"
TCP_RULE_PREF="1024"
UDP_RULE_PREF="1025"
TPROXY_ROUTE_TABLE="80"
TUN_ROUTE_TABLE="81"
TUN_DEVICE="tun"
# paths

View File

@ -3,22 +3,15 @@
. "$IPKG_INSTROOT/lib/functions.sh"
. "$IPKG_INSTROOT/etc/mihomo/scripts/constants.sh"
load_config() {
config_load mihomo
config_get enabled "config" "enabled" 0
config_get transparent_proxy_mode "proxy" "transparent_proxy_mode"
}
config_load mihomo
config_get enabled "config" "enabled" 0
config_get tcp_transparent_proxy_mode "proxy" "tcp_transparent_proxy_mode"
config_get udp_transparent_proxy_mode "proxy" "udp_transparent_proxy_mode"
accept_tun() {
if [ "$enabled" == 1 ] && [[ "$tcp_transparent_proxy_mode" == "tun" || "$udp_transparent_proxy_mode" == "tun" ]]; then
nft insert rule inet fw4 input iifname "$TUN_DEVICE" counter accept
nft insert rule inet fw4 forward oifname "$TUN_DEVICE" counter accept
nft insert rule inet fw4 forward iifname "$TUN_DEVICE" counter accept
}
load_config
if [[ "$enabled" == 0 || "$transparent_proxy_mode" != "tun" ]]; then
return
fi
accept_tun
exit 0

View File

@ -2,135 +2,8 @@
. "$IPKG_INSTROOT/etc/mihomo/scripts/constants.sh"
# delete mihomo.proxy.routing_mark
routing_mark=$(uci -q get mihomo.proxy.routing_mark); [ -n "$routing_mark" ] && uci del mihomo.proxy.routing_mark
# since 1.8.0
# add mihomo.config.mixin
mixin=$(uci -q get mihomo.config.mixin); [ -z "$mixin" ] && uci set mihomo.config.mixin=1
# add mihomo.proxy.dns_hijack
dns_hijack=$(uci -q get mihomo.proxy.dns_hijack); [ -z "$dns_hijack" ] && uci set mihomo.proxy.dns_hijack=1
# add mihomo.mixin.log_level
log_level=$(uci -q get mihomo.mixin.log_level); [ -z "$log_level" ] && uci set mihomo.mixin.log_level=info
# add mihomo.mixin.authentication
authentication=$(uci -q get mihomo.mixin.authentication); [ -z "$authentication" ] && {
uci set mihomo.mixin.authentication=1
uci add mihomo.authentication
uci set mihomo.@authentication[-1].enabled=1
uci set mihomo.@authentication[-1].username=mihomo
uci set mihomo.@authentication[-1].password=$(awk 'BEGIN{srand(); print int(rand() * 1000000)}')
}
# add mihomo.status
status=$(uci -q get mihomo.status); [ -z "$status" ] && uci set mihomo.status=status
# add mihomo.editor
editor=$(uci -q get mihomo.editor); [ -z "$editor" ] && uci set mihomo.editor=editor
# add mihomo.log
log=$(uci -q get mihomo.log); [ -z "$log" ] && uci set mihomo.log=log
# add mihomo.proxy.bypass_china_mainland_ip
bypass_china_mainland_ip=$(uci -q get mihomo.proxy.bypass_china_mainland_ip); [ -z "$bypass_china_mainland_ip" ] && uci set mihomo.proxy.bypass_china_mainland_ip=0
# add mihomo.proxy.acl_tcp_dport
acl_tcp_dport=$(uci -q get mihomo.proxy.acl_tcp_dport); [ -z "$acl_tcp_dport" ] && uci set mihomo.proxy.acl_tcp_dport="1-65535"
# add mihomo.proxy.acl_udp_dport
acl_udp_dport=$(uci -q get mihomo.proxy.acl_udp_dport); [ -z "$acl_udp_dport" ] && uci set mihomo.proxy.acl_udp_dport="1-65535"
# add mihomo.proxy.ipv4_proxy
ipv4_proxy=$(uci -q get mihomo.proxy.ipv4_proxy); [ -z "$ipv4_proxy" ] && uci set mihomo.proxy.ipv4_proxy=1
# add mihomo.proxy.ipv6_proxy
ipv6_proxy=$(uci -q get mihomo.proxy.ipv6_proxy); [ -z "$ipv6_proxy" ] && uci set mihomo.proxy.ipv6_proxy=0
# set mihomo.proxy.access_control_mode
access_control_mode=$(uci -q get mihomo.proxy.access_control_mode); [ -z "$access_control_mode" ] && uci set mihomo.proxy.access_control_mode="all"
# add mihomo.proxy.transparent_proxy_mode
transparent_proxy_mode=$(uci -q get mihomo.proxy.transparent_proxy_mode); [ -z "$transparent_proxy_mode" ] && uci set mihomo.proxy.transparent_proxy_mode="tproxy"
# add mihomo.mixin.tun_stack
tun_stack=$(uci -q get mihomo.mixin.tun_stack); [ -z "$tun_stack" ] && uci set mihomo.mixin.tun_stack="system"
# add mihomo.mixin.tun_mtu
tun_mtu=$(uci -q get mihomo.mixin.tun_mtu); [ -z "$tun_mtu" ] && uci set mihomo.mixin.tun_mtu="9000"
# add mihomo.mixin.tun_gso
tun_gso=$(uci -q get mihomo.mixin.tun_gso); [ -z "$tun_gso" ] && uci set mihomo.mixin.tun_gso=1
# add mihomo.mixin.tun_gso_max_size
tun_gso_max_size=$(uci -q get mihomo.mixin.tun_gso_max_size); [ -z "$tun_gso_max_size" ] && uci set mihomo.mixin.tun_gso_max_size="65536"
# add mihomo.mixin.tun_endpoint_independent_nat
tun_endpoint_independent_nat=$(uci -q get mihomo.mixin.tun_endpoint_independent_nat); [ -z "$tun_endpoint_independent_nat" ] && uci set mihomo.mixin.tun_endpoint_independent_nat=0
# add mihomo.config.test_profile
test_profile=$(uci -q get mihomo.config.test_profile); [ -z "$test_profile" ] && uci set mihomo.config.test_profile=1
# add mihomo.mixin.dns_ipv6
dns_ipv6=$(uci -q get mihomo.mixin.dns_ipv6); [ -z "$dns_ipv6" ] && uci set mihomo.mixin.dns_ipv6=0
# add mihomo.mixin.hosts
hosts=$(uci -q get mihomo.mixin.hosts); [ -z "$hosts" ] && uci set mihomo.mixin.hosts=$(uci -q get mihomo.mixin.dns_hosts)
# add mihomo.mixin.geoip_asn_url
geoip_asn_url=$(uci -q get mihomo.mixin.geoip_asn_url); [ -z "$geoip_asn_url" ] && uci set mihomo.mixin.geoip_asn_url="https://mirror.ghproxy.com/https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb"
# add mihomo.proxy.ipv4_dns_hijack
ipv4_dns_hijack=$(uci -q get mihomo.proxy.ipv4_dns_hijack); [ -z "$ipv4_dns_hijack" ] && uci set mihomo.proxy.ipv4_dns_hijack=$(uci -q get mihomo.proxy.dns_hijack)
# add mihomo.proxy.ipv6_dns_hijack
ipv6_dns_hijack=$(uci -q get mihomo.proxy.ipv6_dns_hijack); [ -z "$ipv6_dns_hijack" ] && uci set mihomo.proxy.ipv6_dns_hijack=$(uci -q get mihomo.proxy.dns_hijack)
# delete mihomo.proxy.dns_hijack
dns_hijack=$(uci -q get mihomo.proxy.dns_hijack); [ -n "$dns_hijack" ] && uci del mihomo.proxy.dns_hijack
# get mihomo.proxy.access_control_mode
access_control_mode=$(uci -q get mihomo.proxy.access_control_mode)
# add mihomo.proxy.lan_proxy
lan_proxy=$(uci -q get mihomo.proxy.lan_proxy); [ -z "$lan_proxy" ] && {
if [ "$access_control_mode" == "forbid" ]; then
uci set mihomo.proxy.lan_proxy=0
uci set mihomo.proxy.access_control_mode="all"
else
uci set mihomo.proxy.lan_proxy=1
fi
}
# add mihomo.mixin.ui_name
ui_name=$(uci -q get mihomo.mixin.ui_name); [ -z "$ui_name" ] && uci set mihomo.mixin.ui_name="metacubexd"
# add mihomo.mixin.ui_url
ui_url=$(uci -q get mihomo.mixin.ui_url); [ -z "$ui_url" ] && uci set mihomo.mixin.ui_url="https://mirror.ghproxy.com/https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip"
# delete mihomo.mixin.ui_razord
ui_razord=$(uci -q get mihomo.mixin.ui_razord); [ -n "$ui_razord" ] && uci delete mihomo.mixin.ui_razord
# delete mihomo.mixin.ui_razord_url
ui_razord_url=$(uci -q get mihomo.mixin.ui_razord_url); [ -n "$ui_razord_url" ] && uci delete mihomo.mixin.ui_razord_url
# delete mihomo.mixin.ui_yacd
ui_yacd=$(uci -q get mihomo.mixin.ui_yacd); [ -n "$ui_yacd" ] && uci delete mihomo.mixin.ui_yacd
# delete mihomo.mixin.ui_yacd_url
ui_yacd_url=$(uci -q get mihomo.mixin.ui_yacd_url); [ -n "$ui_yacd_url" ] && uci delete mihomo.mixin.ui_yacd_url
# delete mihomo.mixin.ui_metacubexd
ui_metacubexd=$(uci -q get mihomo.mixin.ui_metacubexd); [ -n "$ui_metacubexd" ] && uci delete mihomo.mixin.ui_metacubexd
# delete mihomo.mixin.ui_metacubexd_url
ui_metacubexd_url=$(uci -q get mihomo.mixin.ui_metacubexd_url); [ -n "$ui_metacubexd_url" ] && uci delete mihomo.mixin.ui_metacubexd_url
# add mihomo.config.fast_reload
fast_reload=$(uci -q get mihomo.config.fast_reload); [ -z "$fast_reload" ] && uci set mihomo.config.fast_reload=1
# add mihomo.mixin.ipv6
ipv6=$(uci -q get mihomo.mixin.ipv6); [ -z "$ipv6" ] && uci set mihomo.mixin.ipv6=$(uci -q get mihomo.proxy.ipv6_proxy)
# commit
uci commit mihomo