mirror of
https://github.com/juewuy/ShellCrash.git
synced 2026-10-24 20:00:01 +00:00
124 lines
3.5 KiB
Bash
Executable File
124 lines
3.5 KiB
Bash
Executable File
#!/bin/sh
|
|
# Keep the nftables LAN IPv6 prefix set in sync with dynamic prefixes.
|
|
|
|
[ -z "$CRASHDIR" ] && CRASHDIR=$(
|
|
cd "$(dirname "$0")"
|
|
cd ..
|
|
pwd
|
|
)
|
|
. "$CRASHDIR"/libs/get_config.sh
|
|
. "$CRASHDIR"/starts/fw_getlanip.sh
|
|
|
|
[ -z "$TMPDIR" ] && TMPDIR=/tmp/ShellCrash
|
|
ipv6_watch_pid="$TMPDIR/ipv6_watch.pid"
|
|
ipv6_watch_fifo="$TMPDIR/ipv6_route_monitor.$$"
|
|
ipv6_nft_family=${SHELLCRASH_NFT_FAMILY:-inet}
|
|
ipv6_nft_table=${SHELLCRASH_NFT_TABLE:-shellcrash}
|
|
ipv6_nft_set=${SHELLCRASH_IPV6_SET:-lan_ip6}
|
|
|
|
stop_ipv6_watch() {
|
|
[ -s "$ipv6_watch_pid" ] || return 0
|
|
ipv6_watch_old_pid=$(cat "$ipv6_watch_pid" 2>/dev/null)
|
|
case "$ipv6_watch_old_pid" in
|
|
'' | *[!0-9]*) ;;
|
|
*)
|
|
if [ ! -r "/proc/$ipv6_watch_old_pid/cmdline" ] ||
|
|
tr '\0' ' ' <"/proc/$ipv6_watch_old_pid/cmdline" 2>/dev/null | grep -q 'fw_ipv6_watch.sh'; then
|
|
kill "$ipv6_watch_old_pid" 2>/dev/null
|
|
fi
|
|
;;
|
|
esac
|
|
rm -f "$ipv6_watch_pid"
|
|
}
|
|
|
|
cleanup_ipv6_watch() {
|
|
trap - EXIT INT TERM
|
|
[ -n "$ipv6_monitor_pid" ] && kill "$ipv6_monitor_pid" 2>/dev/null
|
|
[ -p "$ipv6_watch_fifo" ] && rm -f "$ipv6_watch_fifo"
|
|
if [ "$(cat "$ipv6_watch_pid" 2>/dev/null)" = "$$" ]; then
|
|
rm -f "$ipv6_watch_pid"
|
|
fi
|
|
exit 0
|
|
}
|
|
|
|
update_ipv6_set() {
|
|
lan_ifaces=$(get_lan_ifaces)
|
|
detected_host_ipv6=$(get_ipv6_prefixes)
|
|
build_host_ipv6 "$detected_host_ipv6"
|
|
ipv6_watch_state="$host_ipv6"
|
|
|
|
if [ "$ipv6_watch_state" = "$ipv6_watch_last_state" ] &&
|
|
nft list set "$ipv6_nft_family" "$ipv6_nft_table" "$ipv6_nft_set" >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
ipv6_watch_elements=$(echo "$host_ipv6" | sed 's/[[:space:]]\+/, /g')
|
|
[ -n "$ipv6_watch_elements" ] || return 1
|
|
nft list set "$ipv6_nft_family" "$ipv6_nft_table" "$ipv6_nft_set" >/dev/null 2>&1 || return 1
|
|
|
|
# nft processes a batch atomically, so packets never observe a partially
|
|
# updated set while an ISP prefix is being replaced.
|
|
printf 'flush set %s %s %s\nadd element %s %s %s { %s }\n' \
|
|
"$ipv6_nft_family" "$ipv6_nft_table" "$ipv6_nft_set" \
|
|
"$ipv6_nft_family" "$ipv6_nft_table" "$ipv6_nft_set" "$ipv6_watch_elements" |
|
|
nft -f - >/dev/null 2>&1 || return 1
|
|
ipv6_watch_last_state="$ipv6_watch_state"
|
|
}
|
|
|
|
run_iproute2_monitor() {
|
|
rm -f "$ipv6_watch_fifo"
|
|
mkfifo "$ipv6_watch_fifo" 2>/dev/null || return 1
|
|
ip -6 monitor route >"$ipv6_watch_fifo" 2>/dev/null &
|
|
ipv6_monitor_pid=$!
|
|
while IFS= read -r _ipv6_route_event; do
|
|
# Coalesce delete/add notifications emitted during renumbering.
|
|
sleep 1
|
|
update_ipv6_set
|
|
done <"$ipv6_watch_fifo"
|
|
wait "$ipv6_monitor_pid" 2>/dev/null
|
|
ipv6_monitor_pid=
|
|
rm -f "$ipv6_watch_fifo"
|
|
return 1
|
|
}
|
|
|
|
run_ipv6_watch() {
|
|
mkdir -p "$TMPDIR"
|
|
echo $$ >"$ipv6_watch_pid"
|
|
trap cleanup_ipv6_watch EXIT INT TERM
|
|
ipv6_watch_last_state=
|
|
update_ipv6_set
|
|
|
|
# Full iproute2 has event monitoring. BusyBox/router variants that do not
|
|
# support it use a small polling fallback instead.
|
|
if ip -Version 2>&1 | grep -qi 'iproute2'; then
|
|
run_iproute2_monitor
|
|
fi
|
|
while :; do
|
|
sleep 30
|
|
update_ipv6_set
|
|
done
|
|
}
|
|
|
|
case "$1" in
|
|
start)
|
|
mkdir -p "$TMPDIR"
|
|
stop_ipv6_watch
|
|
/bin/sh "$0" run >/dev/null 2>&1 &
|
|
echo $! >"$ipv6_watch_pid"
|
|
;;
|
|
stop)
|
|
stop_ipv6_watch
|
|
;;
|
|
run)
|
|
run_ipv6_watch
|
|
;;
|
|
once)
|
|
ipv6_watch_last_state=
|
|
update_ipv6_set
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {start|stop|run|once}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|