update 2024-12-09 16:30:14

This commit is contained in:
kenzok8 2024-12-09 16:30:14 +08:00
parent 2ae34e0655
commit 08ce0bb47f
9 changed files with 143 additions and 54 deletions

View File

@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=floatip
PKG_VERSION:=1.0.5
PKG_VERSION:=1.0.6
PKG_RELEASE:=1
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
@ -18,6 +18,7 @@ define Package/$(PKG_NAME)
CATEGORY:=Network
SUBMENU:=IP Addresses and Names
TITLE:=Float IP
DEPENDS:=+curl
PKGARCH:=all
endef

View File

@ -5,10 +5,13 @@ config floatip 'main'
option role 'fallback'
# option role 'main'
# 对于 fallback 节点,检查到 check_ip 都不在线超过一定时间例如30秒就设置自身的 set_ip然后检查 check_ip 中任一 IP 在线就清除自身的 set_ip重复上述流程。
# 对于 main 节点,启动后不断检查 set_ip ,直到 set_ip 不在线,就设置自身的 set_ip然后退出进程。
# 对于 main 节点,启动后不断检查 set_ip 和 check_url直到 set_ip 不在线且 check_url 没有失败,就设置自身的 set_ip 并允许 LAN 口 ping否则清除自身的 set_ip 并禁止 LAN 口 ping重复上述流程。
# set_ip 可以不提供前缀长度,将会按 lan 口配置的网段的长度
option set_ip '192.168.100.3/24'
# option set_ip '192.168.100.3'
# check_ip 仅 fallback 有效,并且检查时只检查跟 set_ip 同一网段的
list check_ip '192.168.100.2'
# list check_ip '192.168.100.4'
# check_url 仅 main 有效
# list check_url 'https://www.google.com/generate_204'
# option check_url_timeout '5'

View File

@ -3,11 +3,21 @@
START=98
USE_PROCD=1
enable_lan_ping() {
uci -q set firewall.floatip_lan_offline.enabled=0 || return 0
uci changes | grep -Fq 'firewall.floatip_lan_offline.enabled' || return 0
uci commit firewall
/etc/init.d/firewall reload
}
start_service() {
config_load floatip
config_get_bool enabled "main" enabled 0
ifdown floatip
[[ "$enabled" = 1 ]] || return 0
[[ "$enabled" = 1 ]] || {
enable_lan_ping
return 0
}
[[ "`uci -q get network.lan.proto`" = "static" ]] || return 0
local set_ip set_prefix
config_get set_ip "main" set_ip
@ -48,6 +58,7 @@ start_service() {
}
stop_service() {
enable_lan_ping
ifdown floatip
}

View File

@ -40,6 +40,30 @@ set_up() {
ifup floatip
}
set_lan_ping() {
if [[ "$1" = 0 ]]; then
if [[ "x$(uci -q get firewall.floatip_lan_offline)" = xrule ]]; then
uci -q delete firewall.floatip_lan_offline.enabled
uci changes | grep -Fq 'firewall.floatip_lan_offline.enabled' || return 0
else
uci -q batch <<-EOF >/dev/null
set firewall.floatip_lan_offline=rule
set firewall.floatip_lan_offline.name=FloatIP-LAN-Offline
set firewall.floatip_lan_offline.src=lan
set firewall.floatip_lan_offline.proto=icmp
set firewall.floatip_lan_offline.icmp_type=echo-request
set firewall.floatip_lan_offline.family=ipv4
set firewall.floatip_lan_offline.target=DROP
EOF
fi
else
uci -q set firewall.floatip_lan_offline.enabled=0 || return 0
uci changes | grep -Fq 'firewall.floatip_lan_offline.enabled' || return 0
fi
uci commit firewall
/etc/init.d/firewall reload 2>&1
}
. /lib/functions.sh
fallback_loop() {
@ -96,7 +120,7 @@ fallback_loop() {
[[ $consume_time -lt 10 ]] && sleep $((10 - $consume_time))
continue
fi
echo "no host alive, set up floatip $ipaddr"
echo "no host alive, set up floatip $ipaddr" >&2
set_up "$ipaddr"
floatip_up=1
sleep 5
@ -112,17 +136,65 @@ main_loop() {
[[ "$set_prefix" = 32 ]] && set_prefix=$DEFAULT_PREFIX
[[ "$set_ip" = 0.0.0.0 ]] && set_ip=192.168.100.3
local ipaddr="$set_ip/$set_prefix"
local check_urls check_url_timeout
config_get check_urls "main" check_url
config_get check_url_timeout "main" check_url_timeout '5'
local dead_counter=0 floatip_up=0 url_pass check_url curl_code consume_time found_alive
# sleep 2-6s
sleep $(( $(random) / 60 + 2))
while :; do
# sleep 2-6s
sleep $(( random / 60 + 2))
echo "checking host $set_ip alive"
if host_alive $set_ip; then
echo "host $set_ip alive"
continue
consume_time=0
if [[ $floatip_up = 0 ]]; then
found_alive=0
echo "checking host $set_ip alive"
if host_alive $set_ip; then
echo "host $set_ip alive"
found_alive=1
else
consume_time=$(($consume_time + 2))
fi
fi
echo "no host alive, set up floatip $ipaddr"
set_up "$ipaddr"
break
url_pass=1
for check_url in $check_urls ; do
curl -L --fail --show-error --no-progress-meter -o /dev/null \
--connect-timeout "$check_url_timeout" --max-time "$check_url_timeout" \
-I "$check_url" 2>&1
curl_code=$?
[[ $curl_code = 0 ]] && continue
[[ $curl_code = 6 || $curl_code = 7 || $curl_code = 28 ]] && \
consume_time=$(($consume_time + $check_url_timeout))
echo "check_url $check_url fail, code $curl_code"
url_pass=0
break
done
if [[ $floatip_up = 0 ]]; then
if [[ $url_pass = 1 ]]; then
# notify fallback node to offline
set_lan_ping
if [[ $found_alive = 0 ]]; then
echo "no host alive, and url passed, set up floatip $ipaddr" >&2
set_up "$ipaddr"
floatip_up=1
fi
fi
[[ $consume_time -lt 5 ]] && sleep $((5 - $consume_time))
continue
else
if [[ $url_pass = 0 ]]; then
dead_counter=$(($dead_counter + 1))
if [[ $dead_counter -lt 3 ]]; then
[[ $consume_time -lt 5 ]] && sleep $((5 - $consume_time))
continue
fi
echo "set down floatip, and disable ping" >&2
ifdown floatip
set_lan_ping 0
floatip_up=0
fi
dead_counter=0
fi
sleep 20
done
}

View File

@ -30,15 +30,15 @@ return baseclass.extend({
],
dashrepos: [
['metacubex/metacubexd', _('metacubexd')],
['zephyruso/zashboard', _('zashboard')],
['metacubex/metacubexd', _('metacubexd')],
['metacubex/yacd-meta', _('yacd-meta')],
['metacubex/razord-meta', _('razord-meta')]
],
dashrepos_urlparams: {
'metacubex/metacubexd': '#/setup' + '?hostname=%s&port=%s&secret=%s',
'zephyruso/zashboard': '#/setup' + '?hostname=%s&port=%s&secret=%s',
'metacubex/metacubexd': '#/setup' + '?hostname=%s&port=%s&secret=%s',
'metacubex/yacd-meta': '?hostname=%s&port=%s&secret=%s',
'metacubex/razord-meta': '?host=%s&port=%s&secret=%s'
},

View File

@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for floatip
LUCI_DEPENDS:=+floatip
LUCI_PKGARCH:=all
PKG_VERSION:=0.1.1-1
PKG_VERSION:=0.1.2-1
# PKG_RELEASE MUST be empty for luci.mk
PKG_RELEASE:=

View File

@ -5,46 +5,30 @@ m = Map("floatip", translate("FloatingGateway"), translate("FloatingGateway allo
m:section(SimpleSection).template = "floatip_status"
s=m:section(NamedSection, "main", translate("Global settings"))
s.addremove=false
s.anonymous=true
o = s:option(Flag, "enabled", translate("Enable"))
o.rmempty = false
o = s:option(Value, "role", translate("Role"))
o = s:option(ListValue, "role", translate("Node Role"))
o.rmempty = false
o:value("main", translate("Preemptor"))
o:value("fallback", translate("Fallback"))
o.widget = "select"
o:value("main", translate("Preempt Node"))
o:value("fallback", translate("Fallback Node"))
o = s:option(Value, "set_ip", translate("Floating Gateway IP"))
o.rmempty = false
function o.validate(self, value)
local ip, mask = value:match("(%d+%.%d+%.%d+%.%d+)/?(%d*)")
if not ip then
return nil, "Invalid format."
end
o.datatype = "or(ip4addr,cidr4)"
-- 验证 IP 地址格式
for octet in ip:gmatch("%d+") do
if tonumber(octet) < 0 or tonumber(octet) > 255 then
return nil, "IP address octets must be between 0 and 255"
end
end
-- 验证子网掩码(如果存在)
if mask ~= nil and mask ~= "" then
local netmask = tonumber(mask)
if netmask < 0 or netmask > 32 then
return nil, "Netmask must be between 0 and 32"
end
end
return value
end
o = s:option(Value, "check_ip", translate("Check IP"))
o.rmempty = true
o.datatype = "ipaddr"
o = s:option(Value, "check_ip", translate("Preempt Node IP"))
o.datatype = "ip4addr"
o:depends("role", "fallback")
o = s:option(Value, "check_url", translate("Check URL"), translate("If status code of the URL is not 2xx, then release the floating IP and disable LAN port pinging"))
o:depends("role", "main")
o = s:option(Value, "check_url_timeout", translate("Check URL Timeout (s)"), translate("Default is 5 seconds if not set"))
o.datatype = "uinteger"
o:depends("role", "main")
return m

View File

@ -19,14 +19,29 @@ msgstr "服务状态"
msgid "Collecting data..."
msgstr "收集数据..."
msgid "Preemptor"
msgid "Node Role"
msgstr "节点角色"
msgid "Preempt Node"
msgstr "旁路由"
msgid "Fallback"
msgid "Fallback Node"
msgstr "主路由"
msgid "Floating Gateway IP"
msgstr "浮动网关IP"
msgstr "浮动网关 IP"
msgid "Check IP"
msgid "Preempt Node IP"
msgstr "旁路由 IP"
msgid "Check URL"
msgstr "检查 URL"
msgid "If status code of the URL is not 2xx, then release the floating IP and disable LAN port pinging"
msgstr "如果检查URL状态码不是2xx则释放浮动IP并禁止LAN口ping"
msgid "Check URL Timeout (s)"
msgstr "检查 URL 超时(秒)"
msgid "Default is 5 seconds if not set"
msgstr "默认5秒"

View File

@ -135,9 +135,12 @@ natflow_qos_zone_setup_tc()
echo $ifn
done) | sed 's/+$/\.\*/' | sort | uniq | while read IFN; do
#echo $type $idx=$IFN >$DEVCTL
l2dev=$(ubus call network.interface dump | grep "\"l3_device\": \"${IFN}\"" -A2 | grep "\"device\"" | cut -d\" -f4)
l2dev=$(for ifn in $IFN $l2dev; do echo $ifn; done | sort | uniq)
for ifn in $l2dev; do
case $type in
lan_zone)
ifconfig -a | grep "^$IFN " | awk '{print $1}' | while read lan; do
ifconfig -a | grep "^$ifn " | awk '{print $1}' | while read lan; do
if [ "${lan}" = "${lan//:}" ]; then
qos_id=0
cat /dev/qos_ctl | grep "^add user=" | while read line; do
@ -163,7 +166,7 @@ natflow_qos_zone_setup_tc()
done
;;
wan_zone)
ifconfig -a | grep "^$IFN " | awk '{print $1}' | while read wan; do
ifconfig -a | grep "^$ifn " | awk '{print $1}' | while read wan; do
if [ "${wan}" = "${wan//:}" ]; then
qos_id=0
cat /dev/qos_ctl | grep "^add user=" | while read line; do
@ -176,8 +179,7 @@ natflow_qos_zone_setup_tc()
QOSID=$((qos_id*2))
lower1=$(for vif in /sys/class/net/$wan/lower_*; do test -e $vif && echo ${vif##/sys/class/net/*/lower_}; done)
lower2=$(for dev in $lower1; do for vif in /sys/class/net/$dev/lower_*; do test -e $vif && echo ${vif##/sys/class/net/*/lower_}; done; done)
l2dev=$(ubus call network.interface dump | grep "\"l3_device\": \"${wan}\"" -A2 | grep "\"device\"" | cut -d\" -f4)
devs=$(for dev in $wan $lower1 $lower2 $l2dev; do echo $dev; done | sort | uniq);
devs=$(for dev in $wan $lower1 $lower2; do echo $dev; done | sort | uniq);
echo setup tc for @wan=[`echo $devs`] txbytes=$txbytes quantum=$quantum rule_id=${qos_id} QOSID=${QOSID}
for DEVICE in $devs; do
tc qdisc add dev $DEVICE root handle 1: htb &>/dev/null
@ -189,6 +191,7 @@ natflow_qos_zone_setup_tc()
done
;;
esac
done
done
}