update 2025-02-24 20:26:20

This commit is contained in:
actions-user 2025-02-24 20:26:20 +08:00
parent 323296a1af
commit bd3b5ce006
7 changed files with 121 additions and 84 deletions

View File

@ -1,6 +1,6 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.19.2
PKG_VERSION:=1.19.3
LUCI_TITLE:=LuCI Support for nikki
LUCI_DEPENDS:=+luci-base +nikki

View File

@ -158,6 +158,9 @@ return view.extend({
o.retain = true;
o.depends('tun_gso', '1');
o = s.taboption('tun', form.Flag, 'tun_endpoint_independent_nat', '*' + ' ' + _('Endpoint Independent NAT'));
o.rmempty = false;
o = s.taboption('tun', form.Flag, 'tun_dns_hijack', '*' + ' ' + _('Overwrite DNS Hijack'));
o.rmempty = false;
@ -168,9 +171,6 @@ return view.extend({
o.value('tcp://any:53');
o.value('udp://any:53');
o = s.taboption('tun', form.Flag, 'tun_endpoint_independent_nat', '*' + ' ' + _('Endpoint Independent NAT'));
o.rmempty = false;
s.tab('dns', _('DNS Config'));
o = s.taboption('dns', form.Value, 'dns_port', '*' + ' ' + _('DNS Port'));

View File

@ -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

View File

@ -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')
}

View File

@ -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;
};

View File

@ -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);
print(trim_all(config));

View File

@ -6,12 +6,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=sing-box
PKG_VERSION:=1.11.3
PKG_VERSION:=1.11.4
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=51b189549395c132dce781e1c70315e4bb8386c207e171c07124759b45481d97
PKG_HASH:=633e40e2a64937069ada9d8d96dec1a5d735095d44eb3cbea105ee05f4616fc6
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=LICENSE