Sync 2026-05-27 00:45:19

This commit is contained in:
github-actions[bot] 2026-05-27 00:45:19 +08:00
parent 8ab0ff5223
commit 009f8b91ab
6 changed files with 113 additions and 94 deletions

View File

@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=ipv6-neigh
PKG_VERSION:=0.1.0
PKG_RELEASE:=14
PKG_RELEASE:=15
PKG_BUILD_DEPENDS:=rust/host
PKG_BUILD_PARALLEL:=1

View File

@ -525,11 +525,8 @@ async fn main() -> Result<(), ()> {
// reconcile_dns's AXFR pass cannot catch these because the record is
// also absent from DNS, so no probe is ever triggered for them.
if let Ok(neighbours) = dump_neighbours(handle.clone(), private_subnet_v4).await {
// Build a set of IPs that are currently REACHABLE in the kernel,
// used below to detect registered entries the kernel has marked FAILED.
let reachable_ips: std::collections::HashSet<String> = neighbours
let all_dump_ips: std::collections::HashSet<String> = neighbours
.iter()
.filter(|n| n.state == NeighbourState::Reachable)
.map(|n| inet_to_string(&n.inet))
.collect();
@ -622,7 +619,7 @@ async fn main() -> Result<(), ()> {
let to_remove: Vec<(String, String)> = registered
.iter()
.filter(|((_hostname, ip_str), entry)| {
!reachable_ips.contains(ip_str.as_str())
!all_dump_ips.contains(ip_str.as_str())
&& now.duration_since(entry.last_confirmed) > stale_cutoff
})
.map(|(k, _)| k.clone())

View File

@ -10,8 +10,8 @@ LUCI_TITLE:=Antitethering module for luci-app-firewall
#LUCI_DEPENDS:= +luci-app-firewall
PKG_LICENSE:=Apache-2.0
PKG_VERSION:=0.0.5
PKG_RELEASE:=1
PKG_VERSION:=0.0.6
PKG_RELEASE:=2
include $(TOPDIR)/feeds/luci/luci.mk

View File

@ -1,19 +1,37 @@
#!/bin/sh
. /lib/functions.sh
# handle_section is called by config_foreach for each UCI section of type "ttl".
# $1 = section name (e.g. "cfg1", or named section)
handle_section(){
local s="$1"
config_get method "$s" method
config_get advanced "$s" advanced
config_get inet "$s" inet
config_get ports "$s" ports
config_get ttl "$s" ttl 64
config_get iface "$s" iface
config_get proxy "$s" proxy
SECTIONS=$(echo $(uci show ttl | awk -F [\]\[\@=] '/=ttl/{print $3}'))
[ -n "$iface" ] && ifn="$iface" || ifn="lan"
DEV=$(ifstatus "$ifn" | jsonfilter -e '@["l3_device"]')
get_vars(){
for v in method advanced inet ports ttl iface proxy; do
eval $v=$(uci -q get ttl.@ttl[${s}].${v} 2>/dev/nul)
done
case $method in
ttl) method_ttl ;;
proxy) method_proxy ;;
esac
}
config_load ttl
# check iptables or nft
#
if [ -x /usr/sbin/iptables -o /usr/sbin/ip6tables -a ! -x /usr/sbin/nft ]; then
# Choose firewall backend: nft takes priority over iptables
if [ -x /usr/sbin/nft ]; then
. /usr/share/ttlnft.sh
elif [ -x /usr/sbin/iptables ] || [ -x /usr/sbin/ip6tables ]; then
. /usr/share/ttlipt.sh
else
. /usr/share/ttlnft.sh
logger -t ttl "No firewall backend found (nft/iptables/ip6tables)"
exit 1
fi
config_foreach handle_section ttl

View File

@ -1,18 +1,48 @@
# --- Input validation ---
validate_ttl(){
echo "$1" | grep -qE '^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' || {
logger -t ttl "Invalid TTL value: '$1' (must be 0-255)"; exit 1
}
}
validate_ports(){
# accepts: "all", "http", or comma-separated port numbers
case "$1" in
all|http|"") return 0 ;;
esac
echo "$1" | grep -qE '^[0-9]+(,[0-9]+)*$' || {
logger -t ttl "Invalid ports value: '$1'"; exit 1
}
}
validate_iface(){
# interface name: alphanumeric, dash, dot, underscore, max 15 chars
echo "$1" | grep -qE '^[a-zA-Z0-9._-]{1,15}$' || {
logger -t ttl "Invalid iface value: '$1'"; exit 1
}
}
validate_proxy(){
# IP:port or [IPv6]:port
echo "$1" | grep -qE '^(\[?[0-9a-fA-F:.]+\]?):([0-9]{1,5})$' || {
logger -t ttl "Invalid proxy value: '$1'"; exit 1
}
}
# --- End validation ---
method_ttl(){
ttl=${ttl:=64}
validate_ttl "$ttl"
[ -n "$iface" ] && validate_iface "$iface"
#case $(($ttl % 2)) in
# 0) TTL_INC=$(($ttl-1)) ;;
# *) TTL_INC=$ttl ;;
#esac
TTL_INC=$(($ttl-1))
for T in $IPT; do
case $T in
iptables)
SUFFIX="TTL --ttl-set"
if [ $iface ]; then
if [ -n "$iface" ]; then
$T -t mangle -A TTLFIX -i $DEV -m ttl --ttl 1 -j TTL --ttl-inc $TTL_INC
else
$T -t mangle -A TTLFIX -m ttl --ttl 1 -j TTL --ttl-inc $TTL_INC
@ -20,7 +50,7 @@ method_ttl(){
;;
ip6tables)
SUFFIX="HL --hl-set"
if [ $iface ]; then
if [ -n "$iface" ]; then
$T -t mangle -A TTLFIX -i $DEV -m hl --hl 1 -j HL --hl-inc $TTL_INC
else
$T -t mangle -A TTLFIX -m hl --hl 1 -j HL --hl-inc $TTL_INC
@ -28,7 +58,7 @@ method_ttl(){
;;
esac
if [ $iface ]; then
if [ -n "$iface" ]; then
$T -t mangle -A TTL_OUT -o $DEV -j $SUFFIX $ttl
$T -t mangle -A TTL_POST -o $DEV -j $SUFFIX $ttl
else
@ -40,6 +70,9 @@ method_ttl(){
method_proxy(){
validate_ports "$ports"
[ -n "$proxy" ] && validate_proxy "$proxy"
[ -n "$iface" ] && validate_iface "$iface"
for T in $IPT; do
[ "$proxy" ] && {
@ -51,11 +84,11 @@ method_proxy(){
} || {
case $T in
iptables)
IPADDR=$(ifstatus $ifn | jsonfilter -e '@["ipv4-address"][*]["address"]')
IPADDR=$(ifstatus "$ifn" | jsonfilter -e '@["ipv4-address"][*]["address"]')
END="${IPADDR}:3128"
;;
ip6tables)
for a in $(ifstatus $ifn | jsonfilter -e '@["ipv6-prefix-assignment"][*]["local-address"]["address"]'); do
for a in $(ifstatus "$ifn" | jsonfilter -e '@["ipv6-prefix-assignment"][*]["local-address"]["address"]'); do
IPADDR="$a"
done
END="[$IPADDR]:3128"
@ -77,7 +110,7 @@ method_proxy(){
--dports 80,443 -j DNAT --to-destination $END
;;
*)
if [ $ports ]; then
if [ -n "$ports" ]; then
$T -t nat -A FIXPROXY ! -d ${IPADDR} \
! -s ${IPADDR} -p tcp -m multiport \
--dports $ports -j DNAT --to-destination $END
@ -122,31 +155,3 @@ for T in $IPT; do
$T -t nat -${a} PREROUTING -j PROXY
done
done
for s in $SECTIONS; do
if [ "$s" ]; then
get_vars
else
exit 0
fi
[ -n $iface ] && {
ifn=$iface
} || {
ifn=lan
}
case $inet in
ipv4) IPT="iptables" ;;
ipv6) IPT="ip6tables" ;;
*) IPT="iptables ip6tables";;
esac
if ! [ -f /lib/modules/$(uname -r)/ip6table_nat.ko ]; then
IPT="iptables"
fi
DEV=$(ifstatus $iface | jsonfilter -e '@["l3_device"]')
case $method in
ttl) method_ttl ;;
proxy) method_proxy ;;
esac
done

View File

@ -1,6 +1,37 @@
# --- Input validation ---
validate_ttl(){
echo "$1" | grep -qE '^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' || {
logger -t ttl "Invalid TTL value: '$1' (must be 0-255)"; exit 1
}
}
validate_ports(){
case "$1" in
all|http|"") return 0 ;;
esac
echo "$1" | grep -qE '^[0-9]+(,[0-9]+)*$' || {
logger -t ttl "Invalid ports value: '$1'"; exit 1
}
}
validate_iface(){
echo "$1" | grep -qE '^[a-zA-Z0-9._-]{1,15}$' || {
logger -t ttl "Invalid iface value: '$1'"; exit 1
}
}
validate_proxy(){
echo "$1" | grep -qE '^(\[?[0-9a-fA-F:.]+\]?):([0-9]{1,5})$' || {
logger -t ttl "Invalid proxy value: '$1'"; exit 1
}
}
# --- End validation ---
method_ttl(){
ttl=${ttl:=64}
validate_ttl "$ttl"
[ -n "$iface" ] && validate_iface "$iface"
# create mangle table
nft add table ip mangle 2>/dev/null
@ -20,7 +51,7 @@ method_ttl(){
ip) TTLNAME=ttl ;;
ip6) TTLNAME=hoplimit ;;
esac
if [ $iface ]; then
if [ -n "$iface" ]; then
nft add rule $fam mangle TTLFIX iif $DEV $fam $TTLNAME 1 $fam $TTLNAME set $ttl
nft add rule $fam mangle TTL_OUT oif $DEV $fam $TTLNAME set $ttl
nft add rule $fam mangle TTL_POST oif $DEV $fam $TTLNAME set $ttl
@ -33,6 +64,9 @@ method_ttl(){
}
method_proxy(){
validate_ports "$ports"
[ -n "$proxy" ] && validate_proxy "$proxy"
[ -n "$iface" ] && validate_iface "$iface"
for fam in $family; do
# create nat table
nft add table $fam nat 2>/dev/null
@ -46,11 +80,11 @@ method_proxy(){
# get ipaddress from iface if not defined
case $fam in
ip)
IPADDR=$(ifstatus $ifn | jsonfilter -e '@["ipv4-address"][*]["address"]')
IPADDR=$(ifstatus "$ifn" | jsonfilter -e '@["ipv4-address"][*]["address"]')
END="${IPADDR}:3128"
;;
ip6)
IPADDR=$(ifstatus $ifn | jsonfilter -e '@["ipv6-prefix-assignment"][*]["local-address"]["address"]' | head -n1)
IPADDR=$(ifstatus "$ifn" | jsonfilter -e '@["ipv6-prefix-assignment"][*]["local-address"]["address"]' | head -n1)
END="${IPADDR}:3128"
;;
esac
@ -61,7 +95,7 @@ method_proxy(){
nft add chain $fam nat FIXPROXY
# add traffic rule
[ $iface ] && {
[ -n "$iface" ] && {
nft add rule $fam nat PROXY iif $DEV jump FIXPROXY
} || {
nft add rule $fam nat PROXY jump FIXPROXY
@ -92,46 +126,11 @@ method_proxy(){
# init tables and chains
for fml in ip ip6; do
# create table mangle
nft delete table $fml mangle 2>/dev/null
nft delete table $fml nat 2>/dev/null
# define chains
nft add table $fml mangle
nft add chain $fml mangle TTLFIX { type filter hook prerouting priority -150 \; }
nft add chain $fml mangle TTL_OUT { type route hook output priority -150 \; }
nft add chain $fml mangle TTL_POST { type filter hook postrouting priority -150 \; }
done
for s in $SECTIONS; do
if [ "$s" ]; then
get_vars
else
exit 0
fi
[ $iface ] && {
ifn=$iface
} || {
ifn=lan
}
case $inet in
ipv4) family="ip" ;;
ipv6) family="ip6" ;;
*) family="ip ip6" ;;
esac
#if [ ! -f /lib/modules/$(uname -r)/ip6table_nat.ko ]; then
# family="ip"
#fi
DEV=$(ifstatus $iface | jsonfilter -e '@["l3_device"]')
case $method in
ttl) method_ttl ;;
proxy) method_proxy ;;
esac
done