Files
tinyboard/spoke/setup-network.sh

265 lines
7.9 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
die() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
header() { echo -e "\n${CYAN}══════════════════════════════════════════${NC}"; echo -e "${CYAN} $*${NC}"; echo -e "${CYAN}══════════════════════════════════════════${NC}"; }
check_deps() {
local missing=()
for cmd in "$@"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
missing+=("$cmd")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
die "Missing required dependencies: ${missing[*]}"
fi
}
[ "$(id -u)" -eq 0 ] || die "Run as root"
check_deps ip netplan systemctl ping hostnamectl
header "TinyBoard Network Setup"
echo ""
echo " 0) Change hostname"
echo " 1) Configure static IP"
echo " 2) Prefer IPv4 over IPv6"
echo " 3) Prefer IPv6 over IPv4"
echo " q) Quit"
echo ""
read -rp "Choose: " NET_OPT
echo ""
case "$NET_OPT" in
0)
header "Change Hostname"
CURRENT_HOSTNAME=$(hostname)
echo -e "Current hostname: ${YELLOW}$CURRENT_HOSTNAME${NC}"
read -rp "Enter new hostname (e.g. rocky): " NEW_HOSTNAME
[ -n "$NEW_HOSTNAME" ] || die "Hostname cannot be empty."
[[ "$NEW_HOSTNAME" =~ ^[a-zA-Z0-9._-]+$ ]] || die "Invalid hostname — use only letters, numbers, dots, underscores, hyphens."
hostnamectl set-hostname "$NEW_HOSTNAME"
echo "$NEW_HOSTNAME" > /etc/hostname
sed -i "s/${CURRENT_HOSTNAME}/${NEW_HOSTNAME}/g" /etc/hosts
info "Hostname changed to: $NEW_HOSTNAME"
exit 0
;;
1)
;;
2)
header "Prefer IPv4 over IPv6"
if grep -q "precedence ::ffff:0:0/96" /etc/gai.conf 2>/dev/null; then
warn "IPv4 preference already set."
else
echo "precedence ::ffff:0:0/96 100" >> /etc/gai.conf
info "IPv4 preference set. Outgoing connections will prefer IPv4."
fi
exit 0
;;
3)
header "Prefer IPv6 over IPv4"
sed -i '/precedence ::ffff:0:0\/96/d' /etc/gai.conf 2>/dev/null || true
info "IPv4 preference removed. System will use default IPv6-first behavior."
exit 0
;;
q|Q)
exit 0
;;
*)
die "Invalid choice."
;;
esac
info "Available interfaces:"
ip -o link show | awk -F': ' 'NR>1 {print " " $2}'
echo ""
read -rp "Enter interface name to configure (e.g. wlan0, eth0, end0): " IFACE
[ -n "$IFACE" ] || die "Interface name cannot be empty"
ip link show "$IFACE" >/dev/null 2>&1 || die "Interface $IFACE not found"
IS_WIFI=false
if [[ "$IFACE" == wl* ]]; then
IS_WIFI=true
info "Wireless interface detected."
else
info "Wired interface detected — skipping WiFi credential setup."
fi
CURRENT_IP=$(ip -o -4 addr show "$IFACE" 2>/dev/null | awk '{print $4}' | head -1)
CURRENT_GW=$(ip route show default 2>/dev/null | awk '/default/ {print $3}' | head -1)
echo ""
info "Current IP: ${CURRENT_IP:-none}"
info "Current gateway: ${CURRENT_GW:-none}"
echo ""
read -rp "Set a static IP for this spoke? [Y/n]: " SET_STATIC
SET_STATIC="${SET_STATIC:-y}"
if [[ "${SET_STATIC,,}" != "y" ]]; then
info "Keeping DHCP. No changes made."
exit 0
fi
header "Static IP Configuration"
read -rp "Enter static IP with prefix (e.g. 192.168.1.69/24): " STATIC_IP
[ -n "$STATIC_IP" ] || die "IP address cannot be empty"
DEFAULT_GW="${CURRENT_GW:-192.168.1.1}"
read -rp "Gateway [${DEFAULT_GW}]: " GATEWAY
GATEWAY="${GATEWAY:-$DEFAULT_GW}"
read -rp "DNS servers (comma-separated) [${GATEWAY},8.8.8.8]: " DNS_INPUT
DNS_INPUT="${DNS_INPUT:-${GATEWAY},8.8.8.8}"
DNS_YAML=""
IFS=',' read -ra DNS_LIST <<< "$DNS_INPUT"
for DNS in "${DNS_LIST[@]}"; do
DNS=$(echo "$DNS" | tr -d ' ')
if [ -n "$DNS_YAML" ]; then
DNS_YAML="${DNS_YAML}"$'\n'
fi
DNS_YAML="${DNS_YAML} - ${DNS}"
done
info "Current netplan configs:"
ls /etc/netplan/ | sed 's/^/ /'
echo ""
NETPLAN_FILE=$(ls /etc/netplan/*.yaml 2>/dev/null | head -1)
read -rp "Netplan file to update [${NETPLAN_FILE}]: " INPUT_FILE
NETPLAN_FILE="${INPUT_FILE:-$NETPLAN_FILE}"
NETPLAN_FILE="${NETPLAN_FILE:-$(ls /etc/netplan/*.yaml 2>/dev/null | head -1)}"
[ -n "$NETPLAN_FILE" ] || die "No netplan file specified"
if $IS_WIFI; then
header "WiFi Credentials"
CURRENT_SSID=""
if [ -f "$NETPLAN_FILE" ]; then
CURRENT_SSID=$(python3 - "$NETPLAN_FILE" <<'PYEOF'
import sys, re
txt = open(sys.argv[1]).read()
m = re.search(r'access-points:\s*\n\s+["\']{0,1}([^"\':\n]+)["\']{0,1}:', txt)
print(m.group(1).strip() if m else "")
PYEOF
)
fi
KEEP_WIFI="n"
if [ -n "$CURRENT_SSID" ]; then
warn "Existing WiFi config found for: $CURRENT_SSID"
read -rp "Keep existing WiFi credentials? [Y/n]: " KEEP_WIFI
KEEP_WIFI="${KEEP_WIFI:-y}"
fi
if [[ "${KEEP_WIFI,,}" != "y" ]]; then
read -rp "WiFi SSID: " WIFI_SSID
[ -n "$WIFI_SSID" ] || die "SSID cannot be empty"
read -rsp "WiFi password: " WIFI_PASS
echo ""
[ -n "$WIFI_PASS" ] || die "Password cannot be empty"
else
WIFI_SSID="$CURRENT_SSID"
WIFI_PASS=$(grep -FA2 "\"${WIFI_SSID}\"" "$NETPLAN_FILE" 2>/dev/null | grep -F "password" | sed 's/^[^:]*: *//' | tr -d '"' || true)
[ -n "$WIFI_PASS" ] || die "Could not extract WiFi password from existing config — please re-enter credentials."
fi
fi
header "Writing Netplan Config"
BACKUP_FILE=""
if [ -f "$NETPLAN_FILE" ]; then
NETPLAN_BACKUP_DIR="/root/.config/tinyboard/netplan-backups"
mkdir -p "$NETPLAN_BACKUP_DIR"
BACKUP_FILE="$NETPLAN_BACKUP_DIR/$(basename "${NETPLAN_FILE}").$(date +%Y%m%d%H%M%S)"
cp "$NETPLAN_FILE" "$BACKUP_FILE"
info "Netplan config backed up to $BACKUP_FILE"
info "To restore: cp $BACKUP_FILE $NETPLAN_FILE && netplan apply"
fi
if $IS_WIFI; then
cat > "$NETPLAN_FILE" <<NETEOF
network:
version: 2
wifis:
${IFACE}:
dhcp4: no
addresses:
- ${STATIC_IP}
routes:
- to: default
via: ${GATEWAY}
nameservers:
addresses:
${DNS_YAML}
access-points:
"${WIFI_SSID}":
password: "${WIFI_PASS}"
NETEOF
else
cat > "$NETPLAN_FILE" <<NETEOF
network:
version: 2
ethernets:
${IFACE}:
dhcp4: no
addresses:
- ${STATIC_IP}
routes:
- to: default
via: ${GATEWAY}
nameservers:
addresses:
${DNS_YAML}
NETEOF
fi
info "Netplan config written to $NETPLAN_FILE"
header "Applying Configuration"
warn "Applying netplan config — will revert automatically if network is lost..."
netplan apply
CONNECTED=false
for i in $(seq 1 6); do
sleep 5
if ping -c 1 -W 2 "$GATEWAY" >/dev/null 2>&1; then
CONNECTED=true
break
fi
warn "Network check $i/6 failed, retrying..."
done
if [ "$CONNECTED" = "true" ]; then
info "Network connectivity confirmed — config applied permanently."
else
warn "No network connectivity detected after 30 seconds — reverting to backup config."
if [ -n "$BACKUP_FILE" ] && [ -f "$BACKUP_FILE" ]; then
cp "$BACKUP_FILE" "$NETPLAN_FILE"
netplan apply
die "Config reverted to backup. Check your settings and try again."
else
die "No backup found to revert to. Restore $NETPLAN_FILE manually."
fi
fi
STATIC_ADDR="${STATIC_IP%%/*}"
echo ""
echo -e "${YELLOW}══════════════════════════════════════════${NC}"
echo -e "${YELLOW} Network reconfigured.${NC}"
echo -e "${YELLOW} If you are connected via SSH, your session${NC}"
echo -e "${YELLOW} may drop. Reconnect to: ${STATIC_ADDR}${NC}"
echo -e "${YELLOW} Then run: cd .. && ./setup.sh${NC}"
echo -e "${YELLOW}══════════════════════════════════════════${NC}"
echo ""