Files
debian-base/configure-debian-network.sh
T

364 lines
9.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-only
set -euo pipefail
if [[ "${EUID}" -ne 0 ]]; then
echo "Ce script doit etre lance en root."
echo "Exemple: sudo $0"
exit 1
fi
# Cree une copie horodatee d'un fichier avant modification.
backup_file() {
local file="$1"
if [[ -e "${file}" ]]; then
cp -a "${file}" "${file}.bak.$(date +%Y%m%d-%H%M%S)"
fi
}
# Demande une valeur obligatoire et recommence tant que la saisie est vide.
ask_required() {
local prompt="$1"
local value
while true; do
read -r -p "${prompt}: " value
if [[ -n "${value}" ]]; then
printf '%s\n' "${value}"
return 0
fi
echo "Valeur obligatoire." >&2
done
}
# Demande une valeur facultative et retourne une chaine vide si l'utilisateur valide sans saisie.
ask_optional() {
local prompt="$1"
local value
read -r -p "${prompt}: " value
printf '%s\n' "${value}"
}
# Verifie qu'un hostname respecte une forme DNS simple compatible Debian.
is_valid_hostname() {
local value="$1"
[[ "${value}" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]]
}
# Verifie qu'une valeur est une adresse IPv4 composee de quatre octets valides.
is_valid_ipv4() {
local value="$1"
local octets
IFS='.' read -r -a octets <<< "${value}"
[[ "${#octets[@]}" -eq 4 ]] || return 1
for octet in "${octets[@]}"; do
[[ "${octet}" =~ ^[0-9]+$ ]] || return 1
(( octet >= 0 && octet <= 255 )) || return 1
done
}
# Verifie qu'une valeur est une adresse IPv4 avec prefixe CIDR valide.
is_valid_cidr() {
local value="$1"
local ip prefix
[[ "${value}" == */* ]] || return 1
ip="${value%/*}"
prefix="${value#*/}"
is_valid_ipv4 "${ip}" || return 1
[[ "${prefix}" =~ ^[0-9]+$ ]] || return 1
(( prefix >= 1 && prefix <= 32 ))
}
# Demande un hostname facultatif et valide la saisie quand elle est renseignee.
ask_optional_hostname() {
local value
while true; do
value="$(ask_optional "Nom de la machine (laisser vide pour ne pas modifier)")"
if [[ -z "${value}" ]] || is_valid_hostname "${value}"; then
printf '%s\n' "${value}"
return 0
fi
echo "Nom invalide. Utilisez lettres, chiffres et tirets, sans tiret au debut ou a la fin." >&2
done
}
# Demande une adresse IPv4 obligatoire avec le libelle fourni en parametre.
ask_ipv4() {
local prompt="$1"
local value
while true; do
value="$(ask_required "${prompt}")"
if is_valid_ipv4 "${value}"; then
printf '%s\n' "${value}"
return 0
fi
echo "Adresse IPv4 invalide." >&2
done
}
# Demande une adresse CIDR facultative pour activer ou ignorer la configuration reseau.
ask_optional_cidr() {
local value
while true; do
value="$(ask_optional "Adresse IP avec prefixe CIDR (ex: 192.168.1.50/24, laisser vide pour ne pas modifier le reseau)")"
if [[ -z "${value}" ]] || is_valid_cidr "${value}"; then
printf '%s\n' "${value}"
return 0
fi
echo "Adresse CIDR invalide." >&2
done
}
# Demande un ou plusieurs serveurs DNS et valide chaque adresse IPv4.
ask_dns_servers() {
local value server
while true; do
value="$(ask_required "Serveur(s) DNS separes par des espaces (ex: 1.1.1.1 8.8.8.8)")"
for server in ${value}; do
if ! is_valid_ipv4 "${server}"; then
echo "Serveur DNS invalide: ${server}" >&2
continue 2
fi
done
printf '%s\n' "${value}"
return 0
done
}
# Liste les interfaces reseau disponibles et demande celle a configurer.
choose_interface() {
local interfaces value
mapfile -t interfaces < <(find /sys/class/net -mindepth 1 -maxdepth 1 -printf '%f\n' | grep -v '^lo$' | sort)
if [[ "${#interfaces[@]}" -eq 0 ]]; then
echo "Aucune interface reseau detectee." >&2
exit 1
fi
echo "Interfaces disponibles:" >&2
printf ' - %s\n' "${interfaces[@]}" >&2
while true; do
value="$(ask_required "Interface a configurer")"
if [[ -d "/sys/class/net/${value}" && "${value}" != "lo" ]]; then
printf '%s\n' "${value}"
return 0
fi
echo "Interface inconnue." >&2
done
}
# Demande une confirmation explicite avant d'appliquer les modifications.
confirm() {
local answer
read -r -p "Appliquer cette configuration ? [y/N]: " answer
[[ "${answer}" =~ ^[yY]$ ]]
}
# Met a jour /etc/hosts avec la nouvelle entree 127.0.1.1 du hostname.
update_hosts_file() {
local hostname="$1"
local tmp_file
tmp_file="$(mktemp)"
awk '
$1 == "127.0.1.1" { next }
{ print }
' /etc/hosts > "${tmp_file}"
printf '127.0.1.1\t%s\n' "${hostname}" >> "${tmp_file}"
install -m 0644 "${tmp_file}" /etc/hosts
rm -f "${tmp_file}"
}
# Reecrit /etc/network/interfaces avec une configuration IPv4 statique ifupdown.
write_network_interfaces() {
local interface="$1"
local ip_cidr="$2"
local gateway="$3"
local dns_servers="$4"
cat > /etc/network/interfaces <<EOF
# Fichier genere par configure-debian-network.sh
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
allow-hotplug ${interface}
auto ${interface}
iface ${interface} inet static
address ${ip_cidr}
gateway ${gateway}
dns-nameservers ${dns_servers}
EOF
}
# Indique si dhcpcd semble present et susceptible de gerer resolv.conf.
has_dhcpcd() {
[[ -e /etc/dhcpcd.conf ]] ||
[[ -e /lib/systemd/system/dhcpcd.service ]] ||
[[ -e /usr/lib/systemd/system/dhcpcd.service ]] ||
command -v dhcpcd >/dev/null 2>&1 ||
grep -qi 'dhcpcd' /etc/resolv.conf 2>/dev/null
}
# Met a jour /etc/dhcpcd.conf avec un bloc statique dedie au script.
write_dhcpcd_conf() {
local interface="$1"
local ip_cidr="$2"
local gateway="$3"
local dns_servers="$4"
local tmp_file
if ! has_dhcpcd; then
return 0
fi
touch /etc/dhcpcd.conf
tmp_file="$(mktemp)"
awk '
$0 == "# BEGIN configure-debian-network.sh" { skip = 1; next }
$0 == "# END configure-debian-network.sh" { skip = 0; next }
skip != 1 { print }
' /etc/dhcpcd.conf > "${tmp_file}"
{
printf '\n# BEGIN configure-debian-network.sh\n'
printf 'interface %s\n' "${interface}"
printf 'static ip_address=%s\n' "${ip_cidr}"
printf 'static routers=%s\n' "${gateway}"
printf 'static domain_name_servers=%s\n' "${dns_servers}"
printf '# END configure-debian-network.sh\n'
} >> "${tmp_file}"
install -m 0644 "${tmp_file}" /etc/dhcpcd.conf
rm -f "${tmp_file}"
}
# Ecrit les serveurs DNS dans /etc/resolv.conf quand ce fichier n'est pas gere par lien symbolique.
write_resolv_conf() {
local dns_servers="$1"
local server
if [[ -L /etc/resolv.conf ]]; then
echo "/etc/resolv.conf est un lien symbolique, il ne sera pas modifie directement."
return 0
fi
{
echo "# Fichier genere par configure-debian-network.sh"
for server in ${dns_servers}; do
echo "nameserver ${server}"
done
} > /etc/resolv.conf
}
# Orchestre la collecte des informations, la confirmation et l'application des changements.
main() {
local hostname interface ip_cidr gateway dns_servers reboot_answer restart_answer network_changed
echo "Configuration reseau Debian"
echo
hostname="$(ask_optional_hostname)"
ip_cidr="$(ask_optional_cidr)"
if [[ -n "${ip_cidr}" ]]; then
interface="$(choose_interface)"
gateway="$(ask_ipv4 "Gateway (ex: 192.168.1.1)")"
dns_servers="$(ask_dns_servers)"
network_changed=1
else
interface=""
gateway=""
dns_servers=""
network_changed=0
fi
if [[ -z "${hostname}" && "${network_changed}" -eq 0 ]]; then
echo "Aucune modification demandee."
exit 0
fi
echo
echo "Resume:"
if [[ -n "${hostname}" ]]; then
echo " Nom machine : ${hostname}"
else
echo " Nom machine : non modifie"
fi
if [[ "${network_changed}" -eq 1 ]]; then
echo " Interface : ${interface}"
echo " IP : ${ip_cidr}"
echo " Gateway : ${gateway}"
echo " DNS : ${dns_servers}"
else
echo " Reseau : non modifie"
fi
echo
if ! confirm; then
echo "Annule."
exit 0
fi
if [[ -n "${hostname}" ]]; then
backup_file /etc/hostname
backup_file /etc/hosts
hostnamectl set-hostname "${hostname}"
printf '%s\n' "${hostname}" > /etc/hostname
update_hosts_file "${hostname}"
fi
if [[ "${network_changed}" -eq 1 ]]; then
backup_file /etc/network/interfaces
backup_file /etc/dhcpcd.conf
backup_file /etc/resolv.conf
write_network_interfaces "${interface}" "${ip_cidr}" "${gateway}" "${dns_servers}"
write_dhcpcd_conf "${interface}" "${ip_cidr}" "${gateway}" "${dns_servers}"
write_resolv_conf "${dns_servers}"
fi
echo
echo "Configuration ecrite."
if [[ "${network_changed}" -eq 1 ]]; then
read -r -p "Redemarrer le service reseau maintenant ? [y/N]: " restart_answer
if [[ "${restart_answer}" =~ ^[yY]$ ]]; then
if has_dhcpcd && systemctl is-active --quiet dhcpcd; then
systemctl restart dhcpcd
echo "Service dhcpcd redemarre."
fi
if systemctl restart networking; then
echo "Service networking redemarre."
else
echo "Impossible de redemarrer networking. Un redemarrage de la machine peut etre necessaire." >&2
exit 1
fi
else
echo "Redemarrez le reseau ou la machine pour appliquer la configuration IP."
fi
fi
if [[ -n "${hostname}" ]]; then
echo
read -r -p "Redemarrer la machine maintenant pour appliquer completement le hostname ? [y/N]: " reboot_answer
if [[ "${reboot_answer}" =~ ^[yY]$ ]]; then
echo "Redemarrage de la machine."
systemctl reboot
else
echo "Redemarrez la machine plus tard pour que le nouveau hostname soit pris en compte partout."
fi
fi
}
main "$@"