File: /var/chroot/sbin/setup-interfaces
#!/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
case "$i" in
lo|docker0) continue;;
esac
unconfigured_add "$i"
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 "$iface" 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 NR ") " $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"
}
is_number() {
echo "$1" | grep -q -E '^[0-9]+$'
}
essid_by_index() {
if is_number "$1"; then
cut -d/ -f1 "$essids_list" | sed "$1!d"
fi
}
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
local by_index="$(essid_by_index "$resp")"
if essid_is_valid "$by_index"; then
resp="$by_index"
else
echo "Invalid SSID: $resp"
continue
fi
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 <addr>/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 <addr>/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/
}
find_first_iface_up() {
local n=0
[ $# -eq 0 ] && return
while [ $n -le ${SETUP_INTERFACES_LINK_WAIT_MAX:-11} ]; do
for i in "$@"; do
if [ "$(cat "$ROOT/sys/class/net/$i/operstate" 2>/dev/null)" = "up" ]; then
echo "$i"
return
fi
done
sleep 0.1
n=$((n+1))
done
}
auto_setup() {
local iface
set -- $(available_ifaces)
if [ $# -eq 0 ]; then
return
fi
for iface in "$@"; do
$MOCK ip link set dev "$iface" up
done
iface="$(find_first_iface_up "$@")"
if [ -z "$iface" ]; then
iface="$1"
fi
# we will likely use the found interface later so lets keep it up
for i in "$@"; do
if [ "$i" != "$iface" ]; then
$MOCK ip link set dev "$i" down
fi
done
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