setup-interfaces.in 12.2 KB
Newer Older
1 2 3 4 5
#!/bin/sh

PROGRAM=setup-interfaces
PREFIX=

6 7
PKGS=

8 9 10
for i in ./libalpine.sh $PREFIX/lib/libalpine.sh; do
	[ -e $i ] && . $i && break
done
11

12 13 14 15
unconfigured_add() {
	touch $1.noconf
}

16 17 18 19
unconfigured_detect() {
	local i=
	for i in ${INTERFACES:-$(available_ifaces)}; do
		if [ "$i" != "lo" ]; then
20
			unconfigured_add $i
21 22
		fi
	done
23 24
}

25
unconfigured_get_first() {
26 27 28
	ls *.noconf 2>/dev/null | head -n 1 | sed 's/.noconf//'
}

29
unconfigured_del() {
30
	rm -f $1.noconf
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
}

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 ]
}

54 55 56 57
iface_exists() {
	test -e /sys/class/net/$1
}

58 59 60 61
get_default_addr() {
	# check if dhcpcd is running
	if pidof dhcpcd > /dev/null && [ -f "$ROOT/var/lib/dhcpc/dhcpcd-$1.info" ]; then
		echo dhcp
62
	elif iface_exists $1; then
63
		ip addr show $1 | awk '/inet / {print $2}' | head -n 1 | sed 's:/.*::'
64
	fi
65 66 67 68 69 70 71 72 73 74 75
}

get_default_mask() {
	if [ "$1" ] ; then
		ipcalc -m $1 | sed 's/.*=//'
	else
		echo "255.255.255.0"
	fi
}

get_default_gateway() {
76 77 78
	if iface_exists $1; then
		ip route show dev $1 | awk '/^default/ {print $3}'
	fi
79 80
}

81
ipaddr_help() {
82
	cat <<-__EOF__
83

84
		Select the ip address for this interface.
85

86 87 88 89 90 91
		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
92

93
		You will be prompted for netmask if not specified with the address.
94

95
	__EOF__
96
}
97

98
bridge_add_port() {
99 100 101 102 103 104 105 106 107
	local bridge=$1 iface=
	shift
	for iface; do
		echo $iface >> $bridge.bridge_ports
		unconfigured_add $bridge
		unconfigured_del $iface
	done
}

108 109 110 111 112 113
bridge_list_ports() {
	if [ -r $1.bridge_ports ]; then
		echo $(cat $1.bridge_ports)
	fi
}

114 115 116 117
is_bridge() {
	test -r $1.bridge_ports
}

118 119 120 121 122 123 124 125
is_wifi() {
	test -d /sys/class/net/$1/phy80211
}

find_essids() {
	local iface=$1
	export essids_list=wlans
	# Supports only open or PSK
126
	ip link set dev "$iface" up
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
	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
}

175 176
config_iface() {
	local iface=$1
177
	local prefix=$2
178
	local default_address=$3
179
	local address= netmask= gateway= bridge_ports=
180
	local bridge
181
	local conf=$prefix$iface.conf
182
	local answer=
183

184
	while [ -n "$ask_bridge" ] && ! is_bridge $iface; do
185
		ask "Do you want to bridge the interface $iface?" yes
186 187
		case "$resp" in
			yes|y) resp=yes; break;;
188 189 190
			no|n) break;;
		esac
	done
191

192
	if [ "$resp" = "yes" ]; then
193
		bridge="br$(echo $iface | sed 's/[^0-9]//g')"
194
		ask "Name of the bridge you want add $iface to:" $bridge
195
		bridge_add_port $resp $iface
196
		return
197
	fi
198

199
	if [ -r "$iface.bridge_ports" ]; then
200
		bridge_ports=$(echo $(cat $iface.bridge_ports))
201 202
		echo "bridge_ports=\"$bridge_ports\"" >> $conf
	fi
203 204 205 206
	if [ -r "$iface.bond_slaves" ]; then
		bond_slaves=$(echo $(cat $iface.bond_slaves))
		echo "bond_slaves=\"$bond_slaves\"" >> $conf
	fi
207 208 209 210
	if [ -r "$iface.raw_device" ]; then
		raw_device=$(cat $iface.raw_device)
		echo "raw_device=\"$raw_device\"" >> $conf
	fi
211
	if is_wifi $iface; then
212
		apk add --quiet --no-progress wireless-tools wpa_supplicant || prompt_for_interfaces
213 214 215 216
		echo "Available wireless networks (scanning):"
		if find_essids $iface; then
			ask "Type the wireless network name to connect to:"
			local essid=$resp
217
			if wlan_is_not_open $iface "$essid"; then
218 219 220
				ask "Type the \"$essid\" network Pre-Shared Key:"
				psk=$resp
			fi
221
			config_wpa_supp $iface "$essid" "$psk"
222 223 224 225
		else
			echo -e "\nNo available wireless networks\n"
			prompt_for_interfaces
		fi
226
	fi
227 228 229 230
	# 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
231
		address=${default_address:-$(get_default_addr $iface)}
232
		[ -z "$address" ] && address="dhcp"
233
		ask "Ip address for $iface? (or 'dhcp', 'none', '?')" $address
234
		address=$resp
235 236 237 238
		case "$resp" in
		'?')	ipaddr_help;;
		"abort") return;;
		"dhcp")
239
			echo "type=dhcp" >> $conf
240
			unconfigured_del $iface
241
			return ;;
242 243 244 245
		"none")
			echo "type=manual" >> $conf
			unconfigured_del $iface
			return;;
246 247 248 249 250
		br[0-9]*|bridge[0-9]*)
			case "$iface" in
				# we dont allow bridge bridges
				br[0-9]*|bridge[0-9]*) continue;;
			esac
251
			bridge_add_port $resp $iface
252 253
			return ;;
		esac
254 255
	done

256 257 258 259 260 261 262 263
	# 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
264
		netmask=$(get_default_mask $address)
265 266
		ask "Netmask?" $netmask
		netmask=$resp
267 268 269
		[ "$netmask" = "abort" ] && return
	done

270 271 272
	# 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
273
		gateway=$(get_default_gateway $iface)
274
		[ -z "$gateway" ] && gateway=none
275 276
		ask "Gateway? (or 'none')" $gateway
		gateway=$resp
277 278 279 280
		[ "$gateway" = "abort" ] && return
		[ "$gateway" = "none" ] && gateway=""
		[ -z "$gateway" ] && break
	done
281

282
	echo "type=static" >> $conf
283 284 285
	if [ -n "$bridge_ports" ]; then
		echo "bridge_ports=$bridge_ports" >> $conf
	fi
286 287 288
	echo "address=${address%%/*}" >> $conf  #strip off /mask if there
	echo "netmask=$netmask" >> $conf
	echo "gateway=$gateway" >> $conf
289

290

291 292
	# print summary
	echo "Configuration for $iface:"
293
	sed 's/^/  /' $conf
294

295
	unconfigured_del $iface
296 297
}

298
is_bridge() {
299 300 301 302 303
	[ -e /sys/class/net/$1/bridge ] || [ -e $1.bridge_ports ]
}

is_bond_master() {
	[ -e $1.bond_slaves ]
304 305
}

306
unconfigured_available() {
307 308
	local local i= iflist=
	for i in $(unconfigured_list); do
309
		if ! is_bridge $i && ! is_bond_master $i; then
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
			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() {
325
	local bridge=$1 iflist= i= ports=
326
	while ! unconfigured_all_done; do
327
		set -- $(unconfigured_available)
328
		[ $# -eq 0 ] && return 0;
329 330 331 332
		ports=$(bridge_list_ports $bridge)
		if [ -n "$ports" ]; then
			echo "Bridge ports in $bridge are: $ports"
		fi
333 334
		echo "Available bridge ports are: $@"
		ask "Which port(s) do you want add to bridge $bridge? (or 'done')" $1
335 336 337 338
		case $resp in
			'abort') return 1;;
			'done') return 0;;
		esac
339 340 341 342 343 344 345
		for i in $resp; do
			if unconfigured_isin $i; then
				bridge_add_port $bridge $i
			else
				echo "$i is not valid"
			fi
		done
346 347 348
	done
}

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
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
}

390 391 392 393 394 395 396 397 398 399 400 401
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
402 403 404
	if unconfigured_isin $raw_device || is_bond_master $raw_device; then
		return 0
	fi
405 406 407 408
	echo "$raw_device is not a valid raw device for $iface"
	return 1
}

409
usage() {
410 411
	cat <<-__EOF__
		usage: setup-interfaces [-bhi]
412

413
		Setup network interfaces
414

415 416 417 418 419
		options:
		 -b  Ask for bridging of interfaces
		 -h  Show this help
		 -i  Read new contents of ${ROOT}etc/network/interfaces from stdin
	__EOF__
420
	exit 1
421
}
422

423
iface_help() {
424
	cat <<-__EOF__
425

426
		Select the interface you wish to configure.
427

428 429 430 431 432 433 434
		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
435

436 437
		You will be asked which physical interface(s) to
		be used for advanced configurations.
438

439
	__EOF__
440
}
441
prompt_for_interfaces() {
442
	init_tmpdir TMP
443

444
	cd $TMP
445
	unconfigured_detect
446

447
	index=1
448 449
	while ! unconfigured_all_done; do
		echo "Available interfaces are: $(unconfigured_list)."
450 451
		echo "Enter '?' for help on bridges, bonding and vlans."
		ask "Which one do you want to initialize? (or '?' or 'done')" \
452 453
			$(unconfigured_get_first)
		iface=$resp
454

455 456
		case "$iface" in
			"done") break;;
457
			'?') iface_help; continue;;
458 459
			br[0-9]*|bridge[0-9]*|virbr[0-9]*)
				config_bridge $iface || continue;;
460 461 462 463 464 465
			bond[0-9]*.[0-9]*)
				config_bond ${iface%.*} || continue
				config_iface ${iface%.*} $(printf "%.3d~" $index) none
				index=$(( $index + 1 ))
				config_vlan $iface || continue
				;;
466 467
			bond[0-9]*)
				config_bond $iface || continue;;
468 469
			*.[0-9]*|vlan[0-9]*)
				config_vlan $iface || continue;;
470 471
			*) unconfigured_isin $iface || continue;;
		esac
472 473 474
		config_iface $iface $(printf "%.3d~" $index)
		index=$(( $index + 1 ))
	done
475

476
	if [ "$(openrc --sys)" != "LXC" ] || ! ip addr show lo | grep -q 'inet.*127\.0'; then
477 478 479
		echo "type=loopback" > 000~lo.conf
		echo "" > interface
	fi
480
	hostname=$(cat $ROOT/etc/hostname 2>/dev/null)
481

482
	for i in *.conf ; do
483
		iface=$(basename $i .conf)
484
		iface=${iface#[0-9]*~}
485
		bridge_ports=
486
		bond_slaves=
487
		raw_device=
488 489 490
		address=
		type=
		gateway=
491
		. ./$i
492 493
		echo "auto $iface" >> interfaces
		echo "iface $iface inet $type" >> interfaces
494
		if [ -n "$bridge_ports" ]; then
495
			PKGS="$PKGS bridge"
496 497
			echo -e "\tbridge-ports $bridge_ports" >> interfaces
		fi
498
		if [ -n "$bond_slaves" ]; then
499
			PKGS="$PKGS bonding"
500 501
			echo -e "\tbond-slaves $bond_slaves" >> interfaces
		fi
502
		if [ -n "$raw_device" ]; then
503
			echo -e "\tvlan-raw-device $raw_device" >> interfaces
504 505 506 507
		fi
		case "$iface" in
			*.[0-9]*|vlan[0-9]*) PKGS="$PKGS vlan";;
		esac
508
		case $type in
509 510 511 512
		manual)
			echo -e "\tup ip link set \$IFACE up" >> interfaces
			echo -e "\tdown ip link set \$IFACE down" >> interfaces
			;;
513 514 515 516 517 518 519 520 521 522 523
		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
524
		echo "" >> interfaces
525
	done
526

527
	while [ "$answer" != "yes" ] && [ "$answer" != "no" ] ; do
528
		ask "Do you want to do any manual network configuration?" no
529 530 531 532 533
		case $resp in
			y) answer=yes;;
			n) answer=no;;
			*) answer=$resp;;
		esac
534
	done
535

536
	if yesno "$answer"; then
537
		case "$EDITOR" in
538 539
			nano)	apk add nano;;
			vim)	apk add vim;;
540 541 542
		esac
		${EDITOR:-vi} interfaces
	fi
543 544

	if [ -n "$PKGS" ]; then
545
		apk add --quiet $PKGS
546 547
	fi

548 549
	mkdir -p $ROOT/etc/network
	cp interfaces $ROOT/etc/network/
550 551
}

552 553 554
ask_bridge=
is_xen_dom0 && ask_bridge=1

555
while getopts "bhip:" opt; do
556
	case $opt in
557
		b) ask_bridge=1;;
558
		h) usage;;
559
		i) STDINPUT=1;;
560
		p) ROOT=$OPTARG;;
561
	esac
562 563
done

564
mkdir -p $ROOT/etc/network
565 566 567 568
if [ "$STDINPUT" = "1" ]; then
	cat > $ROOT/etc/network/interfaces
else
	prompt_for_interfaces
569
fi