From 6032ccb8619b95334ed2315df7b178c71e61f3cd Mon Sep 17 00:00:00 2001 From: gitea-action Date: Sun, 23 Mar 2025 17:30:27 +0800 Subject: [PATCH] nikki: sync upstream last commit: https://github.com/nikkinikki-org/OpenWrt-nikki/commit/277a7d97d9b95ee0132a045a0488d06994c58c52 --- nikki/Makefile | 8 ++-- nikki/files/nikki.init | 79 +++++++++++++++++++++------------- nikki/files/scripts/include.sh | 15 ++++--- nikki/files/ucode/hijack.ut | 39 +++++++++++++++-- nikki/files/ucode/include.uc | 15 ++++++- 5 files changed, 110 insertions(+), 46 deletions(-) diff --git a/nikki/Makefile b/nikki/Makefile index 64ad9219f..c58f203d8 100644 --- a/nikki/Makefile +++ b/nikki/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git -PKG_SOURCE_DATE:=2025-03-17 -PKG_SOURCE_VERSION:=e3d4ec247670dc88f8a3410e9bca2c69ca053f32 -PKG_MIRROR_HASH:=ab8e39fec0675a77d575acf5ed705bb327a5f9f2b8d72792896e884e491b25e6 +PKG_SOURCE_DATE:=2025-03-20 +PKG_SOURCE_VERSION:=0f32c054f47641a2ee9c9362fc65652e772924b2 +PKG_MIRROR_HASH:=276f1dcc81b3cece5c7de5b16ddac8d596bf20e7c3bb8993d963042acf845a14 PKG_LICENSE:=GPL3.0+ PKG_MAINTAINER:=Joseph Mory @@ -16,7 +16,7 @@ PKG_BUILD_DEPENDS:=golang/host PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 -PKG_BUILD_VERSION:=alpha-e3d4ec2 +PKG_BUILD_VERSION:=alpha-0f32c05 PKG_BUILD_TIME:=$(shell date -u -Iseconds) GO_PKG:=github.com/metacubex/mihomo diff --git a/nikki/files/nikki.init b/nikki/files/nikki.init index 29ea4d6fd..b53ee9c4e 100644 --- a/nikki/files/nikki.init +++ b/nikki/files/nikki.init @@ -69,7 +69,7 @@ start_service() { config_get_bool disable_quic_go_ecn "env" "disable_quic_go_ecn" 0 # get profile if [[ "$profile" == "file:"* ]]; then - local profile_name; profile_name=$(basename "${profile/file:/}") + local profile_name; profile_name="${profile/file:/}" local profile_file; profile_file="$PROFILES_DIR/$profile_name" log "Profile" "Use file: $profile_name." if [ ! -f "$profile_file" ]; then @@ -128,8 +128,8 @@ start_service() { if [ "$fast_reload" == 1 ]; then procd_set_param reload_signal HUP fi + procd_set_param pidfile "$PID_FILE_PATH" procd_set_param respawn - procd_set_param limits core="unlimited" nofile="1048576 1048576" procd_close_instance @@ -140,12 +140,12 @@ start_service() { /etc/init.d/cron restart fi # set started flag - touch "$STARTED_FLAG" + touch "$STARTED_FLAG_PATH" } service_started() { # check if started - if [ ! -f "$STARTED_FLAG" ]; then + if [ ! -f "$STARTED_FLAG_PATH" ]; then return fi # load config @@ -169,7 +169,7 @@ service_started() { config_get udp_transparent_proxy_mode "proxy" "udp_transparent_proxy_mode" config_get_bool ipv4_proxy "proxy" "ipv4_proxy" 0 config_get_bool ipv6_proxy "proxy" "ipv6_proxy" 0 - # prepare + # prepare config local tproxy_enable; tproxy_enable=0 if [[ "$tcp_transparent_proxy_mode" == "tproxy" || "$udp_transparent_proxy_mode" == "tproxy" ]]; then tproxy_enable=1 @@ -178,6 +178,40 @@ service_started() { if [[ "$tcp_transparent_proxy_mode" == "tun" || "$udp_transparent_proxy_mode" == "tun" ]]; then tun_enable=1 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 + local cgroup_v1_path; cgroup_v1_path="/sys/fs/cgroup/net_cls/$CGROUP_NAME" + mkdir -p "$cgroup_v1_path" + echo "$CGROUP_ID" > "$cgroup_v1_path/net_cls.classid" + cat "$PID_FILE_PATH" > "$cgroup_v1_path/cgroup.procs" + # local bypass_cgroup; config_get bypass_cgroup "proxy" "bypass_cgroup" + # if [ -n "$bypass_cgroup" ]; then + # local cgroup + # for cgroup in $bypass_cgroup; do + # ubus call service list "{\"name\": \"$cgroup\"}" | jsonfilter -e "$.$cgroup.instances.*.pid" >> "$cgroup_v1_path/cgroup.procs" + # done + # fi + 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 # transparent proxy log "Transparent Proxy" "Enabled." # wait for tun device online @@ -201,7 +235,7 @@ service_started() { return fi fi - # prepare + # 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" @@ -224,7 +258,7 @@ service_started() { $FIREWALL_INCLUDE_SH fi # hijack - utpl -D tproxy_fw_mark="$TPROXY_FW_MARK" -D tun_fw_mark="$TUN_FW_MARK" -S "$HIJACK_UT" | nft -f - + utpl -D cgroup_name="$CGROUP_NAME" -D cgroup_id="$CGROUP_ID" -D tproxy_fw_mark="$TPROXY_FW_MARK" -D tun_fw_mark="$TUN_FW_MARK" -S "$HIJACK_UT" | nft -f - # check hijack if (nft list tables | grep -q nikki); then log "Transparent Proxy" "Hijack successful." @@ -232,23 +266,6 @@ service_started() { log "Transparent Proxy" "Hijack failed." log "App" "Exit." fi - # fix compatible between tproxy and dockerd (kmod-br-netfilter) - 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" - 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" - sysctl -q -w net.bridge.bridge-nf-call-ip6tables=0 - fi - fi - fi } service_stopped() { @@ -289,14 +306,14 @@ cleanup() { nft delete rule inet fw4 forward handle "$handle" done # delete started flag - rm -f "$STARTED_FLAG" + rm -f "$STARTED_FLAG_PATH" # revert fix compatible between tproxy and dockerd (kmod-br-netfilter) - if [ -f "$BRIDGE_NF_CALL_IPTABLES_FLAG" ]; then - rm -f "$BRIDGE_NF_CALL_IPTABLES_FLAG" + if [ -f "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH" ]; then + rm -f "$BRIDGE_NF_CALL_IPTABLES_FLAG_PATH" sysctl -q -w net.bridge.bridge-nf-call-iptables=1 fi - if [ -f "$BRIDGE_NF_CALL_IP6TABLES_FLAG" ]; then - rm -f "$BRIDGE_NF_CALL_IP6TABLES_FLAG" + if [ -f "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH" ]; then + rm -f "$BRIDGE_NF_CALL_IP6TABLES_FLAG_PATH" sysctl -q -w net.bridge.bridge-nf-call-ip6tables=1 fi # delete cron @@ -327,8 +344,8 @@ update_subscription() { uci_remove "nikki" "$subscription_section" "success" # update subscription log "Profile" "Update subscription: $subscription_name." - local subscription_header_tmpfile; subscription_header_tmpfile="/tmp/$subscription_section.header" - local subscription_tmpfile; subscription_tmpfile="/tmp/$subscription_section.yaml" + local subscription_header_tmpfile; subscription_header_tmpfile="$TEMP_DIR/$subscription_section.header" + local subscription_tmpfile; subscription_tmpfile="$TEMP_DIR/$subscription_section.yaml" local subscription_file; subscription_file="$SUBSCRIPTIONS_DIR/$subscription_section.yaml" if (curl -s -f --connect-timeout 15 --retry 3 -L -X GET -A "$subscription_user_agent" -D "$subscription_header_tmpfile" -o "$subscription_tmpfile" "$subscription_url"); then log "Profile" "Subscription update successful." diff --git a/nikki/files/scripts/include.sh b/nikki/files/scripts/include.sh index 6a0b09105..30445e517 100644 --- a/nikki/files/scripts/include.sh +++ b/nikki/files/scripts/include.sh @@ -7,6 +7,8 @@ TPROXY_RULE_PREF="1024" TUN_RULE_PREF="1025" TPROXY_ROUTE_TABLE="80" TUN_ROUTE_TABLE="81" +CGROUP_ID="0x12061206" +CGROUP_NAME="nikki" # paths PROG="/usr/bin/mihomo" @@ -26,10 +28,11 @@ APP_LOG_PATH="$LOG_DIR/app.log" CORE_LOG_PATH="$LOG_DIR/core.log" # flag -FLAG_DIR="/var/run/nikki" -STARTED_FLAG="$FLAG_DIR/started.flag" -BRIDGE_NF_CALL_IPTABLES_FLAG="$FLAG_DIR/bridge_nf_call_iptables.flag" -BRIDGE_NF_CALL_IP6TABLES_FLAG="$FLAG_DIR/bridge_nf_call_ip6tables.flag" +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" @@ -84,8 +87,8 @@ prepare_files() { if [ ! -f "$CORE_LOG_PATH" ]; then touch "$CORE_LOG_PATH" fi - if [ ! -d "$FLAG_DIR" ]; then - mkdir -p "$FLAG_DIR" + if [ ! -d "$TEMP_DIR" ]; then + mkdir -p "$TEMP_DIR" fi } diff --git a/nikki/files/ucode/hijack.ut b/nikki/files/ucode/hijack.ut index 9f0abfb0d..5873424fe 100644 --- a/nikki/files/ucode/hijack.ut +++ b/nikki/files/ucode/hijack.ut @@ -5,7 +5,9 @@ import { cursor } from 'uci'; import { connect } from 'ubus'; - import { uci_bool, uci_array, get_users, get_groups, get_cgroups } from '/etc/nikki/ucode/include.uc'; + import { uci_bool, uci_array, get_cgroups_version, get_users, get_groups, get_cgroups } from '/etc/nikki/ucode/include.uc'; + + const cgroups_version = get_cgroups_version(); const users = get_users(); const groups = get_groups(); @@ -43,7 +45,15 @@ const bypass_user = filter(uci_array(uci.get('nikki', 'proxy', 'bypass_user')), (x) => x != 'root' && index(users, x) >= 0); const bypass_group = filter(uci_array(uci.get('nikki', 'proxy', 'bypass_group')), (x) => x != 'root' && index(groups, x) >= 0); - const bypass_cgroup = filter(uci_array(uci.get('nikki', 'proxy', 'bypass_cgroup')), (x) => x != 'nikki' && index(cgroups, x) >= 0); + + let bypass_cgroup = []; + if (cgroups_version == 1) { + push(bypass_cgroup, cgroup_id); + } else if (cgroups_version == 2) { + bypass_cgroup = filter(uci_array(uci.get('nikki', 'proxy', 'bypass_cgroup')), (x) => x != 'nikki' && index(cgroups, x) >= 0); + push(bypass_cgroup, cgroup_name); + } + const bypass_dscp = uci_array(uci.get('nikki', 'proxy', 'bypass_dscp')); const bypass_china_mainland_ip = uci_bool(uci.get('nikki', 'proxy', 'bypass_china_mainland_ip')); const proxy_tcp_dport = split((uci.get('nikki', 'proxy', 'proxy_tcp_dport') ?? '0-65535'), ' '); @@ -80,8 +90,6 @@ for (let port in proxy_udp_dport) { push(proxy_dport, `udp . ${port}`); } - - push(bypass_cgroup, 'nikki'); -%} table inet nikki { @@ -135,6 +143,20 @@ table inet nikki { {% endif %} } + {% if (cgroups_version == 1): %} + set bypass_cgroup { + typeof meta cgroup + flags interval + auto-merge + {% if (length(bypass_cgroup) > 0): %} + elements = { + {% for (let x in bypass_cgroup): %} + {{ x }}, + {% endfor %} + } + {% endif %} + } + {% elif (cgroups_version == 2): %} set bypass_cgroup { type cgroupsv2 flags interval @@ -147,6 +169,7 @@ table inet nikki { } {% endif %} } + {% endif %} set reserved_ip { type ipv4_addr @@ -319,7 +342,11 @@ table inet nikki { {% if (router_proxy): %} chain nat_output { type nat hook output priority filter; policy accept; + {% if (cgroups_version == 1): %} + meta cgroup @bypass_cgroup counter return + {% elif (cgroups_version == 2): %} socket cgroupv2 level 2 @bypass_cgroup counter return + {% endif %} meta skuid @bypass_user counter return meta skgid @bypass_group counter return meta nfproto @dns_hijack_nfproto meta l4proto { tcp, udp } th dport 53 counter redirect to :{{ dns_port }} @@ -343,7 +370,11 @@ table inet nikki { chain mangle_output { type route hook output priority mangle; policy accept; + {% if (cgroups_version == 1): %} + meta cgroup @bypass_cgroup counter return + {% elif (cgroups_version == 2): %} socket cgroupv2 level 2 @bypass_cgroup counter return + {% endif %} meta skuid @bypass_user counter return meta skgid @bypass_group counter return fib daddr type { local, multicast, broadcast, anycast } counter return diff --git a/nikki/files/ucode/include.uc b/nikki/files/ucode/include.uc index a9985bb7b..f6cddfdb7 100644 --- a/nikki/files/ucode/include.uc +++ b/nikki/files/ucode/include.uc @@ -1,4 +1,5 @@ import { readfile, lsdir, lstat } from 'fs'; +import { connect } from 'ubus'; export function uci_bool(obj) { return obj == null ? null : obj == '1'; @@ -50,6 +51,10 @@ export function trim_all(obj) { return obj; }; +export function get_cgroups_version() { + return system('mount | grep -q -w -e "^cgroup"') == 0 ? 1 : 2; +}; + export function get_users() { return map(split(readfile('/etc/passwd'), '\n'), (x) => split(x, ':')[0]); }; @@ -59,5 +64,13 @@ export function get_groups() { }; export function get_cgroups() { - return filter(lsdir('/sys/fs/cgroup/services'), (x) => lstat(`/sys/fs/cgroup/services/${x}`).type == 'directory'); + const ubus = connect(); + const services = ubus.call('service', 'list'); + const result = []; + for (let name in services) { + if (length(services[name]['instances']) > 0) { + push(result, name); + } + } + return result; }; \ No newline at end of file