Files
edge/sbin/setup-interfaces
2018-11-06 00:13:24 +00:00

594 lines
13 KiB
Bash
Executable File

#!/bin/sh
PROGRAM=setup-interfaces
PREFIX=
PKGS=
for i in ./libalpine.sh $PREFIX/lib/libalpine.sh; do
[ -e $i ] && . $i && break
done
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 /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
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
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 /sys/class/net/$1/phy80211
}
find_essids() {
local iface=$1
export essids_list=wlans
# Supports only open or PSK
ip link set dev "$iface" up
iwlist $iface scanning | awk -F: '/ESSID/ { printf "%s ",$2 } /Authentication Suites/ \
{ printf ":%s\n",$2 }' | grep -v 802.1x | sort -u >$essids_list
if [ -s $essids_list ]; then
cat $essids_list
else
return 1
fi
}
config_wpa_supp() {
local iface=$1
local essid=$2
local psk=$3
local conffile=/etc/wpa_supplicant/wpa_supplicant.conf
if [ "$auth_type" == "WPA-PSK" ]; then
cat << EOF >> $conffile
network={
ssid="$essid"
key_mgmt=$auth_type
psk="$psk"
}
EOF
else
cat << EOF >> $conffile
network={
ssid="$essid"
key_mgmt=$auth_type
}
EOF
fi
wpa_supplicant -B -c $conffile -i $iface 2>/dev/null
}
wlan_is_not_open() {
local iface=$1
local essid=$2
auth_type=$(awk -F: '/'"$essid"'/ { print $2 }' $essids_list)
echo $auth_type | grep -q PSK
if [ "$?" -eq "0" ]; then
export auth_type="WPA-PSK"
return 0
else
export auth_type="open"
return 1
fi
}
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
local answer=
while [ -n "$ask_bridge" ] && ! is_bridge $iface; do
ask "Do you want to bridge the interface $iface?" yes
case "$resp" in
yes|y) resp=yes; break;;
no|n) break;;
esac
done
if [ "$resp" = "yes" ]; 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 wireless-tools wpa_supplicant || prompt_for_interfaces
echo "Available wireless networks (scanning):"
if find_essids $iface; then
ask "Type the wireless network name to connect to:"
local essid=$resp
if wlan_is_not_open $iface "$essid"; then
ask "Type the \"$essid\" network Pre-Shared Key:"
psk=$resp
fi
config_wpa_supp $iface "$essid" "$psk"
else
echo -e "\nNo available wireless networks\n"
prompt_for_interfaces
fi
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 /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 [-bhi]
Setup network interfaces
options:
-b Ask for bridging of interfaces
-h Show this help
-i Read new contents of ${ROOT}etc/network/interfaces from stdin
__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.
__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
"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
hostname=$(cat $ROOT/etc/hostname 2>/dev/null)
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"
echo -e "\tbridge-ports $bridge_ports" >> interfaces
fi
if [ -n "$bond_slaves" ]; then
PKGS="$PKGS bonding"
echo -e "\tbond-slaves $bond_slaves" >> interfaces
fi
if [ -n "$raw_device" ]; then
echo -e "\tvlan-raw-device $raw_device" >> interfaces
fi
case "$iface" in
*.[0-9]*|vlan[0-9]*) PKGS="$PKGS vlan";;
esac
case $type in
manual)
echo -e "\tup ip link set \$IFACE up" >> interfaces
echo -e "\tdown ip link set \$IFACE down" >> interfaces
;;
dhcp)
[ -n "$hostname" ] \
&& echo -e "\thostname $hostname" >> interfaces
;;
static)
echo -e "\taddress $address" >> interfaces
echo -e "\tnetmask $netmask" >> interfaces
[ "$gateway" ] \
&& echo -e "\tgateway $gateway" >> interfaces
;;
esac
echo "" >> interfaces
done
while [ "$answer" != "yes" ] && [ "$answer" != "no" ] ; do
ask "Do you want to do any manual network configuration?" no
case $resp in
y) answer=yes;;
n) answer=no;;
*) answer=$resp;;
esac
done
if yesno "$answer"; 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
local hostname=$(cat $ROOT/etc/hostname 2>/dev/null)
for iface in $(available_ifaces); do
if [ "$(cat /sys/class/net/$iface/operstate)" = "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
if [ -n "$hostname" ]; then
echo -e "\thostname $hostname" >> $ROOT/etc/network/interfaces
fi
}
ask_bridge=
is_xen_dom0 && ask_bridge=1
while getopts "abhip:" opt; do
case $opt in
a) auto=1;;
b) ask_bridge=1;;
h) usage;;
i) STDINPUT=1;;
p) ROOT=$OPTARG;;
esac
done
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