💐 Sync 2026-10-06 12:33:44

This commit is contained in:
github-actions[bot] committed 2026-10-06 12:33:44 +08:00
1 parent 8be03ce939
commit 7fe69dbb3a
246 files changed
+50330 -3414

No files matched your search

+3 -2
View File
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-flowproxy
PKG_VERSION:=1.0.4
PKG_RELEASE:=3
PKG_RELEASE:=4
LUCI_TITLE:=LuCI Support for FlowProxy Traffic Diversion
LUCI_DEPENDS:=+luci-base +nftables +kmod-nft-core +ip-full
@@ -11,7 +11,8 @@ LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/postinst
#!/bin/sh
if [ -z "$${IPKG_INSTROOT}" ]; then
/etc/init.d/rpcd restart
[ -f /etc/uci-defaults/99_flowproxy ] && ( . /etc/uci-defaults/99_flowproxy ) && rm -f /etc/uci-defaults/99_flowproxy
(sleep 1; /etc/init.d/rpcd reload) >/dev/null 2>&1 &
fi
exit 0
endef
@@ -108,6 +108,12 @@ return L.view.extend({
}, [ _('Restart') ]));
} else {
content.push(E('span', { 'style': 'color: red; font-weight: bold;' }, [ _('stopped') ]));
content.push(' ');
content.push(E('button', {
'class': 'btn cbi-button cbi-button-apply',
'style': 'margin-left: 10px;',
'click': ui.createHandlerFn(this, 'handleRestart')
}, [ _('Restart') ]));
}
L.dom.content(statusEl, content);
}
@@ -276,7 +282,7 @@ return L.view.extend({
};
var selected_interface = s.formvalue(section_id, 'interface');
if (!selected_interface) return true;
if (!selected_interface || selected_interface === 'auto') return true;
var target_iface = null;
for (var i = 0; i < ifaces.length; i++) {
@@ -318,8 +324,9 @@ return L.view.extend({
o.datatype = 'port'; o.default = '5353'; o.rmempty = false;
var iface_opt = s.taboption('settings', form.ListValue, 'interface', _('Proxy server interface'));
iface_opt.value('auto', _('Auto (Detect automatically)'));
devices.forEach(function(d) { iface_opt.value(d.getName(), d.getName()); });
iface_opt.default = 'br-lan';
iface_opt.default = 'auto';
iface_opt.onchange = function(ev, sid, val) {
var ip_opt = m.lookupOption('proxy_server_ip_addr', sid)[0];
if (ip_opt) {
@@ -273,7 +273,5 @@ msgstr ""
msgid "Invalid IPv4 address format"
msgstr ""
msgid "Auto (Detect automatically)"
msgstr ""
+2 -3
View File
@@ -276,6 +276,5 @@ msgstr "启用代理分流时,代理服务器 IP 地址为必填项。"
msgid "Invalid IPv4 address format"
msgstr "无效的 IPv4 地址格式"
msgid "Auto (Detect automatically)"
msgstr "自动探测"
+1 -1
View File
@@ -3,7 +3,7 @@ config flowproxy 'global'
option tcp_enabled '1'
option udp_enabled '1'
option proxy_server_ip_addr ''
option interface 'br-lan'
option interface 'auto'
option traffic_mark '0x666'
option routing_table '888'
option rule_priority '1000'
@@ -6,7 +6,20 @@
enabled=$(uci -q get flowproxy.global.enabled || echo 0)
[ "$enabled" = "1" ] || exit 0
target_iface=$(uci -q get flowproxy.global.interface || echo "br-lan")
proxy_ip=$(uci -q get flowproxy.global.proxy_server_ip_addr)
[ -n "$proxy_ip" ] || exit 0
target_iface=""
if [ -f "/var/run/flowproxy.mark" ]; then
target_iface=$(cut -d':' -f4 /var/run/flowproxy.mark 2>/dev/null)
fi
if [ -z "$target_iface" ]; then
target_iface=$(uci -q get flowproxy.global.interface)
if [ -z "$target_iface" ] || [ "$target_iface" = "auto" ]; then
target_iface=$(ip route get "$proxy_ip" 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") {print $(i+1); exit}}')
fi
fi
target_iface="${target_iface:-br-lan}"
if [ "$DEVICE" = "$target_iface" ] || [ "$INTERFACE" = "$target_iface" ]; then
[ -x /etc/init.d/flowproxy ] && /etc/init.d/flowproxy add_route
+68 -24
View File
@@ -126,10 +126,14 @@ apply_nft_rules() {
FLOWPROXY_LOG_LEVEL="$conf_level" "$GENERATE_SCRIPT" >/dev/null 2> "$err_file"
local ret=$?
# 将脚本的输出记录到日志
# 将脚本的输出记录到日志:成功时按 debug 输出,失败时按 error 输出
if [ -s "$err_file" ]; then
while read -r line; do
log_msg debug "Script: $line"
if [ $ret -eq 0 ]; then
log_msg debug "Script: $line"
else
log_msg error "Generator: $line"
fi
done < "$err_file"
rm -f "$err_file"
fi
@@ -138,14 +142,16 @@ apply_nft_rules() {
log_msg info "Applying nftables rules from $NFT_CONF"
# 确保内核支持 inet 表
nft delete table inet flowproxy 2>/dev/null
if nft -f "$NFT_CONF"; then
local nft_err
nft_err=$(nft -f "$NFT_CONF" 2>&1)
if [ $? -eq 0 ]; then
return 0
else
log_msg error "nftables rules application failed (syntax error)"
log_msg error "nftables rules application failed: $nft_err"
return 1
fi
else
log_msg error "Failed to generate nftables config"
log_msg error "Failed to generate nftables config (exit code: $ret)"
return 1
fi
else
@@ -154,12 +160,26 @@ apply_nft_rules() {
fi
}
get_proxy_interface() {
local proxy_ip="$1"
local cfg_iface=$(uci -q get "$UCI_CONFIG.global.interface")
if [ -n "$cfg_iface" ] && [ "$cfg_iface" != "auto" ]; then
echo "$cfg_iface"
return
fi
local auto_dev=""
if [ -n "$proxy_ip" ]; then
auto_dev=$(ip route get "$proxy_ip" 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") {print $(i+1); exit}}')
fi
echo "${auto_dev:-br-lan}"
}
add_route() {
check_config || return 1
local proxy_server_ip_addr=$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr")
local interface=$(uci -q get "$UCI_CONFIG.global.interface")
interface="${interface:-br-lan}"
local interface=$(get_proxy_interface "$proxy_server_ip_addr")
local traffic_mark=$(uci -q get "$UCI_CONFIG.global.traffic_mark")
traffic_mark="${traffic_mark:-0x666}"
local routing_table=$(uci -q get "$UCI_CONFIG.global.routing_table")
@@ -170,23 +190,30 @@ add_route() {
# 1. 先尝试用旧记录清理一次,防止由于配置变更导致的残留
delete_route "quiet"
log_msg info "Setting up routing table $routing_table and rule for mark $traffic_mark with priority $rule_priority..."
log_msg info "Setting up routing table $routing_table (dev: $interface) and rule for mark $traffic_mark with priority $rule_priority..."
# 2. 记录当前使用的标记值、路由表 ID 和优先级
echo "$traffic_mark:$routing_table:$rule_priority" > "/var/run/flowproxy.mark"
# 2. 记录当前使用的标记值、路由表 ID、优先级和实际出口网卡
echo "$traffic_mark:$routing_table:$rule_priority:$interface" > "/var/run/flowproxy.mark"
# 3. 再次确保新标记和表的规则是干净的
while ip rule del fwmark "$traffic_mark" lookup "$routing_table" 2>/dev/null; do :; done
ip route flush table "$routing_table" 2>/dev/null
# 4. 添加路由和策略
local err
ip route add default via "$proxy_server_ip_addr" dev "$interface" table "$routing_table" 2>/dev/null
err=$(ip rule add fwmark "$traffic_mark" lookup "$routing_table" priority "$rule_priority" 2>&1)
local route_err rule_err
route_err=$(ip route add default via "$proxy_server_ip_addr" dev "$interface" table "$routing_table" 2>&1)
if [ $? -ne 0 ]; then
log_msg error "Failed to add default route to table $routing_table via $proxy_server_ip_addr (dev: $interface): $route_err"
log_msg error "Proxy server IP $proxy_server_ip_addr is unreachable or has no valid route on interface $interface"
return 1
fi
rule_err=$(ip rule add fwmark "$traffic_mark" lookup "$routing_table" priority "$rule_priority" 2>&1)
if [ $? -eq 0 ]; then
log_msg info "Route added: via $proxy_server_ip_addr dev $interface table $routing_table for mark $traffic_mark with priority $rule_priority"
else
log_msg error "Failed to add ip rule: $err"
log_msg error "Failed to add ip rule: $rule_err"
return 1
fi
# 5. 禁用目标网卡的 ICMP 重定向通告,防止客户端绕行或 TCP 连接挂起
@@ -201,12 +228,13 @@ delete_route() {
local quiet="$1"
# 1. 获取两组清理目标:旧值(记录文件) 和 新值(当前UCI)
local old_mark="" old_table="" old_prio=""
local old_mark="" old_table="" old_prio="" old_iface=""
if [ -f "/var/run/flowproxy.mark" ]; then
local saved_val=$(cat "/var/run/flowproxy.mark")
old_mark=$(echo "$saved_val" | cut -d':' -f1)
old_table=$(echo "$saved_val" | cut -d':' -f2)
old_prio=$(echo "$saved_val" | cut -d':' -f3)
old_iface=$(echo "$saved_val" | cut -d':' -f4)
[ "$quiet" != "quiet" ] && rm -f "/var/run/flowproxy.mark"
fi
@@ -216,8 +244,7 @@ delete_route() {
curr_table="${curr_table:-888}"
local curr_prio=$(uci -q get "$UCI_CONFIG.global.rule_priority")
curr_prio="${curr_prio:-1000}"
local curr_iface=$(uci -q get "$UCI_CONFIG.global.interface")
curr_iface="${curr_iface:-br-lan}"
local curr_iface=$(get_proxy_interface "$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr")")
[ "$quiet" != "quiet" ] && log_msg info "Cleaning up FlowProxy routes (Atomic Mode)..."
@@ -249,9 +276,10 @@ delete_route() {
safe_del_rule "$curr_mark" "$curr_table" "$curr_prio"
# 恢复 ICMP 重定向通告
if [ -d "/proc/sys/net/ipv4/conf/$curr_iface" ]; then
[ -n "$old_iface" ] && [ -d "/proc/sys/net/ipv4/conf/$old_iface" ] && \
sysctl -w "net.ipv4.conf.$old_iface.send_redirects=1" >/dev/null 2>&1
[ -n "$curr_iface" ] && [ "$curr_iface" != "$old_iface" ] && [ -d "/proc/sys/net/ipv4/conf/$curr_iface" ] && \
sysctl -w "net.ipv4.conf.$curr_iface.send_redirects=1" >/dev/null 2>&1
fi
}
delete_nft() {
@@ -320,10 +348,14 @@ start_service() {
if [ "$enabled" -eq 0 ]; then
log_msg info "FlowProxy is disabled, ensuring service is stopped"
[ -x /etc/init.d/flowproxy ] && /etc/init.d/flowproxy disable 2>/dev/null
stop_service
return 0
fi
# 状态自愈:当 enabled=1 时,确保服务已在 rc.d 中 enable,防止 luci-reload 因未启用而静默跳过执行
[ -x /etc/init.d/flowproxy ] && /etc/init.d/flowproxy enable 2>/dev/null
log_msg info "Starting FlowProxy..."
check_env || return 1
@@ -331,11 +363,15 @@ start_service() {
local proxy_server_ip_addr=$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr")
local proxy_server_dns_port=$(uci -q get "$UCI_CONFIG.global.proxy_server_dns_port" || echo 5353)
local interface=$(uci -q get "$UCI_CONFIG.global.interface" || echo "br-lan")
local interface=$(get_proxy_interface "$proxy_server_ip_addr")
probe_proxy_server "$proxy_server_ip_addr" "$proxy_server_dns_port" "$interface"
apply_nft_rules || return 1
add_route
if ! add_route; then
log_msg error "Routing setup failed, aborting and cleaning up service..."
stop_service
return 1
fi
setup_dns
touch "$STATE_FILE"
@@ -344,6 +380,10 @@ start_service() {
stop_service() {
log_msg info "Stopping FlowProxy..."
local enabled=$(uci -q get "$UCI_CONFIG.global.enabled" || echo 0)
if [ "$enabled" -eq 0 ]; then
[ -x /etc/init.d/flowproxy ] && /etc/init.d/flowproxy disable 2>/dev/null
fi
# 强制先移除标记,防止状态误报
rm -f "$STATE_FILE"
delete_route
@@ -368,7 +408,11 @@ service_triggers() {
procd_add_reload_trigger "$UCI_CONFIG"
# 监听防火墙重载事件,防止规则被 fw4 清空后无法自动恢复
procd_add_reload_trigger "firewall"
# 监听网络接口事件
local iface=$(uci -q get "$UCI_CONFIG.global.interface" || echo "br-lan")
procd_add_reload_interface_trigger "$iface"
# 监听网络接口事件(procd trigger 需接收 UCI 逻辑网络名,如 lan/wan)
local dev=$(get_proxy_interface "$(uci -q get "$UCI_CONFIG.global.proxy_server_ip_addr")")
local net_name=""
if command -v ubus >/dev/null 2>&1 && [ -n "$dev" ]; then
net_name=$(ubus call network.interface dump 2>/dev/null | jsonfilter -e "@.interface[@.device=\"$dev\"].interface" -e "@.interface[@.l3_device=\"$dev\"].interface" 2>/dev/null | head -n 1)
fi
procd_add_reload_interface_trigger "${net_name:-lan}"
}
@@ -0,0 +1,23 @@
#!/bin/sh
[ ! -f "/usr/share/ucitrack/luci-app-flowproxy.json" ] && {
cat > /usr/share/ucitrack/luci-app-flowproxy.json << EEOF
{
"config": "flowproxy",
"init": "flowproxy"
}
EEOF
}
uci -q batch <<-EOF >/dev/null
delete ucitrack.@flowproxy[-1]
add ucitrack flowproxy
set ucitrack.@flowproxy[-1].init=flowproxy
commit ucitrack
EOF
/etc/init.d/flowproxy enabled || /etc/init.d/flowproxy enable 2>/dev/null
rm -f /tmp/luci-indexcache* 2>/dev/null
rm -f /tmp/luci-modulecache/* 2>/dev/null
exit 0
@@ -178,14 +178,63 @@ TCP_ENABLED=$(uci -q get "$CONFIG.global.tcp_enabled" || echo "1")
UDP_ENABLED=$(uci -q get "$CONFIG.global.udp_enabled" || echo "1")
TRAFFIC_MARK=$(uci -q get "$CONFIG.global.traffic_mark" || echo "0x666")
PROXY_SERVER_IP_ADDR=$(uci -q get "$CONFIG.global.proxy_server_ip_addr")
INTERFACE=$(uci -q get "$CONFIG.global.interface")
[ -z "$INTERFACE" ] && INTERFACE="br-lan"
get_lan_devices() {
local dev="" devs="" nets=""
local z_idx=0
while :; do
local z_name=$(uci -q get firewall.@zone[$z_idx].name)
[ -z "$z_name" ] && break
if [ "$z_name" = "lan" ]; then
nets=$(uci -q get firewall.@zone[$z_idx].network)
break
fi
z_idx=$((z_idx + 1))
done
[ -z "$nets" ] && nets="lan"
for net in $nets; do
dev=""
if command -v ubus >/dev/null 2>&1; then
dev=$(ubus call network.interface."$net" status 2>/dev/null | jsonfilter -e "@.l3_device" 2>/dev/null)
[ -z "$dev" ] && dev=$(ubus call network.interface."$net" status 2>/dev/null | jsonfilter -e "@.device" 2>/dev/null)
fi
[ -z "$dev" ] && dev=$(uci -q get network."$net".device || uci -q get network."$net".device)
if [ -n "$dev" ]; then
case " $devs " in
*" $dev "*) ;;
*) devs="${devs}${devs:+ }$dev" ;;
esac
fi
done
echo "${devs:-br-lan}"
}
render_nft_lan_filter() {
local devs="$1"
set -- $devs
local count=$#
if [ "$count" -le 1 ]; then
echo " iifname != \"$1\" return"
else
local set_str=""
for d in "$@"; do
[ -n "$set_str" ] && set_str="${set_str}, "
set_str="${set_str}\"${d}\""
done
echo " iifname != { $set_str } return"
fi
}
LAN_DEVICES=$(get_lan_devices)
LAN_NFT_FILTER=$(render_nft_lan_filter "$LAN_DEVICES")
if [ "$TCP_ENABLED" = "1" ]; then
cat >> "$OUTPUT_FILE" << EOF
chain LAN_MARKFLOW_TCP {
type filter hook prerouting priority mangle; policy accept;
iifname != "$INTERFACE" return
$LAN_NFT_FILTER
fib daddr type { unspec, local, anycast, multicast } counter return
EOF
if [ -n "$PROXY_SERVER_IP_ADDR" ]; then
@@ -201,7 +250,7 @@ if [ "$UDP_ENABLED" = "1" ]; then
cat >> "$OUTPUT_FILE" << EOF
chain LAN_MARKFLOW_UDP {
type filter hook prerouting priority mangle; policy accept;
iifname != "$INTERFACE" return
$LAN_NFT_FILTER
fib daddr type { unspec, local, anycast, multicast } counter return
EOF
if [ -n "$PROXY_SERVER_IP_ADDR" ]; then