nikki: sync upstream

last commit: 17234645ba
This commit is contained in:
gitea-action 2025-02-23 17:00:29 +08:00
parent 0c96443ce3
commit 4d12f9dece
10 changed files with 731 additions and 724 deletions

View File

@ -1,13 +1,13 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=nikki PKG_NAME:=nikki
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
PKG_SOURCE_DATE:=2025-02-19 PKG_SOURCE_DATE:=2025-02-21
PKG_SOURCE_VERSION:=e2b75b35bbfd3be61b2b5a37142442bb259f99e4 PKG_SOURCE_VERSION:=5830afcbdeeb6c05a3faa56d33353282b8d1f50c
PKG_MIRROR_HASH:=1d377f3087e5109353c78d738424fa3e88e1dfe30a0c9eddcdafc12fabbcf839 PKG_MIRROR_HASH:=3f5c8aaad3959f77ab3099e0a3d76ca7329e073e1f877720b7c42360c66954c9
PKG_LICENSE:=GPL3.0+ PKG_LICENSE:=GPL3.0+
PKG_MAINTAINER:=Joseph Mory <morytyann@gmail.com> PKG_MAINTAINER:=Joseph Mory <morytyann@gmail.com>
@ -16,7 +16,7 @@ PKG_BUILD_DEPENDS:=golang/host
PKG_BUILD_PARALLEL:=1 PKG_BUILD_PARALLEL:=1
PKG_BUILD_FLAGS:=no-mips16 PKG_BUILD_FLAGS:=no-mips16
PKG_BUILD_VERSION:=alpha-e2b75b3 PKG_BUILD_VERSION:=alpha-5830afc
PKG_BUILD_TIME:=$(shell date -u -Iseconds) PKG_BUILD_TIME:=$(shell date -u -Iseconds)
GO_PKG:=github.com/metacubex/mihomo GO_PKG:=github.com/metacubex/mihomo
@ -51,6 +51,7 @@ define Package/nikki/install
$(call GoPackage/Package/Install/Bin,$(1)) $(call GoPackage/Package/Install/Bin,$(1))
$(INSTALL_DIR) $(1)/etc/nikki $(INSTALL_DIR) $(1)/etc/nikki
$(INSTALL_DIR) $(1)/etc/nikki/ucode
$(INSTALL_DIR) $(1)/etc/nikki/scripts $(INSTALL_DIR) $(1)/etc/nikki/scripts
$(INSTALL_DIR) $(1)/etc/nikki/nftables $(INSTALL_DIR) $(1)/etc/nikki/nftables
$(INSTALL_DIR) $(1)/etc/nikki/profiles $(INSTALL_DIR) $(1)/etc/nikki/profiles
@ -59,14 +60,17 @@ define Package/nikki/install
$(INSTALL_DIR) $(1)/etc/nikki/run/providers $(INSTALL_DIR) $(1)/etc/nikki/run/providers
$(INSTALL_DIR) $(1)/etc/nikki/run/providers/rule $(INSTALL_DIR) $(1)/etc/nikki/run/providers/rule
$(INSTALL_DIR) $(1)/etc/nikki/run/providers/proxy $(INSTALL_DIR) $(1)/etc/nikki/run/providers/proxy
$(INSTALL_DIR) $(1)/etc/nikki/run/ui
$(INSTALL_DATA) $(CURDIR)/files/mixin.yaml $(1)/etc/nikki/mixin.yaml $(INSTALL_DATA) $(CURDIR)/files/mixin.yaml $(1)/etc/nikki/mixin.yaml
$(INSTALL_BIN) $(CURDIR)/files/ucode/include.uc $(1)/etc/nikki/ucode/include.uc
$(INSTALL_BIN) $(CURDIR)/files/ucode/mixin.uc $(1)/etc/nikki/ucode/mixin.uc
$(INSTALL_BIN) $(CURDIR)/files/ucode/hijack.ut $(1)/etc/nikki/ucode/hijack.ut
$(INSTALL_BIN) $(CURDIR)/files/scripts/include.sh $(1)/etc/nikki/scripts/include.sh $(INSTALL_BIN) $(CURDIR)/files/scripts/include.sh $(1)/etc/nikki/scripts/include.sh
$(INSTALL_BIN) $(CURDIR)/files/scripts/firewall_include.sh $(1)/etc/nikki/scripts/firewall_include.sh $(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/hijack.nft $(1)/etc/nikki/nftables/hijack.nft
$(INSTALL_BIN) $(CURDIR)/files/nftables/reserved_ip.nft $(1)/etc/nikki/nftables/reserved_ip.nft $(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/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/geoip_cn.nft $(1)/etc/nikki/nftables/geoip_cn.nft

View File

@ -1,243 +0,0 @@
#!/usr/sbin/nft -f
table inet nikki {
set bypass_user {
type uid
flags interval
auto-merge
}
set bypass_group {
type gid
flags interval
auto-merge
elements = {
$NIKKI_GROUP
}
}
set bypass_dscp {
type dscp
flags interval
}
set dns_hijack_nfproto {
type nf_proto
flags interval
}
set proxy_nfproto {
type nf_proto
flags interval
}
set china_ip {
type ipv4_addr
flags interval
}
set china_ip6 {
type ipv6_addr
flags interval
}
set reserved_ip {
type ipv4_addr
flags interval
auto-merge
}
set reserved_ip6 {
type ipv6_addr
flags interval
auto-merge
}
set proxy_dport {
type inet_proto . inet_service
flags interval
auto-merge
}
set acl_ip {
type ipv4_addr
flags interval
auto-merge
}
set acl_ip6 {
type ipv6_addr
flags interval
auto-merge
}
set acl_mac {
type ether_addr
flags interval
auto-merge
}
set acl_interface {
type ifname
flags interval
auto-merge
}
chain router_dns_hijack {
meta skuid @bypass_user counter return
meta skgid @bypass_group counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter redirect to :$DNS_PORT
}
chain all_dns_hijack {
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter redirect to :$DNS_PORT
}
chain allow_dns_hijack {
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 ip saddr @acl_ip counter redirect to :$DNS_PORT
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 ip6 saddr @acl_ip6 counter redirect to :$DNS_PORT
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 ether saddr @acl_mac counter redirect to :$DNS_PORT
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 iifname @acl_interface counter redirect to :$DNS_PORT
}
chain block_dns_hijack {
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 ip saddr @acl_ip counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 ip6 saddr @acl_ip6 counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 ether saddr @acl_mac counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 iifname @acl_interface counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter redirect to :$DNS_PORT
}
chain router_redirect {
meta nfproto @proxy_nfproto meta l4proto tcp counter redirect to :$REDIR_PORT
}
chain all_redirect {
meta nfproto @proxy_nfproto meta l4proto tcp counter redirect to :$REDIR_PORT
}
chain allow_redirect {
meta nfproto @proxy_nfproto meta l4proto tcp ip saddr @acl_ip counter redirect to :$REDIR_PORT
meta nfproto @proxy_nfproto meta l4proto tcp ip6 saddr @acl_ip6 counter redirect to :$REDIR_PORT
meta nfproto @proxy_nfproto meta l4proto tcp ether saddr @acl_mac counter redirect to :$REDIR_PORT
meta nfproto @proxy_nfproto meta l4proto tcp iifname @acl_interface counter redirect to :$REDIR_PORT
}
chain block_redirect {
meta nfproto @proxy_nfproto meta l4proto tcp ip saddr @acl_ip counter return
meta nfproto @proxy_nfproto meta l4proto tcp ip6 saddr @acl_ip6 counter return
meta nfproto @proxy_nfproto meta l4proto tcp ether saddr @acl_mac counter return
meta nfproto @proxy_nfproto meta l4proto tcp iifname @acl_interface counter return
meta nfproto @proxy_nfproto meta l4proto tcp counter redirect to :$REDIR_PORT
}
chain router_tproxy {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK counter
}
chain all_tproxy {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK tproxy to :$TPROXY_PORT counter accept
}
chain allow_tproxy {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip saddr @acl_ip meta mark set mark ^ $FW_MARK tproxy ip to :$TPROXY_PORT counter accept
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip6 saddr @acl_ip6 meta mark set mark ^ $FW_MARK tproxy ip6 to :$TPROXY_PORT counter accept
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ether saddr @acl_mac meta mark set mark ^ $FW_MARK tproxy to :$TPROXY_PORT counter accept
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } iifname @acl_interface meta mark set mark ^ $FW_MARK tproxy to :$TPROXY_PORT counter accept
}
chain block_tproxy {
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 } iifname @acl_interface counter return
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK tproxy to :$TPROXY_PORT counter accept
}
chain router_tun {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK counter
}
chain all_tun {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK counter
}
chain allow_tun {
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip saddr @acl_ip meta mark set mark ^ $FW_MARK counter
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ip6 saddr @acl_ip6 meta mark set mark ^ $FW_MARK counter
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } ether saddr @acl_mac meta mark set mark ^ $FW_MARK counter
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } iifname @acl_interface meta mark set mark ^ $FW_MARK counter
}
chain block_tun {
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 } iifname @acl_interface counter return
meta nfproto @proxy_nfproto meta l4proto { tcp, udp } meta mark set mark ^ $FW_MARK counter
}
chain dstnat {
type nat hook prerouting priority dstnat + 1; policy accept;
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != $FAKE_IP 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 counter return
meta l4proto { tcp, udp } ip6 dscp == @bypass_dscp counter return
}
chain nat_output {
type nat hook output priority filter; policy accept;
meta skuid @bypass_user counter return
meta skgid @bypass_group counter return
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != $FAKE_IP 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 counter return
meta l4proto { tcp, udp } ip6 dscp == @bypass_dscp counter return
}
chain mangle_prerouting {
type filter hook prerouting priority mangle; policy accept;
meta l4proto { tcp, udp } iifname lo meta mark & $FW_MARK_MASK == $FW_MARK tproxy to :$TPROXY_PORT counter accept
meta l4proto { tcp, udp } iifname $TUN_DEVICE counter accept
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != $FAKE_IP 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 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
}
chain mangle_output {
type route hook output priority mangle; policy accept;
meta skuid @bypass_user counter return
meta skgid @bypass_group counter return
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != $FAKE_IP 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 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
}
}

View File

@ -59,6 +59,7 @@ config mixin 'mixin'
option 'tcp_concurrent' '1' option 'tcp_concurrent' '1'
option 'tcp_keep_alive_idle' '600' option 'tcp_keep_alive_idle' '600'
option 'tcp_keep_alive_interval' '15' option 'tcp_keep_alive_interval' '15'
option 'ui_path' 'ui'
option 'ui_name' '' option 'ui_name' ''
option 'ui_url' 'https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip' option 'ui_url' 'https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip'
option 'api_port' '9090' option 'api_port' '9090'

View File

@ -51,88 +51,7 @@ start_service() {
config_get_bool mixin "config" "mixin" 0 config_get_bool mixin "config" "mixin" 0
config_get_bool test_profile "config" "test_profile" 0 config_get_bool test_profile "config" "test_profile" 0
config_get_bool fast_reload "config" "fast_reload" 0 config_get_bool fast_reload "config" "fast_reload" 0
## proxy config
### transparent proxy
local tcp_transparent_proxy_mode udp_transparent_proxy_mode
config_get_bool transparent_proxy "proxy" "transparent_proxy" 0
config_get tcp_transparent_proxy_mode "proxy" "tcp_transparent_proxy_mode" "tproxy"
config_get udp_transparent_proxy_mode "proxy" "udp_transparent_proxy_mode" "tproxy"
## mixin config ## mixin config
### general
local mode match_process outbound_interface ipv6 unify_delay tcp_concurrent 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_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"
config_get ui_url "mixin" "ui_url"
config_get api_port "mixin" "api_port" "9090"
config_get api_secret "mixin" "api_secret" "666666"
config_get_bool selection_cache "mixin" "selection_cache" 0
### inbound
local allow_lan http_port socks_port mixed_port redir_port tproxy_port authentication
config_get_bool allow_lan "mixin" "allow_lan" 0
config_get http_port "mixin" "http_port" "8080"
config_get socks_port "mixin" "socks_port" "1080"
config_get mixed_port "mixin" "mixed_port" "7890"
config_get redir_port "mixin" "redir_port" "7891"
config_get tproxy_port "mixin" "tproxy_port" "7892"
config_get_bool authentication "mixin" "authentication" 0
### tun
local tun_device tun_stack tun_mtu tun_gso tun_gso_max_size tun_dns_hijack tun_endpoint_independent_nat
config_get tun_device "mixin" "tun_device" "nikki"
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_dns_hijack "mixin" "tun_dns_hijack" 0
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_filter_mode fake_ip_cache dns_respect_rules dns_doh_prefer_http3 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" "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_doh_prefer_http3 "mixin" "dns_doh_prefer_http3" 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_nameserver_policy "mixin" "dns_nameserver_policy" 0
### sniffer
local sniffer sniffer_sniff_dns_mapping sniffer_sniff_pure_ip sniffer_overwrite_destination sniffer_force_domain_name sniffer_ignore_domain_name sniffer_sniff
config_get_bool sniffer "mixin" sniffer 0
config_get_bool sniffer_sniff_dns_mapping "mixin" sniffer_sniff_dns_mapping 0
config_get_bool sniffer_sniff_pure_ip "mixin" sniffer_sniff_pure_ip 0
config_get_bool sniffer_overwrite_destination "mixin" sniffer_overwrite_destination 0
config_get_bool sniffer_force_domain_name "mixin" sniffer_force_domain_name 0
config_get_bool sniffer_ignore_domain_name "mixin" sniffer_ignore_domain_name 0
config_get_bool sniffer_sniff "mixin" sniffer_sniff 0
### rule
local rule rule_provider
config_get_bool rule "mixin" "rule" 0
config_get_bool rule_provider "mixin" "rule_provider" 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" "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"
### mixin file content ### mixin file content
local mixin_file_content local mixin_file_content
config_get_bool mixin_file_content "mixin" "mixin_file_content" 0 config_get_bool mixin_file_content "mixin" "mixin_file_content" 0
@ -142,15 +61,6 @@ start_service() {
config_get_bool disable_loopback_detector "env" "disable_loopback_detector" 0 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_gso "env" "disable_quic_go_gso" 0
config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0 config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0
# 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 # get profile
if [[ "$profile" == "file:"* ]]; then if [[ "$profile" == "file:"* ]]; then
local profile_name; profile_name=$(basename "${profile/file:/}") local profile_name; profile_name=$(basename "${profile/file:/}")
@ -187,104 +97,16 @@ start_service() {
if [ "$mixin" == 0 ]; then if [ "$mixin" == 0 ]; then
log "Mixin" "Disabled." log "Mixin" "Disabled."
log "Mixin" "Mixin neccesary config." log "Mixin" "Mixin neccesary config."
# do mixin
log_level="$log_level" mode="$mode" match_process="$match_process" 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" \
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_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" \
yq -M -i '
.log-level = strenv(log_level) | .mode = strenv(mode) | .find-process-mode = strenv(match_process) | .ipv6 = env(ipv6) == 1 |
.external-ui = strenv(ui_path) | .external-ui-name = strenv(ui_name) | .external-ui-url = strenv(ui_url) | .external-controller = strenv(api_listen) | .secret = strenv(api_secret) |
.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.enable = env(tun_enable) == 1 | .tun.stack = strenv(tun_stack) | .tun.device = strenv(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.auto-route = false | .tun.auto-redirect = false | .tun.auto-detect-interface = false |
.dns.enable = env(dns_enable) | .dns.listen = strenv(dns_listen) | .dns.enhanced-mode = strenv(dns_mode) | .dns.fake-ip-range = strenv(fake_ip_range)
' "$RUN_PROFILE_PATH"
else else
log "Mixin" "Enabled." log "Mixin" "Enabled."
log "Mixin" "Mixin all config." log "Mixin" "Mixin all config."
# do mixin
log_level="$log_level" mode="$mode" match_process="$match_process" ipv6="$ipv6" unify_delay="$unify_delay" tcp_concurrent="$tcp_concurrent" tcp_keep_alive_idle="$tcp_keep_alive_idle" tcp_keep_alive_interval="$tcp_keep_alive_interval" \
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_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_respect_rules="$dns_respect_rules" dns_doh_prefer_http3="$dns_doh_prefer_http3" dns_ipv6="$dns_ipv6" dns_system_hosts="$dns_system_hosts" dns_hosts="$dns_hosts" \
sniffer="$sniffer" sniffer_sniff_dns_mapping="$sniffer_sniff_dns_mapping" sniffer_sniff_pure_ip="$sniffer_sniff_pure_ip" sniffer_overwrite_destination="$sniffer_overwrite_destination" \
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 = strenv(log_level) | .mode = strenv(mode) | .find-process-mode = strenv(match_process) | .ipv6 = env(ipv6) == 1 | .unified-delay = env(unify_delay) == 1 | .tcp-concurrent = env(tcp_concurrent) == 1 | .keep-alive-idle = env(tcp_keep_alive_idle) | .keep-alive-interval = env(tcp_keep_alive_interval) |
.external-ui = strenv(ui_path) | .external-ui-name = strenv(ui_name) | .external-ui-url = strenv(ui_url) | .external-controller = strenv(api_listen) | .secret = strenv(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.enable = env(tun_enable) == 1 | .tun.stack = strenv(tun_stack) | .tun.device = strenv(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.auto-route = false | .tun.auto-redirect = false | .tun.auto-detect-interface = false |
.dns.enable = env(dns_enable) | .dns.listen = strenv(dns_listen) | .dns.enhanced-mode = strenv(dns_mode) | .dns.fake-ip-range = strenv(fake_ip_range) | .profile.store-fake-ip = env(fake_ip_cache) == 1 |
.dns.respect-rules = env(dns_respect_rules) == 1 | .dns.prefer-h3 = env(dns_doh_prefer_http3) == 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(sniffer_sniff_dns_mapping) == 1 | .sniffer.parse-pure-ip = env(sniffer_sniff_pure_ip) == 1 | .sniffer.override-destination = env(sniffer_overwrite_destination) == 1 |
.geodata-mode = strenv(geoip_format) == "dat" | .geodata-loader = strenv(geodata_loader) | .geox-url.geosite = strenv(geosite_url) | .geox-url.mmdb = strenv(geoip_mmdb_url) | .geox-url.geoip = strenv(geoip_dat_url) | .geox-url.asn = strenv(geoip_asn_url) |
.geo-auto-update = env(geox_auto_update) == 1 | .geo-update-interval = env(geox_update_interval)
' "$RUN_PROFILE_PATH"
if [ "$fake_ip_filter" == 1 ]; then
fake_ip_filter_mode="$fake_ip_filter_mode" \
yq -M -i 'del(.dns.fake-ip-filter) | .dns.fake-ip-filter-mode = strenv(fake_ip_filter_mode)' "$RUN_PROFILE_PATH"
config_list_foreach "mixin" "fake_ip_filters" mixin_fake_ip_filters
fi
if [ "$hosts" == 1 ]; then
yq -M -i 'del(.hosts)' "$RUN_PROFILE_PATH"
config_foreach mixin_hosts "hosts"
fi
if [ "$dns_nameserver" == 1 ]; then
yq -M -i 'del(.dns.default-nameserver) | del(.dns.proxy-server-nameserver) | del(.dns.direct-nameserver) | del(.dns.nameserver) | del(.dns.fallback)' "$RUN_PROFILE_PATH"
config_foreach mixin_nameservers "nameserver"
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_force_domain_name" == 1 ]; then
yq -M -i 'del(.sniffer.force-domain)' "$RUN_PROFILE_PATH"
config_list_foreach "mixin" "sniffer_force_domain_names" mixin_sniffer_domain_names "force-domain"
fi
if [ "$sniffer_ignore_domain_name" == 1 ]; then
yq -M -i 'del(.sniffer.skip-domain)' "$RUN_PROFILE_PATH"
config_list_foreach "mixin" "sniffer_ignore_domain_names" mixin_sniffer_domain_names "skip-domain"
fi
if [ "$sniffer_sniff" == 1 ]; then
yq -M -i 'del(.sniffer.sniff)' "$RUN_PROFILE_PATH"
config_foreach mixin_sniffs "sniff"
fi
fi
yq -M -i 'del (.bind-address)' "$RUN_PROFILE_PATH"
if [ -n "$outbound_interface" ]; then
local outbound_device; network_get_device outbound_device "$outbound_interface"
if [ -n "$outbound_device" ]; then
outbound_device="$outbound_device" yq -M -i '.interface-name = strenv(outbound_device)' "$RUN_PROFILE_PATH"
fi
fi
if [ "$authentication" == 1 ]; then
yq -M -i 'del(.authentication)' "$RUN_PROFILE_PATH"
config_foreach mixin_authentications "authentication"
fi
if [ "$tun_dns_hijack" == 1 ]; then
yq -M -i 'del(.tun.dns-hijack)' "$RUN_PROFILE_PATH"
config_list_foreach "mixin" "tun_dns_hijacks" mixin_tun_dns_hijacks
fi
if [ "$rule_provider" == 1 ]; then
config_foreach mixin_rule_providers "rule_provider"
fi
if [ "$rule" == 1 ]; then
yq -M -i 'del(.nikki-rules)' "$RUN_PROFILE_PATH"
config_foreach mixin_rules "rule"
yq -M -i '.rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH"
fi
if [ "$mixin_file_content" == 1 ]; then
if [ -s "$MIXIN_FILE_PATH" ]; then
yq -M -i ea '. as $item ireduce ({}; . * $item ) | ... comments=""' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH"
fi fi
if [ "$mixin_file_content" == 0 ]; then
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '. as $item ireduce ({}; . * $item ) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" -
elif [ "$mixin_file_content" == 1 ]; then
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '. as $item ireduce ({}; . * $item ) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" -
fi fi
yq -M -i '... comments=""' "$RUN_PROFILE_PATH"
# test profile # test profile
if [ "$test_profile" == 1 ]; then if [ "$test_profile" == 1 ]; then
log "Profile" "Testing..." log "Profile" "Testing..."
@ -339,17 +161,7 @@ service_started() {
return return
fi fi
# get config # get config
### inbound ## mixin
local http_port socks_port mixed_port redir_port tproxy_port
config_get http_port "mixin" "http_port" "8080"
config_get socks_port "mixin" "socks_port" "1080"
config_get mixed_port "mixin" "mixed_port" "7890"
config_get redir_port "mixin" "redir_port" "7891"
config_get tproxy_port "mixin" "tproxy_port" "7892"
### dns
local dns_port fake_ip_range
config_get dns_port "mixin" "dns_port" "1053"
config_get fake_ip_range "mixin" "fake_ip_range" "198.18.0.1/16"
### tun ### tun
local tun_device local tun_device
config_get tun_device "mixin" "tun_device" "nikki" config_get tun_device "mixin" "tun_device" "nikki"
@ -365,8 +177,12 @@ service_started() {
config_get_bool router_proxy "proxy" "router_proxy" 0 config_get_bool router_proxy "proxy" "router_proxy" 0
config_get_bool lan_proxy "proxy" "lan_proxy" 0 config_get_bool lan_proxy "proxy" "lan_proxy" 0
### access control ### access control
local access_control_mode bypass_china_mainland_ip proxy_tcp_dport proxy_udp_dport bypass_dscp local access_control_mode
config_get access_control_mode "proxy" "access_control_mode" config_get access_control_mode "proxy" "access_control_mode"
### bypass
local bypass_user bypass_group bypass_china_mainland_ip proxy_tcp_dport proxy_udp_dport bypass_dscp
config_get bypass_user "proxy" "bypass_user"
config_get bypass_group "proxy" "bypass_group"
config_get_bool bypass_china_mainland_ip "proxy" "bypass_china_mainland_ip" 0 config_get_bool bypass_china_mainland_ip "proxy" "bypass_china_mainland_ip" 0
config_get proxy_tcp_dport "proxy" "proxy_tcp_dport" "0-65535" config_get proxy_tcp_dport "proxy" "proxy_tcp_dport" "0-65535"
config_get proxy_udp_dport "proxy" "proxy_udp_dport" "0-65535" config_get proxy_udp_dport "proxy" "proxy_udp_dport" "0-65535"
@ -409,72 +225,48 @@ service_started() {
if [ "$tproxy_enable" == 1 ]; then if [ "$tproxy_enable" == 1 ]; then
if [ "$ipv4_proxy" == 1 ]; then if [ "$ipv4_proxy" == 1 ]; then
ip -4 route add local default dev lo table "$TPROXY_ROUTE_TABLE" ip -4 route add local default dev lo table "$TPROXY_ROUTE_TABLE"
ip -4 rule add pref "$TPROXY_RULE_PREF" fwmark "$TPROXY_FW_MARK" table "$TPROXY_ROUTE_TABLE"
fi fi
if [ "$ipv6_proxy" == 1 ]; then if [ "$ipv6_proxy" == 1 ]; then
ip -6 route add local default dev lo table "$TPROXY_ROUTE_TABLE" ip -6 route add local default dev lo table "$TPROXY_ROUTE_TABLE"
ip -4 rule add pref "$TPROXY_RULE_PREF" fwmark "$TPROXY_FW_MARK" table "$TPROXY_ROUTE_TABLE"
fi fi
fi fi
if [ "$tun_enable" == 1 ]; then if [ "$tun_enable" == 1 ]; then
if [ "$ipv4_proxy" == 1 ]; then if [ "$ipv4_proxy" == 1 ]; then
ip -4 route add unicast default dev "$tun_device" table "$TUN_ROUTE_TABLE" ip -4 route add unicast default dev "$tun_device" table "$TUN_ROUTE_TABLE"
ip -4 rule add pref "$TUN_RULE_PREF" fwmark "$TUN_FW_MARK" table "$TUN_ROUTE_TABLE"
fi fi
if [ "$ipv6_proxy" == 1 ]; then if [ "$ipv6_proxy" == 1 ]; then
ip -6 route add unicast default dev "$tun_device" table "$TUN_ROUTE_TABLE" ip -6 route add unicast default dev "$tun_device" table "$TUN_ROUTE_TABLE"
ip -4 rule add pref "$TUN_RULE_PREF" fwmark "$TUN_FW_MARK" table "$TUN_ROUTE_TABLE"
fi fi
$FIREWALL_INCLUDE_SH $FIREWALL_INCLUDE_SH
fi fi
local tcp_route_table utpl -D nikki_group="$NIKKI_GROUP" -D tproxy_fw_mark="$TPROXY_FW_MARK" -D tun_fw_mark="$TUN_FW_MARK" -S "$HIJACK_UT" | nft -f -
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 -4 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 rule add pref "$TCP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto tcp table "$tcp_route_table"
fi
fi
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 -4 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 NIKKI_GROUP="$NIKKI_GROUP" -D FW_MARK="$FW_MARK" -D FW_MARK_MASK="$FW_MARK_MASK" -D TUN_DEVICE="$tun_device" -D FAKE_IP="$fake_ip_range" -D DNS_PORT="$dns_port" -D REDIR_PORT="$redir_port" -D TPROXY_PORT="$tproxy_port"
nft -f "$RESERVED_IP_NFT" nft -f "$RESERVED_IP_NFT"
nft -f "$RESERVED_IP6_NFT" nft -f "$RESERVED_IP6_NFT"
# dns hijack # dns hijack
if [ "$ipv4_dns_hijack" == 1 ]; then if [ "$ipv4_dns_hijack" == 1 ]; then
log "Transparent Proxy" "Hijack IPv4 dns request." log "Transparent Proxy" "Hijack IPv4 dns request."
nft add element inet "$FW_TABLE" dns_hijack_nfproto \{ ipv4 \}
fi fi
if [ "$ipv6_dns_hijack" == 1 ]; then if [ "$ipv6_dns_hijack" == 1 ]; then
log "Transparent Proxy" "Hijack IPv6 dns request." log "Transparent Proxy" "Hijack IPv6 dns request."
nft add element inet "$FW_TABLE" dns_hijack_nfproto \{ ipv6 \}
fi fi
# proxy # proxy
if [ "$ipv4_proxy" == 1 ]; then if [ "$ipv4_proxy" == 1 ]; then
log "Transparent Proxy" "Proxy IPv4 traffic." log "Transparent Proxy" "Proxy IPv4 traffic."
nft add element inet "$FW_TABLE" proxy_nfproto \{ ipv4 \}
fi fi
if [ "$ipv6_proxy" == 1 ]; then if [ "$ipv6_proxy" == 1 ]; then
log "Transparent Proxy" "Proxy IPv6 traffic." log "Transparent Proxy" "Proxy IPv6 traffic."
nft add element inet "$FW_TABLE" proxy_nfproto \{ ipv6 \}
fi fi
# bypass # bypass
config_list_foreach "proxy" "bypass_user" add_bypass_user if [ -n "$bypass_user" ]; then
config_list_foreach "proxy" "bypass_group" add_bypass_group log "Transparent Proxy" "Bypass user: $bypass_user."
fi
if [ -n "$bypass_group" ]; then
log "Transparent Proxy" "Bypass group: $bypass_group."
fi
if [ "$bypass_china_mainland_ip" == 1 ]; then if [ "$bypass_china_mainland_ip" == 1 ]; then
log "Transparent Proxy" "Bypass china mainland ip." log "Transparent Proxy" "Bypass china mainland ip."
if [ "$ipv4_proxy" == 1 ]; then if [ "$ipv4_proxy" == 1 ]; then
@ -486,32 +278,12 @@ service_started() {
fi fi
log "Transparent Proxy" "Destination TCP Port to Proxy: $proxy_tcp_dport." log "Transparent Proxy" "Destination TCP Port to Proxy: $proxy_tcp_dport."
log "Transparent Proxy" "Destination UDP Port to Proxy: $proxy_udp_dport." log "Transparent Proxy" "Destination UDP Port to Proxy: $proxy_udp_dport."
local proxy_dport
for proxy_dport in $proxy_tcp_dport; do
nft add element inet "$FW_TABLE" proxy_dport \{ "tcp" . "$proxy_dport" \}
done
for proxy_dport in $proxy_udp_dport; do
nft add element inet "$FW_TABLE" proxy_dport \{ "udp" . "$proxy_dport" \}
done
if [ -n "$bypass_dscp" ]; then if [ -n "$bypass_dscp" ]; then
log "Transparent Proxy" "Bypass DSCP: $bypass_dscp." log "Transparent Proxy" "Bypass DSCP: $bypass_dscp."
local dscp
for dscp in $bypass_dscp; do
nft add element inet "$FW_TABLE" bypass_dscp \{ "$dscp" \}
done
fi fi
# router proxy # router proxy
if [ "$router_proxy" == 1 ]; then if [ "$router_proxy" == 1 ]; then
log "Transparent Proxy" "Set proxy for router." log "Transparent Proxy" "Set proxy for router."
if [ "$tcp_transparent_proxy_mode" == "redirect" ]; then
nft insert rule inet "$FW_TABLE" nat_output jump router_dns_hijack
nft add rule inet "$FW_TABLE" nat_output meta l4proto tcp jump "router_${tcp_transparent_proxy_mode}"
else
nft flush chain inet "$FW_TABLE" nat_output
nft add rule inet "$FW_TABLE" nat_output jump router_dns_hijack
nft add rule inet "$FW_TABLE" mangle_output meta l4proto tcp jump "router_${tcp_transparent_proxy_mode}"
fi
nft add rule inet "$FW_TABLE" mangle_output meta l4proto udp jump "router_${udp_transparent_proxy_mode}"
fi fi
# lan proxy # lan proxy
if [ "$lan_proxy" == 1 ]; then if [ "$lan_proxy" == 1 ]; then
@ -524,19 +296,6 @@ service_started() {
elif [ "$access_control_mode" == "block" ]; then elif [ "$access_control_mode" == "block" ]; then
log "Transparent Proxy" "Access Control is using block mode, set proxy for client which is not in acl." log "Transparent Proxy" "Access Control is using block mode, set proxy for client which is not in acl."
fi fi
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
config_list_foreach "proxy" "acl_interface" add_acl_interface
if [ "$tcp_transparent_proxy_mode" == "redirect" ]; then
nft insert rule inet "$FW_TABLE" dstnat jump "${access_control_mode}_dns_hijack"
nft add rule inet "$FW_TABLE" dstnat meta l4proto tcp jump "${access_control_mode}_${tcp_transparent_proxy_mode}"
else
nft flush chain inet "$FW_TABLE" dstnat
nft add rule inet "$FW_TABLE" dstnat jump "${access_control_mode}_dns_hijack"
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
# fix compatible between tproxy and dockerd (kmod-br-netfilter) # fix compatible between tproxy and dockerd (kmod-br-netfilter)
if [ "$tproxy_enable" == 1 ] && (lsmod | grep -q br_netfilter); then if [ "$tproxy_enable" == 1 ] && (lsmod | grep -q br_netfilter); then
@ -574,21 +333,17 @@ cleanup() {
# clear log # clear log
clear_log clear_log
# delete routing policy # delete routing policy
ip -4 rule del ipproto tcp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip -4 rule del table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -4 rule del ipproto udp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip -4 rule del table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
ip -4 rule del ipproto tcp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -6 rule del table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -4 rule del ipproto udp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -6 rule del 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 # delete routing table
ip -4 route flush table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip -4 route flush table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -4 route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -4 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 "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1
ip -6 route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -6 route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1
# delete hijack # delete hijack
nft delete table inet "$FW_TABLE" > /dev/null 2>&1 nft delete table inet nikki > /dev/null 2>&1
local handles handle 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 | yq -M '.nftables[] | select(has("rule")) | .rule | select(.chain == "input" and .comment == "nikki") | .handle')
for handle in $handles; do for handle in $handles; do
@ -614,201 +369,6 @@ cleanup() {
/etc/init.d/cron restart /etc/init.d/cron restart
} }
mixin_authentications() {
local section="$1"
local enabled username password
config_get_bool enabled "$section" "enabled" 0
config_get username "$section" "username"
config_get password "$section" "password"
if [ "$enabled" == 0 ]; then
return
fi
authentication="$username:$password" yq -M -i '.authentication += [strenv(authentication)]' "$RUN_PROFILE_PATH"
}
mixin_tun_dns_hijacks() {
dns_hijack="$1" yq -M -i '.tun.dns-hijack += [strenv(dns_hijack)]' "$RUN_PROFILE_PATH"
}
mixin_fake_ip_filters() {
domain_name="$1" yq -M -i '.dns.fake-ip-filter += [strenv(domain_name)]' "$RUN_PROFILE_PATH"
}
mixin_hosts() {
local section="$1"
local enabled domain_name
config_get_bool enabled "$section" "enabled" 0
config_get domain_name "$section" "domain_name"
if [ "$enabled" == 0 ]; then
return
fi
config_list_foreach "$section" "ip" mixin_host "$domain_name"
}
mixin_host() {
ip="$1" domain_name="$2" yq -M -i '.hosts.[strenv(domain_name)] += [strenv(ip)]' "$RUN_PROFILE_PATH"
}
mixin_nameservers() {
local section="$1"
local enabled type
config_get_bool enabled "$section" "enabled" 0
config_get type "$section" "type"
if [ "$enabled" == 0 ]; then
return
fi
config_list_foreach "$section" "nameserver" mixin_nameserver "$type"
}
mixin_nameserver() {
nameserver="$1" type="$2" yq -M -i '.dns.[strenv(type)] += [strenv(nameserver)]' "$RUN_PROFILE_PATH"
}
mixin_nameserver_policies() {
local section="$1"
local enabled matcher
config_get_bool enabled "$section" "enabled" 0
config_get matcher "$section" "matcher"
if [ "$enabled" == 0 ]; then
return
fi
config_list_foreach "$section" "nameserver" mixin_nameserver_policy "$matcher"
}
mixin_nameserver_policy() {
nameserver="$1" matcher="$2" yq -M -i '.dns.nameserver-policy.[strenv(matcher)] += [strenv(nameserver)]' "$RUN_PROFILE_PATH"
}
mixin_sniffer_domain_names() {
domain_name="$1" type="$2" yq -M -i '.sniffer.[strenv(type)] += [strenv(domain_name)]' "$RUN_PROFILE_PATH"
}
mixin_sniffs() {
local section="$1"
local enabled protocol overwrite_destination
config_get_bool enabled "$section" "enabled" 0
config_get protocol "$section" "protocol"
config_get_bool overwrite_destination "$section" "overwrite_destination" 0
if [ "$enabled" == 0 ]; then
return
fi
protocol="$protocol" overwrite_destination="$overwrite_destination" yq -M -i '.sniffer.sniff.[strenv(protocol)].override-destination = env(overwrite_destination) == 1' "$RUN_PROFILE_PATH"
config_list_foreach "$section" "port" mixin_sniff "$protocol"
}
mixin_sniff() {
port="$1" protocol="$2" yq -M -i '.sniffer.sniff.[strenv(protocol)].ports += [env(port)]' "$RUN_PROFILE_PATH"
}
mixin_rule_providers() {
local section="$1"
local enabled
config_get_bool enabled "$section" "enabled" 0
if [ "$enabled" == 0 ]; then
return
fi
local name type url node file_size_limit file_path file_format behavior update_interval
config_get name "$section" "name"
config_get type "$section" "type"
config_get url "$section" "url"
config_get node "$section" "node"
config_get file_size_limit "$section" "file_size_limit" 0
config_get file_path "$section" "file_path"
config_get file_format "$section" "file_format"
config_get behavior "$section" "behavior"
config_get update_interval "$section" "update_interval" 0
if [ "$type" == "http" ]; then
name="$name" type="$type" url="$url" node="$node" file_size_limit="$file_size_limit" file_format="$file_format" behavior="$behavior" update_interval="$update_interval" \
yq -M -i '
.rule-providers.[strenv(name)].type = strenv(type) |
.rule-providers.[strenv(name)].url = strenv(url) |
.rule-providers.[strenv(name)].proxy = strenv(node) |
.rule-providers.[strenv(name)].size_limit = env(file_size_limit) |
.rule-providers.[strenv(name)].format = strenv(file_format) |
.rule-providers.[strenv(name)].behavior = strenv(behavior) |
.rule-providers.[strenv(name)].interval = env(update_interval)
' "$RUN_PROFILE_PATH"
elif [ "$type" == "file" ]; then
name="$name" type="$type" file_path="$file_path" file_format="$file_format" behavior="$behavior" \
yq -M -i '
.rule-providers.[strenv(name)].type = strenv(type) |
.rule-providers.[strenv(name)].path = strenv(file_path) |
.rule-providers.[strenv(name)].format = strenv(file_format) |
.rule-providers.[strenv(name)].behavior = strenv(behavior)
' "$RUN_PROFILE_PATH"
fi
}
mixin_rules() {
local section="$1"
local enabled
config_get_bool enabled "$section" "enabled" 0
if [ "$enabled" == 0 ]; then
return
fi
local type match node no_resolve
config_get type "$section" "type"
config_get match "$section" "match"
config_get node "$section" "node"
config_get_bool no_resolve "$section" "no_resolve" 0
local rule
if [ -z "$type" ]; then
rule="$match,$node"
else
rule="$type,$match,$node"
fi
if [ "$no_resolve" == 1 ]; then
rule="$rule,no-resolve"
fi
rule="$rule" yq -M -i '.nikki-rules += [strenv(rule)]' "$RUN_PROFILE_PATH"
}
add_bypass_user() {
local user; user="$1"
if [ "$user" != "root" ] && (cut -d ':' -f 1 < /etc/passwd | grep -q "$user"); then
nft add element inet "$FW_TABLE" bypass_user \{ "$user" \}
fi
}
add_bypass_group() {
local group; group="$1"
if [ "$group" != "root" ] && (cut -d ':' -f 1 < /etc/group | grep -q "$group"); then
nft add element inet "$FW_TABLE" bypass_group \{ "$group" \}
fi
}
add_acl_ip() {
nft add element inet "$FW_TABLE" acl_ip \{ "$1" \}
}
add_acl_ip6() {
nft add element inet "$FW_TABLE" acl_ip6 \{ "$1" \}
}
add_acl_mac() {
nft add element inet "$FW_TABLE" acl_mac \{ "$1" \}
}
add_acl_interface() {
local interface; interface="$1"
local device; network_get_device device "$interface"
if [ -n "$device" ]; then
nft add element inet "$FW_TABLE" acl_interface \{ "$device" \}
fi
}
update_subscription() { update_subscription() {
local subscription_section; subscription_section="$1" local subscription_section; subscription_section="$1"
if [ -z "$subscription_section" ]; then if [ -z "$subscription_section" ]; then

View File

@ -0,0 +1,73 @@
#!/bin/sh
echo \
"
# Nikki Debug Info
## system
\`\`\`shell
$(cat /etc/openwrt_release)
\`\`\`
## kernel
\`\`\`
$(uname -a)
\`\`\`
## application
\`\`\`
`
if [ -x "/bin/opkg" ]; then
opkg list-installed "nikki"
opkg list-installed "luci-app-nikki"
elif [ -x "/usr/bin/apk" ]; then
apk list -I "nikki"
apk list -I "luci-app-nikki"
fi
`
\`\`\`
## config
\`\`\`
$(uci show nikki)
\`\`\`
## profile
\`\`\`yaml
$(cat /etc/nikki/run/config.yaml)
\`\`\`
## ip rule
\`\`\`
$(ip rule list)
\`\`\`
## ip route
\`\`\`
TPROXY:
$(ip route list table 80)
TUN:
$(ip route list table 81)
\`\`\`
## ip6 rule
\`\`\`
$(ip -6 rule list)
\`\`\`
## ip6 route
\`\`\`
TPROXY:
$(ip -6 route list table 80)
TUN:
$(ip -6 route list table 81)
\`\`\`
## nftables
\`\`\`
$(nft list ruleset)
\`\`\`
## service
\`\`\`json
$(service nikki info)
\`\`\`
## process
\`\`\`
$(ps | grep mihomo)
\`\`\`
## netstat
\`\`\`
$(netstat -nalp | grep mihomo)
\`\`\`
"

View File

@ -5,11 +5,10 @@ NIKKI_USER="root"
NIKKI_GROUP="nikki" NIKKI_GROUP="nikki"
# routing # routing
FW_TABLE="nikki" TPROXY_FW_MARK="0x80"
FW_MARK="0x80" TUN_FW_MARK="0x81"
FW_MARK_MASK="0xFF" TPROXY_RULE_PREF="1024"
TCP_RULE_PREF="1024" TUN_RULE_PREF="1025"
UDP_RULE_PREF="1025"
TPROXY_ROUTE_TABLE="80" TPROXY_ROUTE_TABLE="80"
TUN_ROUTE_TABLE="81" TUN_ROUTE_TABLE="81"
@ -24,7 +23,6 @@ RUN_PROFILE_PATH="$RUN_DIR/config.yaml"
PROVIDERS_DIR="$RUN_DIR/providers" PROVIDERS_DIR="$RUN_DIR/providers"
RULE_PROVIDERS_DIR="$PROVIDERS_DIR/rule" RULE_PROVIDERS_DIR="$PROVIDERS_DIR/rule"
PROXY_PROVIDERS_DIR="$PROVIDERS_DIR/proxy" PROXY_PROVIDERS_DIR="$PROVIDERS_DIR/proxy"
RUN_UI_DIR="$RUN_DIR/ui"
# log # log
LOG_DIR="/var/log/nikki" LOG_DIR="/var/log/nikki"
@ -37,6 +35,12 @@ STARTED_FLAG="$FLAG_DIR/started.flag"
BRIDGE_NF_CALL_IPTABLES_FLAG="$FLAG_DIR/bridge_nf_call_iptables.flag" BRIDGE_NF_CALL_IPTABLES_FLAG="$FLAG_DIR/bridge_nf_call_iptables.flag"
BRIDGE_NF_CALL_IP6TABLES_FLAG="$FLAG_DIR/bridge_nf_call_ip6tables.flag" BRIDGE_NF_CALL_IP6TABLES_FLAG="$FLAG_DIR/bridge_nf_call_ip6tables.flag"
# ucode
UCODE_DIR="$HOME_DIR/ucode"
INCLUDE_UCODE="$UCODE_DIR/include.uc"
MIXIN_UC="$UCODE_DIR/mixin.uc"
HIJACK_UT="$UCODE_DIR/hijack.ut"
# scripts # scripts
SH_DIR="$HOME_DIR/scripts" SH_DIR="$HOME_DIR/scripts"
INCLUDE_SH="$SH_DIR/include.sh" INCLUDE_SH="$SH_DIR/include.sh"
@ -44,7 +48,6 @@ FIREWALL_INCLUDE_SH="$SH_DIR/firewall_include.sh"
# nftables # nftables
NFT_DIR="$HOME_DIR/nftables" NFT_DIR="$HOME_DIR/nftables"
HIJACK_NFT="$NFT_DIR/hijack.nft"
RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft" RESERVED_IP_NFT="$NFT_DIR/reserved_ip.nft"
RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft" RESERVED_IP6_NFT="$NFT_DIR/reserved_ip6.nft"
GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft" GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft"

View File

@ -8,6 +8,12 @@ mixin_rule=$(uci -q get nikki.mixin.rule); [ -z "$mixin_rule" ] && uci set nikki
mixin_rule_provider=$(uci -q get nikki.mixin.rule_provider); [ -z "$mixin_rule_provider" ] && uci set nikki.mixin.rule_provider=0 mixin_rule_provider=$(uci -q get nikki.mixin.rule_provider); [ -z "$mixin_rule_provider" ] && uci set nikki.mixin.rule_provider=0
# since v1.19.0
mixin_ui_path=$(uci -q get nikki.mixin.ui_path); [ -z "$mixin_ui_path" ] && uci set nikki.mixin.ui_path=ui
uci show nikki | grep -E 'nikki.@rule\[[[:digit:]]+\]=rule' | sed 's/nikki.@rule\[\([[:digit:]]\+\)\]=rule/rename nikki.@rule[\1].match=matcher/' | uci batch
# commit # commit
uci commit nikki uci commit nikki

403
nikki/files/ucode/hijack.ut Normal file
View File

@ -0,0 +1,403 @@
#!/usr/bin/utpl
{%-
'use strict';
import { readfile } from 'fs';
import { cursor } from 'uci';
import { ensure_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]);
const uci = cursor();
uci.load('nikki');
const redir_port = uci.get('nikki', 'mixin', 'redir_port');
const tproxy_port = uci.get('nikki', 'mixin', 'tproxy_port');
const dns_port = uci.get('nikki', 'mixin', 'dns_port');
const fake_ip_range = uci.get('nikki', 'mixin', 'fake_ip_range');
const tun_device = uci.get('nikki', 'mixin', 'tun_device');
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 router_proxy = uci.get('nikki', 'proxy', 'router_proxy');
const lan_proxy = 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 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 proxy_tcp_dport = ensure_array(uci.get('nikki', 'proxy', 'proxy_tcp_dport'));
const proxy_udp_dport = ensure_array(uci.get('nikki', 'proxy', 'proxy_udp_dport'));
const bypass_dscp = ensure_array(uci.get('nikki', 'proxy', 'bypass_dscp'));
const dns_hijack_nfproto = [];
if (ipv4_dns_hijack == '1') {
push(dns_hijack_nfproto, 'ipv4')
}
if (ipv6_dns_hijack == '1') {
push(dns_hijack_nfproto, 'ipv6')
}
const proxy_nfproto = [];
if (ipv4_proxy == '1') {
push(proxy_nfproto, 'ipv4')
}
if (ipv6_proxy == '1') {
push(proxy_nfproto, 'ipv6')
}
const proxy_dport = [];
for (let port in proxy_tcp_dport) {
push(proxy_dport, `tcp . ${port}`)
}
for (let port in proxy_udp_dport) {
push(proxy_dport, `udp . ${port}`)
}
push(bypass_group, nikki_group);
-%}
table inet nikki {
set bypass_user {
type uid
flags interval
auto-merge
{% if (length(bypass_user) > 0): %}
elements = {
{% for (let x in bypass_user): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set bypass_group {
type gid
flags interval
auto-merge
{% if (length(bypass_group) > 0): %}
elements = {
{% for (let x in bypass_group): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set bypass_dscp {
type dscp
flags interval
auto-merge
{% if (length(bypass_dscp) > 0): %}
elements = {
{% for (let x in bypass_dscp): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set dns_hijack_nfproto {
type nf_proto
flags interval
{% if (length(dns_hijack_nfproto) > 0): %}
elements = {
{% for (let x in dns_hijack_nfproto): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set proxy_nfproto {
type nf_proto
flags interval
{% if (length(proxy_nfproto) > 0): %}
elements = {
{% for (let x in proxy_nfproto): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set china_ip {
type ipv4_addr
flags interval
}
set china_ip6 {
type ipv6_addr
flags interval
}
set reserved_ip {
type ipv4_addr
flags interval
auto-merge
}
set reserved_ip6 {
type ipv6_addr
flags interval
auto-merge
}
set proxy_dport {
type inet_proto . inet_service
flags interval
auto-merge
{% if (length(proxy_dport) > 0): %}
elements = {
{% for (let x in proxy_dport): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set acl_ip {
type ipv4_addr
flags interval
auto-merge
{% if (length(acl_ip) > 0): %}
elements = {
{% for (let x in acl_ip): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set acl_ip6 {
type ipv6_addr
flags interval
auto-merge
{% if (length(acl_ip6) > 0): %}
elements = {
{% for (let x in acl_ip6): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set acl_mac {
type ether_addr
flags interval
auto-merge
{% if (length(acl_mac) > 0): %}
elements = {
{% for (let x in acl_mac): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
set acl_interface {
type ifname
flags interval
auto-merge
{% if (length(acl_interface) > 0): %}
elements = {
{% for (let x in acl_interface): %}
{{ x }},
{% endfor %}
}
{% endif %}
}
chain all_dns_hijack {
meta l4proto { tcp, udp } th dport 53 counter redirect to :{{ dns_port }}
}
chain allow_dns_hijack {
meta l4proto { tcp, udp } th dport 53 ip saddr @acl_ip counter redirect to :{{ dns_port }}
meta l4proto { tcp, udp } th dport 53 ip6 saddr @acl_ip6 counter redirect to :{{ dns_port }}
meta l4proto { tcp, udp } th dport 53 ether saddr @acl_mac counter redirect to :{{ dns_port }}
meta l4proto { tcp, udp } th dport 53 iifname @acl_interface counter redirect to :{{ dns_port }}
}
chain block_dns_hijack {
meta l4proto { tcp, udp } th dport 53 ip saddr @acl_ip counter return
meta l4proto { tcp, udp } th dport 53 ip6 saddr @acl_ip6 counter return
meta l4proto { tcp, udp } th dport 53 ether saddr @acl_mac counter return
meta l4proto { tcp, udp } th dport 53 iifname @acl_interface counter return
meta l4proto { tcp, udp } th dport 53 counter redirect to :{{ dns_port }}
}
chain all_redirect {
meta l4proto tcp counter redirect to :{{ redir_port }}
}
chain allow_redirect {
meta l4proto tcp ip saddr @acl_ip counter redirect to :{{ redir_port }}
meta l4proto tcp ip6 saddr @acl_ip6 counter redirect to :{{ redir_port }}
meta l4proto tcp ether saddr @acl_mac counter redirect to :{{ redir_port }}
meta l4proto tcp iifname @acl_interface counter redirect to :{{ redir_port }}
}
chain block_redirect {
meta l4proto tcp ip saddr @acl_ip counter return
meta l4proto tcp ip6 saddr @acl_ip6 counter return
meta l4proto tcp ether saddr @acl_mac counter return
meta l4proto tcp iifname @acl_interface counter return
meta l4proto tcp counter redirect to :{{ redir_port }}
}
chain all_tproxy {
meta l4proto { tcp, udp } meta mark set {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
}
chain allow_tproxy {
meta l4proto { tcp, udp } ip saddr @acl_ip meta mark set {{ tproxy_fw_mark }} tproxy ip to :{{ tproxy_port }} counter accept
meta l4proto { tcp, udp } ip6 saddr @acl_ip6 meta mark set {{ tproxy_fw_mark }} tproxy ip6 to :{{ tproxy_port }} counter accept
meta l4proto { tcp, udp } ether saddr @acl_mac meta mark set {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
meta l4proto { tcp, udp } iifname @acl_interface meta mark set {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
}
chain block_tproxy {
meta l4proto { tcp, udp } ip saddr @acl_ip counter return
meta l4proto { tcp, udp } ip6 saddr @acl_ip6 counter return
meta l4proto { tcp, udp } ether saddr @acl_mac counter return
meta l4proto { tcp, udp } iifname @acl_interface counter return
meta l4proto { tcp, udp } meta mark set {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
}
chain all_tun {
meta l4proto { tcp, udp } meta mark set {{ tun_fw_mark }} counter
}
chain allow_tun {
meta l4proto { tcp, udp } ip saddr @acl_ip meta mark set {{ tun_fw_mark }} counter
meta l4proto { tcp, udp } ip6 saddr @acl_ip6 meta mark set {{ tun_fw_mark }} counter
meta l4proto { tcp, udp } ether saddr @acl_mac meta mark set {{ tun_fw_mark }} counter
meta l4proto { tcp, udp } iifname @acl_interface meta mark set {{ tun_fw_mark }} counter
}
chain block_tun {
meta l4proto { tcp, udp } ip saddr @acl_ip counter return
meta l4proto { tcp, udp } ip6 saddr @acl_ip6 counter return
meta l4proto { tcp, udp } ether saddr @acl_mac counter return
meta l4proto { tcp, udp } iifname @acl_interface counter return
meta l4proto { tcp, udp } meta mark set {{ tun_fw_mark }} counter
}
{% if (router_proxy == '1'): %}
chain nat_output {
type nat hook output priority filter; policy accept;
meta skuid @bypass_user counter return
meta skgid @bypass_group counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter redirect to :{{ dns_port }}
{% if (tcp_transparent_proxy_mode == 'redirect'): %}
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} 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 } ip6 dscp == @bypass_dscp counter return
meta nfproto @proxy_nfproto meta l4proto tcp counter redirect to :{{ redir_port }}
{% endif %}
}
chain mangle_output {
type route hook output priority mangle; policy accept;
meta skuid @bypass_user counter return
meta skgid @bypass_group counter return
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} 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 } ip6 dscp == @bypass_dscp counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
{% if (tcp_transparent_proxy_mode == 'tproxy'): %}
meta nfproto @proxy_nfproto meta l4proto tcp meta mark set {{ tproxy_fw_mark }} counter
{% elif (tcp_transparent_proxy_mode == 'tun'): %}
meta nfproto @proxy_nfproto meta l4proto tcp meta mark set {{ tun_fw_mark }} counter
{% endif %}
{% if (udp_transparent_proxy_mode == 'tproxy'): %}
meta nfproto @proxy_nfproto meta l4proto udp meta mark set {{ tproxy_fw_mark }} counter
{% elif (udp_transparent_proxy_mode == 'tun'): %}
meta nfproto @proxy_nfproto meta l4proto udp meta mark set {{ tun_fw_mark }} counter
{% endif %}
}
chain mangle_prerouting_router {
type filter hook prerouting priority mangle - 1; policy accept;
{% if (tcp_transparent_proxy_mode == 'tproxy' || udp_transparent_proxy_mode == 'tproxy'): %}
meta l4proto { tcp, udp } iifname lo meta mark {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
{% endif %}
{% if (tcp_transparent_proxy_mode == 'tun' || udp_transparent_proxy_mode == 'tun'): %}
meta l4proto { tcp, udp } iifname {{ tun_device }} counter accept
{% endif %}
}
{% endif %}
{% if (lan_proxy == '1'): %}
chain dstnat {
type nat hook prerouting priority dstnat + 1; policy accept;
meta nfproto @dns_hijack_nfproto jump {{ access_control_mode }}_dns_hijack
{% if (tcp_transparent_proxy_mode == 'redirect'): %}
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} 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 } ip6 dscp == @bypass_dscp counter return
meta nfproto @proxy_nfproto jump {{ access_control_mode }}_redirect
{% endif %}
}
chain mangle_prerouting_lan {
type filter hook prerouting priority mangle; policy accept;
fib daddr type { local, multicast, broadcast, anycast } 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 nfproto ipv4 meta l4proto . th dport != @proxy_dport ip daddr != {{ fake_ip_range }} 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 } ip6 dscp == @bypass_dscp counter return
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
{% if (tcp_transparent_proxy_mode == 'tproxy'): %}
meta nfproto @proxy_nfproto meta l4proto tcp jump {{ access_control_mode }}_tproxy
{% elif (tcp_transparent_proxy_mode == 'tun'): %}
meta nfproto @proxy_nfproto meta l4proto tcp jump {{ access_control_mode }}_tun
{% endif %}
{% if (udp_transparent_proxy_mode == 'tproxy'): %}
meta nfproto @proxy_nfproto meta l4proto udp jump {{ access_control_mode }}_tproxy
{% elif (udp_transparent_proxy_mode == 'tun'): %}
meta nfproto @proxy_nfproto meta l4proto udp jump {{ access_control_mode }}_tun
{% endif %}
}
{% endif %}
}

View File

@ -0,0 +1,9 @@
export function ensure_array(obj) {
if (obj == null) {
return [];
}
if (type(obj) == 'array') {
return uniq(obj);
}
return [obj];
};

191
nikki/files/ucode/mixin.uc Normal file
View File

@ -0,0 +1,191 @@
#!/usr/bin/ucode
'use strict';
import { cursor } from 'uci';
import { connect } from 'ubus';
import { ensure_array } from '/etc/nikki/ucode/include.uc';
const uci = cursor();
const ubus = connect();
const config = {};
const mixin = uci.get('nikki', 'config', 'mixin') == '1';
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';
if (mixin) {
config['unified-delay'] = uci.get('nikki', 'mixin', 'unify_delay') == '1';
config['tcp-concurrent'] = uci.get('nikki', 'mixin', 'tcp_concurrent') == '1';
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');
}
config['external-ui'] = uci.get('nikki', 'mixin', 'ui_path') || 'ui';
config['external-ui-name'] = uci.get('nikki', 'mixin', 'ui_name') || '';
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['allow-lan'] = uci.get('nikki', 'mixin', 'allow_lan') == '1';
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') {
config['authentication'] = [];
uci.foreach('nikki', 'authentication', (section) => {
if (section.enabled == '1') {
push(config['authentication'], `${section.username}:${section.password}`);
}
});
}
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'));
}
} else {
config['tun']['enable'] = false;
}
config['dns'] = {};
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'));
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['hosts'] = {};
uci.foreach('nikki', 'hosts', (section) => {
if (section.enabled == '1') {
config['hosts'][section.domain_name] = ensure_array(section.ip);
}
});
}
if (uci.get('nikki', 'mixin', 'dns_nameserver') == '1') {
config['dns']['default-nameserver'] = [];
config['dns']['proxy-server-nameserver'] = [];
config['dns']['direct-nameserver'] = [];
config['dns']['nameserver'] = [];
config['dns']['fallback'] = [];
uci.foreach('nikki', 'nameserver', (section) => {
push(config['dns'][section.type], ...ensure_array(section.nameserver));
})
}
if (uci.get('nikki', 'mixin', 'dns_nameserver_policy') == '1') {
config['dns']['nameserver-policy'] = {};
uci.foreach('nikki', 'nameserver_policy', (section) => {
if (section.enabled == '1') {
config['dns']['nameserver-policy'][section.matcher] = ensure_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');
}
if (uci.get('nikki', 'mixin', 'sniffer_ignore_domain_name') == '1') {
config['sniffer']['skip-domain'] = uci.get('nikki', 'mixin', 'sniffer_ignore_domain_names');
}
if (uci.get('nikki', 'mixin', 'sniffer_sniff') == '1') {
config['sniffer']['sniff'] = {};
config['sniffer']['sniff']['HTTP'] = {};
config['sniffer']['sniff']['TLS'] = {};
config['sniffer']['sniff']['QUIC'] = {};
uci.foreach('nikki', 'sniff', (section) => {
if (section.enabled == '1') {
config['sniffer']['sniff'][section.protocol]['port'] = ensure_array(section.port);
config['sniffer']['sniff'][section.protocol]['override-destination'] = section.overwrite_destination == '1';
}
});
}
}
if (uci.get('nikki', 'mixin', 'rule_provider') == '1') {
config['rule-providers'] = {};
uci.foreach('nikki', 'rule_provider', (section) => {
if (section.type == 'http') {
config['rule-providers'][section.name] = {
type: section.type,
url: section.url,
proxy: section.node,
size_limit: section.file_size_limit,
format: section.file_format,
behavior: section.behavior,
interval: section.update_interval,
}
} else if (section.type == 'file') {
config['rule-providers'][section.name] = {
type: section.type,
path: section.file_path,
format: section.file_format,
behavior: section.behavior,
}
}
})
}
if (uci.get('nikki', 'mixin', 'rule') == '1') {
config['nikki-rules'] = [];
uci.foreach('nikki', 'rule', (section) => {
let rule;
if (section.type == null || section.type == '') {
rule = `${section.matcher},${section.node}`;
} else {
rule = `${section.type},${section.matcher},${section.node}`;
}
if (section.no_resolve == '1') {
rule += ',no_resolve';
}
push(config['nikki-rules'], rule);
})
}
if (mixin) {
config['geodata-mode'] = (uci.get('nikki', 'mixin', 'geoip_format') || 'mmdb') == '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-update-interval'] = int(uci.get('nikki', 'mixin', 'geox_update_interval') || '24');
}
print(config);