diff --git a/nikki/Makefile b/nikki/Makefile index cf11f245b..017771f2c 100644 --- a/nikki/Makefile +++ b/nikki/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nikki -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git diff --git a/nikki/files/ucode/hijack.ut b/nikki/files/ucode/hijack.ut index e3a5303b7..8f9287d56 100644 --- a/nikki/files/ucode/hijack.ut +++ b/nikki/files/ucode/hijack.ut @@ -5,7 +5,7 @@ import { readfile } from 'fs'; import { cursor } from 'uci'; - import { ensure_array } from '/etc/nikki/ucode/include.uc'; + import { uci_bool, uci_array } from '/etc/nikki/ucode/include.uc'; let users = map(split(readfile('/etc/passwd'), '\n'), (x) => split(x, ':')[0]); let groups = map(split(readfile('/etc/group'), '\n'), (x) => split(x, ':')[0]); @@ -24,39 +24,39 @@ const tcp_transparent_proxy_mode = uci.get('nikki', 'proxy', 'tcp_transparent_proxy_mode'); const udp_transparent_proxy_mode = uci.get('nikki', 'proxy', 'udp_transparent_proxy_mode'); - const ipv4_dns_hijack = uci.get('nikki', 'proxy', 'ipv4_dns_hijack'); - const ipv6_dns_hijack = uci.get('nikki', 'proxy', 'ipv6_dns_hijack'); - const ipv4_proxy = uci.get('nikki', 'proxy', 'ipv4_proxy'); - const ipv6_proxy = uci.get('nikki', 'proxy', 'ipv6_proxy'); - const fake_ip_ping_hijack = uci.get('nikki', 'proxy', 'fake_ip_ping_hijack'); - const router_proxy = uci.get('nikki', 'proxy', 'router_proxy'); - const lan_proxy = uci.get('nikki', 'proxy', 'lan_proxy'); + const ipv4_dns_hijack = uci_bool(uci.get('nikki', 'proxy', 'ipv4_dns_hijack')); + const ipv6_dns_hijack = uci_bool(uci.get('nikki', 'proxy', 'ipv6_dns_hijack')); + const ipv4_proxy = uci_bool(uci.get('nikki', 'proxy', 'ipv4_proxy')); + const ipv6_proxy = uci_bool(uci.get('nikki', 'proxy', 'ipv6_proxy')); + const fake_ip_ping_hijack = uci_bool(uci.get('nikki', 'proxy', 'fake_ip_ping_hijack')); + const router_proxy = uci_bool(uci.get('nikki', 'proxy', 'router_proxy')); + const lan_proxy = uci_bool(uci.get('nikki', 'proxy', 'lan_proxy')); const access_control_mode = uci.get('nikki', 'proxy', 'access_control_mode'); - const acl_ip = ensure_array(uci.get('nikki', 'proxy', 'acl_ip')); - const acl_ip6 = ensure_array(uci.get('nikki', 'proxy', 'acl_ip6')); - const acl_mac = ensure_array(uci.get('nikki', 'proxy', 'acl_mac')); - const acl_interface = ensure_array(uci.get('nikki', 'proxy', 'acl_interface')); + const acl_ip = uci_array(uci.get('nikki', 'proxy', 'acl_ip')); + const acl_ip6 = uci_array(uci.get('nikki', 'proxy', 'acl_ip6')); + const acl_mac = uci_array(uci.get('nikki', 'proxy', 'acl_mac')); + const acl_interface = uci_array(uci.get('nikki', 'proxy', 'acl_interface')); - const bypass_user = filter(ensure_array(uci.get('nikki', 'proxy', 'bypass_user')), (x) => x != "root" && index(users, x) >= 0); - const bypass_group = filter(ensure_array(uci.get('nikki', 'proxy', 'bypass_group')), (x) => x != "root" && index(groups, x) >= 0); + const bypass_user = filter(uci_array(uci.get('nikki', 'proxy', 'bypass_user')), (x) => x != "root" && index(users, x) >= 0); + const bypass_group = filter(uci_array(uci.get('nikki', 'proxy', 'bypass_group')), (x) => x != "root" && index(groups, x) >= 0); const proxy_tcp_dport = split((uci.get('nikki', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' '); const proxy_udp_dport = split((uci.get('nikki', 'proxy', 'proxy_udp_dport') ?? '0-65535'), ' '); - const bypass_dscp = ensure_array(uci.get('nikki', 'proxy', 'bypass_dscp')); + const bypass_dscp = uci_array(uci.get('nikki', 'proxy', 'bypass_dscp')); const dns_hijack_nfproto = []; - if (ipv4_dns_hijack == '1') { + if (ipv4_dns_hijack) { push(dns_hijack_nfproto, 'ipv4') } - if (ipv6_dns_hijack == '1') { + if (ipv6_dns_hijack) { push(dns_hijack_nfproto, 'ipv6') } const proxy_nfproto = []; - if (ipv4_proxy == '1') { + if (ipv4_proxy) { push(proxy_nfproto, 'ipv4') } - if (ipv6_proxy == '1') { + if (ipv6_proxy) { push(proxy_nfproto, 'ipv6') } diff --git a/nikki/files/ucode/include.uc b/nikki/files/ucode/include.uc index ad2af4d92..974b36b9f 100644 --- a/nikki/files/ucode/include.uc +++ b/nikki/files/ucode/include.uc @@ -1,4 +1,8 @@ -export function ensure_array(obj) { +export function uci_bool(obj) { + return obj == '1'; +}; + +export function uci_array(obj) { if (obj == null) { return []; } @@ -6,4 +10,36 @@ export function ensure_array(obj) { return uniq(obj); } return [obj]; +}; + +export function trim_all(obj) { + if (obj == null) { + return null; + } + if (type(obj) == 'string') { + if (length(obj) == 0) { + return null; + } + return obj; + } + if (type(obj) == 'array') { + if (length(obj) == 0) { + return null; + } + return obj; + } + if (type(obj) == 'object') { + const obj_keys = keys(obj); + for (let key in obj_keys) { + obj[key] = trim_all(obj[key]); + if (obj[key] == null) { + delete obj[key]; + } + } + if (length(obj_keys) == 0) { + return null; + } + return obj; + } + return obj; }; \ No newline at end of file diff --git a/nikki/files/ucode/mixin.uc b/nikki/files/ucode/mixin.uc index 0b6faec1c..c27edeb6c 100644 --- a/nikki/files/ucode/mixin.uc +++ b/nikki/files/ucode/mixin.uc @@ -4,23 +4,23 @@ import { cursor } from 'uci'; import { connect } from 'ubus'; -import { ensure_array } from '/etc/nikki/ucode/include.uc'; +import { uci_bool, uci_array, trim_all } from '/etc/nikki/ucode/include.uc'; const uci = cursor(); const ubus = connect(); const config = {}; -const mixin = uci.get('nikki', 'config', 'mixin') == '1'; +const mixin = uci_bool(uci.get('nikki', 'config', 'mixin')); config['log-level'] = uci.get('nikki', 'mixin', 'log_level') ?? 'info'; config['mode'] = uci.get('nikki', 'mixin', 'mode') ?? 'rule'; config['find-process-mode'] = uci.get('nikki', 'mixin', 'match_process') ?? 'off'; config['interface-name'] = ubus.call('network.interface', 'status', {'interface': uci.get('nikki', 'mixin', 'outbound_interface')})?.l3_device ?? ''; -config['ipv6'] = uci.get('nikki', 'mixin', 'ipv6') == '1'; +config['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'ipv6')); if (mixin) { - config['unified-delay'] = uci.get('nikki', 'mixin', 'unify_delay') == '1'; - config['tcp-concurrent'] = uci.get('nikki', 'mixin', 'tcp_concurrent') == '1'; + config['unified-delay'] = uci_bool(uci.get('nikki', 'mixin', 'unify_delay')); + config['tcp-concurrent'] = uci_bool(uci.get('nikki', 'mixin', 'tcp_concurrent')); config['keep-alive-idle'] = int(uci.get('nikki', 'mixin', 'tcp_keep_alive_idle') ?? '600'); config['keep-alive-interval'] = int(uci.get('nikki', 'mixin', 'tcp_keep_alive_interval') ?? '15'); } @@ -31,20 +31,20 @@ config['external-ui-url'] = uci.get('nikki', 'mixin', 'ui_url'); config['external-controller'] = '0.0.0.0' + ':' + (uci.get('nikki', 'mixin', 'api_port') ?? '9090'); config['secret'] = uci.get('nikki', 'mixin', 'api_secret') ?? '666666'; config['profile'] = {}; -config['profile']['store-selected'] = uci.get('nikki', 'mixin', 'selection_cache') == '1'; -config['profile']['store-fake-ip'] = uci.get('nikki', 'mixin', 'fake_ip_cache') == '1'; +config['profile']['store-selected'] = uci_bool(uci.get('nikki', 'mixin', 'selection_cache')); +config['profile']['store-fake-ip'] = uci_bool(uci.get('nikki', 'mixin', 'fake_ip_cache')); -config['allow-lan'] = uci.get('nikki', 'mixin', 'allow_lan') == '1'; +config['allow-lan'] = uci_bool(uci.get('nikki', 'mixin', 'allow_lan')); config['port'] = int(uci.get('nikki', 'mixin', 'http_port') ?? '8080'); config['socks-port'] = int(uci.get('nikki', 'mixin', 'socks_port') ?? '1080'); config['mixed-port'] = int(uci.get('nikki', 'mixin', 'mixed_port') ?? '7890'); config['redir-port'] = int(uci.get('nikki', 'mixin', 'redir_port') ?? '7891'); config['tproxy-port'] = int(uci.get('nikki', 'mixin', 'tproxy_port') ?? '7892'); -if (uci.get('nikki', 'mixin', 'authentication') == '1') { +if (uci_bool(uci.get('nikki', 'mixin', 'authentication'))) { config['authentication'] = []; uci.foreach('nikki', 'authentication', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } push(config['authentication'], `${section.username}:${section.password}`); @@ -54,100 +54,101 @@ if (uci.get('nikki', 'mixin', 'authentication') == '1') { config['tun'] = {}; if (uci.get('nikki', 'proxy', 'tcp_transparent_proxy_mode') == 'tun' || uci.get('nikki', 'proxy', 'udp_transparent_proxy_mode') == 'tun') { config['tun']['enable'] = true; - config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device') ?? 'nikki'; - config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack') ?? 'system'; - config['tun']['mtu'] = int(uci.get('nikki', 'mixin', 'tun_mtu') ?? '9000'); - config['tun']['gso'] = uci.get('nikki', 'mixin', 'tun_gso') == '1'; - config['tun']['gso-max-size'] = int(uci.get('nikki', 'mixin', 'tun_gso_max_size') ?? '65536'); - config['tun']['endpoint-independent-nat'] = uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat') == '1'; config['tun']['auto-route'] = false; config['tun']['auto-redirect'] = false; config['tun']['auto-detect-interface'] = false; - if (uci.get('nikki', 'mixin', 'tun_dns_hijack') == '1') { - config['tun']['dns-hijack'] = ensure_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks')); + config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device') ?? 'nikki'; + config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack') ?? 'system'; + config['tun']['mtu'] = int(uci.get('nikki', 'mixin', 'tun_mtu') ?? '9000'); + config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso')); + config['tun']['gso-max-size'] = int(uci.get('nikki', 'mixin', 'tun_gso_max_size') ?? '65536'); + config['tun']['endpoint-independent-nat'] = uci_bool(uci.get('nikki', 'mixin', 'tun_endpoint_independent_nat')); + if (uci_bool(uci.get('nikki', 'mixin', 'tun_dns_hijack'))) { + config['tun']['dns-hijack'] = uci_array(uci.get('nikki', 'mixin', 'tun_dns_hijacks')); } } else { config['tun']['enable'] = false; } config['dns'] = {}; +config['dns']['enable'] = true; config['dns']['listen'] = '0.0.0.0' + ':' + (uci.get('nikki', 'mixin', 'dns_port') ?? '1053'); config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode') ?? 'redir-host'; config['dns']['fake-ip-range'] = uci.get('nikki', 'mixin', 'fake_ip_range') ?? '198.18.0.1/16'; -if (uci.get('nikki', 'mixin', 'fake_ip_filter') == '1') { - config['dns']['fake-ip-filter'] = ensure_array(uci.get('nikki', 'mixin', 'fake_ip_filters')); +if (uci_bool(uci.get('nikki', 'mixin', 'fake_ip_filter'))) { + config['dns']['fake-ip-filter'] = uci_array(uci.get('nikki', 'mixin', 'fake_ip_filters')); config['dns']['fake-ip-filter-mode'] = uci.get('nikki', 'mixin', 'fake_ip_filter_mode') ?? 'blacklist'; } if (mixin) { - config['dns']['respect-rules'] = uci.get('nikki', 'mixin', 'dns_respect_rules') == '1'; - config['dns']['prefer-h3'] = uci.get('nikki', 'mixin', 'dns_doh_prefer_http3') == '1'; - config['dns']['ipv6'] = uci.get('nikki', 'mixin', 'dns_ipv6') == '1'; - config['dns']['use-system-hosts'] = uci.get('nikki', 'mixin', 'dns_system_hosts') == '1'; - config['dns']['use-hosts'] = uci.get('nikki', 'mixin', 'dns_hosts') == '1'; - if (uci.get('nikki', 'mixin', 'hosts') == '1') { + config['dns']['respect-rules'] = uci_bool(uci.get('nikki', 'mixin', 'dns_respect_rules')); + config['dns']['prefer-h3'] = uci_bool(uci.get('nikki', 'mixin', 'dns_doh_prefer_http3')); + config['dns']['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'dns_ipv6')); + config['dns']['use-system-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_system_hosts')); + config['dns']['use-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_hosts')); + if (uci_bool(uci.get('nikki', 'mixin', 'hosts'))) { config['hosts'] = {}; uci.foreach('nikki', 'hosts', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } - config['hosts'][section.domain_name] = ensure_array(section.ip); + config['hosts'][section.domain_name] = uci_array(section.ip); }); } - if (uci.get('nikki', 'mixin', 'dns_nameserver') == '1') { + if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver'))) { config['dns']['default-nameserver'] = []; config['dns']['proxy-server-nameserver'] = []; config['dns']['direct-nameserver'] = []; config['dns']['nameserver'] = []; config['dns']['fallback'] = []; uci.foreach('nikki', 'nameserver', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } - push(config['dns'][section.type], ...ensure_array(section.nameserver)); + push(config['dns'][section.type], ...uci_array(section.nameserver)); }) } - if (uci.get('nikki', 'mixin', 'dns_nameserver_policy') == '1') { + if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver_policy'))) { config['dns']['nameserver-policy'] = {}; uci.foreach('nikki', 'nameserver_policy', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } - config['dns']['nameserver-policy'][section.matcher] = ensure_array(section.nameserver); + config['dns']['nameserver-policy'][section.matcher] = uci_array(section.nameserver); }); } } if (mixin) { config['sniffer'] = {}; - config['sniffer']['enable'] = uci.get('nikki', 'mixin', 'sniffer') == '1'; - config['sniffer']['force-dns-mapping'] = uci.get('nikki', 'mixin', 'sniffer_sniff_dns_mapping') == '1'; - config['sniffer']['parse-pure-ip'] = uci.get('nikki', 'mixin', 'sniffer_sniff_pure_ip') == '1'; - config['sniffer']['override-destination'] = uci.get('nikki', 'mixin', 'sniffer_overwrite_destination') == '1'; - if (uci.get('nikki', 'mixin', 'sniffer_force_domain_name') == '1') { - config['sniffer']['force-domain'] = uci.get('nikki', 'mixin', 'sniffer_force_domain_names'); + config['sniffer']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer')); + config['sniffer']['force-dns-mapping'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_dns_mapping')); + config['sniffer']['parse-pure-ip'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_pure_ip')); + config['sniffer']['override-destination'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_overwrite_destination')); + if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_force_domain_name'))) { + config['sniffer']['force-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_force_domain_names')); } - if (uci.get('nikki', 'mixin', 'sniffer_ignore_domain_name') == '1') { - config['sniffer']['skip-domain'] = uci.get('nikki', 'mixin', 'sniffer_ignore_domain_names'); + if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_name'))) { + config['sniffer']['skip-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_names')); } - if (uci.get('nikki', 'mixin', 'sniffer_sniff') == '1') { + if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff'))) { config['sniffer']['sniff'] = {}; config['sniffer']['sniff']['HTTP'] = {}; config['sniffer']['sniff']['TLS'] = {}; config['sniffer']['sniff']['QUIC'] = {}; uci.foreach('nikki', 'sniff', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } - config['sniffer']['sniff'][section.protocol]['port'] = ensure_array(section.port); - config['sniffer']['sniff'][section.protocol]['override-destination'] = section.overwrite_destination == '1'; + config['sniffer']['sniff'][section.protocol]['port'] = uci_array(section.port); + config['sniffer']['sniff'][section.protocol]['override-destination'] = uci_bool(section.overwrite_destination); }); } } -if (uci.get('nikki', 'mixin', 'rule_provider') == '1') { +if (uci_bool(uci.get('nikki', 'mixin', 'rule_provider'))) { config['rule-providers'] = {}; uci.foreach('nikki', 'rule_provider', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } if (section.type == 'http') { @@ -170,19 +171,19 @@ if (uci.get('nikki', 'mixin', 'rule_provider') == '1') { } }) } -if (uci.get('nikki', 'mixin', 'rule') == '1') { +if (uci_bool(uci.get('nikki', 'mixin', 'rule'))) { config['nikki-rules'] = []; uci.foreach('nikki', 'rule', (section) => { - if (section.enabled != '1') { + if (!uci_bool(section.enabled)) { return; } let rule; - if (section.type == null ?? section.type == '') { - rule = `${section.matcher},${section.node}`; - } else { + if (length(section.type) > 0) { rule = `${section.type},${section.matcher},${section.node}`; + } else { + rule = `${section.matcher},${section.node}`; } - if (section.no_resolve == '1') { + if (uci_bool(section.no_resolve)) { rule += ',no_resolve'; } push(config['nikki-rules'], rule); @@ -190,15 +191,15 @@ if (uci.get('nikki', 'mixin', 'rule') == '1') { } if (mixin) { - config['geodata-mode'] = (uci.get('nikki', 'mixin', 'geoip_format') ?? 'mmdb') == 'dat'; + config['geodata-mode'] = uci.get('nikki', 'mixin', 'geoip_format') == 'dat'; config['geodata-loader'] = uci.get('nikki', 'mixin', 'geodata_loader') ?? 'memconservative'; config['geox-url'] = {}; config['geox-url']['geosite'] = uci.get('nikki', 'mixin', 'geosite_url'); config['geox-url']['mmdb'] = uci.get('nikki', 'mixin', 'geoip_mmdb_url'); config['geox-url']['geoip'] = uci.get('nikki', 'mixin', 'geoip_dat_url'); config['geox-url']['asn'] = uci.get('nikki', 'mixin', 'geoip_asn_url'); - config['geo-auto-update'] = uci.get('nikki', 'mixin', 'geox_auto_update') == '1'; + config['geo-auto-update'] = uci_bool(uci.get('nikki', 'mixin', 'geox_auto_update')); config['geo-update-interval'] = int(uci.get('nikki', 'mixin', 'geox_update_interval') ?? '24'); } -print(config); \ No newline at end of file +print(trim_all(config)); \ No newline at end of file