small-package/luci-app-fchomo/root/etc/fchomo/scripts/generate_client.uc

731 lines
24 KiB
Plaintext
Raw Normal View History

2024-10-26 10:27:23 +08:00
#!/usr/bin/ucode
'use strict';
import { readfile, writefile } from 'fs';
import { connect } from 'ubus';
import { cursor } from 'uci';
import { urldecode, urlencode } from 'luci.http';
import {
2024-11-03 20:36:08 +08:00
isEmpty, strToBool, strToInt, durationToSecond,
2024-11-16 20:36:29 +08:00
arrToObj, removeBlankAttrs,
2024-10-26 10:27:23 +08:00
HM_DIR, RUN_DIR, PRESET_OUTBOUND
} from 'fchomo';
const ubus = connect();
/* UCI config START */
const uci = cursor();
const uciconf = 'fchomo';
uci.load(uciconf);
const ucifchm = 'config',
ucires = 'resources',
uciroute = 'routing';
const uciglobal = 'global',
uciinbound = 'inbound',
ucitls = 'tls',
uciapi = 'api',
ucisniffer = 'sniffer',
ucidns = 'dns',
uciexpr = 'experimental';
const ucisniff = 'sniff',
ucidnser = 'dns_server',
ucidnspoli = 'dns_policy',
ucipgrp = 'proxy_group',
2024-11-16 20:36:29 +08:00
ucinode = 'node',
2024-10-26 10:27:23 +08:00
uciprov = 'provider',
ucirule = 'ruleset',
2024-11-06 00:26:14 +08:00
ucirout = 'rules',
ucisubro = 'subrules';
2024-10-26 10:27:23 +08:00
/* 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',
common_udpport = uci.get(uciconf, ucifchm, 'common_udpport') || '20-21,22,53,80,110,143,443,853,993,995,8080,8443,9418',
stun_port = uci.get(uciconf, ucifchm, 'stun_port') || '3478,19302',
tun_name = uci.get(uciconf, ucifchm, 'tun_name') || 'hmtun0',
tun_addr4 = uci.get(uciconf, ucifchm, 'tun_addr4') || '198.19.0.1/30',
tun_addr6 = uci.get(uciconf, ucifchm, 'tun_addr6') || 'fdfe:dcba:9877::1/126',
route_table_id = strToInt(uci.get(uciconf, ucifchm, 'route_table_id')) || 2022, // global.js
route_rule_pref = strToInt(uci.get(uciconf, ucifchm, 'route_rule_pref')) || 9000, // global.js
redirect_gate_mark = strToInt(uci.get(uciconf, ucifchm, 'redirect_gate_mark')) || 2023,
redirect_pass_mark = strToInt(uci.get(uciconf, ucifchm, 'redirect_pass_mark')) || 2024,
self_mark = strToInt(uci.get(uciconf, ucifchm, 'self_mark')) || 200, // global.js
tproxy_mark = strToInt(uci.get(uciconf, ucifchm, 'tproxy_mark')) || 201, // global.js
tun_mark = strToInt(uci.get(uciconf, ucifchm, 'tun_mark')) || 202, // global.js
posh = 'c2luZ2JveA'; // Yes. Is true.
const listen_interfaces = uci.get(uciconf, uciroute, 'listen_interfaces') || null,
bind_interface = uci.get(uciconf, uciroute, 'bind_interface') || null,
lan_filter = uci.get(uciconf, uciroute, 'lan_filter') || null,
lan_direct_ipv4_ips = uci.get(uciconf, uciroute, 'lan_direct_ipv4_ips') || null,
lan_direct_ipv6_ips = uci.get(uciconf, uciroute, 'lan_direct_ipv6_ips') || null,
lan_direct_mac_addrs = uci.get(uciconf, uciroute, 'lan_direct_mac_addrs') || null,
lan_proxy_ipv4_ips = uci.get(uciconf, uciroute, 'lan_proxy_ipv4_ips') || null,
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,
2024-11-06 00:26:14 +08:00
client_enabled = uci.get(uciconf, uciroute, 'client_enabled') || '0',
2024-10-26 10:27:23 +08:00
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,
routing_domain = strToBool(uci.get(uciconf, uciroute, 'routing_domain')),
tposh = 'c2luZ2JveA';
/* WAN DNS server array */
let wan_dns = ubus.call('network.interface', 'status', {'interface': 'wan'})?.['dns-server'];
if (length(wan_dns) === 0)
wan_dns = ['223.5.5.5'];
/* All DNS server object */
const dnsservers = {};
uci.foreach(uciconf, ucidnser, (cfg) => {
if (cfg.enabled === '0')
return;
dnsservers[cfg['.name']] = {
label: cfg.label,
address: cfg.address
};
});
/* UCI config END */
/* Config helper START */
function parse_filter(cfg) {
if (isEmpty(cfg))
return null;
if (type(cfg) === 'array')
return join('|', cfg);
else
return cfg;
}
function get_proxynode(cfg) {
if (isEmpty(cfg))
return null;
const label = uci.get(uciconf, cfg, 'label');
if (isEmpty(label))
die(sprintf("%s's label is missing, please check your configuration.", cfg));
else
return label;
}
function get_proxygroup(cfg) {
if (isEmpty(cfg))
return null;
if (cfg in PRESET_OUTBOUND)
return cfg;
const label = uci.get(uciconf, cfg, 'label');
if (isEmpty(label))
die(sprintf("%s's label is missing, please check your configuration.", cfg));
else
return label;
}
function get_nameserver(cfg, detour) {
if (isEmpty(cfg))
return [];
if ('block-dns' in cfg)
//https://github.com/MetaCubeX/mihomo/blob/0128a0bb1fce17d39158c745a912d7b2b87cf975/config/config.go#L1131
return 'rcode://name_error';
let servers = [];
for (let k in cfg) {
if (k === 'system-dns') {
push(servers, 'system');
} else if (k === 'default-dns') {
map(wan_dns, (dns) => {
push(servers, dns + '#DIRECT');
});
} else
push(servers, replace(dnsservers[k]?.address || '', /#detour=([^&]+)/, (m, c1) => {
return '#' + urlencode(get_proxygroup(detour || c1));
}));
}
return servers;
}
2024-11-06 00:26:14 +08:00
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);
}
2024-10-26 10:27:23 +08:00
/* Config helper END */
/* Main */
const config = {};
/* General START */
/* General settings */
config["global-ua"] = 'clash.meta';
config.mode = uci.get(uciconf, uciglobal, 'mode') || 'rule';
config["find-process-mode"] = uci.get(uciconf, uciglobal, 'find_process_mode') || 'off';
config["log-level"] = uci.get(uciconf, uciglobal, 'log_level') || 'warning';
config["etag-support"] = (uci.get(uciconf, uciglobal, 'etag_support') === '0') ? false : true;
config.ipv6 = (uci.get(uciconf, uciglobal, 'ipv6') === '0') ? false : true;
config["unified-delay"] = strToBool(uci.get(uciconf, uciglobal, 'unified_delay')) || false;
config["tcp-concurrent"] = strToBool(uci.get(uciconf, uciglobal, 'tcp_concurrent')) || false;
2024-11-03 20:36:08 +08:00
config["keep-alive-interval"] = durationToSecond(uci.get(uciconf, uciglobal, 'keep_alive_interval')) || 30;
config["keep-alive-idle"] = durationToSecond(uci.get(uciconf, uciglobal, 'keep_alive_idle')) || 600;
2024-10-26 10:27:23 +08:00
/* ACL settings */
config["interface-name"] = bind_interface;
config["routing-mark"] = self_mark;
/* Global Authentication */
config.authentication = uci.get(uciconf, uciglobal, 'authentication');
config["skip-auth-prefixes"] = uci.get(uciconf, uciglobal, 'skip_auth_prefixes');
/* General END */
/* GEOX START */
/* GEOX settings */
config["geodata-mode"] = true;
config["geodata-loader"] = 'memconservative';
config["geo-auto-update"] = false;
/* GEOX END */
/* TLS START */
/* TLS settings */
config["global-client-fingerprint"] = uci.get(uciconf, ucitls, 'global_client_fingerprint');
config.tls = {
"certificate": uci.get(uciconf, ucitls, 'tls_cert_path'),
"private-key": uci.get(uciconf, ucitls, 'tls_key_path')
};
/* TLS END */
/* API START */
const api_port = uci.get(uciconf, uciapi, 'external_controller_port');
const api_tls_port = uci.get(uciconf, uciapi, 'external_controller_tls_port');
/* API settings */
config["external-controller-cors"] = {
"allow-origins": uci.get(uciconf, uciapi, 'external_controller_cors_allow_origins') || ['*'],
"allow-private-network" : (uci.get(uciconf, uciapi, 'external_controller_cors_allow_private_network') === '0') ? false : true
};
config["external-controller"] = api_port ? '[::]:' + api_port : null;
config["external-controller-tls"] = api_tls_port ? '[::]:' + api_tls_port : null;
config["external-doh-server"] = uci.get(uciconf, uciapi, 'external_doh_server');
config.secret = uci.get(uciconf, uciapi, 'secret') || trim(readfile('/proc/sys/kernel/random/uuid'));
config["external-ui"] = RUN_DIR + '/ui';
/* API END */
/* Cache START */
/* Cache settings */
config.profile = {
"store-selected": true,
"store-fake-ip": false
};
/* Cache END */
/* Experimental START */
/* Experimental settings */
config.experimental = {
"quic-go-disable-gso": strToBool(uci.get(uciconf, uciexpr, 'quic_go_disable_gso')),
"quic-go-disable-ecn": strToBool(uci.get(uciconf, uciexpr, 'quic_go_disable_ecn')),
"dialer-ip4p-convert": strToBool(uci.get(uciconf, uciexpr, 'dialer_ip4p_convert'))
};
/* Experimental END */
/* Sniffer START */
/* Sniffer settings */
config.sniffer = {
enable: true,
"force-dns-mapping": true,
"parse-pure-ip": true,
"override-destination": (uci.get(uciconf, ucisniffer, 'override_destination') === '0') ? false : true,
sniff: {},
"force-domain": uci.get(uciconf, ucisniffer, 'force_domain'),
"skip-domain": uci.get(uciconf, ucisniffer, 'skip_domain'),
"skip-src-address": uci.get(uciconf, ucisniffer, 'skip_src_address'),
"skip-dst-address": uci.get(uciconf, ucisniffer, 'skip_dst_address')
};
/* Sniff protocol settings */
uci.foreach(uciconf, ucisniff, (cfg) => {
if (cfg.enabled === '0')
return null;
config.sniffer.sniff[cfg.protocol] = {
ports: map(cfg.ports, (ports) => {
return strToInt(ports); // DEBUG ERROR data type *utils.IntRanges[uint16]
}),
"override-destination": (cfg.override_destination === '0') ? false : true
};
});
/* Sniffer END */
/* Inbound START */
const proxy_mode = uci.get(uciconf, uciinbound, 'proxy_mode') || 'redir_tproxy';
/* Listen ports */
config.listeners = [];
push(config.listeners, {
name: 'mixed-in',
type: 'mixed',
port: strToInt(uci.get(uciconf, uciinbound, 'mixed_port')) || '7890',
listen: '::',
udp: true
});
if (match(proxy_mode, /redir/))
push(config.listeners, {
name: 'redir-in',
type: 'redir',
port: strToInt(uci.get(uciconf, uciinbound, 'redir_port')) || '7891',
listen: '::'
});
if (match(proxy_mode, /tproxy/))
push(config.listeners, {
name: 'tproxy-in',
type: 'tproxy',
port: strToInt(uci.get(uciconf, uciinbound, 'tproxy_port')) || '7892',
listen: '::',
udp: true
});
push(config.listeners, {
name: 'dns-in',
type: 'tunnel',
port: strToInt(uci.get(uciconf, uciinbound, 'tunnel_port')) || '7893',
listen: '::',
network: ['tcp', 'udp'],
target: '1.1.1.1:53'
});
/* Tun settings */
if (match(proxy_mode, /tun/))
push(config.listeners, {
name: 'tun-in',
type: 'tun',
device: tun_name,
stack: uci.get(uciconf, uciinbound, 'tun_stack') || 'system',
"dns-hijack": ['udp://[::]:53', 'tcp://[::]:53'],
"inet4-address": [ tun_addr4 ],
"inet6-address": [ tun_addr6 ],
mtu: strToInt(uci.get(uciconf, uciinbound, 'tun_mtu')) || 9000,
gso: strToBool(uci.get(uciconf, uciinbound, 'tun_gso')) || false,
"gso-max-size": strToInt(uci.get(uciconf, uciinbound, 'tun_gso_max_size')) || 65536,
"auto-route": false,
"iproute2-table-index": route_table_id,
"iproute2-rule-index": route_rule_pref,
"auto-redirect": false,
"auto-redirect-input-mark": redirect_gate_mark,
"auto-redirect-output-mark": redirect_pass_mark,
"strict-route": false,
"route-address": [
"0.0.0.0/1",
"128.0.0.0/1",
"::/1",
"8000::/1"
],
"route-exclude-address": [
"192.168.0.0/16",
"fc00::/7"
],
"route-address-set": [],
"route-exclude-address-set": [],
"include-interface": [],
"exclude-interface": [],
2024-11-03 20:36:08 +08:00
"udp-timeout": durationToSecond(uci.get(uciconf, uciinbound, 'tun_udp_timeout')) || 300,
2024-10-26 10:27:23 +08:00
"endpoint-independent-nat": strToBool(uci.get(uciconf, uciinbound, 'tun_endpoint_independent_nat')),
"auto-detect-interface": true
});
/* Inbound END */
/* DNS START */
/* DNS settings */
config.dns = {
enable: true,
"prefer-h3": false,
listen: '[::]:' + (uci.get(uciconf, ucidns, 'port') || '7853'),
ipv6: (uci.get(uciconf, ucidns, 'ipv6') === '0') ? false : true,
"enhanced-mode": 'redir-host',
"use-hosts": true,
"use-system-hosts": true,
"respect-rules": true,
"default-nameserver": get_nameserver(uci.get(uciconf, ucidns, 'boot_server')),
"proxy-server-nameserver": get_nameserver(uci.get(uciconf, ucidns, 'bootnode_server')),
nameserver: get_nameserver(uci.get(uciconf, ucidns, 'default_server')),
fallback: get_nameserver(uci.get(uciconf, ucidns, 'fallback_server')),
"nameserver-policy": {},
"fallback-filter": {
geoip: false
}
};
/* DNS policy */
uci.foreach(uciconf, ucidnspoli, (cfg) => {
if (cfg.enabled === '0')
return null;
let key;
if (cfg.type === 'domain') {
key = isEmpty(cfg.domain) ? null : join(',', cfg.domain);
} else if (cfg.type === 'geosite') {
key = isEmpty(cfg.geosite) ? null : 'geosite:' + join(',', cfg.geosite);
} else if (cfg.type === 'rule_set') {
key = isEmpty(cfg.rule_set) ? null : 'rule-set:' + join(',', cfg.rule_set);
};
if (!key)
return null;
config.dns["nameserver-policy"][key] = get_nameserver(cfg.server, cfg.proxy);
});
/* Fallback filter */
if (!isEmpty(config.dns.fallback))
config.dns["fallback-filter"] = {
geoip: (uci.get(uciconf, ucidns, 'fallback_filter_geoip') === '0') ? false : true,
"geoip-code": uci.get(uciconf, ucidns, 'fallback_filter_geoip_code') || 'cn',
geosite: uci.get(uciconf, ucidns, 'fallback_filter_geosite') || [],
ipcidr: uci.get(uciconf, ucidns, 'fallback_filter_ipcidr') || [],
domain: uci.get(uciconf, ucidns, 'fallback_filter_domain') || [],
};
/* DNS END */
/* Hosts START */
/* Hosts */
config.hosts = {};
/* Hosts END */
/* Proxy Node START */
/* Proxy Node */
config.proxies = [
/*{
name: 'direct-out',
type: 'direct',
udp: true,
"ip-version": undefined,
"interface-name": undefined,
"routing-mark": undefined
},*/
{
name: 'dns-out',
type: 'dns'
}
];
2024-11-16 20:36:29 +08:00
uci.foreach(uciconf, ucinode, (cfg) => {
if (cfg.enabled === '0')
return null;
push(config.proxies, {
name: cfg.label,
type: cfg.type,
server: cfg.server,
port: strToInt(cfg.port),
/* Dial fields */
tfo: strToBool(cfg.tfo),
mptcp: strToBool(cfg.mptcp),
// dev: Features under development
["dialer-proxy"]: null, //cfg.dialer_proxy,
["interface-name"]: cfg.interface_name,
["routing-mark"]: strToInt(cfg.routing_mark),
["ip-version"]: cfg.ip_version,
2024-11-27 11:29:22 +08:00
/* HTTP / SOCKS / Shadowsocks / VMess / VLESS / Trojan / hysteria2 / TUIC / SSH / WireGuard */
2024-11-16 20:36:29 +08:00
username: cfg.username,
uuid: cfg.vmess_uuid || cfg.uuid,
cipher: cfg.vmess_chipher || cfg.shadowsocks_chipher,
password: cfg.shadowsocks_password || cfg.password,
headers: cfg.headers ? json(cfg.headers) : null,
2024-11-27 11:29:22 +08:00
["private-key"]: cfg.wireguard_private_key || cfg.ssh_priv_key,
2024-11-16 20:36:29 +08:00
/* Hysteria / Hysteria2 */
ports: isEmpty(cfg.hysteria_ports) ? null : join(',', cfg.hysteria_ports),
up: cfg.hysteria_up_mbps ? cfg.hysteria_up_mbps + ' Mbps' : null,
down: cfg.hysteria_down_mbps ? cfg.hysteria_down_mbps + ' Mbps' : null,
obfs: cfg.hysteria_obfs_type,
["obfs-password"]: cfg.hysteria_obfs_password,
/* SSH */
["private-key-passphrase"]: cfg.ssh_priv_key_passphrase,
["host-key-algorithms"]: cfg.ssh_host_key_algorithms,
["host-key"]: cfg.ssh_host_key,
/* Shadowsocks */
/* Snell */
psk: cfg.snell_psk,
version: cfg.snell_version,
["obfs-opts"]: cfg.type === 'snell' ? {
mode: cfg.plugin_opts_obfsmode,
host: cfg.plugin_opts_host,
} : null,
/* TUIC */
ip: cfg.tuic_ip,
["congestion-controller"]: cfg.tuic_congestion_controller,
["udp-relay-mode"]: cfg.tuic_udp_relay_mode,
["udp-over-stream"]: strToBool(cfg.tuic_udp_over_stream),
["udp-over-stream-version"]: cfg.tuic_udp_over_stream_version,
["max-udp-relay-packet-size"]: strToInt(cfg.tuic_max_udp_relay_packet_size),
["reduce-rtt"]: strToBool(cfg.tuic_reduce_rtt),
["heartbeat-interval"]: strToInt(cfg.tuic_heartbeat),
["request-timeout"]: strToInt(cfg.tuic_request_timeout),
// fast-open: true
// max-open-streams: 20
/* Trojan */
["ss-opts"]: cfg.trojan_ss_enabled === '1' ? {
enabled: true,
method: cfg.trojan_ss_chipher,
password: cfg.trojan_ss_password
}: null,
/* VMess / VLESS */
flow: cfg.vless_flow,
alterId: strToInt(cfg.vmess_alterid),
["global-padding"]: cfg.type === 'vmess' ? (cfg.vmess_global_padding === '0' ? false : true) : null,
["authenticated-length"]: strToBool(cfg.vmess_authenticated_length),
["packet-encoding"]: cfg.vmess_packet_encoding,
2024-11-27 11:29:22 +08:00
/* WireGuard */
ip: cfg.wireguard_ip,
ipv6: cfg.wireguard_ipv6,
["public-key"]: cfg.wireguard_peer_public_key,
["pre-shared-key"]: cfg.wireguard_pre_shared_key,
["allowed-ips"]: cfg.wireguard_allowed_ips,
reserved: cfg.wireguard_reserved,
mtu: strToInt(cfg.wireguard_mtu),
["remote-dns-resolve"]: strToBool(cfg.wireguard_remote_dns_resolve),
dns: cfg.wireguard_dns,
2024-11-16 20:36:29 +08:00
/* Plugin fields */
plugin: cfg.plugin,
["plugin-opts"]: cfg.plugin ? {
mode: cfg.plugin_opts_obfsmode,
host: cfg.plugin_opts_host,
password: cfg.plugin_opts_thetlspassword,
version: cfg.plugin_opts_shadowtls_version,
["version-hint"]: cfg.plugin_opts_restls_versionhint,
["restls-script"]: cfg.plugin_opts_restls_script
} : null,
/* Extra fields */
udp: strToBool(cfg.udp),
["udp-over-tcp"]: strToBool(cfg.uot),
["udp-over-tcp-version"]: cfg.uot_version,
/* TLS fields */
tls: (cfg.type in ['trojan', 'hysteria', 'hysteria2', 'tuic']) ? null : strToBool(cfg.tls),
["disable-sni"]: strToBool(cfg.tls_disable_sni),
...arrToObj([[(cfg.type in ['vmess', 'vless']) ? 'servername' : 'sni', cfg.tls_sni]]),
fingerprint: cfg.tls_fingerprint,
alpn: cfg.tls_alpn, // Array
["skip-cert-verify"]: strToBool(cfg.tls_skip_cert_verify),
["client-fingerprint"]: cfg.tls_client_fingerprint,
["reality-opts"]: cfg.tls_reality === '1' ? {
["public-key"]: cfg.tls_reality_public_key,
["short-id"]: cfg.tls_reality_short_id
} : null,
/* Transport fields */
// https://github.com/muink/mihomo/blob/3e966e82c793ca99e3badc84bf3f2907b100edae/adapter/outbound/vmess.go#L74
...(cfg.transport_enabled === '1' ? {
network: cfg.transport_type,
["http-opts"]: cfg.transport_type === 'http' ? {
method: cfg.transport_http_method,
path: isEmpty(cfg.transport_paths) ? ['/'] : cfg.transport_paths, // Array
headers: cfg.transport_http_headers ? json(cfg.transport_http_headers) : null,
} : null,
["h2-opts"]: cfg.transport_type === 'h2' ? {
host: cfg.transport_hosts, // Array
path: cfg.transport_path || '/',
} : null,
["grpc-opts"]: cfg.transport_type === 'grpc' ? {
["grpc-service-name"]: cfg.transport_grpc_servicename
} : null,
["ws-opts"]: cfg.transport_type === 'ws' ? {
path: cfg.transport_path || '/',
headers: cfg.transport_http_headers ? json(cfg.transport_http_headers) : null,
["max-early-data"]: strToInt(cfg.transport_ws_max_early_data),
["early-data-header-name"]: cfg.transport_ws_early_data_header,
["v2ray-http-upgrade"]: strToBool(cfg.transport_ws_v2ray_http_upgrade),
["v2ray-http-upgrade-fast-open"]: strToBool(cfg.transport_ws_v2ray_http_upgrade_fast_open)
} : null
} : {}),
/* Multiplex fields */
smux: cfg.smux_enabled === '1' ? {
enabled: true,
protocol: cfg.smux_protocol,
["max-connections"]: strToInt(cfg.smux_max_connections),
["min-streams"]: strToInt(cfg.smux_min_streams),
["max-streams"]: strToInt(cfg.smux_max_streams),
statistic: strToBool(cfg.smux_statistic),
["only-tcp"]: strToBool(cfg.smux_only_tcp),
padding: strToBool(cfg.smux_padding),
["brutal-opts"]: cfg.smux_brutal === '1' ? {
enabled: true,
up: strToInt(cfg.smux_brutal_up), // Mbps
down: strToInt(cfg.smux_brutal_down) // Mbps
} : null
} : null
});
});
2024-10-26 10:27:23 +08:00
/* Proxy Node END */
/* Proxy Group START */
/* Proxy Group */
config["proxy-groups"] = [];
uci.foreach(uciconf, ucipgrp, (cfg) => {
if (cfg.enabled === '0')
return null;
push(config["proxy-groups"], {
name: cfg.label,
type: cfg.type,
proxies: [
...map(cfg.groups || [], cfg => get_proxygroup(cfg)),
...map(cfg.proxies || [], cfg => get_proxynode(cfg))
],
use: cfg.use,
"include-all": strToBool(cfg.include_all),
"include-all-proxies": strToBool(cfg.include_all_proxies),
"include-all-providers": strToBool(cfg.include_all_providers),
// Url-test fields
tolerance: (cfg.type === 'url-test') ? strToInt(cfg.tolerance) || 150 : null,
// Load-balance fields
strategy: cfg.strategy,
// Override fields
"disable-udp": strToBool(cfg.disable_udp) || false,
["interface-name"]: cfg.interface_name,
["routing-mark"]: strToInt(cfg.routing_mark),
// Health fields
url: cfg.url,
2024-11-03 20:36:08 +08:00
interval: cfg.url ? durationToSecond(cfg.interval) || 600 : null,
2024-10-26 10:27:23 +08:00
timeout: cfg.url ? strToInt(cfg.timeout) || 5000 : null,
lazy: (cfg.lazy === '0') ? false : null,
"expected-status": cfg.url ? cfg.expected_status || '204' : null,
"max-failed-times": cfg.url ? strToInt(cfg.max_failed_times) || 5 : null,
filter: parse_filter(cfg.filter),
"exclude-filter": parse_filter(cfg.exclude_filter),
"exclude-type": parse_filter(cfg.exclude_type)
});
});
/* Proxy Group END */
/* Provider START */
/* Provider settings */
config["proxy-providers"] = {};
uci.foreach(uciconf, uciprov, (cfg) => {
if (cfg.enabled === '0')
return null;
/* General fields */
config["proxy-providers"][cfg['.name']] = {
type: cfg.type,
path: HM_DIR + '/provider/' + cfg['.name'],
url: cfg.url,
2024-11-03 20:36:08 +08:00
interval: (cfg.type === 'http') ? durationToSecond(cfg.interval) || 86400 : null,
2024-10-26 10:27:23 +08:00
proxy: get_proxygroup(cfg.proxy),
header: cfg.header ? json(cfg.header) : null,
"health-check": {},
override: {},
filter: parse_filter(cfg.filter),
"exclude-filter": parse_filter(cfg.exclude_filter),
"exclude-type": parse_filter(cfg.exclude_type)
};
/* Override fields */
config["proxy-providers"][cfg['.name']].override = {
["additional-prefix"]: cfg.override_prefix,
["additional-suffix"]: cfg.override_suffix,
["proxy-name"]: isEmpty(cfg.override_replace) ? null : map(cfg.override_replace, (obj) => json(obj)),
// Configuration Items
tfo: strToBool(cfg.override_tfo),
mptcp: strToBool(cfg.override_mptcp),
udp: (cfg.override_udp === '0') ? false : true,
"udp-over-tcp": strToBool(cfg.override_uot),
up: cfg.override_up ? cfg.override_up + ' Mbps' : null,
down: cfg.override_down ? cfg.override_down + ' Mbps' : null,
["skip-cert-verify"]: strToBool(cfg.override_skip_cert_verify) || false,
// dev: Features under development
["dialer-proxy"]: null, //cfg.override_dialer_proxy,
["interface-name"]: cfg.override_interface_name,
["routing-mark"]: strToInt(cfg.override_routing_mark),
["ip-version"]: cfg.override_ip_version
};
/* Health fields */
if (cfg.health_enable === '0') {
config["proxy-providers"][cfg['.name']]["health-check"] = null;
} else {
config["proxy-providers"][cfg['.name']]["health-check"] = {
enable: true,
url: cfg.health_url,
2024-11-03 20:36:08 +08:00
interval: durationToSecond(cfg.health_interval) || 600,
2024-10-26 10:27:23 +08:00
timeout: strToInt(cfg.health_timeout) || 5000,
lazy: (cfg.health_lazy === '0') ? false : null,
"expected-status": cfg.health_expected_status || '204'
};
}
});
/* Provider END */
/* Rule set START */
/* Rule set settings */
config["rule-providers"] = {};
uci.foreach(uciconf, ucirule, (cfg) => {
if (cfg.enabled === '0')
return null;
config["rule-providers"][cfg['.name']] = {
type: cfg.type,
format: cfg.format,
behavior: cfg.behavior,
path: HM_DIR + '/ruleset/' + cfg['.name'],
url: cfg.url,
2024-11-03 20:36:08 +08:00
interval: (cfg.type === 'http') ? durationToSecond(cfg.interval) || 259200 : null,
2024-10-26 10:27:23 +08:00
proxy: get_proxygroup(cfg.proxy)
};
});
/* Rule set END */
/* Routing rules START */
/* Routing rules */
config.rules = [
"IN-NAME,dns-in,dns-out",
"DST-PORT,53,dns-out"
];
uci.foreach(uciconf, ucirout, (cfg) => {
if (cfg.enabled === '0')
return null;
2024-11-06 00:26:14 +08:00
push(config.rules, parse_entry(cfg.entry));
2024-10-26 10:27:23 +08:00
});
/* Routing rules END */
2024-11-06 00:26:14 +08:00
/* 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 */
2024-10-26 10:27:23 +08:00
printf('%.J\n', removeBlankAttrs(config));