🐶 Sync 2025-11-02 14:26:26
This commit is contained in:
30
nikki/files/mixin.yaml
Normal file
30
nikki/files/mixin.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
# Mixin File
|
||||
# You can set any mihomo profile's config at here, it will mixin to the profile.
|
||||
# Mixin file have lower priority than the LuCI mixin options.
|
||||
#
|
||||
# Mihomo's Wiki: https://wiki.metacubex.one
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# experimental: # experimental config
|
||||
# dialer-ip4p-convert: false # IP4P support
|
||||
# listeners: # overwrite listeners
|
||||
# - name: shadowsocks
|
||||
# type: shadowsocks
|
||||
# listen: "::"
|
||||
# port: 12060
|
||||
# nikki-proxies: # prepend proxies
|
||||
# - name: PROXY
|
||||
# type: ss
|
||||
# server: proxy.example.com
|
||||
# port: 443
|
||||
# cipher: chacha20-ietf-poly1305
|
||||
# password: password
|
||||
# nikki-proxy-groups: # prepend proxy groups
|
||||
# - name: PROXY_GROUP
|
||||
# type: select
|
||||
# proxies:
|
||||
# - PROXY
|
||||
# nikki-rules: # prepend rules
|
||||
# - DOMAIN,direct.example.com,DIRECT
|
||||
# - DOMAIN-SUFFIX,proxy.example.com,PROXY
|
||||
12812
nikki/files/nftables/geoip6_cn.nft
Normal file
12812
nikki/files/nftables/geoip6_cn.nft
Normal file
File diff suppressed because it is too large
Load Diff
7363
nikki/files/nftables/geoip_cn.nft
Normal file
7363
nikki/files/nftables/geoip_cn.nft
Normal file
File diff suppressed because it is too large
Load Diff
224
nikki/files/nikki.conf
Normal file
224
nikki/files/nikki.conf
Normal file
@@ -0,0 +1,224 @@
|
||||
config status 'status'
|
||||
|
||||
config config 'config'
|
||||
option 'init' '1'
|
||||
option 'enabled' '0'
|
||||
option 'profile' 'subscription:subscription'
|
||||
option 'start_delay' '0'
|
||||
option 'scheduled_restart' '0'
|
||||
option 'cron_expression' '0 3 * * *'
|
||||
option 'test_profile' '1'
|
||||
option 'core_only' '0'
|
||||
|
||||
config procd 'procd'
|
||||
option 'fast_reload' '0'
|
||||
option 'env_disable_loopback_detector' '0'
|
||||
option 'env_disable_quic_go_gso' '0'
|
||||
option 'env_disable_quic_go_ecn' '0'
|
||||
option 'env_skip_system_ipv6_check' '0'
|
||||
|
||||
config subscription 'subscription'
|
||||
option 'name' 'default'
|
||||
option 'url' 'http://example.com/default.yaml'
|
||||
option 'user_agent' 'clash'
|
||||
option 'prefer' 'remote'
|
||||
|
||||
config mixin 'mixin'
|
||||
option 'log_level' 'warning'
|
||||
option 'mode' 'rule'
|
||||
option 'match_process' 'off'
|
||||
option 'ipv6' '1'
|
||||
option 'ui_url' 'https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip'
|
||||
option 'api_listen' '[::]:9090'
|
||||
option 'selection_cache' '1'
|
||||
option 'allow_lan' '1'
|
||||
option 'http_port' '8080'
|
||||
option 'socks_port' '1080'
|
||||
option 'mixed_port' '7890'
|
||||
option 'redir_port' '7891'
|
||||
option 'tproxy_port' '7892'
|
||||
option 'authentication' '1'
|
||||
option 'tun_enabled' '1'
|
||||
option 'tun_device' 'nikki'
|
||||
option 'tun_stack' 'mixed'
|
||||
option 'tun_dns_hijack' '0'
|
||||
list 'tun_dns_hijacks' 'tcp://any:53'
|
||||
list 'tun_dns_hijacks' 'udp://any:53'
|
||||
option 'dns_enabled' '1'
|
||||
option 'dns_listen' '[::]:1053'
|
||||
option 'dns_ipv6' '1'
|
||||
option 'dns_mode' 'fake-ip'
|
||||
option 'fake_ip_range' '198.18.0.1/16'
|
||||
option 'fake_ip_filter' '0'
|
||||
list 'fake_ip_filters' '+.lan'
|
||||
list 'fake_ip_filters' '+.local'
|
||||
option 'fake_ip_cache' '1'
|
||||
option 'hosts' '0'
|
||||
option 'dns_nameserver' '0'
|
||||
option 'dns_nameserver_policy' '0'
|
||||
option 'sniffer_force_domain_name' '0'
|
||||
option 'sniffer_ignore_domain_name' '0'
|
||||
option 'sniffer_sniff' '0'
|
||||
option 'rule' '0'
|
||||
option 'rule_provider' '0'
|
||||
option 'mixin_file_content' '0'
|
||||
|
||||
config authentication
|
||||
option 'enabled' '1'
|
||||
option 'username' 'nikki'
|
||||
option 'password' ''
|
||||
|
||||
config hosts
|
||||
option 'enabled' '0'
|
||||
option 'domain_name' 'localhost'
|
||||
list 'ip' '127.0.0.1'
|
||||
list 'ip' '::1'
|
||||
|
||||
config nameserver
|
||||
option 'enabled' '1'
|
||||
option 'type' 'default-nameserver'
|
||||
list 'nameserver' '223.5.5.5'
|
||||
list 'nameserver' '223.6.6.6'
|
||||
|
||||
config nameserver
|
||||
option 'enabled' '0'
|
||||
option 'type' 'proxy-server-nameserver'
|
||||
list 'nameserver' 'https://223.5.5.5/dns-query'
|
||||
list 'nameserver' 'https://223.6.6.6/dns-query'
|
||||
|
||||
config nameserver
|
||||
option 'enabled' '0'
|
||||
option 'type' 'direct-nameserver'
|
||||
list 'nameserver' 'https://223.5.5.5/dns-query'
|
||||
list 'nameserver' 'https://223.6.6.6/dns-query'
|
||||
|
||||
config nameserver
|
||||
option 'enabled' '1'
|
||||
option 'type' 'nameserver'
|
||||
list 'nameserver' 'https://223.5.5.5/dns-query'
|
||||
list 'nameserver' 'https://223.6.6.6/dns-query'
|
||||
|
||||
config nameserver_policy
|
||||
option 'enabled' '1'
|
||||
option 'matcher' 'geosite:private,cn'
|
||||
list 'nameserver' 'https://223.5.5.5/dns-query'
|
||||
list 'nameserver' 'https://223.6.6.6/dns-query'
|
||||
|
||||
config nameserver_policy
|
||||
option 'enabled' '1'
|
||||
option 'matcher' 'geosite:geolocation-!cn'
|
||||
list 'nameserver' 'https://1.1.1.1/dns-query'
|
||||
list 'nameserver' 'https://8.8.8.8/dns-query'
|
||||
|
||||
config sniff
|
||||
option 'enabled' '1'
|
||||
option 'protocol' 'HTTP'
|
||||
list 'port' '80'
|
||||
list 'port' '8080'
|
||||
option 'overwrite_destination' '1'
|
||||
|
||||
config sniff
|
||||
option 'enabled' '1'
|
||||
option 'protocol' 'TLS'
|
||||
list 'port' '443'
|
||||
list 'port' '8443'
|
||||
option 'overwrite_destination' '1'
|
||||
|
||||
config sniff
|
||||
option 'enabled' '1'
|
||||
option 'protocol' 'QUIC'
|
||||
list 'port' '443'
|
||||
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 'bypass_china_mainland_ip6' '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 'tproxy_fw_mask' '0xFF'
|
||||
option 'tun_fw_mark' '0x81'
|
||||
option 'tun_fw_mask' '0xFF'
|
||||
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'
|
||||
553
nikki/files/nikki.init
Normal file
553
nikki/files/nikki.init
Normal file
@@ -0,0 +1,553 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
PROG="/usr/bin/mihomo"
|
||||
|
||||
. "$IPKG_INSTROOT/etc/nikki/scripts/include.sh"
|
||||
|
||||
extra_command 'update_subscription' 'Update subscription by section id'
|
||||
|
||||
boot_func() {
|
||||
# prepare files
|
||||
prepare_files
|
||||
# load config
|
||||
config_load nikki
|
||||
# start delay
|
||||
local enabled start_delay
|
||||
config_get_bool enabled "config" "enabled" 0
|
||||
config_get start_delay "config" "start_delay" 0
|
||||
if [ "$enabled" = 1 ] && [ "$start_delay" -gt 0 ]; then
|
||||
log "App" "Start after $start_delay seconds."
|
||||
sleep "$start_delay"
|
||||
fi
|
||||
# start
|
||||
start
|
||||
}
|
||||
|
||||
boot() {
|
||||
boot_func &
|
||||
}
|
||||
|
||||
start_service() {
|
||||
# prepare files
|
||||
prepare_files
|
||||
# load config
|
||||
config_load nikki
|
||||
# check if enabled
|
||||
local enabled
|
||||
config_get_bool enabled "config" "enabled" 0
|
||||
if [ "$enabled" = 0 ]; then
|
||||
log "App" "Disabled."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
# start
|
||||
log "App" "Enabled."
|
||||
log "App" "Start."
|
||||
# check if executable
|
||||
if [ ! -x $PROG ]; then
|
||||
log "App" "Core is not executable."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
# get config
|
||||
## app config
|
||||
local scheduled_restart cron_expression profile test_profile fast_reload core_only
|
||||
config_get_bool scheduled_restart "config" "scheduled_restart" 0
|
||||
config_get cron_expression "config" "cron_expression"
|
||||
config_get profile "config" "profile"
|
||||
config_get_bool test_profile "config" "test_profile" 0
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
## procd config
|
||||
### fast reload
|
||||
config_get_bool fast_reload "procd" "fast_reload" 0
|
||||
### rlimit
|
||||
local rlimit_address_space_soft rlimit_address_space_hard rlimit_data_soft rlimit_data_hard rlimit_stack_soft rlimit_stack_hard rlimit_nofile_soft rlimit_nofile_hard
|
||||
config_get rlimit_address_space_soft "procd" "rlimit_address_space_soft"
|
||||
config_get rlimit_address_space_hard "procd" "rlimit_address_space_hard"
|
||||
config_get rlimit_data_soft "procd" "rlimit_data_soft"
|
||||
config_get rlimit_data_hard "procd" "rlimit_data_hard"
|
||||
config_get rlimit_stack_soft "procd" "rlimit_stack_soft"
|
||||
config_get rlimit_stack_hard "procd" "rlimit_stack_hard"
|
||||
config_get rlimit_nofile_soft "procd" "rlimit_nofile_soft"
|
||||
config_get rlimit_nofile_hard "procd" "rlimit_nofile_hard"
|
||||
### environment variable
|
||||
local env_safe_paths env_disable_loopback_detector env_disable_quic_go_gso env_disable_quic_go_ecn env_skip_system_ipv6_check
|
||||
config_get env_safe_paths "procd" "env_safe_paths"
|
||||
config_get_bool env_disable_loopback_detector "procd" "env_disable_loopback_detector" 0
|
||||
config_get_bool env_disable_quic_go_gso "procd" "env_disable_quic_go_gso" 0
|
||||
config_get_bool env_disable_quic_go_ecn "procd" "env_disable_quic_go_ecn" 0
|
||||
config_get_bool env_skip_system_ipv6_check "procd" "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
|
||||
config_get_bool overwrite_authentication "mixin" "authentication" 0
|
||||
config_get_bool overwrite_tun_dns_hijack "mixin" "tun_dns_hijack" 0
|
||||
config_get_bool overwrite_fake_ip_filter "mixin" "fake_ip_filter" 0
|
||||
config_get_bool overwrite_hosts "mixin" "hosts" 0
|
||||
config_get_bool overwrite_dns_nameserver "mixin" "dns_nameserver" 0
|
||||
config_get_bool overwrite_dns_nameserver_policy "mixin" "dns_nameserver_policy" 0
|
||||
config_get_bool overwrite_sniffer_force_domain_name "mixin" "sniffer_force_domain_name" 0
|
||||
config_get_bool overwrite_sniffer_ignore_domain_name "mixin" "sniffer_ignore_domain_name" 0
|
||||
config_get_bool overwrite_sniffer_sniff "mixin" "sniffer_sniff" 0
|
||||
### mixin file content
|
||||
local mixin_file_content
|
||||
config_get_bool mixin_file_content "mixin" "mixin_file_content" 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)
|
||||
if [ "$profile_type" = "file" ]; then
|
||||
local profile_name; profile_name="$profile_id"
|
||||
local profile_file; profile_file="$PROFILES_DIR/$profile_name"
|
||||
log "Profile" "Use file: $profile_name."
|
||||
if [ ! -f "$profile_file" ]; then
|
||||
log "Profile" "File not found."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
cp -f "$profile_file" "$RUN_PROFILE_PATH"
|
||||
elif [ "$profile_type" = "subscription" ]; then
|
||||
local subscription_section; subscription_section="$profile_id"
|
||||
local subscription_name subscription_prefer
|
||||
config_get subscription_name "$subscription_section" "name"
|
||||
config_get subscription_prefer "$subscription_section" "prefer" "remote"
|
||||
log "Profile" "Use subscription: $subscription_name."
|
||||
local subscription_file; subscription_file="$SUBSCRIPTIONS_DIR/$subscription_section.yaml"
|
||||
if [ "$subscription_prefer" = "remote" ] || [ ! -f "$subscription_file" ]; then
|
||||
update_subscription "$subscription_section"
|
||||
fi
|
||||
if [ ! -f "$subscription_file" ]; then
|
||||
log "Profile" "Subscription file not found."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
cp -f "$subscription_file" "$RUN_PROFILE_PATH"
|
||||
else
|
||||
log "Profile" "No profile/subscription selected."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
# mixin
|
||||
if [ "$core_only" = 0 ]; then
|
||||
log "Mixin" "Mixin config."
|
||||
if [ "$overwrite_authentication" = 1 ]; then
|
||||
yq -M -i 'del(.authentication)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_tun_dns_hijack" = 1 ]; then
|
||||
yq -M -i 'del(.tun.dns-hijack)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_fake_ip_filter" = 1 ]; then
|
||||
yq -M -i 'del(.dns.fake-ip-filter)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_hosts" = 1 ]; then
|
||||
yq -M -i 'del(.hosts)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_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"
|
||||
fi
|
||||
if [ "$overwrite_dns_nameserver_policy" = 1 ]; then
|
||||
yq -M -i 'del(.dns.nameserver-policy)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_sniffer_force_domain_name" = 1 ]; then
|
||||
yq -M -i 'del(.sniffer.force-domain)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_sniffer_ignore_domain_name" = 1 ]; then
|
||||
yq -M -i 'del(.sniffer.skip-domain)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$overwrite_sniffer_sniff" = 1 ]; then
|
||||
yq -M -i 'del(.sniffer.sniff)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$mixin_file_content" = 0 ]; then
|
||||
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) | .proxy-groups = .nikki-proxy-groups + .proxy-groups | del(.nikki-proxy-groups) | .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 '... comments="" | . as $item ireduce ({}; . * $item ) | .proxies = .nikki-proxies + .proxies | del(.nikki-proxies) | .proxy-groups = .nikki-proxy-groups + .proxy-groups | del(.nikki-proxy-groups) | .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"))) | not' "$RUN_PROFILE_PATH" > /dev/null 2>&1; 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")) | not' "$RUN_PROFILE_PATH" > /dev/null 2>&1; 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")) | not' "$RUN_PROFILE_PATH" > /dev/null 2>&1; 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"))) | not' "$RUN_PROFILE_PATH" > /dev/null 2>&1; 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..."
|
||||
if $PROG -d "$RUN_DIR" -t >> "$CORE_LOG_PATH" 2>&1; then
|
||||
log "Profile" "Test passed."
|
||||
else
|
||||
log "Profile" "Test failed."
|
||||
log "Profile" "Please check the core log to find out the problem."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
# start core
|
||||
log "Core" "Start."
|
||||
procd_open_instance nikki
|
||||
|
||||
procd_set_param command /bin/sh -c "$PROG -d $RUN_DIR >> $CORE_LOG_PATH 2>&1"
|
||||
procd_set_param file "$RUN_PROFILE_PATH"
|
||||
procd_append_param env SAFE_PATHS="$env_safe_paths"
|
||||
procd_append_param env DISABLE_LOOPBACK_DETECTOR="$env_disable_loopback_detector"
|
||||
procd_append_param env QUIC_GO_DISABLE_GSO="$env_disable_quic_go_gso"
|
||||
procd_append_param env QUIC_GO_DISABLE_ECN="$env_disable_quic_go_ecn"
|
||||
procd_append_param env SKIP_SYSTEM_IPV6_CHECK="$env_skip_system_ipv6_check"
|
||||
if [ "$fast_reload" = 1 ]; then
|
||||
procd_set_param reload_signal HUP
|
||||
fi
|
||||
procd_set_param pidfile "$PID_FILE_PATH"
|
||||
procd_set_param respawn
|
||||
procd_append_param limits as="${rlimit_address_space_soft:-unlimited} ${rlimit_address_space_hard:-unlimited}"
|
||||
procd_append_param limits data="${rlimit_data_soft:-unlimited} ${rlimit_data_hard:-unlimited}"
|
||||
procd_append_param limits stack="${rlimit_stack_soft:-unlimited} ${rlimit_stack_hard:-unlimited}"
|
||||
procd_append_param limits nofile="${rlimit_nofile_soft:-unlimited} ${rlimit_nofile_hard:-unlimited}"
|
||||
|
||||
procd_close_instance
|
||||
# cron
|
||||
if [ "$scheduled_restart" = 1 ] && [ -n "$cron_expression" ]; then
|
||||
log "App" "Set scheduled restart."
|
||||
echo "$cron_expression /etc/init.d/nikki restart #nikki" >> "/etc/crontabs/root"
|
||||
/etc/init.d/cron restart
|
||||
fi
|
||||
# set started flag
|
||||
touch "$STARTED_FLAG_PATH"
|
||||
}
|
||||
|
||||
service_started() {
|
||||
# check if started
|
||||
if [ ! -f "$STARTED_FLAG_PATH" ]; then
|
||||
return
|
||||
fi
|
||||
# load config
|
||||
config_load nikki
|
||||
# check if proxy enabled
|
||||
local proxy_enabled
|
||||
config_get_bool proxy_enabled "proxy" "enabled" 0
|
||||
if [ "$proxy_enabled" = 0 ]; then
|
||||
log "Proxy" "Disabled."
|
||||
return
|
||||
fi
|
||||
# get config
|
||||
## app config
|
||||
local core_only
|
||||
config_get_bool core_only "config" "core_only" 0
|
||||
## proxy config
|
||||
### general
|
||||
local tcp_mode udp_mode ipv4_proxy ipv6_proxy tun_timeout tun_interval
|
||||
config_get tcp_mode "proxy" "tcp_mode"
|
||||
config_get udp_mode "proxy" "udp_mode"
|
||||
config_get_bool ipv4_proxy "proxy" "ipv4_proxy" 0
|
||||
config_get_bool ipv6_proxy "proxy" "ipv6_proxy" 0
|
||||
config_get tun_timeout "proxy" "tun_timeout" 30
|
||||
config_get tun_interval "proxy" "tun_interval" 1
|
||||
## routing config
|
||||
local tproxy_fw_mark tproxy_fw_mask tun_fw_mark tun_fw_mask tproxy_rule_pref tun_rule_pref tproxy_route_table tun_route_table cgroup_id cgroup_name
|
||||
config_get tproxy_fw_mark "routing" "tproxy_fw_mark" "0x80"
|
||||
config_get tproxy_fw_mask "routing" "tproxy_fw_mask" "0xFF"
|
||||
config_get tun_fw_mark "routing" "tun_fw_mark" "0x81"
|
||||
config_get tun_fw_mask "routing" "tun_fw_mask" "0xFF"
|
||||
config_get tproxy_rule_pref "routing" "tproxy_rule_pref" "1024"
|
||||
config_get tun_rule_pref "routing" "tun_rule_pref" "1025"
|
||||
config_get tproxy_route_table "routing" "tproxy_route_table" "80"
|
||||
config_get tun_route_table "routing" "tun_route_table" "81"
|
||||
config_get cgroup_id "routing" "cgroup_id" "0x12061206"
|
||||
config_get cgroup_name "routing" "cgroup_name" "nikki"
|
||||
# prepare config
|
||||
local tproxy_enable; tproxy_enable=0
|
||||
if [ "$tcp_mode" = "tproxy" ] || [ "$udp_mode" = "tproxy" ]; then
|
||||
tproxy_enable=1
|
||||
fi
|
||||
local tun_enable; tun_enable=0
|
||||
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."
|
||||
# wait for tun device online
|
||||
if [ "$tun_enable" = 1 ]; then
|
||||
log "Proxy" "Waiting for tun device online within $tun_timeout seconds..."
|
||||
while [ "$tun_timeout" -gt 0 ]; do
|
||||
if ip -j link show dev "$tun_device" 2>/dev/null | jsonfilter -q -e "@[@['flags'][@='UP']]" > /dev/null 2>&1; then
|
||||
log "Proxy" "TUN device is online."
|
||||
break
|
||||
fi
|
||||
tun_timeout=$((tun_timeout - tun_interval))
|
||||
sleep "$tun_interval"
|
||||
done
|
||||
if [ "$tun_timeout" -le 0 ]; then
|
||||
log "Proxy" "Timeout, TUN device is not online."
|
||||
log "App" "Exit."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
# fix compatible with dockerd
|
||||
## cgroupfs-mount
|
||||
### when cgroupfs-mount is installed, cgroupv1 will mounted instead of cgroupv2, we need to create cgroup manually
|
||||
if mount | grep -q -w "^cgroup"; then
|
||||
mkdir -p "/sys/fs/cgroup/net_cls/$cgroup_name"
|
||||
echo "$cgroup_id" > "/sys/fs/cgroup/net_cls/$cgroup_name/net_cls.classid"
|
||||
cat "$PID_FILE_PATH" > "/sys/fs/cgroup/net_cls/$cgroup_name/cgroup.procs"
|
||||
fi
|
||||
## kmod-br-netfilter
|
||||
### when kmod-br-netfilter is loaded, bridge-nf-call-iptables and bridge-nf-call-ip6tables are set to 1, we need to set them to 0 if tproxy is enabled
|
||||
if [ "$tproxy_enable" = 1 ] && (lsmod | grep -q br_netfilter); then
|
||||
if [ "$ipv4_proxy" = 1 ]; then
|
||||
local bridge_nf_call_iptables; bridge_nf_call_iptables=$(sysctl -e -n net.bridge.bridge-nf-call-iptables)
|
||||
if [ "$bridge_nf_call_iptables" = 1 ]; then
|
||||
touch "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH"
|
||||
sysctl -q -w net.bridge.bridge-nf-call-iptables=0
|
||||
fi
|
||||
fi
|
||||
if [ "$ipv6_proxy" = 1 ]; then
|
||||
local bridge_nf_call_ip6tables; bridge_nf_call_ip6tables=$(sysctl -e -n net.bridge.bridge-nf-call-ip6tables)
|
||||
if [ "$bridge_nf_call_ip6tables" = 1 ]; then
|
||||
touch "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH"
|
||||
sysctl -q -w net.bridge.bridge-nf-call-ip6tables=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# ip route and rule
|
||||
if [ "$tproxy_enable" = 1 ]; then
|
||||
if [ "$ipv4_proxy" = 1 ]; then
|
||||
ip -4 route add local default dev lo table "$tproxy_route_table"
|
||||
ip -4 rule add pref "$tproxy_rule_pref" fwmark "$tproxy_fw_mark/$tproxy_fw_mask" table "$tproxy_route_table"
|
||||
fi
|
||||
if [ "$ipv6_proxy" = 1 ]; then
|
||||
ip -6 route add local default dev lo table "$tproxy_route_table"
|
||||
ip -6 rule add pref "$tproxy_rule_pref" fwmark "$tproxy_fw_mark/$tproxy_fw_mask" table "$tproxy_route_table"
|
||||
fi
|
||||
fi
|
||||
if [ "$tun_enable" = 1 ]; then
|
||||
if [ "$ipv4_proxy" = 1 ]; then
|
||||
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/$tun_fw_mask" table "$tun_route_table"
|
||||
fi
|
||||
if [ "$ipv6_proxy" = 1 ]; then
|
||||
ip -6 route add unicast default dev "$tun_device" table "$tun_route_table"
|
||||
ip -6 rule add pref "$tun_rule_pref" fwmark "$tun_fw_mark/$tun_fw_mask" table "$tun_route_table"
|
||||
fi
|
||||
$FIREWALL_INCLUDE_SH
|
||||
fi
|
||||
# hijack
|
||||
utpl -S "$HIJACK_UT" | nft -f -
|
||||
# check hijack
|
||||
if nft list tables | grep -q nikki; then
|
||||
log "Proxy" "Hijack successful."
|
||||
else
|
||||
log "Proxy" "Hijack failed."
|
||||
log "App" "Exit."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
service_stopped() {
|
||||
cleanup
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
cleanup
|
||||
start
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "nikki"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
# clear log
|
||||
clear_log
|
||||
# load config
|
||||
config_load nikki
|
||||
# get config
|
||||
## routing config
|
||||
local tproxy_route_table tun_route_table
|
||||
config_get tproxy_route_table "routing" "tproxy_route_table" "80"
|
||||
config_get tun_route_table "routing" "tun_route_table" "81"
|
||||
# delete routing policy
|
||||
ip -4 rule del table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -4 rule del table "$tun_route_table" > /dev/null 2>&1
|
||||
ip -6 rule del table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -6 rule del table "$tun_route_table" > /dev/null 2>&1
|
||||
# delete routing table
|
||||
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 -6 route flush table "$tproxy_route_table" > /dev/null 2>&1
|
||||
ip -6 route flush table "$tun_route_table" > /dev/null 2>&1
|
||||
# delete hijack
|
||||
nft delete table inet nikki > /dev/null 2>&1
|
||||
local handles 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 | 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
|
||||
# delete started flag
|
||||
rm "$STARTED_FLAG_PATH" > /dev/null 2>&1
|
||||
# revert fix compatible with dockerd
|
||||
## kmod-br-netfilter
|
||||
if rm "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH" > /dev/null 2>&1; then
|
||||
sysctl -q -w net.bridge.bridge-nf-call-iptables=1
|
||||
fi
|
||||
if rm "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH" > /dev/null 2>&1; then
|
||||
sysctl -q -w net.bridge.bridge-nf-call-ip6tables=1
|
||||
fi
|
||||
# delete cron
|
||||
sed -i "/#nikki/d" "/etc/crontabs/root" > /dev/null 2>&1
|
||||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
update_subscription() {
|
||||
local subscription_section; subscription_section="$1"
|
||||
if [ -z "$subscription_section" ]; then
|
||||
return
|
||||
fi
|
||||
# load config
|
||||
config_load nikki
|
||||
# get subscription config
|
||||
local subscription_name subscription_info_url subscription_url subscription_user_agent
|
||||
config_get subscription_name "$subscription_section" "name"
|
||||
config_get subscription_info_url "$subscription_section" "info_url"
|
||||
config_get subscription_url "$subscription_section" "url"
|
||||
config_get subscription_user_agent "$subscription_section" "user_agent"
|
||||
# reset subscription info
|
||||
uci_remove "nikki" "$subscription_section" "expire" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "upload" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "download" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "total" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "used" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "avaliable" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "update" > /dev/null 2>&1
|
||||
uci_remove "nikki" "$subscription_section" "success" > /dev/null 2>&1
|
||||
# update subscription
|
||||
log "Profile" "Update subscription: $subscription_name."
|
||||
local success
|
||||
local subscription_info_header_tmpfile; subscription_info_header_tmpfile="$TEMP_DIR/$subscription_section.info.header"
|
||||
local subscription_header_tmpfile; subscription_header_tmpfile="$TEMP_DIR/$subscription_section.header"
|
||||
local subscription_tmpfile; subscription_tmpfile="$TEMP_DIR/$subscription_section.yaml"
|
||||
local subscription_info_file
|
||||
local subscription_file; subscription_file="$SUBSCRIPTIONS_DIR/$subscription_section.yaml"
|
||||
# fetch subscription info
|
||||
if [ -n "$subscription_info_url" ]; then
|
||||
log "Profile" "Fetch subscription info."
|
||||
if curl -s -f -m 120 --connect-timeout 15 --retry 3 -L -X GET -A "$subscription_user_agent" -D "$subscription_info_header_tmpfile" "$subscription_info_url" > /dev/null 2>&1; then
|
||||
if [ ! -f "$subscription_info_file" ] && grep -q -i "subscription-userinfo:" "$subscription_info_header_tmpfile"; then
|
||||
subscription_info_file="$subscription_info_header_tmpfile"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# download subscription
|
||||
log "Profile" "Download subscription."
|
||||
if curl -s -f -m 120 --connect-timeout 15 --retry 3 -L -X GET -A "$subscription_user_agent" -D "$subscription_header_tmpfile" -o "$subscription_tmpfile" "$subscription_url" > /dev/null 2>&1; then
|
||||
log "Profile" "Subscription download successful."
|
||||
if [ ! -f "$subscription_info_file" ] && grep -q -i "subscription-userinfo:" "$subscription_header_tmpfile"; then
|
||||
subscription_info_file="$subscription_header_tmpfile"
|
||||
fi
|
||||
if yq -p yaml -o yaml -e 'has("proxies") or has("proxy-providers")' "$subscription_tmpfile" > /dev/null 2>&1; then
|
||||
log "Profile" "Subscription is valid."
|
||||
success=1
|
||||
else
|
||||
log "Profile" "Subscription is not valid."
|
||||
success=0
|
||||
fi
|
||||
else
|
||||
log "Profile" "Subscription download failed."
|
||||
success=0
|
||||
fi
|
||||
# check if success
|
||||
if [ "$success" = 1 ]; then
|
||||
log "Profile" "Subscription update successful."
|
||||
if [ -f "$subscription_info_file" ]; then
|
||||
local subscription_expire subscription_upload subscription_download subscription_total subscription_used subscription_avaliable
|
||||
subscription_expire=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "expire=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
subscription_upload=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "upload=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
subscription_download=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "download=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
subscription_total=$(grep -i "subscription-userinfo: " "$subscription_info_file" | grep -i -o -E "total=[[:digit:]]+" | cut -d '=' -f 2)
|
||||
if [ -n "$subscription_upload" ] && [ -n "$subscription_download" ]; then
|
||||
subscription_used=$((subscription_upload + subscription_download))
|
||||
if [ -n "$subscription_total" ]; then
|
||||
subscription_avaliable=$((subscription_total - subscription_used))
|
||||
fi
|
||||
fi
|
||||
# update subscription info
|
||||
if [ -n "$subscription_expire" ]; then
|
||||
uci_set "nikki" "$subscription_section" "expire" "$(date "+%Y-%m-%d %H:%M:%S" -d "@$subscription_expire")"
|
||||
fi
|
||||
if [ -n "$subscription_upload" ]; then
|
||||
uci_set "nikki" "$subscription_section" "upload" "$(format_filesize "$subscription_upload")"
|
||||
fi
|
||||
if [ -n "$subscription_download" ]; then
|
||||
uci_set "nikki" "$subscription_section" "download" "$(format_filesize "$subscription_download")"
|
||||
fi
|
||||
if [ -n "$subscription_total" ]; then
|
||||
uci_set "nikki" "$subscription_section" "total" "$(format_filesize "$subscription_total")"
|
||||
fi
|
||||
if [ -n "$subscription_used" ]; then
|
||||
uci_set "nikki" "$subscription_section" "used" "$(format_filesize "$subscription_used")"
|
||||
fi
|
||||
if [ -n "$subscription_avaliable" ]; then
|
||||
uci_set "nikki" "$subscription_section" "avaliable" "$(format_filesize "$subscription_avaliable")"
|
||||
fi
|
||||
fi
|
||||
uci_set "nikki" "$subscription_section" "update" "$(date "+%Y-%m-%d %H:%M:%S")"
|
||||
uci_set "nikki" "$subscription_section" "success" "1"
|
||||
# update subscription file
|
||||
rm -f "$subscription_info_header_tmpfile"
|
||||
rm -f "$subscription_header_tmpfile"
|
||||
mv -f "$subscription_tmpfile" "$subscription_file"
|
||||
elif [ "$success" = 0 ]; then
|
||||
log "Profile" "Subscription update failed."
|
||||
# update subscription info
|
||||
uci_set "nikki" "$subscription_section" "success" "0"
|
||||
# remove tmpfile
|
||||
rm -f "$subscription_info_header_tmpfile"
|
||||
rm -f "$subscription_header_tmpfile"
|
||||
rm -f "$subscription_tmpfile"
|
||||
fi
|
||||
uci_commit "nikki"
|
||||
}
|
||||
5
nikki/files/nikki.upgrade
Normal file
5
nikki/files/nikki.upgrade
Normal file
@@ -0,0 +1,5 @@
|
||||
/etc/nikki/profiles/
|
||||
/etc/nikki/subscriptions/
|
||||
/etc/nikki/mixin.yaml
|
||||
/etc/nikki/run/providers/rule/
|
||||
/etc/nikki/run/providers/proxy/
|
||||
248
nikki/files/scripts/debug.sh
Normal file
248
nikki/files/scripts/debug.sh
Normal file
@@ -0,0 +1,248 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/nikki/scripts/include.sh"
|
||||
|
||||
enabled=`uci get nikki.config.enabled`
|
||||
|
||||
if [ "$enabled" == "0" ]; then
|
||||
uci set nikki.config.enabled=1
|
||||
uci commit nikki
|
||||
/etc/init.d/nikki restart
|
||||
fi
|
||||
|
||||
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
|
||||
\`\`\`json
|
||||
`
|
||||
ucode -S -e '
|
||||
import { cursor } from "uci";
|
||||
|
||||
const uci = cursor();
|
||||
|
||||
const config = uci.get_all("nikki");
|
||||
const result = {};
|
||||
|
||||
for (let section_id in config) {
|
||||
const section = config[section_id];
|
||||
const section_type = section[".type"];
|
||||
if (result[section_type] == null) {
|
||||
result[section_type] = [];
|
||||
}
|
||||
push(result[section_type], section);
|
||||
}
|
||||
for (let section_type in result) {
|
||||
for (let section in result[section_type]) {
|
||||
delete section[".anonymous"];
|
||||
delete section[".type"];
|
||||
delete section[".name"];
|
||||
delete section[".index"];
|
||||
}
|
||||
}
|
||||
if (exists(result, "mixin")) {
|
||||
for (let x in result["mixin"]) {
|
||||
if (exists(x, "api_secret")) {
|
||||
x["api_secret"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(result, "authentication")) {
|
||||
for (let x in result["authentication"]) {
|
||||
if (exists(x, "password")) {
|
||||
x["password"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(result, "subscription")) {
|
||||
for (let x in result["subscription"]) {
|
||||
if (exists(x, "url")) {
|
||||
x["url"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(result, "lan_access_control")) {
|
||||
for (let x in result["lan_access_control"]) {
|
||||
if (exists(x, "ip")) {
|
||||
for (let i = 0; i < length(x["ip"]); i++) {
|
||||
x["ip"][i] = "*";
|
||||
}
|
||||
}
|
||||
if (exists(x, "ip6")) {
|
||||
for (let i = 0; i < length(x["ip6"]); i++) {
|
||||
x["ip6"][i] = "*";
|
||||
}
|
||||
}
|
||||
if (exists(x, "mac")) {
|
||||
for (let i = 0; i < length(x["mac"]); i++) {
|
||||
x["mac"][i] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete result["status"];
|
||||
delete result["editor"];
|
||||
delete result["log"];
|
||||
print(result);
|
||||
'
|
||||
`
|
||||
\`\`\`
|
||||
## profile
|
||||
\`\`\`json
|
||||
`
|
||||
ucode -S -e '
|
||||
import { popen } from "fs";
|
||||
|
||||
function desensitize_proxies(proxies) {
|
||||
for (let x in proxies) {
|
||||
if (exists(x, "server")) {
|
||||
x["server"] = "*";
|
||||
}
|
||||
if (exists(x, "servername")) {
|
||||
x["servername"] = "*";
|
||||
}
|
||||
if (exists(x, "sni")) {
|
||||
x["sni"] = "*";
|
||||
}
|
||||
if (exists(x, "port")) {
|
||||
x["port"] = "*";
|
||||
}
|
||||
if (exists(x, "ports")) {
|
||||
x["ports"] = "*";
|
||||
}
|
||||
if (exists(x, "port-range")) {
|
||||
x["port-range"] = "*";
|
||||
}
|
||||
if (exists(x, "uuid")) {
|
||||
x["uuid"] = "*";
|
||||
}
|
||||
if (exists(x, "private-key")) {
|
||||
x["private-key"] = "*";
|
||||
}
|
||||
if (exists(x, "public-key")) {
|
||||
x["public-key"] = "*";
|
||||
}
|
||||
if (exists(x, "token")) {
|
||||
x["token"] = "*";
|
||||
}
|
||||
if (exists(x, "username")) {
|
||||
x["username"] = "*";
|
||||
}
|
||||
if (exists(x, "password")) {
|
||||
x["password"] = "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function desensitize_profile() {
|
||||
let profile = {};
|
||||
const process = popen("yq -p yaml -o json /etc/nikki/run/config.yaml");
|
||||
if (process) {
|
||||
profile = json(process);
|
||||
if (exists(profile, "secret")) {
|
||||
profile["secret"] = "*";
|
||||
}
|
||||
if (exists(profile, "authentication")) {
|
||||
profile["authentication"] = [];
|
||||
}
|
||||
if (exists(profile, "proxy-providers")) {
|
||||
for (let x in profile["proxy-providers"]) {
|
||||
if (exists(profile["proxy-providers"][x], "url")) {
|
||||
profile["proxy-providers"][x]["url"] = "*";
|
||||
}
|
||||
if (exists(profile["proxy-providers"][x], "payload")) {
|
||||
desensitize_proxies(profile["proxy-providers"][x]["payload"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exists(profile, "proxies")) {
|
||||
desensitize_proxies(profile["proxies"]);
|
||||
}
|
||||
process.close();
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
print(desensitize_profile());
|
||||
'
|
||||
`
|
||||
\`\`\`
|
||||
## ip rule
|
||||
\`\`\`
|
||||
`
|
||||
ip rule list
|
||||
`
|
||||
\`\`\`
|
||||
## ip route
|
||||
\`\`\`
|
||||
TPROXY:
|
||||
`
|
||||
ip route list table "$(uci get nikki.routing.tproxy_route_table)"
|
||||
`
|
||||
|
||||
TUN:
|
||||
`
|
||||
ip route list table "$(uci get nikki.routing.tun_route_table)"
|
||||
`
|
||||
\`\`\`
|
||||
## ip6 rule
|
||||
\`\`\`
|
||||
`
|
||||
ip -6 rule list
|
||||
`
|
||||
\`\`\`
|
||||
## ip6 route
|
||||
\`\`\`
|
||||
TPROXY:
|
||||
`
|
||||
ip -6 route list table "$(uci get nikki.routing.tproxy_route_table)"
|
||||
`
|
||||
|
||||
TUN:
|
||||
`
|
||||
ip -6 route list table "$(uci get nikki.routing.tun_route_table)"
|
||||
`
|
||||
\`\`\`
|
||||
## nftables
|
||||
\`\`\`
|
||||
`
|
||||
nft list table inet nikki
|
||||
`
|
||||
\`\`\`
|
||||
## service
|
||||
\`\`\`json
|
||||
`
|
||||
/etc/init.d/nikki info
|
||||
`
|
||||
\`\`\`
|
||||
"
|
||||
|
||||
if [ "$enabled" == "0" ]; then
|
||||
uci set nikki.config.enabled=0
|
||||
uci commit nikki
|
||||
/etc/init.d/nikki restart
|
||||
fi
|
||||
22
nikki/files/scripts/firewall_include.sh
Normal file
22
nikki/files/scripts/firewall_include.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/lib/functions.sh"
|
||||
. "$IPKG_INSTROOT/etc/nikki/scripts/include.sh"
|
||||
|
||||
config_load nikki
|
||||
config_get_bool enabled "config" "enabled" 0
|
||||
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"
|
||||
|
||||
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"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
90
nikki/files/scripts/include.sh
Normal file
90
nikki/files/scripts/include.sh
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/bin/sh
|
||||
|
||||
# paths
|
||||
HOME_DIR="/etc/nikki"
|
||||
PROFILES_DIR="$HOME_DIR/profiles"
|
||||
SUBSCRIPTIONS_DIR="$HOME_DIR/subscriptions"
|
||||
MIXIN_FILE_PATH="$HOME_DIR/mixin.yaml"
|
||||
RUN_DIR="$HOME_DIR/run"
|
||||
RUN_PROFILE_PATH="$RUN_DIR/config.yaml"
|
||||
PROVIDERS_DIR="$RUN_DIR/providers"
|
||||
RULE_PROVIDERS_DIR="$PROVIDERS_DIR/rule"
|
||||
PROXY_PROVIDERS_DIR="$PROVIDERS_DIR/proxy"
|
||||
|
||||
# log
|
||||
LOG_DIR="/var/log/nikki"
|
||||
APP_LOG_PATH="$LOG_DIR/app.log"
|
||||
CORE_LOG_PATH="$LOG_DIR/core.log"
|
||||
|
||||
# temp
|
||||
TEMP_DIR="/var/run/nikki"
|
||||
PID_FILE_PATH="$TEMP_DIR/nikki.pid"
|
||||
STARTED_FLAG_PATH="$TEMP_DIR/started.flag"
|
||||
BRIDGE_NF_CALL_IPTABLES_FLAG_PATH="$TEMP_DIR/bridge_nf_call_iptables.flag"
|
||||
BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH="$TEMP_DIR/bridge_nf_call_ip6tables.flag"
|
||||
|
||||
# ucode
|
||||
UCODE_DIR="$HOME_DIR/ucode"
|
||||
INCLUDE_UC="$UCODE_DIR/include.uc"
|
||||
MIXIN_UC="$UCODE_DIR/mixin.uc"
|
||||
HIJACK_UT="$UCODE_DIR/hijack.ut"
|
||||
|
||||
# scripts
|
||||
SH_DIR="$HOME_DIR/scripts"
|
||||
INCLUDE_SH="$SH_DIR/include.sh"
|
||||
FIREWALL_INCLUDE_SH="$SH_DIR/firewall_include.sh"
|
||||
|
||||
# nftables
|
||||
NFT_DIR="$HOME_DIR/nftables"
|
||||
GEOIP_CN_NFT="$NFT_DIR/geoip_cn.nft"
|
||||
GEOIP6_CN_NFT="$NFT_DIR/geoip6_cn.nft"
|
||||
|
||||
# functions
|
||||
format_filesize() {
|
||||
local b; b=1
|
||||
local kb; kb=$((b * 1024))
|
||||
local mb; mb=$((kb * 1024))
|
||||
local gb; gb=$((mb * 1024))
|
||||
local tb; tb=$((gb * 1024))
|
||||
local pb; pb=$((tb * 1024))
|
||||
local size; size="$1"
|
||||
if [ -n "$size" ]; then
|
||||
if [ "$size" -lt "$kb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $b}") B"
|
||||
elif [ "$size" -lt "$mb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $kb}") KB"
|
||||
elif [ "$size" -lt "$gb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $mb}") MB"
|
||||
elif [ "$size" -lt "$tb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $gb}") GB"
|
||||
elif [ "$size" -lt "$pb" ]; then
|
||||
echo "$(awk "BEGIN {print $size / $tb}") TB"
|
||||
else
|
||||
echo "$(awk "BEGIN {print $size / $pb}") PB"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_files() {
|
||||
if [ ! -d "$LOG_DIR" ]; then
|
||||
mkdir -p "$LOG_DIR"
|
||||
fi
|
||||
if [ ! -f "$APP_LOG_PATH" ]; then
|
||||
touch "$APP_LOG_PATH"
|
||||
fi
|
||||
if [ ! -f "$CORE_LOG_PATH" ]; then
|
||||
touch "$CORE_LOG_PATH"
|
||||
fi
|
||||
if [ ! -d "$TEMP_DIR" ]; then
|
||||
mkdir -p "$TEMP_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
clear_log() {
|
||||
echo -n > "$APP_LOG_PATH"
|
||||
echo -n > "$CORE_LOG_PATH"
|
||||
}
|
||||
|
||||
log() {
|
||||
echo "[$(date "+%Y-%m-%d %H:%M:%S")] [$1] $2" >> "$APP_LOG_PATH"
|
||||
}
|
||||
12
nikki/files/uci-defaults/firewall.sh
Normal file
12
nikki/files/uci-defaults/firewall.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/nikki/scripts/include.sh"
|
||||
|
||||
uci -q batch <<-EOF > /dev/null
|
||||
del firewall.nikki
|
||||
set firewall.nikki=include
|
||||
set firewall.nikki.type=script
|
||||
set firewall.nikki.path=$FIREWALL_INCLUDE_SH
|
||||
set firewall.nikki.fw4_compatible=1
|
||||
commit firewall
|
||||
EOF
|
||||
24
nikki/files/uci-defaults/init.sh
Normal file
24
nikki/files/uci-defaults/init.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/nikki/scripts/include.sh"
|
||||
|
||||
# check nikki.config.init
|
||||
init=$(uci -q get nikki.config.init); [ -z "$init" ] && return
|
||||
|
||||
# generate random string for api secret and authentication password
|
||||
random=$(awk 'BEGIN{srand(); print int(rand() * 1000000)}')
|
||||
|
||||
# set nikki.mixin.api_secret
|
||||
uci set nikki.mixin.api_secret="$random"
|
||||
|
||||
# set nikki.@authentication[0].password
|
||||
uci set nikki.@authentication[0].password="$random"
|
||||
|
||||
# remove nikki.config.init
|
||||
uci del nikki.config.init
|
||||
|
||||
# commit
|
||||
uci commit nikki
|
||||
|
||||
# exit with 0
|
||||
exit 0
|
||||
218
nikki/files/uci-defaults/migrate.sh
Normal file
218
nikki/files/uci-defaults/migrate.sh
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/etc/nikki/scripts/include.sh"
|
||||
|
||||
# since v1.18.0
|
||||
|
||||
mixin_rule=$(uci -q get nikki.mixin.rule); [ -z "$mixin_rule" ] && uci set nikki.mixin.rule=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:]]+\].match=' | sed 's/nikki.@rule\[\([[:digit:]]\+\)\].match=.*/rename nikki.@rule[\1].match=matcher/' | uci batch
|
||||
|
||||
# since v1.19.1
|
||||
|
||||
proxy_fake_ip_ping_hijack=$(uci -q get nikki.proxy.fake_ip_ping_hijack); [ -z "$proxy_fake_ip_ping_hijack" ] && uci set nikki.proxy.fake_ip_ping_hijack=0
|
||||
|
||||
# since v1.20.0
|
||||
|
||||
mixin_api_port=$(uci -q get nikki.mixin.api_port); [ -n "$mixin_api_port" ] && {
|
||||
uci del nikki.mixin.api_port
|
||||
uci set nikki.mixin.api_listen="[::]:$mixin_api_port"
|
||||
}
|
||||
|
||||
mixin_dns_port=$(uci -q get nikki.mixin.dns_port); [ -n "$mixin_dns_port" ] && {
|
||||
uci del nikki.mixin.dns_port
|
||||
uci set nikki.mixin.dns_listen="[::]:$mixin_dns_port"
|
||||
}
|
||||
|
||||
# since v1.22.0
|
||||
|
||||
proxy_transparent_proxy=$(uci -q get nikki.proxy.transparent_proxy); [ -n "$proxy_transparent_proxy" ] && {
|
||||
uci rename nikki.proxy.transparent_proxy=enabled
|
||||
uci rename nikki.proxy.tcp_transparent_proxy_mode=tcp_mode
|
||||
uci rename nikki.proxy.udp_transparent_proxy_mode=udp_mode
|
||||
|
||||
uci add nikki router_access_control
|
||||
uci set nikki.@router_access_control[-1].enabled=1
|
||||
proxy_bypass_user=$(uci -q get nikki.proxy.bypass_user); [ -n "$proxy_bypass_user" ] && {
|
||||
for router_access_control_user in $proxy_bypass_user; do
|
||||
uci add_list nikki.@router_access_control[-1].user="$router_access_control_user"
|
||||
done
|
||||
}
|
||||
proxy_bypass_group=$(uci -q get nikki.proxy.bypass_group); [ -n "$proxy_bypass_group" ] && {
|
||||
for router_access_control_group in $proxy_bypass_group; do
|
||||
uci add_list nikki.@router_access_control[-1].group="$router_access_control_group"
|
||||
done
|
||||
}
|
||||
proxy_bypass_cgroup=$(uci -q get nikki.proxy.bypass_cgroup); [ -n "$proxy_bypass_cgroup" ] && {
|
||||
for router_access_control_cgroup in $proxy_bypass_cgroup; do
|
||||
uci add_list nikki.@router_access_control[-1].cgroup="$router_access_control_cgroup"
|
||||
done
|
||||
}
|
||||
uci set nikki.@router_access_control[-1].proxy=0
|
||||
|
||||
uci add nikki router_access_control
|
||||
uci set nikki.@router_access_control[-1].enabled=1
|
||||
uci set nikki.@router_access_control[-1].proxy=1
|
||||
|
||||
uci add_list nikki.proxy.lan_inbound_interface=lan
|
||||
|
||||
proxy_access_control_mode=$(uci -q get nikki.proxy.access_control_mode)
|
||||
|
||||
[ "$proxy_access_control_mode" != "all" ] && {
|
||||
proxy_acl_ip=$(uci -q get nikki.proxy.acl_ip); [ -n "$proxy_acl_ip" ] && {
|
||||
for ip in $proxy_acl_ip; do
|
||||
uci add nikki lan_access_control
|
||||
uci set nikki.@lan_access_control[-1].enabled=1
|
||||
uci add_list nikki.@lan_access_control[-1].ip="$ip"
|
||||
[ "$proxy_access_control_mode" = "allow" ] && uci set nikki.@lan_access_control[-1].proxy=1
|
||||
[ "$proxy_access_control_mode" = "block" ] && uci set nikki.@lan_access_control[-1].proxy=0
|
||||
done
|
||||
}
|
||||
proxy_acl_ip6=$(uci -q get nikki.proxy.acl_ip6); [ -n "$proxy_acl_ip6" ] && {
|
||||
for ip6 in $proxy_acl_ip6; do
|
||||
uci add nikki lan_access_control
|
||||
uci set nikki.@lan_access_control[-1].enabled=1
|
||||
uci add_list nikki.@lan_access_control[-1].ip6="$ip6"
|
||||
[ "$proxy_access_control_mode" = "allow" ] && uci set nikki.@lan_access_control[-1].proxy=1
|
||||
[ "$proxy_access_control_mode" = "block" ] && uci set nikki.@lan_access_control[-1].proxy=0
|
||||
done
|
||||
}
|
||||
proxy_acl_mac=$(uci -q get nikki.proxy.acl_mac); [ -n "$proxy_acl_mac" ] && {
|
||||
for mac in $proxy_acl_mac; do
|
||||
uci add nikki lan_access_control
|
||||
uci set nikki.@lan_access_control[-1].enabled=1
|
||||
uci add_list nikki.@lan_access_control[-1].mac="$mac"
|
||||
[ "$proxy_access_control_mode" = "allow" ] && uci set nikki.@lan_access_control[-1].proxy=1
|
||||
[ "$proxy_access_control_mode" = "block" ] && uci set nikki.@lan_access_control[-1].proxy=0
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
[ "$proxy_access_control_mode" != "allow" ] && {
|
||||
uci add nikki lan_access_control
|
||||
uci set nikki.@lan_access_control[-1].enabled=1
|
||||
uci set nikki.@lan_access_control[-1].proxy=1
|
||||
}
|
||||
|
||||
uci del nikki.proxy.access_control_mode
|
||||
uci del nikki.proxy.acl_ip
|
||||
uci del nikki.proxy.acl_ip6
|
||||
uci del nikki.proxy.acl_mac
|
||||
uci del nikki.proxy.acl_interface
|
||||
uci del nikki.proxy.bypass_user
|
||||
uci del nikki.proxy.bypass_group
|
||||
uci del nikki.proxy.bypass_cgroup
|
||||
}
|
||||
|
||||
# since v1.23.0
|
||||
|
||||
routing=$(uci -q get nikki.routing); [ -z "$routing" ] && {
|
||||
uci set nikki.routing=routing
|
||||
uci set nikki.routing.tproxy_fw_mark=0x80
|
||||
uci set nikki.routing.tun_fw_mark=0x81
|
||||
uci set nikki.routing.tproxy_rule_pref=1024
|
||||
uci set nikki.routing.tun_rule_pref=1025
|
||||
uci set nikki.routing.tproxy_route_table=80
|
||||
uci set nikki.routing.tun_route_table=81
|
||||
uci set nikki.routing.cgroup_id=0x12061206
|
||||
uci set nikki.routing.cgroup_name=nikki
|
||||
}
|
||||
|
||||
proxy_tun_timeout=$(uci -q get nikki.proxy.tun_timeout); [ -z "$proxy_tun_timeout" ] && uci set nikki.proxy.tun_timeout=30
|
||||
|
||||
proxy_tun_interval=$(uci -q get nikki.proxy.tun_interval); [ -z "$proxy_tun_interval" ] && uci set nikki.proxy.tun_interval=1
|
||||
|
||||
# since v1.23.1
|
||||
|
||||
uci show nikki | grep -o -E 'nikki\.@router_access_control\[[[:digit:]]+\]=router_access_control' | cut -d '=' -f 1 | while read -r router_access_control; do
|
||||
for router_access_control_cgroup in $(uci -q get "$router_access_control.cgroup"); do
|
||||
[ -d "/sys/fs/cgroup/$router_access_control_cgroup" ] && continue
|
||||
[ -d "/sys/fs/cgroup/services/$router_access_control_cgroup" ] && {
|
||||
uci del_list "$router_access_control.cgroup=$router_access_control_cgroup"
|
||||
uci add_list "$router_access_control.cgroup=services/$router_access_control_cgroup"
|
||||
}
|
||||
done
|
||||
done
|
||||
|
||||
# since v1.23.2
|
||||
|
||||
env_disable_safe_path_check=$(uci -q get nikki.env.disable_safe_path_check); [ -n "$env_disable_safe_path_check" ] && uci del nikki.env.disable_safe_path_check
|
||||
|
||||
env_skip_system_ipv6_check=$(uci -q get nikki.env.skip_system_ipv6_check); [ -z "$env_skip_system_ipv6_check" ] && uci set nikki.env.skip_system_ipv6_check=0
|
||||
|
||||
# since v1.23.3
|
||||
|
||||
uci show nikki | grep -o -E 'nikki\.@router_access_control\[[[:digit:]]+\]=router_access_control' | cut -d '=' -f 1 | while read -r router_access_control; do
|
||||
router_access_control_proxy=$(uci -q get "$router_access_control.proxy")
|
||||
router_access_control_dns=$(uci -q get "$router_access_control.dns")
|
||||
[ -z "$router_access_control_dns" ] && uci set "$router_access_control.dns=$router_access_control_proxy"
|
||||
done
|
||||
|
||||
uci show nikki | grep -o -E 'nikki\.@lan_access_control\[[[:digit:]]+\]=lan_access_control' | cut -d '=' -f 1 | while read -r lan_access_control; do
|
||||
lan_access_control_proxy=$(uci -q get "$lan_access_control.proxy")
|
||||
lan_access_control_dns=$(uci -q get "$lan_access_control.dns")
|
||||
[ -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
|
||||
}
|
||||
|
||||
# since v1.24.3
|
||||
|
||||
proxy_bypass_china_mainland_ip=$(uci -q get nikki.proxy.bypass_china_mainland_ip)
|
||||
proxy_bypass_china_mainland_ip6=$(uci -q get nikki.proxy.bypass_china_mainland_ip6)
|
||||
[ -z "$proxy_bypass_china_mainland_ip6" ] && uci set nikki.proxy.bypass_china_mainland_ip6=$proxy_bypass_china_mainland_ip
|
||||
|
||||
routing_tproxy_fw_mask=$(uci -q get nikki.routing.tproxy_fw_mask); [ -z "$routing_tproxy_fw_mask" ] && uci set nikki.routing.tproxy_fw_mask=0xFF
|
||||
routing_tun_fw_mask=$(uci -q get nikki.routing.tun_fw_mask); [ -z "$routing_tun_fw_mask" ] && uci set nikki.routing.tun_fw_mask=0xFF
|
||||
|
||||
procd=$(uci -q get nikki.procd); [ -z "$procd" ] && {
|
||||
uci set nikki.procd=procd
|
||||
uci set nikki.procd.fast_reload=$(uci -q get nikki.config.fast_reload)
|
||||
uci set nikki.procd.env_safe_paths=$(uci -q get nikki.env.safe_paths)
|
||||
uci set nikki.procd.env_disable_loopback_detector=$(uci -q get nikki.env.disable_loopback_detector)
|
||||
uci set nikki.procd.env_disable_quic_go_gso=$(uci -q get nikki.env.disable_quic_go_gso)
|
||||
uci set nikki.procd.env_disable_quic_go_ecn=$(uci -q get nikki.env.disable_quic_go_ecn)
|
||||
uci set nikki.procd.env_skip_system_ipv6_check=$(uci -q get nikki.env.skip_system_ipv6_check)
|
||||
uci del nikki.config.fast_reload
|
||||
uci del nikki.env
|
||||
}
|
||||
|
||||
# commit
|
||||
uci commit nikki
|
||||
|
||||
# exit with 0
|
||||
exit 0
|
||||
568
nikki/files/ucode/hijack.ut
Normal file
568
nikki/files/ucode/hijack.ut
Normal file
@@ -0,0 +1,568 @@
|
||||
#!/usr/bin/utpl
|
||||
|
||||
{%-
|
||||
'use strict';
|
||||
|
||||
import { cursor } from 'uci';
|
||||
import { connect } from 'ubus';
|
||||
import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups, load_profile } from '/etc/nikki/ucode/include.uc';
|
||||
|
||||
const fw4 = require('fw4');
|
||||
|
||||
const cgroups_version = get_cgroups_version();
|
||||
|
||||
const users = get_users();
|
||||
const groups = get_groups();
|
||||
const cgroups = get_cgroups();
|
||||
|
||||
const uci = cursor();
|
||||
const ubus = connect();
|
||||
|
||||
const profile = load_profile();
|
||||
|
||||
const redir_port = profile['redir-port'];
|
||||
const tproxy_port = profile['tproxy-port'];
|
||||
|
||||
let dns_listen;
|
||||
let dns_port;
|
||||
let fake_ip_range;
|
||||
if (profile['dns']) {
|
||||
dns_listen = profile['dns']['listen'];
|
||||
const dns_listen_rindex = rindex(dns_listen, ':');
|
||||
if (dns_listen_rindex >= 0 && dns_listen_rindex + 1 < length(dns_listen)) {
|
||||
dns_port = substr(dns_listen, dns_listen_rindex + 1);
|
||||
}
|
||||
fake_ip_range = profile['dns']['fake-ip-range'];
|
||||
}
|
||||
|
||||
let tun_device;
|
||||
if (profile['tun']) {
|
||||
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');
|
||||
const ipv4_dns_hijack = uci_bool(uci.get('nikki', 'proxy', 'ipv4_dns_hijack'));
|
||||
const ipv6_dns_hijack = uci_bool(uci.get('nikki', 'proxy', 'ipv6_dns_hijack'));
|
||||
const ipv4_proxy = uci_bool(uci.get('nikki', 'proxy', 'ipv4_proxy'));
|
||||
const ipv6_proxy = uci_bool(uci.get('nikki', 'proxy', 'ipv6_proxy'));
|
||||
const fake_ip_ping_hijack = uci_bool(uci.get('nikki', 'proxy', 'fake_ip_ping_hijack'));
|
||||
|
||||
const router_proxy = uci_bool(uci.get('nikki', 'proxy', 'router_proxy'));
|
||||
const router_access_control = [];
|
||||
uci.foreach('nikki', 'router_access_control', (access_control) => {
|
||||
access_control['enabled'] = uci_bool(access_control['enabled']);
|
||||
access_control['user'] = filter(uci_array(access_control['user']), (x) => index(users, x) >= 0);
|
||||
access_control['group'] = filter(uci_array(access_control['group']), (x) => index(groups, x) >= 0);
|
||||
access_control['cgroup'] = filter(uci_array(access_control['cgroup']), (x) => index(cgroups, x) >= 0);
|
||||
access_control['proxy'] = uci_bool(access_control['proxy']);
|
||||
access_control['dns'] = uci_bool(access_control['dns']);
|
||||
push(router_access_control, access_control);
|
||||
});
|
||||
|
||||
const lan_proxy = uci_bool(uci.get('nikki', 'proxy', 'lan_proxy'));
|
||||
const lan_inbound_interface = uci_array(uci.get('nikki', 'proxy', 'lan_inbound_interface'));
|
||||
const lan_inbound_device = [];
|
||||
for (let interface in lan_inbound_interface) {
|
||||
const status = ubus.call('network.interface', 'status', { 'interface': interface });
|
||||
const device = status?.l3_device ?? status?.device ?? '';
|
||||
if (device != '') {
|
||||
push(lan_inbound_device, device);
|
||||
}
|
||||
}
|
||||
const lan_access_control = [];
|
||||
uci.foreach('nikki', 'lan_access_control', (access_control) => {
|
||||
access_control['enabled'] = uci_bool(access_control['enabled']);
|
||||
access_control['ip'] = uci_array(access_control['ip']);
|
||||
access_control['ip6'] = uci_array(access_control['ip6']);
|
||||
access_control['mac'] = uci_array(access_control['mac']);
|
||||
access_control['proxy'] = uci_bool(access_control['proxy']);
|
||||
access_control['dns'] = uci_bool(access_control['dns']);
|
||||
push(lan_access_control, access_control);
|
||||
});
|
||||
|
||||
const reserved_ip = uci_array(uci.get('nikki', 'proxy', 'reserved_ip'));
|
||||
const reserved_ip6 = uci_array(uci.get('nikki', '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 bypass_china_mainland_ip6 = uci_bool(uci.get('nikki', 'proxy', 'bypass_china_mainland_ip6'));
|
||||
const proxy_tcp_dport = split((uci.get('nikki', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' ');
|
||||
const proxy_udp_dport = split((uci.get('nikki', 'proxy', 'proxy_udp_dport') ?? '0-65535'), ' ');
|
||||
|
||||
const cgroup_id = uci.get('nikki', 'routing', 'cgroup_id') ?? '0x12061206';
|
||||
const cgroup_name = uci.get('nikki', 'routing', 'cgroup_name') ?? 'nikki';
|
||||
const tproxy_fw_mark = uci.get('nikki', 'routing', 'tproxy_fw_mark') ?? '0x80';
|
||||
const tproxy_fw_mask = uci.get('nikki', 'routing', 'tproxy_fw_mask') ?? '0xFF';
|
||||
const tproxy_fw_umask = fw4.hex(~tproxy_fw_mask & 0xFFFFFFFF);
|
||||
const tun_fw_mark = uci.get('nikki', 'routing', 'tun_fw_mark') ?? '0x81';
|
||||
const tun_fw_mask = uci.get('nikki', 'routing', 'tun_fw_mask') ?? '0xFF';
|
||||
const tun_fw_umask = fw4.hex(~tun_fw_mask & 0xFFFFFFFF);
|
||||
|
||||
const dns_hijack_nfproto = [];
|
||||
if (ipv4_dns_hijack) {
|
||||
push(dns_hijack_nfproto, 'ipv4');
|
||||
}
|
||||
if (ipv6_dns_hijack) {
|
||||
push(dns_hijack_nfproto, 'ipv6');
|
||||
}
|
||||
|
||||
const proxy_nfproto = [];
|
||||
if (ipv4_proxy) {
|
||||
push(proxy_nfproto, 'ipv4');
|
||||
}
|
||||
if (ipv6_proxy) {
|
||||
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}`);
|
||||
}
|
||||
-%}
|
||||
|
||||
table inet nikki {
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
set dns_hijack_nfproto {
|
||||
type nf_proto
|
||||
flags interval
|
||||
elements = {
|
||||
{{ join(', ', dns_hijack_nfproto) }}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
set proxy_nfproto {
|
||||
type nf_proto
|
||||
flags interval
|
||||
{% if (length(proxy_nfproto) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', proxy_nfproto) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set reserved_ip {
|
||||
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 {
|
||||
type ifname
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(lan_inbound_device) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', map(lan_inbound_device, (x) => `"${x}"`)) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set china_ip {
|
||||
type ipv4_addr
|
||||
flags interval
|
||||
}
|
||||
|
||||
set china_ip6 {
|
||||
type ipv6_addr
|
||||
flags interval
|
||||
}
|
||||
|
||||
set proxy_dport {
|
||||
type inet_proto . inet_service
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(proxy_dport) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', proxy_dport) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
set bypass_dscp {
|
||||
type dscp
|
||||
flags interval
|
||||
auto-merge
|
||||
{% if (length(bypass_dscp) > 0): %}
|
||||
elements = {
|
||||
{{ join(', ', bypass_dscp) }}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% 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']): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
meta l4proto { tcp, udp } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
chain router_redirect {
|
||||
{% for (let access_control in router_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
meta l4proto tcp counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
meta l4proto tcp meta skuid { {{ join(', ', access_control['user']) }} } counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
meta l4proto tcp meta skgid { {{ join(', ', access_control['group']) }} } counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
meta l4proto tcp socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% 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']): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
meta l4proto { tcp, udp } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% 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']): %}
|
||||
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
|
||||
meta l4proto { tcp, udp } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['user']) > 0): %}
|
||||
meta l4proto { tcp, udp } meta skuid { {{ join(', ', access_control['user']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['group']) > 0): %}
|
||||
meta l4proto { tcp, udp } meta skgid { {{ join(', ', access_control['group']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (cgroups_version == 2 && length(access_control['cgroup']) > 0): %}
|
||||
{% for (let cgroup in access_control['cgroup']): %}
|
||||
meta l4proto { tcp, udp } socket cgroupv2 level {{ length(split(cgroup, '/')) }} "{{ cgroup }}" {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% 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']): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
meta l4proto { tcp, udp } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } th dport 53 counter {% if (access_control.dns == '1'): %} redirect to :{{ dns_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
chain lan_redirect {
|
||||
{% for (let access_control in lan_access_control): %}
|
||||
{% if (access_control['enabled']): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
meta l4proto tcp counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} counter return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
meta l4proto tcp ip saddr { {{ join(', ', access_control['ip']) }} } counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
meta l4proto tcp ip6 saddr { {{ join(', ', access_control['ip6']) }} } counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
meta l4proto tcp ether saddr { {{ join(', ', access_control['mac']) }} } counter {% if (access_control.proxy == '1'): %} redirect to :{{ redir_port }} {% else %} return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% 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']): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
meta l4proto { tcp, udp } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy ip to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy ip6 to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tproxy_fw_umask }} | {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept {% else %} counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% 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']): %}
|
||||
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
|
||||
meta l4proto { tcp, udp } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %}counter return {% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if (length(access_control['ip']) > 0): %}
|
||||
meta l4proto { tcp, udp } ip saddr { {{ join(', ', access_control['ip']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %}counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['ip6']) > 0): %}
|
||||
meta l4proto { tcp, udp } ip6 saddr { {{ join(', ', access_control['ip6']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %}counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if (length(access_control['mac']) > 0): %}
|
||||
meta l4proto { tcp, udp } ether saddr { {{ join(', ', access_control['mac']) }} } {% if (access_control.proxy == '1'): %} meta mark set meta mark & {{ tun_fw_umask }} | {{ tun_fw_mark }} counter accept {% else %}counter return {% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if (router_proxy): %}
|
||||
chain nat_output {
|
||||
type nat hook output priority filter; policy accept;
|
||||
{% if (cgroups_version == 1): %}
|
||||
meta cgroup {{ cgroup_id }} counter return
|
||||
{% elif (cgroups_version == 2): %}
|
||||
socket cgroupv2 level 2 "services/{{ cgroup_name }}" counter return
|
||||
{% endif %}
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto jump router_dns_hijack
|
||||
{% endif %}
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
fib daddr type { local, broadcast, anycast, multicast } 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 {% 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 {% 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): %}
|
||||
{% if (fake_ip_range ): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain mangle_output {
|
||||
type route hook output priority mangle; policy accept;
|
||||
{% if (cgroups_version == 1): %}
|
||||
meta cgroup {{ cgroup_id }} counter return
|
||||
{% elif (cgroups_version == 2): %}
|
||||
socket cgroupv2 level 2 "services/{{ cgroup_name }}" counter return
|
||||
{% endif %}
|
||||
fib daddr type { local, broadcast, anycast, multicast } 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 {% 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 {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
|
||||
{% endif %}
|
||||
{% if (tcp_mode == 'tproxy'): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp jump router_tproxy
|
||||
{% elif (tcp_mode == 'tun'): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto tcp jump router_tun
|
||||
{% endif %}
|
||||
{% if (udp_mode == 'tproxy'): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto udp jump router_tproxy
|
||||
{% elif (udp_mode == 'tun'): %}
|
||||
meta nfproto @proxy_nfproto meta l4proto udp jump router_tun
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain mangle_prerouting_router {
|
||||
type filter hook prerouting priority mangle - 1; policy accept;
|
||||
{% if (tcp_mode == 'tproxy' || udp_mode == 'tproxy'): %}
|
||||
iifname lo meta l4proto { tcp, udp } meta mark & {{ tproxy_fw_mask }} == {{ tproxy_fw_mark }} tproxy to :{{ tproxy_port }} counter accept
|
||||
{% endif %}
|
||||
{% if (tcp_mode == 'tun' || udp_mode == 'tun'): %}
|
||||
iifname "{{ tun_device }}" meta l4proto { icmp, tcp, udp } counter accept
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if (lan_proxy): %}
|
||||
chain dstnat {
|
||||
type nat hook prerouting priority dstnat + 1; policy accept;
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
iifname @lan_inbound_device meta nfproto @dns_hijack_nfproto jump lan_dns_hijack
|
||||
{% endif %}
|
||||
{% if (tcp_mode == 'redirect'): %}
|
||||
fib daddr type { local, broadcast, anycast, multicast } 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 {% 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 {% 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): %}
|
||||
{% if (fake_ip_range): %}
|
||||
icmp type echo-request ip daddr {{ fake_ip_range }} counter redirect
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
chain mangle_prerouting_lan {
|
||||
type filter hook prerouting priority mangle; policy accept;
|
||||
fib daddr type { local, broadcast, anycast, multicast } 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 {% 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 {% if (fake_ip_range): %} ip daddr != {{ fake_ip_range }} {% endif %} counter return
|
||||
meta l4proto { tcp, udp } ip6 dscp @bypass_dscp counter return
|
||||
{% if (length(dns_hijack_nfproto) > 0): %}
|
||||
meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter return
|
||||
{% endif %}
|
||||
{% if (tcp_mode == 'tproxy'): %}
|
||||
iifname @lan_inbound_device meta nfproto @proxy_nfproto meta l4proto tcp jump lan_tproxy
|
||||
{% elif (tcp_mode == 'tun'): %}
|
||||
iifname @lan_inbound_device meta nfproto @proxy_nfproto meta l4proto tcp jump lan_tun
|
||||
{% endif %}
|
||||
{% if (udp_mode == 'tproxy'): %}
|
||||
iifname @lan_inbound_device meta nfproto @proxy_nfproto meta l4proto udp jump lan_tproxy
|
||||
{% elif (udp_mode == 'tun'): %}
|
||||
iifname @lan_inbound_device meta nfproto @proxy_nfproto meta l4proto udp jump lan_tun
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if (bypass_china_mainland_ip): %}
|
||||
include "/etc/nikki/nftables/geoip_cn.nft"
|
||||
{% endif %}
|
||||
{% if (bypass_china_mainland_ip6): %}
|
||||
include "/etc/nikki/nftables/geoip6_cn.nft"
|
||||
{% endif %}
|
||||
87
nikki/files/ucode/include.uc
Normal file
87
nikki/files/ucode/include.uc
Normal file
@@ -0,0 +1,87 @@
|
||||
import { readfile, popen } from 'fs';
|
||||
|
||||
export function uci_bool(obj) {
|
||||
return obj == null ? null : obj == '1';
|
||||
};
|
||||
|
||||
export function uci_int(obj) {
|
||||
return obj == null ? null : int(obj);
|
||||
};
|
||||
|
||||
export function uci_array(obj) {
|
||||
if (obj == null) {
|
||||
return [];
|
||||
}
|
||||
if (type(obj) == 'array') {
|
||||
return uniq(obj);
|
||||
}
|
||||
return [obj];
|
||||
};
|
||||
|
||||
export function trim_all(obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (type(obj) == 'string') {
|
||||
if (length(obj) == 0) {
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if (type(obj) == 'array') {
|
||||
if (length(obj) == 0) {
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
if (type(obj) == 'object') {
|
||||
const obj_keys = keys(obj);
|
||||
for (let key in obj_keys) {
|
||||
obj[key] = trim_all(obj[key]);
|
||||
if (obj[key] == null) {
|
||||
delete obj[key];
|
||||
}
|
||||
}
|
||||
if (length(keys(obj)) == 0) {
|
||||
return null;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
export function get_cgroups_version() {
|
||||
return system('mount | grep -q -w "^cgroup"') == 0 ? 1 : 2;
|
||||
};
|
||||
|
||||
export function get_users() {
|
||||
return map(split(readfile('/etc/passwd'), '\n'), (x) => split(x, ':')[0]);
|
||||
};
|
||||
|
||||
export function get_groups() {
|
||||
return map(split(readfile('/etc/group'), '\n'), (x) => split(x, ':')[0]);
|
||||
};
|
||||
|
||||
export function get_cgroups() {
|
||||
const result = [];
|
||||
if (get_cgroups_version() == 2) {
|
||||
const cgroup_path = '/sys/fs/cgroup/';
|
||||
const process = popen(`find ${cgroup_path} -type d -mindepth 1`);
|
||||
if (process) {
|
||||
for (let line = process.read('line'); length(line); line = process.read('line')) {
|
||||
push(result, substr(trim(line), length(cgroup_path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
};
|
||||
192
nikki/files/ucode/mixin.uc
Normal file
192
nikki/files/ucode/mixin.uc
Normal file
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/ucode
|
||||
|
||||
'use strict';
|
||||
|
||||
import { cursor } from 'uci';
|
||||
import { connect } from 'ubus';
|
||||
import { uci_bool, uci_int, uci_array, trim_all } from '/etc/nikki/ucode/include.uc';
|
||||
|
||||
const uci = cursor();
|
||||
const ubus = connect();
|
||||
|
||||
const config = {};
|
||||
|
||||
const outbound_interface = uci.get('nikki', 'mixin', 'outbound_interface');
|
||||
const outbound_interface_status = ubus.call('network.interface', 'status', { 'interface': outbound_interface });
|
||||
const outbound_device = outbound_interface_status?.l3_device ?? outbound_interface_status?.device ?? '';
|
||||
|
||||
config['log-level'] = uci.get('nikki', 'mixin', 'log_level');
|
||||
config['mode'] = uci.get('nikki', 'mixin', 'mode');
|
||||
config['find-process-mode'] = uci.get('nikki', 'mixin', 'match_process');
|
||||
config['interface-name'] = outbound_device;
|
||||
config['ipv6'] = uci_bool(uci.get('nikki', 'mixin', 'ipv6'));
|
||||
config['unified-delay'] = uci_bool(uci.get('nikki', 'mixin', 'unify_delay'));
|
||||
config['tcp-concurrent'] = uci_bool(uci.get('nikki', 'mixin', 'tcp_concurrent'));
|
||||
config['disable-keep-alive'] = uci_bool(uci.get('nikki', 'mixin', 'disable_tcp_keep_alive'));
|
||||
config['keep-alive-idle'] = uci_int(uci.get('nikki', 'mixin', 'tcp_keep_alive_idle'));
|
||||
config['keep-alive-interval'] = uci_int(uci.get('nikki', 'mixin', 'tcp_keep_alive_interval'));
|
||||
config['global-client-fingerprint'] = uci.get('nikki', 'mixin', 'global_client_fingerprint');
|
||||
|
||||
config['external-ui'] = uci.get('nikki', 'mixin', 'ui_path');
|
||||
config['external-ui-name'] = uci.get('nikki', 'mixin', 'ui_name');
|
||||
config['external-ui-url'] = uci.get('nikki', 'mixin', 'ui_url');
|
||||
config['external-controller'] = uci.get('nikki', 'mixin', 'api_listen');
|
||||
config['secret'] = uci.get('nikki', 'mixin', 'api_secret');
|
||||
|
||||
config['allow-lan'] = uci_bool(uci.get('nikki', 'mixin', 'allow_lan'));
|
||||
config['port'] = uci_int(uci.get('nikki', 'mixin', 'http_port'));
|
||||
config['socks-port'] = uci_int(uci.get('nikki', 'mixin', 'socks_port'));
|
||||
config['mixed-port'] = uci_int(uci.get('nikki', 'mixin', 'mixed_port'));
|
||||
config['redir-port'] = uci_int(uci.get('nikki', 'mixin', 'redir_port'));
|
||||
config['tproxy-port'] = uci_int(uci.get('nikki', 'mixin', 'tproxy_port'));
|
||||
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'authentication'))) {
|
||||
config['authentication'] = [];
|
||||
uci.foreach('nikki', 'authentication', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
push(config['authentication'], `${section.username}:${section.password}`);
|
||||
});
|
||||
}
|
||||
|
||||
config['tun'] = {};
|
||||
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'));
|
||||
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['dns'] = {};
|
||||
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');
|
||||
config['dns']['fake-ip-range'] = uci.get('nikki', 'mixin', 'fake_ip_range');
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'fake_ip_filter'))) {
|
||||
config['dns']['fake-ip-filter'] = uci_array(uci.get('nikki', 'mixin', 'fake_ip_filters'));
|
||||
}
|
||||
config['dns']['fake-ip-filter-mode'] = uci.get('nikki', 'mixin', 'fake_ip_filter_mode');
|
||||
|
||||
config['dns']['respect-rules'] = uci_bool(uci.get('nikki', 'mixin', 'dns_respect_rules'));
|
||||
config['dns']['prefer-h3'] = uci_bool(uci.get('nikki', 'mixin', 'dns_doh_prefer_http3'));
|
||||
config['dns']['use-system-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_system_hosts'));
|
||||
config['dns']['use-hosts'] = uci_bool(uci.get('nikki', 'mixin', 'dns_hosts'));
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'hosts'))) {
|
||||
config['hosts'] = {};
|
||||
uci.foreach('nikki', 'hosts', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
config['hosts'][section.domain_name] = uci_array(section.ip);
|
||||
});
|
||||
}
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver'))) {
|
||||
config['dns']['default-nameserver'] = [];
|
||||
config['dns']['proxy-server-nameserver'] = [];
|
||||
config['dns']['direct-nameserver'] = [];
|
||||
config['dns']['nameserver'] = [];
|
||||
config['dns']['fallback'] = [];
|
||||
uci.foreach('nikki', 'nameserver', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
push(config['dns'][section.type], ...uci_array(section.nameserver));
|
||||
})
|
||||
}
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'dns_nameserver_policy'))) {
|
||||
config['dns']['nameserver-policy'] = {};
|
||||
uci.foreach('nikki', 'nameserver_policy', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
config['dns']['nameserver-policy'][section.matcher] = uci_array(section.nameserver);
|
||||
});
|
||||
}
|
||||
|
||||
config['sniffer'] = {};
|
||||
config['sniffer']['enable'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer'));
|
||||
config['sniffer']['force-dns-mapping'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_dns_mapping'));
|
||||
config['sniffer']['parse-pure-ip'] = uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff_pure_ip'));
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_force_domain_name'))) {
|
||||
config['sniffer']['force-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_force_domain_names'));
|
||||
}
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_name'))) {
|
||||
config['sniffer']['skip-domain'] = uci_array(uci.get('nikki', 'mixin', 'sniffer_ignore_domain_names'));
|
||||
}
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'sniffer_sniff'))) {
|
||||
config['sniffer']['sniff'] = {};
|
||||
config['sniffer']['sniff']['HTTP'] = {};
|
||||
config['sniffer']['sniff']['TLS'] = {};
|
||||
config['sniffer']['sniff']['QUIC'] = {};
|
||||
uci.foreach('nikki', 'sniff', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
config['sniffer']['sniff'][section.protocol]['port'] = uci_array(section.port);
|
||||
config['sniffer']['sniff'][section.protocol]['override-destination'] = uci_bool(section.overwrite_destination);
|
||||
});
|
||||
}
|
||||
|
||||
config['profile'] = {};
|
||||
config['profile']['store-selected'] = uci_bool(uci.get('nikki', 'mixin', 'selection_cache'));
|
||||
config['profile']['store-fake-ip'] = uci_bool(uci.get('nikki', 'mixin', 'fake_ip_cache'));
|
||||
|
||||
if (uci_bool(uci.get('nikki', 'mixin', 'rule_provider'))) {
|
||||
config['rule-providers'] = {};
|
||||
uci.foreach('nikki', 'rule_provider', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
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_bool(uci.get('nikki', 'mixin', 'rule'))) {
|
||||
config['nikki-rules'] = [];
|
||||
uci.foreach('nikki', 'rule', (section) => {
|
||||
if (!uci_bool(section.enabled)) {
|
||||
return;
|
||||
}
|
||||
const rule = [ section.type, section.matcher, section.node, uci_bool(section.no_resolve) ? 'no-resolve' : null ];
|
||||
push(config['nikki-rules'], join(',', filter(rule, (item) => item != null && item != '')));
|
||||
})
|
||||
}
|
||||
|
||||
const geoip_format = uci.get('nikki', 'mixin', 'geoip_format');
|
||||
config['geodata-mode'] = geoip_format == null ? null : geoip_format == 'dat';
|
||||
config['geodata-loader'] = uci.get('nikki', 'mixin', 'geodata_loader');
|
||||
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_bool(uci.get('nikki', 'mixin', 'geox_auto_update'));
|
||||
config['geo-update-interval'] = uci_int(uci.get('nikki', 'mixin', 'geox_update_interval'));
|
||||
|
||||
print(trim_all(config));
|
||||
Reference in New Issue
Block a user