#!/bin/sh PROGRAM=setup-interfaces PREFIX= : ${LIBDIR=$PREFIX/lib} . "$LIBDIR/libalpine.sh" PKGS= unconfigured_add() { touch $1.noconf } unconfigured_detect() { local i= for i in ${INTERFACES:-$(available_ifaces)}; do if [ "$i" != "lo" ]; then unconfigured_add $i fi done } unconfigured_get_first() { ls *.noconf 2>/dev/null | head -n 1 | sed 's/.noconf//' } unconfigured_del() { rm -f $1.noconf } unconfigured_all_done() { local i= for i in *.noconf; do [ -e $i ] && return 1 done return 0 } unconfigured_list() { local list= i= for i in *.noconf; do [ -e "$i" ] || continue list="${list} ${i%.noconf}" done echo $list } unconfigured_isin() { [ -f $1.noconf ] } iface_exists() { test -e "$ROOT"/sys/class/net/$1 } get_default_addr() { # check if dhcpcd is running if pidof dhcpcd > /dev/null && [ -f "$ROOT/var/lib/dhcpc/dhcpcd-$1.info" ]; then echo dhcp elif iface_exists $1; then $MOCK ip addr show $1 | awk '/inet / {print $2}' | head -n 1 | sed 's:/.*::' fi } get_default_mask() { if [ "$1" ] ; then ipcalc -m $1 | sed 's/.*=//' else echo "255.255.255.0" fi } get_default_gateway() { if iface_exists $1; then $MOCK ip route show dev $1 | awk '/^default/ {print $3}' fi } ipaddr_help() { cat <<-__EOF__ Select the ip address for this interface. dhcp Dynamic/automatic ip via DHCP none Do not add any address n.n.n.n (ex: 192.168.0.1) Static ip n.n.n.n/m (ex: 192.168.0.1/24) Static ip with mask br[0-9]+ (ex: br0) Add this interface to a bridge bridge[0-9] (ex: bridge0) Add this interface to a bridge You will be prompted for netmask if not specified with the address. __EOF__ } bridge_add_port() { local bridge="$1" iface= shift for iface; do echo $iface >> $bridge.bridge_ports unconfigured_add $bridge unconfigured_del $iface done } bridge_list_ports() { if [ -r $1.bridge_ports ]; then echo $(cat $1.bridge_ports) fi } is_bridge() { test -r $1.bridge_ports } is_wifi() { test -d "$ROOT"/sys/class/net/$1/phy80211 } find_essids() { local iface="$1" export essids_list=wlans # Supports only open or PSK $MOCK ip link set dev "$iface" up (iw dev wlan0 scan; echo BSS) | awk -F": " ' /^BSS/ { if (ssid) { print ssid "/" auth }; ssid=""; auth="" } $1 ~ /^[[:blank:]]*SSID$/ { ssid=$2 } $1 ~ /Authentication suites/ { auth=$2 }' \ | grep -E -v '(802.1x|\\x00)' | sort -u >"$essids_list" if [ -s "$essids_list" ]; then # we use / as separator since it is an illegal char in ssids awk -F/ '{print $1}' "$essids_list" else return 1 fi } config_wpa_supp() { local iface="$1" essid="$2" auth_type="$3" psk="$4" local conffile="$ROOT"/etc/wpa_supplicant/wpa_supplicant.conf mkdir -p "${conffile%/*}" if [ "$auth_type" = "WPA-PSK" ]; then (umask 0077 && wpa_passphrase "$essid" "$psk" | sed -e '/^\t#psk=.*/d' >> "$conffile") else cat << EOF >> $conffile network={ ssid="$essid" key_mgmt=$auth_type } EOF fi mkdir -p "$ROOT/etc/conf.d" if grep -q ^wpa_supplicant_args= "$ROOT"/etc/conf.d/wpa_supplicant 2>/dev/null; then sed -i -e "s/^wpa_supplicant_args=.*/wpa_supplicant_args=\"-i $iface\"/" /etc/conf.d/wpa_supplicant else printf 'wpa_supplicant_args="-i%s"\n' "$iface" >> "$ROOT"/etc/conf.d/wpa_supplicant fi rc-update --quiet add wpa_supplicant boot rc-service wpa_supplicant start } essid_is_valid() { [ -n "$1" ] && cut -d/ -f1 "$essids_list" | grep -q -w -F "$1" } wlan_is_psk() { local essid="$1" awk -F/ -v essid="$essid" '$1==essid {print $2}' "$essids_list" | grep -q -F -w 'PSK' } config_iface() { local iface="$1" local prefix="$2" local default_address="$3" local address= netmask= gateway= bridge_ports= local bridge local conf="$prefix$iface.conf" if [ -n "$ask_bridge" ] && ! is_bridge $iface \ && ask_yesno "Do you want to bridge the interface $iface? (y/n)" y; then bridge="br$(echo $iface | sed 's/[^0-9]//g')" ask "Name of the bridge you want add $iface to:" $bridge bridge_add_port $resp $iface return fi if [ -r "$iface.bridge_ports" ]; then bridge_ports=$(echo $(cat $iface.bridge_ports)) echo "bridge_ports=\"$bridge_ports\"" >> $conf fi if [ -r "$iface.bond_slaves" ]; then bond_slaves=$(echo $(cat $iface.bond_slaves)) echo "bond_slaves=\"$bond_slaves\"" >> $conf fi if [ -r "$iface.raw_device" ]; then raw_device=$(cat $iface.raw_device) echo "raw_device=\"$raw_device\"" >> $conf fi if is_wifi $iface; then apk add --quiet --no-progress iw wpa_supplicant || return local wifi_configured=false while ! $wifi_configured; do echo "Available wireless networks (scanning):" if ! find_essids $iface; then printf "\nNo available wireless networks\n" return fi local essid= auth_type="NONE" ask "Type the wireless network name to connect to:" if ! essid_is_valid "$resp"; then case "$resp" in ""|done|abort) echo "Aborting $iface setup"; return;; esac echo "Invalid SSID: $resp" continue fi essid="$resp" if wlan_is_psk "$essid"; then auth_type="WPA-PSK" askpass "Type the \"$essid\" network Pre-Shared Key (will not echo):" psk="$resp" fi config_wpa_supp "$iface" "$essid" "$auth_type" "$psk" && wifi_configured=true done fi # use ipcalc to validate the address. we do accept /mask # we are no interested in the result, only error code, so # we send result to /dev/null while ! ipcalc -s -m $address >/dev/null 2>&1; do address=${default_address:-$(get_default_addr $iface)} [ -z "$address" ] && address="dhcp" ask "Ip address for $iface? (or 'dhcp', 'none', '?')" $address address=$resp case "$resp" in '?') ipaddr_help;; "abort") return;; "dhcp") echo "type=dhcp" >> $conf unconfigured_del $iface return ;; "none") echo "type=manual" >> $conf unconfigured_del $iface return;; br[0-9]*|bridge[0-9]*) case "$iface" in # we dont allow bridge bridges br[0-9]*|bridge[0-9]*) continue;; esac bridge_add_port $resp $iface return ;; esac done # extract netmask if entered together with address if [ "$address" != "${address%%/*}" ]; then netmask=$(ipcalc -s -m $address | cut -d= -f2) fi # use ipcalc -m to validate netmask. we dont accept /mask suffix # so we pass on a dummy mask to ipcalc. while ! ipcalc -s -m $netmask/0 >/dev/null 2>&1; do netmask=$(get_default_mask $address) ask "Netmask?" $netmask netmask=$resp [ "$netmask" = "abort" ] && return done # use ipcalc -m to validate netmask. we dont accept /mask suffix # so we pass on a dummy mask to ipcalc. while ! ipcalc -s -m $gateway/0 >/dev/null 2>&1; do gateway=$(get_default_gateway $iface) [ -z "$gateway" ] && gateway=none ask "Gateway? (or 'none')" $gateway gateway=$resp [ "$gateway" = "abort" ] && return [ "$gateway" = "none" ] && gateway="" [ -z "$gateway" ] && break done echo "type=static" >> $conf if [ -n "$bridge_ports" ]; then echo "bridge_ports=$bridge_ports" >> $conf fi echo "address=${address%%/*}" >> $conf #strip off /mask if there echo "netmask=$netmask" >> $conf echo "gateway=$gateway" >> $conf # print summary echo "Configuration for $iface:" sed 's/^/ /' $conf unconfigured_del $iface } is_bridge() { [ -e "$ROOT"/sys/class/net/$1/bridge ] || [ -e $1.bridge_ports ] } is_bond_master() { [ -e $1.bond_slaves ] } unconfigured_available() { local local i= iflist= for i in $(unconfigured_list); do if ! is_bridge $i && ! is_bond_master $i; then iflist="${iflist}${iflist:+ }$i" fi done echo $iflist } unconfigured_all_are() { local i= for i; do unconfigured_isin $i || return 1 done return 0 } config_bridge() { local bridge="$1" iflist= i= ports= while ! unconfigured_all_done; do set -- $(unconfigured_available) [ $# -eq 0 ] && return 0; ports=$(bridge_list_ports $bridge) if [ -n "$ports" ]; then echo "Bridge ports in $bridge are: $ports" fi echo "Available bridge ports are: $@" ask "Which port(s) do you want add to bridge $bridge? (or 'done')" $1 case $resp in 'abort') return 1;; 'done') return 0;; esac for i in $resp; do if unconfigured_isin $i; then bridge_add_port $bridge $i else echo "$i is not valid" fi done done } bond_add_slave() { local master="$1" slave= shift for slave; do echo $slave >> $master.bond_slaves unconfigured_add $master unconfigured_del $slave done } bond_list_slaves() { if [ -r $1.bond_slaves ]; then echo $(cat $1.bond_slaves) fi } config_bond() { local master="$1" slaves= while ! unconfigured_all_done; do set -- $(unconfigured_available) [ $# -eq 0 ] && return 0; slaves=$(bond_list_slaves $master) if [ -n "$slaves" ]; then echo "Bond slaves in $master are: $slaves" fi echo "Available bond slaves are: $@" ask "Which slave(s) do you want add to $master? (or 'done')" $1 case $resp in 'abort') return 1;; 'done') return 0;; esac for i in $resp; do if unconfigured_isin $i; then bond_add_slave $master $i else echo "$i is not valid" fi done done } config_vlan() { local iface="$1" vid= raw_device= case $iface in *.*) raw_device=${iface%.*} vid=${iface#*.} ;; vlan*) vid=${iface#vlan} ask_which "raw device" "do you want use for $iface" "$(unconfigured_list)" echo "$resp" > $iface.raw_device return 0 ;; esac if unconfigured_isin $raw_device || is_bond_master $raw_device; then return 0 fi echo "$raw_device is not a valid raw device for $iface" return 1 } usage() { cat <<-__EOF__ usage: setup-interfaces [-abhir] [-p ROOT] Setup network interfaces options: -a Automatic interface setup using DHCP -b Ask for bridging of interfaces -h Show this help -i Read new contents of ${ROOT}etc/network/interfaces from stdin -p Set the system root to operate in -r Restart the networking service after the setup __EOF__ exit $1 } iface_help() { cat <<-__EOF__ Select the interface you wish to configure. For advanced configurations, you can also enter: br[0-9]+ (ex: br0) bridge interface bridge[0-9]+ (ex: bridge0) bridge interface bond[0-9]+ (ex: bond32) bonded interface vlan[0-9]+ (ex: vlan371) vlan interface eth?.[0-9]+ (ex: eth0.371) vlan interface bond?.[0.9]+ (ex: bond0.371) vlan interface You will be asked which physical interface(s) to be used for advanced configurations. Select 'none' to leave configuration unmodified. __EOF__ } prompt_for_interfaces() { init_tmpdir TMP cd $TMP unconfigured_detect index=1 while ! unconfigured_all_done; do echo "Available interfaces are: $(unconfigured_list)." echo "Enter '?' for help on bridges, bonding and vlans." ask "Which one do you want to initialize? (or '?' or 'done')" \ $(unconfigured_get_first) iface=$resp case "$iface" in "none") exit;; "done") break;; '?') iface_help; continue;; br[0-9]*|bridge[0-9]*|virbr[0-9]*) config_bridge $iface || continue;; bond[0-9]*.[0-9]*) config_bond ${iface%.*} || continue config_iface ${iface%.*} $(printf "%.3d~" $index) none index=$(( $index + 1 )) config_vlan $iface || continue ;; bond[0-9]*) config_bond $iface || continue;; *.[0-9]*|vlan[0-9]*) config_vlan $iface || continue;; *) unconfigured_isin $iface || continue;; esac config_iface $iface $(printf "%.3d~" $index) index=$(( $index + 1 )) done if [ "$(openrc --sys)" != "LXC" ] || ! ip addr show lo | grep -q 'inet.*127\.0'; then echo "type=loopback" > 000~lo.conf echo "" > interface fi for i in *.conf ; do iface=$(basename $i .conf) iface=${iface#[0-9]*~} bridge_ports= bond_slaves= raw_device= address= type= gateway= . ./$i echo "auto $iface" >> interfaces echo "iface $iface inet $type" >> interfaces if [ -n "$bridge_ports" ]; then PKGS="$PKGS bridge" printf "\tbridge-ports %s\n" "$bridge_ports" >> interfaces fi if [ -n "$bond_slaves" ]; then PKGS="$PKGS bonding" printf "\tbond-slaves %s\n" "$bond_slaves" >> interfaces fi if [ -n "$raw_device" ]; then printf "\tvlan-raw-device %s\n" "$raw_device" >> interfaces fi case "$iface" in *.[0-9]*|vlan[0-9]*) if ! [ -f "$ROOT"usr/libexec/ifupdown-ng/link ]; then PKGS="$PKGS vlan" fi ;; esac case $type in manual) printf "\tup ip link set \$IFACE up\n" >> interfaces printf "\tdown ip link set \$IFACE down\n" >> interfaces ;; static) printf "\taddress %s\n" "$address" >> interfaces printf "\tnetmask %s\n" "$netmask" >> interfaces [ "$gateway" ] \ && printf "\tgateway %s\n" "$gateway" >> interfaces ;; esac echo "" >> interfaces done if ask_yesno "Do you want to do any manual network configuration? (y/n)" n; then case "$EDITOR" in nano) apk add nano;; vim) apk add vim;; esac ${EDITOR:-vi} interfaces fi if [ -n "$PKGS" ]; then apk add --quiet $PKGS fi mkdir -p $ROOT/etc/network cp interfaces $ROOT/etc/network/ } auto_setup() { local iface for iface in $(available_ifaces); do if [ "$(cat "$ROOT"/sys/class/net/$iface/operstate 2>/dev/null)" = "up" ]; then break fi done [ -z "$iface" ] && return 0 cat >$ROOT/etc/network/interfaces <<-EOF auto lo iface lo inet loopback auto $iface iface $iface inet dhcp EOF } ask_bridge= is_xen_dom0 && ask_bridge=1 while getopts "abhip:r" opt; do case $opt in a) auto=1;; b) ask_bridge=1;; h) usage 0;; i) STDINPUT=1;; p) ROOT=$OPTARG;; r) restart=1;; '?') usage "1" >&2;; esac done if [ "$1" = none ]; then exit fi mkdir -p $ROOT/etc/network if [ "$STDINPUT" = "1" ]; then cat > $ROOT/etc/network/interfaces elif [ -n "$auto" ]; then auto_setup else prompt_for_interfaces fi if [ -n "$restart" ]; then rc-service networking --quiet restart >/dev/null fi