feat(zones): persist per-zone brightness and update submodules
Store zone brightness in model/data flow, apply it in the zones UI, and record updated led-driver, led-simulator, and led-tool submodule pointers. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
253
scripts/pi-eth-lan-router.sh
Executable file
253
scripts/pi-eth-lan-router.sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env bash
|
||||
# Configure Raspberry Pi OS: Wi-Fi client on IF_WAN (default wlan0), Ethernet IF_LAN
|
||||
# (default eth0) toward an external AP. Static LAN IP, DHCP via dnsmasq, NAT masquerade.
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./pi-eth-lan-router.sh install
|
||||
# sudo ./pi-eth-lan-router.sh remove
|
||||
#
|
||||
# Environment overrides (optional):
|
||||
# IF_WAN=wlan0 IF_LAN=eth0 LAN_IP=192.168.4.1 LAN_PREFIX=24 \
|
||||
# DHCP_START=192.168.4.100 DHCP_END=192.168.4.200 \
|
||||
# DNSMASQ_DNS=1.1.1.1,8.8.8.8 \
|
||||
# sudo ./pi-eth-lan-router.sh install
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
IF_WAN="${IF_WAN:-wlan0}"
|
||||
IF_LAN="${IF_LAN:-eth0}"
|
||||
LAN_IP="${LAN_IP:-192.168.4.1}"
|
||||
LAN_PREFIX="${LAN_PREFIX:-24}"
|
||||
DHCP_START="${DHCP_START:-192.168.4.100}"
|
||||
DHCP_END="${DHCP_END:-192.168.4.200}"
|
||||
# Comma-separated DNS for DHCP clients (Pi does not need to run a resolver).
|
||||
DNSMASQ_DNS="${DNSMASQ_DNS:-1.1.1.1,8.8.8.8}"
|
||||
|
||||
NM_CON_NAME="pi-eth-lan-router"
|
||||
MARK_BEGIN="# BEGIN pi-eth-lan-router (scripts/pi-eth-lan-router.sh)"
|
||||
MARK_END="# END pi-eth-lan-router"
|
||||
SYSCTL_FILE="/etc/sysctl.d/99-pi-eth-lan-router.conf"
|
||||
DNSMASQ_SNIPPET="/etc/dnsmasq.d/pi-eth-lan-router.conf"
|
||||
NFT_SNIPPET="/etc/nftables.d/50-pi-eth-lan-router.nft"
|
||||
NFT_INCLUDE='include "/etc/nftables.d/50-pi-eth-lan-router.nft"'
|
||||
NFTABLES_CONF="/etc/nftables.conf"
|
||||
DHCPCD_CONF="/etc/dhcpcd.conf"
|
||||
|
||||
die() { echo "error: $*" >&2; exit 1; }
|
||||
log() { echo "$*"; }
|
||||
|
||||
need_root() {
|
||||
[[ "${EUID:-0}" -eq 0 ]] || die "run as root (sudo)"
|
||||
}
|
||||
|
||||
have_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
apt_install() {
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq dnsmasq nftables
|
||||
}
|
||||
|
||||
write_sysctl() {
|
||||
cat >"$SYSCTL_FILE" <<EOF
|
||||
# Managed by scripts/pi-eth-lan-router.sh
|
||||
net.ipv4.ip_forward=1
|
||||
EOF
|
||||
sysctl --system -q 2>/dev/null || sysctl -p "$SYSCTL_FILE" || true
|
||||
}
|
||||
|
||||
remove_sysctl() {
|
||||
rm -f "$SYSCTL_FILE"
|
||||
sysctl --system -q 2>/dev/null || true
|
||||
}
|
||||
|
||||
write_dnsmasq() {
|
||||
local mask="255.255.255.0"
|
||||
if [[ "$LAN_PREFIX" != "24" ]]; then
|
||||
die "only LAN_PREFIX=24 is supported by this script (extend dnsmasq netmask manually)"
|
||||
fi
|
||||
cat >"$DNSMASQ_SNIPPET" <<EOF
|
||||
# Managed by scripts/pi-eth-lan-router.sh
|
||||
interface=$IF_LAN
|
||||
bind-interfaces
|
||||
dhcp-range=$DHCP_START,$DHCP_END,$mask,24h
|
||||
dhcp-option=option:router,$LAN_IP
|
||||
dhcp-option=option:dns-server,$DNSMASQ_DNS
|
||||
EOF
|
||||
}
|
||||
|
||||
remove_dnsmasq() {
|
||||
rm -f "$DNSMASQ_SNIPPET"
|
||||
}
|
||||
|
||||
write_nft() {
|
||||
mkdir -p /etc/nftables.d
|
||||
cat >"$NFT_SNIPPET" <<EOF
|
||||
# Managed by scripts/pi-eth-lan-router.sh
|
||||
table ip pi_eth_wlan_nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 100; policy accept;
|
||||
oifname "$IF_WAN" masquerade
|
||||
}
|
||||
}
|
||||
EOF
|
||||
if [[ -f "$NFTABLES_CONF" ]] && ! grep -qF '50-pi-eth-lan-router.nft' "$NFTABLES_CONF" 2>/dev/null; then
|
||||
printf '\n# pi-eth-lan-router\n%s\n' "$NFT_INCLUDE" >>"$NFTABLES_CONF"
|
||||
elif [[ ! -f "$NFTABLES_CONF" ]]; then
|
||||
log "warning: $NFTABLES_CONF missing; NAT was not added for boot persistence. Install/configure nftables, or add: $NFT_INCLUDE"
|
||||
fi
|
||||
}
|
||||
|
||||
remove_nft() {
|
||||
rm -f "$NFT_SNIPPET"
|
||||
if [[ -f "$NFTABLES_CONF" ]]; then
|
||||
sed -i '/# pi-eth-lan-router/d;/50-pi-eth-lan-router\.nft/d' "$NFTABLES_CONF" || true
|
||||
fi
|
||||
nft delete table ip pi_eth_wlan_nat 2>/dev/null || true
|
||||
}
|
||||
|
||||
apply_nft() {
|
||||
if have_cmd nft; then
|
||||
nft delete table ip pi_eth_wlan_nat 2>/dev/null || true
|
||||
nft -f "$NFT_SNIPPET"
|
||||
fi
|
||||
}
|
||||
|
||||
configure_nm_eth() {
|
||||
have_cmd nmcli || return 1
|
||||
systemctl is-active --quiet NetworkManager 2>/dev/null || return 1
|
||||
|
||||
if nmcli -t -f NAME con show --active 2>/dev/null | grep -qxF "$NM_CON_NAME"; then
|
||||
nmcli con down "$NM_CON_NAME" || true
|
||||
fi
|
||||
if nmcli -t -f NAME con show 2>/dev/null | grep -qxF "$NM_CON_NAME"; then
|
||||
nmcli con mod "$NM_CON_NAME" \
|
||||
connection.interface-name "$IF_LAN" \
|
||||
ipv4.method manual \
|
||||
ipv4.addresses "${LAN_IP}/${LAN_PREFIX}" \
|
||||
ipv4.gateway "" \
|
||||
ipv4.dns "" \
|
||||
ipv4.never-default yes \
|
||||
ipv6.method ignore
|
||||
else
|
||||
nmcli con add type ethernet con-name "$NM_CON_NAME" ifname "$IF_LAN" \
|
||||
ipv4.method manual \
|
||||
ipv4.addresses "${LAN_IP}/${LAN_PREFIX}" \
|
||||
ipv4.gateway "" \
|
||||
ipv4.dns "" \
|
||||
ipv4.never-default yes \
|
||||
ipv6.method ignore
|
||||
fi
|
||||
if ! nmcli con up "$NM_CON_NAME"; then
|
||||
log "warning: could not activate '$NM_CON_NAME' (is $IF_LAN connected?); profile saved for next boot."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
remove_nm_eth() {
|
||||
have_cmd nmcli || return 0
|
||||
if nmcli -t -f NAME con show 2>/dev/null | grep -qxF "$NM_CON_NAME"; then
|
||||
nmcli con delete "$NM_CON_NAME" || true
|
||||
fi
|
||||
}
|
||||
|
||||
configure_dhcpcd_eth() {
|
||||
[[ -f "$DHCPCD_CONF" ]] || return 1
|
||||
if grep -qF "$MARK_BEGIN" "$DHCPCD_CONF" 2>/dev/null; then
|
||||
sed -i "/$MARK_BEGIN/,/$MARK_END/d" "$DHCPCD_CONF" || true
|
||||
fi
|
||||
{
|
||||
echo "$MARK_BEGIN"
|
||||
echo "interface $IF_LAN"
|
||||
echo "static ip_address=${LAN_IP}/${LAN_PREFIX}"
|
||||
echo "nohook wpa_supplicant"
|
||||
echo "$MARK_END"
|
||||
} >>"$DHCPCD_CONF"
|
||||
systemctl restart dhcpcd 2>/dev/null || true
|
||||
return 0
|
||||
}
|
||||
|
||||
remove_dhcpcd_block() {
|
||||
[[ -f "$DHCPCD_CONF" ]] || return 0
|
||||
if grep -qF "$MARK_BEGIN" "$DHCPCD_CONF" 2>/dev/null; then
|
||||
sed -i "/$MARK_BEGIN/,/$MARK_END/d" "$DHCPCD_CONF" || true
|
||||
systemctl restart dhcpcd 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
configure_eth_static() {
|
||||
if configure_nm_eth; then
|
||||
log "configured $IF_LAN via NetworkManager profile '$NM_CON_NAME'"
|
||||
return 0
|
||||
fi
|
||||
if configure_dhcpcd_eth; then
|
||||
log "configured $IF_LAN via dhcpcd ($DHCPCD_CONF)"
|
||||
return 0
|
||||
fi
|
||||
die "neither NetworkManager (active) nor $DHCPCD_CONF found; set $IF_LAN to ${LAN_IP}/${LAN_PREFIX} manually"
|
||||
}
|
||||
|
||||
remove_eth_static() {
|
||||
remove_nm_eth
|
||||
remove_dhcpcd_block
|
||||
}
|
||||
|
||||
do_install() {
|
||||
need_root
|
||||
log "installing packages (dnsmasq, nftables)…"
|
||||
apt_install
|
||||
|
||||
log "writing sysctl, dnsmasq, nftables snippets…"
|
||||
write_sysctl
|
||||
write_dnsmasq
|
||||
write_nft
|
||||
|
||||
log "setting static IP on $IF_LAN…"
|
||||
configure_eth_static
|
||||
|
||||
log "restarting dnsmasq…"
|
||||
systemctl enable dnsmasq
|
||||
systemctl restart dnsmasq
|
||||
|
||||
log "loading NAT rules and enabling nftables…"
|
||||
apply_nft
|
||||
systemctl enable nftables 2>/dev/null || true
|
||||
systemctl restart nftables 2>/dev/null || true
|
||||
|
||||
log "done. Connect $IF_LAN to the external AP (DHCP off on the AP)."
|
||||
log "Join Wi-Fi on $IF_WAN to the uplink network and complete any captive portal on the Pi."
|
||||
}
|
||||
|
||||
do_remove() {
|
||||
need_root
|
||||
remove_eth_static
|
||||
remove_dnsmasq
|
||||
systemctl restart dnsmasq 2>/dev/null || true
|
||||
|
||||
remove_nft
|
||||
systemctl restart nftables 2>/dev/null || true
|
||||
|
||||
remove_sysctl
|
||||
sysctl -w net.ipv4.ip_forward=0 2>/dev/null || true
|
||||
|
||||
log "removed pi-eth-lan-router configuration snippets and NM profile '$NM_CON_NAME' (if present)."
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: sudo $0 install|remove
|
||||
|
||||
WAN (Wi-Fi client): $IF_WAN
|
||||
LAN (Ethernet to AP): $IF_LAN
|
||||
LAN address: ${LAN_IP}/${LAN_PREFIX}
|
||||
DHCP range: $DHCP_START – $DHCP_END
|
||||
|
||||
Override with environment variables (see script header).
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
install) do_install ;;
|
||||
remove) do_remove ;;
|
||||
*) usage; exit 1 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user