update 2025-08-20 09:20:05

This commit is contained in:
actions-user 2025-08-20 09:20:05 +08:00
parent e725853e6c
commit cc9e0b310c
17 changed files with 278 additions and 193 deletions

View File

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

View File

@ -65,8 +65,6 @@ const appLogPath = `${logDir}/app.log`;
const coreLogPath = `${logDir}/core.log`;
const debugLogPath = `${logDir}/debug.log`;
const nftDir = `${homeDir}/nftables`;
const reservedIPNFT = `${nftDir}/reserved_ip.nft`;
const reservedIP6NFT = `${nftDir}/reserved_ip6.nft`;
return baseclass.extend({
homeDir: homeDir,
@ -80,8 +78,6 @@ return baseclass.extend({
appLogPath: appLogPath,
coreLogPath: coreLogPath,
debugLogPath: debugLogPath,
reservedIPNFT: reservedIPNFT,
reservedIP6NFT: reservedIP6NFT,
status: async function () {
return (await callRCList('nikki'))?.nikki?.running;

View File

@ -47,8 +47,6 @@ return view.extend({
o.value(nikki.mixinFilePath, _('File for Mixin'));
o.value(nikki.runProfilePath, _('Profile for Startup'));
o.value(nikki.reservedIPNFT, _('File for Reserved IP'));
o.value(nikki.reservedIP6NFT, _('File for Reserved IP6'));
o.write = function (section_id, formvalue) {
return true;

View File

@ -117,10 +117,9 @@ return view.extend({
o.value('https://github.com/MetaCubeX/Yacd-meta/archive/refs/heads/gh-pages.zip', 'YACD');
o.value('https://github.com/MetaCubeX/Razord-meta/archive/refs/heads/gh-pages.zip', 'Razord');
o = s.taboption('external_control', form.Value, 'api_listen', '*' + ' ' + _('API Listen'));
o = s.taboption('external_control', form.Value, 'api_listen', _('API Listen'));
o.datatype = 'ipaddrport(1)';
o.placeholder = _('Unmodified');
o.rmempty = false;
o = s.taboption('external_control', form.Value, 'api_secret', _('API Secret'));
o.password = true;
@ -152,15 +151,13 @@ return view.extend({
o.datatype = 'port';
o.placeholder = _('Unmodified');
o = s.taboption('inbound', form.Value, 'redir_port', '*' + ' ' + _('Redirect Port'));
o = s.taboption('inbound', form.Value, 'redir_port', _('Redirect Port'));
o.datatype = 'port';
o.placeholder = _('Unmodified');
o.rmempty = false;
o = s.taboption('inbound', form.Value, 'tproxy_port', '*' + ' ' + _('TPROXY Port'));
o = s.taboption('inbound', form.Value, 'tproxy_port', _('TPROXY Port'));
o.datatype = 'port';
o.placeholder = _('Unmodified');
o.rmempty = false;
o = s.taboption('inbound', form.Flag, 'authentication', _('Overwrite Authentication'));
o.rmempty = false;
@ -185,9 +182,14 @@ return view.extend({
s.tab('tun', _('TUN Config'));
o = s.taboption('tun', form.Value, 'tun_device', '*' + ' ' + _('Device Name'));
o = s.taboption('tun', form.ListValue, 'tun_enabled', _('Enable'));
o.optional = true;
o.placeholder = _('Unmodified');
o.value('0', _('Disable'));
o.value('1', _('Enable'));
o = s.taboption('tun', form.Value, 'tun_device', _('Device Name'));
o.placeholder = _('Unmodified');
o.rmempty = false;
o = s.taboption('tun', form.ListValue, 'tun_stack', _('Stack'));
o.optional = true;
@ -227,10 +229,15 @@ return view.extend({
s.tab('dns', _('DNS Config'));
o = s.taboption('dns', form.Value, 'dns_listen', '*' + ' ' + _('DNS Listen'));
o = s.taboption('dns', form.ListValue, 'dns_enabled', _('Enable'));
o.optional = true;
o.placeholder = _('Unmodified');
o.value('0', _('Disable'));
o.value('1', _('Enable'));
o = s.taboption('dns', form.Value, 'dns_listen', _('DNS Listen'));
o.datatype = 'ipaddrport(1)';
o.placeholder = _('Unmodified');
o.rmempty = false;
o = s.taboption('dns', form.ListValue, 'dns_ipv6', 'IPv6');
o.optional = true;
@ -238,15 +245,15 @@ return view.extend({
o.value('0', _('Disable'));
o.value('1', _('Enable'));
o = s.taboption('dns', form.ListValue, 'dns_mode', '*' + ' ' + _('DNS Mode'));
o = s.taboption('dns', form.ListValue, 'dns_mode', _('DNS Mode'));
o.optional = true;
o.placeholder = _('Unmodified');
o.value('redir-host', 'Redir-Host');
o.value('fake-ip', 'Fake-IP');
o = s.taboption('dns', form.Value, 'fake_ip_range', '*' + ' ' + _('Fake-IP Range'));
o = s.taboption('dns', form.Value, 'fake_ip_range', _('Fake-IP Range'));
o.datatype = 'cidr4';
o.placeholder = _('Unmodified');
o.rmempty = false;
o = s.taboption('dns', form.Flag, 'fake_ip_filter', _('Overwrite Fake-IP Filter'));
o.rmempty = false;

View File

@ -132,6 +132,7 @@ return view.extend({
so.rmempty = false;
so = o.subsection.option(form.DynamicList, 'ip', 'IP');
so.datatype = 'ip4addr';
for (const mac in hosts) {
const host = hosts[mac];
@ -142,6 +143,7 @@ return view.extend({
};
so = o.subsection.option(form.DynamicList, 'ip6', 'IP6');
so.datatype = 'ip6addr';
for (const mac in hosts) {
const host = hosts[mac];
@ -152,6 +154,7 @@ return view.extend({
};
so = o.subsection.option(form.DynamicList, 'mac', 'MAC');
so.datatype = 'macaddr';
for (const mac in hosts) {
const host = hosts[mac];

View File

@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=nikki
PKG_VERSION:=2025.07.27
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
@ -43,8 +43,6 @@ endef
define Package/nikki/conffiles
/etc/config/nikki
/etc/nikki/mixin.yaml
/etc/nikki/nftables/reserved_ip.nft
/etc/nikki/nftables/reserved_ip6.nft
endef
define Package/nikki/install
@ -71,8 +69,6 @@ define Package/nikki/install
$(INSTALL_BIN) $(CURDIR)/files/scripts/firewall_include.sh $(1)/etc/nikki/scripts/firewall_include.sh
$(INSTALL_BIN) $(CURDIR)/files/scripts/debug.sh $(1)/etc/nikki/scripts/debug.sh
$(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip.nft $(1)/etc/nikki/nftables/reserved_ip.nft
$(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip6.nft $(1)/etc/nikki/nftables/reserved_ip6.nft
$(INSTALL_BIN) $(CURDIR)/files/nftables/geoip_cn.nft $(1)/etc/nikki/nftables/geoip_cn.nft
$(INSTALL_BIN) $(CURDIR)/files/nftables/geoip6_cn.nft $(1)/etc/nikki/nftables/geoip6_cn.nft

View File

@ -1,19 +0,0 @@
#!/usr/sbin/nft -f
table inet nikki {
set reserved_ip {
type ipv4_addr
flags interval
elements = {
0.0.0.0/8,
10.0.0.0/8,
127.0.0.0/8,
100.64.0.0/10,
169.254.0.0/16,
172.16.0.0/12,
192.168.0.0/16,
224.0.0.0/4,
240.0.0.0/4
}
}
}

View File

@ -1,23 +0,0 @@
#!/usr/sbin/nft -f
table inet nikki {
set reserved_ip6 {
type ipv6_addr
flags interval
elements = {
::/128,
::1/128,
::ffff:0:0/96,
100::/64,
64:ff9b::/96,
2001::/32,
2001:10::/28,
2001:20::/28,
2001:db8::/32,
2002::/16,
fc00::/7,
fe80::/10,
ff00::/8
}
}
}

View File

@ -11,24 +11,11 @@ config config 'config'
option 'fast_reload' '0'
option 'core_only' '0'
config proxy 'proxy'
option 'enabled' '1'
option 'tcp_mode' 'redirect'
option 'udp_mode' 'tun'
option 'ipv4_dns_hijack' '1'
option 'ipv6_dns_hijack' '1'
option 'ipv4_proxy' '1'
option 'ipv6_proxy' '1'
option 'fake_ip_ping_hijack' '1'
option 'router_proxy' '1'
option 'lan_proxy' '1'
list 'lan_inbound_interface' 'lan'
list 'bypass_dscp' '4'
option 'bypass_china_mainland_ip' '0'
option 'proxy_tcp_dport' '0-65535'
option 'proxy_udp_dport' '0-65535'
option 'tun_timeout' '30'
option 'tun_interval' '1'
config env 'env'
option 'disable_loopback_detector' '0'
option 'disable_quic_go_gso' '0'
option 'disable_quic_go_ecn' '0'
option 'skip_system_ipv6_check' '0'
config subscription 'subscription'
option 'name' 'default'
@ -74,56 +61,6 @@ config mixin 'mixin'
option 'rule_provider' '0'
option 'mixin_file_content' '0'
config env 'env'
option 'disable_loopback_detector' '0'
option 'disable_quic_go_gso' '0'
option 'disable_quic_go_ecn' '0'
option 'skip_system_ipv6_check' '0'
config router_access_control
option 'enabled' '1'
list 'user' 'dnsmasq'
list 'user' 'ftp'
list 'user' 'logd'
list 'user' 'nobody'
list 'user' 'ntp'
list 'user' 'ubus'
list 'group' 'dnsmasq'
list 'group' 'ftp'
list 'group' 'logd'
list 'group' 'nogroup'
list 'group' 'ntp'
list 'group' 'ubus'
list 'cgroup' 'services/adguardhome'
list 'cgroup' 'services/aria2'
list 'cgroup' 'services/dnsmasq'
list 'cgroup' 'services/netbird'
list 'cgroup' 'services/qbittorrent'
list 'cgroup' 'services/sysntpd'
list 'cgroup' 'services/tailscale'
list 'cgroup' 'services/zerotier'
option 'proxy' '0'
config router_access_control
option 'enabled' '1'
option 'dns' '1'
option 'proxy' '1'
config lan_access_control
option 'enabled' '1'
option 'dns' '1'
option 'proxy' '1'
config routing 'routing'
option 'tproxy_fw_mark' '0x80'
option 'tun_fw_mark' '0x81'
option 'tproxy_rule_pref' '1024'
option 'tun_rule_pref' '1025'
option 'tproxy_route_table' '80'
option 'tun_route_table' '81'
option 'cgroup_id' '0x12061206'
option 'cgroup_name' 'nikki'
config authentication
option 'enabled' '1'
option 'username' 'nikki'
@ -192,6 +129,91 @@ config sniff
list 'port' '8443'
option 'overwrite_destination' '1'
config proxy 'proxy'
option 'enabled' '1'
option 'tcp_mode' 'redirect'
option 'udp_mode' 'tun'
option 'ipv4_dns_hijack' '1'
option 'ipv6_dns_hijack' '1'
option 'ipv4_proxy' '1'
option 'ipv6_proxy' '1'
option 'fake_ip_ping_hijack' '1'
option 'router_proxy' '1'
option 'lan_proxy' '1'
list 'lan_inbound_interface' 'lan'
list 'reserved_ip' '0.0.0.0/8'
list 'reserved_ip' '10.0.0.0/8'
list 'reserved_ip' '127.0.0.0/8'
list 'reserved_ip' '100.64.0.0/10'
list 'reserved_ip' '169.254.0.0/16'
list 'reserved_ip' '172.16.0.0/12'
list 'reserved_ip' '192.168.0.0/16'
list 'reserved_ip' '224.0.0.0/4'
list 'reserved_ip' '240.0.0.0/4'
list 'reserved_ip6' '::/128'
list 'reserved_ip6' '::1/128'
list 'reserved_ip6' '::ffff:0:0/96'
list 'reserved_ip6' '100::/64'
list 'reserved_ip6' '64:ff9b::/96'
list 'reserved_ip6' '2001::/32'
list 'reserved_ip6' '2001:10::/28'
list 'reserved_ip6' '2001:20::/28'
list 'reserved_ip6' '2001:db8::/32'
list 'reserved_ip6' '2002::/16'
list 'reserved_ip6' 'fc00::/7'
list 'reserved_ip6' 'fe80::/10'
list 'reserved_ip6' 'ff00::/8'
list 'bypass_dscp' '4'
option 'bypass_china_mainland_ip' '0'
option 'proxy_tcp_dport' '0-65535'
option 'proxy_udp_dport' '0-65535'
option 'tun_timeout' '30'
option 'tun_interval' '1'
config router_access_control
option 'enabled' '1'
list 'user' 'dnsmasq'
list 'user' 'ftp'
list 'user' 'logd'
list 'user' 'nobody'
list 'user' 'ntp'
list 'user' 'ubus'
list 'group' 'dnsmasq'
list 'group' 'ftp'
list 'group' 'logd'
list 'group' 'nogroup'
list 'group' 'ntp'
list 'group' 'ubus'
list 'cgroup' 'services/adguardhome'
list 'cgroup' 'services/aria2'
list 'cgroup' 'services/dnsmasq'
list 'cgroup' 'services/netbird'
list 'cgroup' 'services/qbittorrent'
list 'cgroup' 'services/sysntpd'
list 'cgroup' 'services/tailscale'
list 'cgroup' 'services/zerotier'
option 'proxy' '0'
config router_access_control
option 'enabled' '1'
option 'dns' '1'
option 'proxy' '1'
config lan_access_control
option 'enabled' '1'
option 'dns' '1'
option 'proxy' '1'
config routing 'routing'
option 'tproxy_fw_mark' '0x80'
option 'tun_fw_mark' '0x81'
option 'tproxy_rule_pref' '1024'
option 'tun_rule_pref' '1025'
option 'tproxy_route_table' '80'
option 'tun_route_table' '81'
option 'cgroup_id' '0x12061206'
option 'cgroup_name' 'nikki'
config editor 'editor'
config log 'log'

View File

@ -52,6 +52,13 @@ start_service() {
config_get_bool test_profile "config" "test_profile" 0
config_get_bool fast_reload "config" "fast_reload" 0
config_get_bool core_only "config" "core_only" 0
## environment variable
local safe_paths disable_loopback_detector disable_quic_go_gso disable_quic_go_ecn skip_system_ipv6_check
config_get safe_paths "env" "safe_paths"
config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0
config_get_bool disable_quic_go_gso "env" "disable_quic_go_gso" 0
config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0
config_get_bool skip_system_ipv6_check "env" "skip_system_ipv6_check" 0
## mixin config
### overwrite
local overwrite_authentication overwrite_tun_dns_hijack overwrite_fake_ip_filter overwrite_hosts overwrite_dns_nameserver overwrite_dns_nameserver_policy overwrite_sniffer_sniff overwrite_sniffer_force_domain_name overwrite_sniffer_ignore_domain_name
@ -67,13 +74,13 @@ start_service() {
### mixin file content
local mixin_file_content
config_get_bool mixin_file_content "mixin" "mixin_file_content" 0
## environment variable
local safe_paths disable_loopback_detector disable_quic_go_gso disable_quic_go_ecn skip_system_ipv6_check
config_get safe_paths "env" "safe_paths"
config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0
config_get_bool disable_quic_go_gso "env" "disable_quic_go_gso" 0
config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0
config_get_bool skip_system_ipv6_check "env" "skip_system_ipv6_check" 0
## proxy config
local proxy_enabled ipv4_dns_hijack ipv6_dns_hijack tcp_mode udp_mode
config_get_bool proxy_enabled "proxy" "enabled" 0
config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0
config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0
config_get tcp_mode "proxy" "tcp_mode"
config_get udp_mode "proxy" "udp_mode"
# get profile
local profile_type; profile_type=$(echo "$profile" | cut -d ':' -f 1)
local profile_id; profile_id=$(echo "$profile" | cut -d ':' -f 2)
@ -144,6 +151,43 @@ start_service() {
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .proxies = .nikki-proxies + .proxies | del(.nikki-proxies) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" -
fi
fi
# check profile
if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
log "Profile" "Checking..."
if [ "$ipv4_dns_hijack" = 1 ] || [ "$ipv6_dns_hijack" = 1 ]; then
if (! yq -M -e 'has("dns") and (.dns | .enable) and (.dns | has("listen"))' "$RUN_PROFILE_PATH"); then
log "Profile" "Check failed."
log "Profile" "DNS should be enabled and listen should be defined."
log "App" "Exit."
return
fi
fi
if [ "$tcp_mode" = "redirect" ]; then
if (! yq -M -e 'has("redir-port")' "$RUN_PROFILE_PATH"); then
log "Profile" "Check failed."
log "Profile" "Redirect Port should be defined."
log "App" "Exit."
return
fi
fi
if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then
if (! yq -M -e 'has("tproxy-port")' "$RUN_PROFILE_PATH"); then
log "Profile" "Check failed."
log "Profile" "TPROXY Port should be defined."
log "App" "Exit."
return
fi
fi
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
if (! yq -M -e 'has("tun") and (.tun | .enable) and (.tun | has("device"))' "$RUN_PROFILE_PATH"); then
log "Profile" "Check failed."
log "Profile" "TUN should be enabled and device should be defined."
log "App" "Exit."
return
fi
fi
log "Profile" "Check passed."
fi
# test profile
if [ "$test_profile" = 1 ]; then
log "Profile" "Testing..."
@ -204,10 +248,6 @@ service_started() {
## app config
local core_only
config_get_bool core_only "config" "core_only" 0
## mixin
### tun
local tun_device
config_get tun_device "mixin" "tun_device" "nikki"
## proxy config
### general
local tcp_mode udp_mode ipv4_proxy ipv6_proxy tun_timeout tun_interval
@ -236,6 +276,7 @@ service_started() {
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
tun_enable=1
fi
local tun_device; tun_device=$(yq -M '.tun.device' "$RUN_PROFILE_PATH")
if [ "$core_only" = 0 ]; then
# proxy
log "Proxy" "Enabled."
@ -243,12 +284,10 @@ service_started() {
if [ "$tun_enable" = 1 ]; then
log "Proxy" "Waiting for tun device online within $tun_timeout seconds..."
while [ "$tun_timeout" -gt 0 ]; do
if (ip link show dev "$tun_device" > /dev/null 2>&1); then
if [ "$(ip -json addr show dev "$tun_device" | tun_device="$tun_device" yq -M '.[] | select(.ifname = strenv(tun_device)) | .addr_info | length')" -gt 0 ]; then
if (ip -j link show dev "$tun_device" | jsonfilter -q -e "@[@['flags'][@='UP']]" > /dev/null 2>&1); then
log "Proxy" "TUN device is online."
break
fi
fi
tun_timeout=$((tun_timeout - tun_interval))
sleep "$tun_interval"
done
@ -354,11 +393,11 @@ cleanup() {
# delete hijack
nft delete table inet nikki > /dev/null 2>&1
local handles handle
handles=$(nft --json list table inet fw4 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "input" and .comment == "nikki") | .handle')
handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='input']" | jsonfilter -q -a -e "@[@['comment']='nikki']" | jsonfilter -q -a -e "@[*]['handle']")
for handle in $handles; do
nft delete rule inet fw4 input handle "$handle"
done
handles=$(nft --json list table inet fw4 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "forward" and .comment == "nikki") | .handle')
handles=$(nft --json list table inet fw4 | jsonfilter -q -e "@['nftables'][*]['rule']" | jsonfilter -q -a -e "@[@['chain']='forward']" | jsonfilter -q -a -e "@[@['comment']='nikki']" | jsonfilter -q -a -e "@[*]['handle']")
for handle in $handles; do
nft delete rule inet fw4 forward handle "$handle"
done

View File

@ -9,10 +9,10 @@ config_get_bool core_only "config" "core_only" 0
config_get_bool proxy_enabled "proxy" "enabled" 0
config_get tcp_mode "proxy" "tcp_mode"
config_get udp_mode "proxy" "udp_mode"
config_get tun_device "mixin" "tun_device"
if [ "$enabled" = 1 ] && [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
if [ "$tcp_mode" = "tun" ] || [ "$udp_mode" = "tun" ]; then
tun_device=$(yq -M '.tun.device' "$RUN_PROFILE_PATH")
nft insert rule inet fw4 input iifname "$tun_device" counter accept comment "nikki"
nft insert rule inet fw4 forward oifname "$tun_device" counter accept comment "nikki"
nft insert rule inet fw4 forward iifname "$tun_device" counter accept comment "nikki"

View File

@ -36,8 +36,6 @@ FIREWALL_INCLUDE_SH="$SH_DIR/firewall_include.sh"
# nftables
NFT_DIR="$HOME_DIR/nftables"
RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft"
RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft"
GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft"
GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft"

View File

@ -156,6 +156,35 @@ uci show nikki | grep -o -E 'nikki.@lan_access_control\[[[:digit:]]+\]=lan_acces
[ -z "$lan_access_control_dns" ] && uci set "$lan_access_control.dns=$lan_access_control_proxy"
done
# since v1.24.0
proxy_reserved_ip=$(uci -q get nikki.proxy.reserved_ip); [ -z "$proxy_reserved_ip" ] && {
uci add_list nikki.proxy.reserved_ip=0.0.0.0/8
uci add_list nikki.proxy.reserved_ip=10.0.0.0/8
uci add_list nikki.proxy.reserved_ip=127.0.0.0/8
uci add_list nikki.proxy.reserved_ip=100.64.0.0/10
uci add_list nikki.proxy.reserved_ip=169.254.0.0/16
uci add_list nikki.proxy.reserved_ip=172.16.0.0/12
uci add_list nikki.proxy.reserved_ip=192.168.0.0/16
uci add_list nikki.proxy.reserved_ip=224.0.0.0/4
uci add_list nikki.proxy.reserved_ip=240.0.0.0/4
}
proxy_reserved_ip6=$(uci -q get nikki.proxy.reserved_ip6); [ -z "$proxy_reserved_ip6" ] && {
uci add_list nikki.proxy.reserved_ip6=::/128
uci add_list nikki.proxy.reserved_ip6=::1/128
uci add_list nikki.proxy.reserved_ip6=::ffff:0:0/96
uci add_list nikki.proxy.reserved_ip6=100::/64
uci add_list nikki.proxy.reserved_ip6=64:ff9b::/96
uci add_list nikki.proxy.reserved_ip6=2001::/32
uci add_list nikki.proxy.reserved_ip6=2001:10::/28
uci add_list nikki.proxy.reserved_ip6=2001:20::/28
uci add_list nikki.proxy.reserved_ip6=2001:db8::/32
uci add_list nikki.proxy.reserved_ip6=2002::/16
uci add_list nikki.proxy.reserved_ip6=fc00::/7
uci add_list nikki.proxy.reserved_ip6=fe80::/10
uci add_list nikki.proxy.reserved_ip6=ff00::/8
}
# commit
uci commit nikki

View File

@ -5,7 +5,7 @@
import { cursor } from 'uci';
import { connect } from 'ubus';
import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups } from '/etc/nikki/ucode/include.uc';
import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups, load_profile } from '/etc/nikki/ucode/include.uc';
const cgroups_version = get_cgroups_version();
@ -16,16 +16,18 @@
const uci = cursor();
const ubus = connect();
uci.load('nikki');
const profile = load_profile();
const redir_port = uci.get('nikki', 'mixin', 'redir_port');
const tproxy_port = uci.get('nikki', 'mixin', 'tproxy_port');
const redir_port = profile['redir-port'];
const tproxy_port = profile['tproxy-port'];
const dns_listen = uci.get('nikki', 'mixin', 'dns_listen');
const dns_listen = profile['dns']['listen'];
const dns_port = substr(dns_listen, rindex(dns_listen, ':') + 1);
const fake_ip_range = uci.get('nikki', 'mixin', 'fake_ip_range');
const fake_ip_range = profile['dns']['fake-ip-range'];
const tun_device = uci.get('nikki', 'mixin', 'tun_device');
const tun_device = profile['tun']['device'];
uci.load('nikki');
const tcp_mode = uci.get('nikki', 'proxy', 'tcp_mode');
const udp_mode = uci.get('nikki', 'proxy', 'udp_mode');
@ -68,6 +70,8 @@
push(lan_access_control, access_control);
});
const reserved_ip = uci_array(uci.get('momo', 'proxy', 'reserved_ip'));
const reserved_ip6 = uci_array(uci.get('momo', 'proxy', 'reserved_ip6'));
const bypass_dscp = uci_array(uci.get('nikki', 'proxy', 'bypass_dscp'));
const bypass_china_mainland_ip = uci_bool(uci.get('nikki', 'proxy', 'bypass_china_mainland_ip'));
const proxy_tcp_dport = split((uci.get('nikki', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' ');
@ -128,12 +132,22 @@ table inet nikki {
type ipv4_addr
flags interval
auto-merge
{% if (length(reserved_ip) > 0): %}
elements = {
{{ join(', ', reserved_ip) }}
}
{% endif %}
}
set reserved_ip6 {
type ipv6_addr
flags interval
auto-merge
{% if (length(reserved_ip6) > 0): %}
elements = {
{{ join(', ', reserved_ip6) }}
}
{% endif %}
}
set lan_inbound_device {
@ -180,6 +194,7 @@ table inet nikki {
}
{% if (router_proxy): %}
{% if (length(dns_hijack_nfproto) > 0): %}
chain router_dns_hijack {
{% for (let access_control in router_access_control): %}
{% if (access_control['enabled']): %}
@ -205,7 +220,9 @@ table inet nikki {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'redirect'): %}
chain router_redirect {
{% for (let access_control in router_access_control): %}
{% if (access_control['enabled']): %}
@ -231,7 +248,9 @@ table inet nikki {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
chain router_tproxy {
{% for (let access_control in router_access_control): %}
{% if (access_control['enabled']): %}
@ -257,7 +276,9 @@ table inet nikki {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
chain router_tun {
{% for (let access_control in router_access_control): %}
{% if (access_control['enabled']): %}
@ -284,8 +305,10 @@ table inet nikki {
{% endfor %}
}
{% endif %}
{% endif %}
{% if (lan_proxy): %}
{% if (length(dns_hijack_nfproto) > 0): %}
chain lan_dns_hijack {
{% for (let access_control in lan_access_control): %}
{% if (access_control['enabled']): %}
@ -309,7 +332,9 @@ table inet nikki {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'redirect'): %}
chain lan_redirect {
{% for (let access_control in lan_access_control): %}
{% if (access_control['enabled']): %}
@ -333,7 +358,9 @@ table inet nikki {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
chain lan_tproxy {
{% for (let access_control in lan_access_control): %}
{% if (access_control['enabled']): %}
@ -357,7 +384,9 @@ table inet nikki {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
chain lan_tun {
{% for (let access_control in lan_access_control): %}
{% if (access_control['enabled']): %}
@ -382,6 +411,7 @@ table inet nikki {
{% endfor %}
}
{% endif %}
{% endif %}
{% if (router_proxy): %}
chain nat_output {
@ -399,14 +429,16 @@ table inet nikki {
ip6 daddr @reserved_ip6 counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
meta nfproto @proxy_nfproto jump router_redirect
{% endif %}
{% if (fake_ip_ping_hijack): %}
ip protocol icmp icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
{% if (fake_ip_range ): %}
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
{% endif %}
{% endif %}
}
@ -423,9 +455,9 @@ table inet nikki {
ip6 daddr @reserved_ip6 counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
{% if (tcp_mode == 'tproxy'): %}
@ -462,14 +494,16 @@ table inet nikki {
ip6 daddr @reserved_ip6 counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
iifname @lan_inbound_device meta nfproto @proxy_nfproto jump lan_redirect
{% endif %}
{% if (fake_ip_ping_hijack): %}
ip protocol icmp icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
{% if (fake_ip_range): %}
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
{% endif %}
{% endif %}
}
@ -481,9 +515,9 @@ table inet nikki {
ip6 daddr @reserved_ip6 counter return
ip daddr @china_ip counter return
ip6 daddr @china_ip6 counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} counter return
meta nfproto ipv4 meta l4proto . th dport != @proxy_dport {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta nfproto ipv6 meta l4proto . th dport != @proxy_dport counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp ip daddr != {{ fake_ip_range }} counter return
meta l4proto { tcp, udp } ip dscp @bypass_dscp {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
{% if (tcp_mode == 'tproxy'): %}
@ -500,9 +534,6 @@ table inet nikki {
{% endif %}
}
include "/etc/nikki/nftables/reserved_ip.nft"
include "/etc/nikki/nftables/reserved_ip6.nft"
{% if (bypass_china_mainland_ip): %}
include "/etc/nikki/nftables/geoip_cn.nft"
include "/etc/nikki/nftables/geoip6_cn.nft"

View File

@ -75,3 +75,13 @@ export function get_cgroups() {
}
return result;
};
export function load_profile() {
let result = {};
const process = popen('yq -M -p yaml -o json /etc/nikki/run/config.yaml');
if (process) {
result = json(process);
process.close();
}
return result;
};

View File

@ -51,26 +51,24 @@ if (uci_bool(uci.get('nikki', 'mixin', 'authentication'))) {
}
config['tun'] = {};
if (uci.get('nikki', 'proxy', 'tcp_mode') == 'tun' || uci.get('nikki', 'proxy', 'udp_mode') == 'tun') {
config['tun']['enable'] = true;
config['tun']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'tun_enabled'));
config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device');
config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack');
config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu'));
config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso'));
config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size'));
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'));
}
if (uci_bool(uci.get('nikki', 'proxy', 'enabled'))) {
config['tun']['auto-route'] = false;
config['tun']['auto-redirect'] = false;
config['tun']['auto-detect-interface'] = false;
config['tun']['device'] = uci.get('nikki', 'mixin', 'tun_device');
config['tun']['stack'] = uci.get('nikki', 'mixin', 'tun_stack');
config['tun']['mtu'] = uci_int(uci.get('nikki', 'mixin', 'tun_mtu'));
config['tun']['gso'] = uci_bool(uci.get('nikki', 'mixin', 'tun_gso'));
config['tun']['gso-max-size'] = uci_int(uci.get('nikki', 'mixin', 'tun_gso_max_size'));
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']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'dns_enabled'));
config['dns']['listen'] = uci.get('nikki', 'mixin', 'dns_listen');
config['dns']['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'dns_ipv6'));
config['dns']['enhanced-mode'] = uci.get('nikki', 'mixin', 'dns_mode');