|
|
|
@@ -5,6 +5,8 @@
|
|
|
|
|
# using nmcli device modify (active session only, NOT saved to the profile).
|
|
|
|
|
# The persistent profile always keeps ipv4.link-local=enabled so that
|
|
|
|
|
# direct-connect (no DHCP) plug-ins always activate and trigger events.
|
|
|
|
|
# Avahi is reloaded on each event — no /etc/avahi/hosts file, avahi uses
|
|
|
|
|
# natural per-interface advertisement so each segment gets the right IP.
|
|
|
|
|
#
|
|
|
|
|
# Triggers: up, down, dhcp4-change on ethernet interfaces
|
|
|
|
|
# Install to: /etc/NetworkManager/dispatcher.d/10-link-local-mgmt
|
|
|
|
@@ -12,47 +14,31 @@
|
|
|
|
|
|
|
|
|
|
INTERFACE="$1"
|
|
|
|
|
ACTION="$2"
|
|
|
|
|
CONNECTION_NAME="${CONNECTION_ID:-}"
|
|
|
|
|
|
|
|
|
|
# Only handle ethernet interfaces
|
|
|
|
|
if [[ ! "$INTERFACE" =~ ^eth ]]; then
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# If CONNECTION_ID env var is not set, look up the active connection for this interface
|
|
|
|
|
if [ -z "$CONNECTION_NAME" ]; then
|
|
|
|
|
CONNECTION_NAME=$(nmcli -t -f NAME,DEVICE connection show --active 2>/dev/null \
|
|
|
|
|
| grep ":${INTERFACE}$" | cut -d: -f1 | head -n1)
|
|
|
|
|
[ -z "$CONNECTION_NAME" ] && exit 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Update /etc/avahi/hosts to point mDNS hostname at the best available DHCP address
|
|
|
|
|
# across all ethernet interfaces (so Avahi doesn't advertise a link-local address).
|
|
|
|
|
update_avahi() {
|
|
|
|
|
local hostname
|
|
|
|
|
hostname=$(hostname)
|
|
|
|
|
# Find first non-link-local IPv4 across all ethernet interfaces
|
|
|
|
|
local dhcp_ip
|
|
|
|
|
dhcp_ip=$(ip -4 addr show 2>/dev/null \
|
|
|
|
|
| grep -A5 ': eth' \
|
|
|
|
|
| grep -oP '(?<=inet\s)\d+(\.\d+){3}' \
|
|
|
|
|
| grep -v '^127\.' \
|
|
|
|
|
| grep -v '^169\.254\.' \
|
|
|
|
|
| head -n1)
|
|
|
|
|
|
|
|
|
|
if [ -n "$dhcp_ip" ]; then
|
|
|
|
|
mkdir -p /etc/avahi
|
|
|
|
|
echo "$dhcp_ip $hostname $hostname.local" > /etc/avahi/hosts
|
|
|
|
|
logger -t nm-link-local "Avahi: pinned $hostname -> $dhcp_ip"
|
|
|
|
|
else
|
|
|
|
|
rm -f /etc/avahi/hosts
|
|
|
|
|
logger -t nm-link-local "Avahi: removed hosts pin, using all addresses"
|
|
|
|
|
fi
|
|
|
|
|
systemctl restart avahi-daemon 2>/dev/null
|
|
|
|
|
reload_avahi() {
|
|
|
|
|
systemctl reload avahi-daemon 2>/dev/null || systemctl restart avahi-daemon 2>/dev/null
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] $ACTION — avahi reloaded"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "$ACTION" in
|
|
|
|
|
up|dhcp4-change)
|
|
|
|
|
up)
|
|
|
|
|
# On 'up' the interface may still carry a stale DHCP address from the previous
|
|
|
|
|
# session (NM hasn't cleaned it up yet). Reading ip-addr here is unreliable.
|
|
|
|
|
# Always re-enable link-local as a clean slate; let dhcp4-change suppress it
|
|
|
|
|
# later if a real DHCP lease is obtained.
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] Up — ensuring link-local active (clean slate)"
|
|
|
|
|
(sleep 2 && nmcli device modify "$INTERFACE" ipv4.link-local enabled 2>/dev/null \
|
|
|
|
|
&& logger -t nm-link-local "[$INTERFACE] Link-local explicitly enabled on up") &
|
|
|
|
|
reload_avahi
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
dhcp4-change)
|
|
|
|
|
# dhcp4-change fires only when DHCP actually succeeds (new/renewed lease).
|
|
|
|
|
# At this point the DHCP IP is reliably present — safe to read and suppress link-local.
|
|
|
|
|
DHCP_IP=$(ip -4 addr show "$INTERFACE" 2>/dev/null \
|
|
|
|
|
| grep -oP '(?<=inet\s)\d+(\.\d+){3}' \
|
|
|
|
|
| grep -v '^127\.' \
|
|
|
|
@@ -60,24 +46,19 @@ case "$ACTION" in
|
|
|
|
|
| head -n1)
|
|
|
|
|
|
|
|
|
|
if [ -n "$DHCP_IP" ]; then
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] DHCP $DHCP_IP detected — suppressing link-local (session only)"
|
|
|
|
|
# Use device modify (not connection modify) so the persistent profile keeps
|
|
|
|
|
# ipv4.link-local=enabled. This ensures direct-connect plug-ins always activate.
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] DHCP $DHCP_IP confirmed — suppressing link-local (session only)"
|
|
|
|
|
# Run in background after a delay — nmcli blocks on NM, which is waiting for
|
|
|
|
|
# this dispatcher to return, causing a deadlock if called synchronously.
|
|
|
|
|
(sleep 2 && nmcli device modify "$INTERFACE" ipv4.link-local disabled 2>/dev/null \
|
|
|
|
|
&& logger -t nm-link-local "[$INTERFACE] Link-local suppressed for current session") &
|
|
|
|
|
else
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] No DHCP on $INTERFACE — keeping link-local active"
|
|
|
|
|
fi
|
|
|
|
|
update_avahi
|
|
|
|
|
reload_avahi
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
down)
|
|
|
|
|
# Profile always has ipv4.link-local=enabled so no action needed here.
|
|
|
|
|
# The suppression from device modify was session-only and is gone when the
|
|
|
|
|
# connection goes down.
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] Down — link-local will be active on next connect"
|
|
|
|
|
update_avahi
|
|
|
|
|
# NOTE: a carrier-change does NOT fully reset session-level 'device modify' state.
|
|
|
|
|
# The re-enable is therefore handled in the 'up' handler when no DHCP is detected.
|
|
|
|
|
logger -t nm-link-local "[$INTERFACE] Down — link-local will be re-enabled on next up without DHCP"
|
|
|
|
|
reload_avahi
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|