##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 ## Calculateur d'adresse IP ##@cooked nocomments ##@require base uprovide ipcalc urequire base function get_random_kvm_macaddr() { # Obtenir une adresse mac au hasard commençant par 52:54:00 pour KVM echo "52:54:00:$(awk 'BEGIN {srand(); printf("%02X:%02X:%02X", rand()*256, rand()*256, rand()*256)}' 2>/dev/null)" } function ipcalc_splitipmask() { # Découper $1 de la forme ip[/mask] entre l'adresse ip, qui est placé dans # la variable $2(=ip) et le masque, qui est placée dans la variable # $3(=mask) if [[ "$1" == */* ]]; then _setv "${2:-ip}" "${1%%/*}" _setv "${3:-mask}" "${1#*/}" else _setv "${2:-ip}" "$1" _setv "${3:-mask}" fi } function ipcalc_checkip() { # Vérifier l'adresse ip $1 pour voir si elle est valide. Si l'adresse est # valide, l'afficher. Sinon, retourner 1 awkrun status=0 '{ # si l"adresse ne fait pas la taille voulue, rajouter des .0 ip = $0 gsub(/[^.]/, "", ip) count = length(ip) while (count < 3) { $0 = $0 ".0" count++ } # puis tester la validité if ($0 !~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) { status = 1 exit } match($0, /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/, ps) for (i = 1; i <= 4; i++) { p = 0 + ps[i] if (p > 255) { status = 1 exit } } print $0 } END { exit status }' <<<"$1" } function ipcalc_checkmask() { # vérifier le masque de sous-réseau $1 pour voir si elle est valide. Si oui, # afficher le suffixe (0, 8, 16, 24, 32) associé. Sinon retourner 1 case "$1" in 0|0.0.0.0) echo 0;; 8|255.0.0.0) echo 8;; 16|255.255.0.0) echo 16;; 24|255.255.255.0) echo 24;; 32|255.255.255.255) echo 32;; *) return 1;; esac return 0 } function ipcalc_netmask() { # à partir d'un suffixe (0, 8, 16, 24, 32) ou d'un masque de sous-réseau, # afficher le masque de sous-réseau. si le suffixe ou le masque ne sont pas # reconnus, retourner 1 case "$1" in 0|0.0.0.0) echo 0.0.0.0;; 8|255.0.0.0) echo 255.0.0.0;; 16|255.255.0.0) echo 255.255.0.0;; 24|255.255.255.0) echo 255.255.255.0;; 32|255.255.255.255) echo 255.255.255.255;; *) return 1;; esac return 0 } function ipcalc_network() { # Calculer l'adresse de réseau correspondant à l'adresse ip $1. Le masque # de sous-réseau peut-être indiqué dans l'adresse ip avec le suffixe /n ou # /x.x.x.x ou donné dans l'argument $2. Seuls les suffixes 0, 8, 16, 24, 32 # sont supportés. # Retourner 1 si un erreur s'est produite, par exemple si l'adresse ou le # suffixe sont invalides ou non supportés. [ -n "$1" ] || return local ip mask ipcalc_splitipmask "$1" ip mask [ -n "$mask" ] || mask="$2" [ -n "$mask" ] || mask=24 ip="$(ipcalc_checkip "$ip")" || return mask="$(ipcalc_checkmask "$mask")" || return case "$mask" in 0) echo "0.0.0.0";; 8) ip="${ip%.*.*.*}"; echo "$ip.0.0.0";; 16) ip="${ip%.*.*}"; echo "$ip.0.0";; 24) ip="${ip%.*}"; echo "$ip.0";; 32) echo "$ip";; esac } function ipcalc_broadcast() { # Calculer l'adresse de broadcast correspondant à l'adresse ip $1. Le masque # de sous-réseau peut-être indiqué dans l'adresse ip avec le suffixe /n ou # /x.x.x.x ou donné dans l'argument $2. Seuls les suffixes 0, 8, 16, 24, 32 # sont supportés. # Retourner 1 si un erreur s'est produite, par exemple si l'adresse ou le # suffixe sont invalides ou non supportés. [ -n "$1" ] || return local ip mask ipcalc_splitipmask "$1" ip mask [ -n "$mask" ] || mask="$2" [ -n "$mask" ] || mask=24 ip="$(ipcalc_checkip "$ip")" || return mask="$(ipcalc_checkmask "$mask")" || return case "$mask" in 0) echo "255.255.255.255";; 8) ip="${ip%.*.*.*}"; echo "$ip.255.255.255";; 16) ip="${ip%.*.*}"; echo "$ip.255.255";; 24) ip="${ip%.*}"; echo "$ip.255";; 32) echo "$ip";; esac } function ipcalc_gateway() { # Calculer l'adresse du gateway correspondant à l'adresse ip $1, en # considérant que le gateway est la première adresse du réseau. Le masque de # sous-réseau peut-être indiqué dans l'adresse ip avec le suffixe /n ou # /x.x.x.x ou donné dans l'argument $2. Seuls les suffixes 0, 8, 16, 24, 32 # sont supportés. # Retourner 1 si un erreur s'est produite, par exemple si l'adresse ou le # suffixe sont invalides ou non supportés. [ -n "$1" ] || return local ip mask ipcalc_splitipmask "$1" ip mask [ -n "$mask" ] || mask="$2" [ -n "$mask" ] || mask=24 ip="$(ipcalc_checkip "$ip")" || return mask="$(ipcalc_checkmask "$mask")" || return case "$mask" in 0) echo "0.0.0.1";; 8) ip="${ip%.*.*.*}"; echo "$ip.0.0.1";; 16) ip="${ip%.*.*}"; echo "$ip.0.1";; 24) ip="${ip%.*}"; echo "$ip.1";; 32) echo "$ip";; esac } function ipcalc_match() { # Vérifier si l'adresse $1 correspond au modèle $2, e.g.: # ipcalc_match 10.75.0.23 10/8 --> TRUE # ipcalc_match 10.75.0.23 10.75.0.0/24 --> TRUE # ipcalc_match 10.75.0.23 10.75.0.28 --> FALSE [ -n "$1" -a -n "$2" ] || return local ip tip tmask ipcalc_splitipmask "$2" tip tmask [ -n "$tmask" ] || tmask=32 ip="$(ipcalc_checkip "$1")" || return tip="$(ipcalc_checkip "$tip")" || return tmask="$(ipcalc_checkmask "$tmask")" || return case "$tmask" in 0) return 0;; 8) [ "${ip%.*.*.*}" == "${tip%.*.*.*}" ];; 16) [ "${ip%.*.*}" == "${tip%.*.*}" ];; 24) [ "${ip%.*}" == "${tip%.*}" ];; 32) [ "$ip" == "$tip" ];; esac } function ipcalc_fqdn() { # Calculer si possible le nom pleinement qualifié correspondant à l'hôte $1. # Dans tous les cas, afficher l'hôte, mais retourner 1 si la calcul n'a pas # pu être effectué. local -a ips hosts local ip host if ! ips=("$(ipcalc_checkip "$1")"); then resolv_ips ips "$1" if [ -z "${ips[*]}" ]; then echo "$1" return 1 fi fi for ip in "${ips[@]}"; do resolv_hosts hosts "$ip" if [ -n "${hosts[*]}" ]; then echo "${hosts[0]}" return 0 fi done echo "$1" return 1 } function ipcalc_fqdn_maybe() { # Si $1 *semble* déjà être un nom d'hôte pleinement qualifié, l'afficher tel # quel. Sinon utiliser ipcalc_fqdn() pour afficher le nom d'hôte pleinement # qualifié correspondant. if ipcalc_checkip "$1" >/dev/null; then ipcalc_fqdn "$1" elif [[ "$1" == *.* ]]; then echo "$1" else ipcalc_fqdn "$1" fi } ################################################################################ # Fonctions génériques pour la gestion du réseau __NETWORK_DEVEL_SHOW_MODIFS= function __network_parse_confbr() { local br; local -a ifaces splitpair "$1" br ifaces array_split ifaces "$ifaces" , __npc_destbr="$br" array_copy __npc_destifaces ifaces } function network_parse_confbr() { # network_parse_confbr "$confbr" br ifaces local __npc_destbr; local -a __npc_destifaces __network_parse_confbr "$1" _setv "${2:-br}" "$__npc_destbr" array_copy "${3:-ifaces}" __npc_destifaces } function network_format_confbr() { # network_format_confbr "$br" ifaces --> "br:ifaces" echo "$1:$(array_join "${2:-ifaces}" ,)" } function __network_parse_confip() { local tmpig iface gateway; local -a ipsuffixes splitfsep2 "$1" : tmpig ipsuffixes splitfsep "$tmpig" // iface gateway array_split ipsuffixes "$ipsuffixes" , __npc_destiface="$iface" __npc_destgateway="$gateway" array_copy __npc_destipsuffixes ipsuffixes } function network_parse_confip() { # network_parse_confip "$confip" iface gateway ipsuffixes local __npc_destiface __npc_destgateway; local -a __npc_destipsuffixes __network_parse_confip "$1" _setv "${2:-iface}" "$__npc_destiface" _setv "${3:-gateway}" "$__npc_destgateway" array_copy "${4:-ipsuffixes}" __npc_destipsuffixes } function network_parse_ipsuffix() { # network_parse_ipsuffix "$ipsuffix" ip suffix splitfsep "$1" / "${2:-ip}" "${3:-suffix}" } function network_format_confip() { # network_format_confip "$iface" "$gateway" ipsuffixes --> "iface//gateway:ipsuffixes" local tmpig="$1${2:+//$2}" echo "${tmpig:+$tmpig:}$(array_join "${3:-ipsuffixes}" ,)" } function network_format_ipsuffix() { # network_format_ipsuffix "$ip" "$suffix" --> "ip/suffix" local ip="$(strlower "$1")" if [ "$ip" == "dhcp" ]; then echo "$ip" else echo "$1${2:+/$2}" fi } function __network_fix_confbrs() { local -a confbrs ifaces brs ips local confbr br iface # recenser les bridges et créer les tableaux __BR_ifaces for confbr in "${__nfc_confbrs[@]}"; do network_parse_confbr "$confbr" br ifaces array_addu brs "$br" eval "local -a ${br}_ifaces" done # puis constuire la liste des interfaces associées à chaque bridge for confbr in "${__nfc_confbrs[@]}"; do network_parse_confbr "$confbr" br ifaces array_extendu "${br}_ifaces" ifaces done # puis construire le tableau final array_new confbrs for br in "${brs[@]}"; do array_add confbrs "$(network_format_confbr "$br" "${br}_ifaces")" done array_copy __nfc_destconfbrs confbrs } function network_fix_confbrs() { # normaliser le tableau $1(=confbrs): fusionner les doublons local -a __nfc_confbrs __nfc_destconfbrs array_copy __nfc_confbrs "${1:-confbrs}" __network_fix_confbrs array_copy "${1:-confbrs}" __nfc_destconfbrs } function __network_fix_confips() { local -a confips ipsuffixes ifaces ips local confip iface gateway network ip suffix mainip local mainiface="$1" # recenser les interfaces et créer les tableaux __IFACE_ipspecs for confip in "${__nfc_confips[@]}"; do network_parse_confip "$confip" iface gateway ipsuffixes if [ -n "$iface" ]; then network="${iface}_network" if ! array_contains ifaces "$iface"; then array_add ifaces "$iface" eval "local ${iface}_gateway $network; local -a ${iface}_ipsuffixes" fi if [ -z "${!network}" -a -n "${ipsuffixes[0]}" ]; then _setv "$network" "$(ipcalc_network "${ipsuffixes[0]}")" fi fi done if [ -n "$mainiface" ]; then iface="$mainiface" if ! array_contains ifaces "$iface"; then array_add ifaces "$iface" eval "local ${iface}_gateway $network; local -a ${iface}_ipsuffixes" fi fi # puis construire la liste des adresses IP associées à chaque interface for confip in "${__nfc_confips[@]}"; do network_parse_confip "$confip" iface gateway ipsuffixes # si aucune interface n'est spécifiée, sélectionner celle correspondant # à la même adresse de réseau. sinon prendre $mainiface if [ -z "$iface" ]; then network="$(ipcalc_network "${ipsuffixes[0]}")" local ip_iface ip_network for ip_iface in "${ifaces[@]}"; do ip_network="${ip_iface}_network" if [ "${!ip_network}" == "$network" ]; then iface="$ip_iface" break fi done fi [ -n "$iface" ] || iface="$mainiface" # si la passerelle a déjà été spécifiée, la récupérer local tmpgw="${iface}_gateway" [ -n "${!tmpgw}" ] && gateway="${!tmpgw}" # calculer l'adresse ip principale, pour pouvoir traiter le cas où # l'adresse ip principale est l'adresse de la passerelle. mainip= for ipsuffix in "${ipsuffixes[@]}"; do network_parse_ipsuffix "$ipsuffix" ip suffix if ! array_contains ips "$ip"; then [ -n "$suffix" ] || suffix=24 if [ -z "$mainip" ]; then [ -n "$gateway" ] || gateway="$(ipcalc_gateway "$ip" "$suffix")" mainip="$ip" fi array_add "${iface}_ipsuffixes" "$(network_format_ipsuffix "$ip" "$suffix")" array_add ips "$ip" fi done [ "$gateway" == "$mainip" ] && gateway= # si l'adresse ip principale est obtenue par dhcp, il ne faut pas # spécifier la passerelle: elle sera fournie par le serveur DHCP. # Utiliser le marqueur "none" pour que la valeur ne soit pas modifiée. [ "${ipsuffixes[0]}" == "dhcp" ] && gateway=none _setv "${iface}_gateway" "$gateway" done # puis construire le tableau final array_new confips for iface in "${ifaces[@]}"; do gateway="${iface}_gateway"; gateway="${!gateway}" [ "$gateway" == "none" ] && gateway= array_add confips "$(network_format_confip "$iface" "$gateway" "${iface}_ipsuffixes")" done array_copy __nfc_destconfips confips } function network_fix_confips() { # normaliser le tableau $1(=confips): fusionner les doublons, spécifier le # suffixe /24 par défaut, etc. $2 est le cas échéant l'interface associée # aux adresses ip non qualifiées local -a __nfc_confips __nfc_destconfips array_copy __nfc_confips "${1:-confips}" __network_fix_confips "$2" array_copy "${1:-confips}" __nfc_destconfips } function __network_fix_mainiface() { local -a confips ifaces ipsuffixes local br iface gateway confip mainconfip local mainiface="$1" # déterminer mainiface if [ -z "$mainiface" -a -n "${__nfm_confbrs[0]}" ]; then network_parse_confbr "${__nfm_confbrs[0]}" br ifaces mainiface="$br" fi if [ -z "$mainiface" -a -n "${__nfm_confips[0]}" ]; then network_parse_confip "${__nfm_confips[0]}" iface gateway ipsuffixes mainiface="$iface" fi [ -n "$mainiface" ] || mainiface=eth0 # ensuite, il faut reécrire confips avec la valeur de mainiface array_new confips for confip in "${__nfm_confips[@]}"; do network_parse_confip "$confip" iface gateway ipsuffixes [ -n "$iface" ] || iface="$mainiface" confip="$(network_format_confip "$iface" "$gateway" ipsuffixes)" if [ "$iface" == "$mainiface" ]; then mainconfip="$confip" else array_add confips "$confip" fi done [ -n "$mainconfip" ] && array_ins confips "$mainconfip" array_copy __nfm_destconfips confips } function network_fix_mainiface() { # A partir des valeurs des tableaux $1(=confbrs) et $2(=confips), et de # l'interface principale $3, déterminer l'interface principale. Si $3 est # spécifié, c'est la valeur sélectionnée. Sinon, si un bridge existe, c'est # le premier bridge qui est sélectionné. Sinon, la première interface est # sélectionnée. Sinon, on prend eth0. # Ensuite, réorganiser les tableaux de façon que confips[0] devienne la # configuration ip de l'interface principale. local -a __nfm_confbrs __nfm_confips __nfm_destconfips array_copy __nfm_confbrs "${1:-confbrs}" array_copy __nfm_confips "${2:-confips}" __network_fix_mainiface "$3" array_copy "${2:-confips}" __nfm_destconfips } function network_fix_confs() { network_fix_confbrs "${1:-confbrs}" network_fix_confips "${2:-confips}" network_fix_mainiface "${1:-confbrs}" "${2:-confips}" "$3" } function __network_valid_ifaces() { ip link | awk '/<.*>/ { flags = $0; sub(/^.*.*$/, ",", flags) if (flags ~ /,LOOPBACK,/) next if (flags !~ /,UP,/) next sub(/:$/, "", $2); print $2 }' } function __network_set_confbrs() { local -a ifaces tmpconfbrs confbrs local confbr br iface array_from_lines ifaces "$(__network_valid_ifaces)" array_from_lines tmpconfbrs "$(brctl show 2>/dev/null | awk ' BEGIN { confbrs = "" } NR == 1 { next } { if ($1 != "" && $2 != "") { if (confbr != "") print confbr confbr = $1 ":" $4 } else { confbr = confbr "," $1 } } END { if (confbr != "") print confbr } ')" for confbr in "${tmpconfbrs[@]}"; do splitpair "$confbr" br iface array_contains ifaces "$br" || continue array_add confbrs "$confbr" done array_copy __nsc_destconfbrs confbrs } function network_set_confbrs() { # initialiser $1(=confbrs) avec l'état des bridges sur le système courant local -a __nsc_destconfbrs __network_set_confbrs array_copy "${1:-confbrs}" __nsc_destconfbrs } function __network_set_gateway() { # initialiser la variable gateway avec la passerelle associée à l'interface # $1 gateway="$(ip route | awk -v iface="$1" '$1 == "default" { via = "" dev = "" for (i = 2; i <= NF; i++) { if ($i == "via") via = $(i+1) else if ($i == "dev") dev = $(i+1) if (via != "" && dev != "") break } if (dev == iface && via != "") { print via } }')" # le code précédent utilisait route, mais ce n'est pas toujours disponible #gateway="$(route -n | awk -v iface="$1" '$1 == "0.0.0.0" && $8 == iface { print $2 }')" } function __network_set_confip() { # initialiser la variable confip avec l'état de l'interface $1, en assumant # que la passerelle vaut $2. # retourner 1 si l'interface n'a pas d'adresse ip associée local -a ipsuffixes array_from_lines ipsuffixes "$(ip addr show dev "$1" | awk '$1 == "inet" { print $2 }')" confip="$(network_format_confip "$1" "$2" ipsuffixes)" [ "${#ipsuffixes[*]}" -gt 0 ] } function __network_set_confips() { local -a confips ifaces local iface gateway array_from_lines ifaces "$(__network_valid_ifaces)" for iface in "${ifaces[@]}"; do __network_set_gateway "$iface" [ -n "$gateway" ] || gateway=- __network_set_confip "$iface" "$gateway" || continue array_add confips "$confip" done array_copy __nsc_destconfips confips } function network_set_confips() { # initialiser le tableau $1(=confips) avec l'état des interfaces sur le # système courant local -a __nsc_destconfips __network_set_confips array_copy "${1:-confips}" __nsc_destconfips } function __network_backup() { local file="$1" local backup="$file.orig$(date +%Y%m%d)" [ -f "$backup" ] || cat "$file" >"$backup" 2>/dev/null } function network_fix_exim4() { local host="$1" oldhost="$2" local tmpfile; ac_set_tmpfile tmpfile local modified sed "$tmpfile" " /^dc_other_hostnames=/c\\ dc_other_hostnames='$host'" if [ -n "$__NETWORK_DEVEL_SHOW_MODIFS" ]; then if testdiff "$tmpfile" /etc/exim4/update-exim4.conf.conf; then uecho "Setting /etc/exim4/update-exim4.conf.conf to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else uecho "/etc/exim4/update-exim4.conf.conf: pas de modifications" fi elif testdiff "$tmpfile" /etc/exim4/update-exim4.conf.conf; then __network_backup /etc/exim4/update-exim4.conf.conf if show_debug; then edebug "Setting /etc/exim4/update-exim4.conf.conf to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else estep /etc/exim4/update-exim4.conf.conf fi cat "$tmpfile" >/etc/exim4/update-exim4.conf.conf update-exim4.conf modified=1 fi ac_clean "$tmpfile" [ -n "$modified" ] } function network_fix_postfix() { local host="$1" oldhost="$2" local tmpfile; ac_set_tmpfile tmpfile local modified awkrun "$tmpfile" host="$host" oldhost="$oldhost" ' /^myhostname *=/ { $0 = "myhostname = " host } /^mydestination *=/ { gsub(" *" oldhost " *,? *", "") if ($0 !~ (" *" host " *,? *")) { sub(/^mydestination *= */, "mydestination = " host ", ") } } { print }' if [ -n "$__NETWORK_DEVEL_SHOW_MODIFS" ]; then if testdiff "$tmpfile" /etc/postfix/main.cf; then uecho "Setting /etc/postfix/main.cf to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else uecho "/etc/postfix/main.cf: pas de modifications" fi elif testdiff "$tmpfile" /etc/postfix/main.cf; then __network_backup /etc/postfix/main.cf if show_debug; then edebug "Setting /etc/postfix/main.cf to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else estep /etc/postfix/main.cf fi cat "$tmpfile" >/etc/postfix/main.cf modified=1 fi ac_clean "$tmpfile" [ -n "$modified" ] } function network_fix_hosts() { local host="$1" hostname="${1%%.*}"; local shost="${host//./\\.}" local ip="$2"; local sip="${ip//./\\.}" local oldhost="$3" oldhostname="${3%%.*}"; soldhost="${host//./\\.}" local tmpfile; ac_set_tmpfile tmpfile local modified awkrun "$tmpfile" \ host="$host" hostname="$hostname" \ ip="$ip" \ oldhost="$oldhost" oldhostname="$oldhostname" \ ' /^[^# \t]/ { gsub("[ \\t]+" host "[ \\t]*", " ") gsub("[ \\t]+" hostname "[ \\t]*", " ") gsub("[ \\t]+" oldhost "[ \\t]*", " ") gsub("[ \\t]+" oldhostname "[ \\t]*", " ") if ($0 ~ /^[^ \t]+[ \t]*$/) next gsub(/[ \t]*$/, "") } { print }' if quietgrep "^$sip[ $TAB]\\+$shost[ $TAB]\\+$hostname" "$tmpfile"; then sed -i "\ s/\$/ / /^[ $TAB]$oldhost[ $TAB]/d /^[ $TAB]$oldhostname[ $TAB]/d s/ \$// " "$tmpfile" fi if ! quietgrep "^$sip[ $TAB]\\+$shost[ $TAB]\\+$hostname" "$tmpfile"; then sed -i "/^$sip[ $TAB]/d" "$tmpfile" sed -i "1i\\ $ip$TAB$host $hostname" "$tmpfile" fi if [ -n "$__NETWORK_DEVEL_SHOW_MODIFS" ]; then if testdiff "$tmpfile" /etc/hosts; then uecho "Setting /etc/hosts to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else uecho "/etc/hosts: pas de modifications" fi elif testdiff "$tmpfile" /etc/hosts; then __network_backup /etc/hosts if show_debug; then edebug "Setting /etc/hosts to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else estep /etc/hosts fi cat "$tmpfile" >/etc/hosts modified=1 fi ac_clean "$tmpfile" [ -n "$modified" ] }