xref: /openbsd/etc/netstart (revision 4f9a4669)
1df930be7Sderaadt#!/bin/sh -
2df930be7Sderaadt#
3*4f9a4669Sderaadt#	$OpenBSD: netstart,v 1.208 2020/11/29 20:14:06 deraadt Exp $
45116749bSrpe
55116749bSrpe# Turn off Strict Bourne shell mode.
65116749bSrpeset +o sh
78fc5e153Smillert
82511c2f6Srpe# Show usage of the netstart script and exit.
92511c2f6Srpeusage() {
102511c2f6Srpe	print -u2 "usage: ${0##*/} [[-n] interface ...]"
112511c2f6Srpe	exit 1
122511c2f6Srpe}
132511c2f6Srpe
149ed80bb0Skn# Echo file $1 to stdout. Skip comment lines. Strip leading and trailing
15952fbff6Srpe# whitespace if IFS is set.
16e57a083bSrpe# Usage: stripcom /path/to/file
178fc5e153Smillertstripcom() {
18e57a083bSrpe	local _file=$1 _line
19e57a083bSrpe
20e57a083bSrpe	[[ -f $_file ]] || return
21e57a083bSrpe
22e57a083bSrpe	while read _line; do
23e57a083bSrpe		[[ -n ${_line%%#*} ]] && print -r -- "$_line"
24e57a083bSrpe	done <$_file
258fc5e153Smillert}
2604e0ac27Smillert
278222f376Srpe# Parse and "unpack" a hostname.if(5) line given as positional parameters.
288222f376Srpe# Fill the _cmds array with the resulting interface configuration commands.
298222f376Srpeparse_hn_line() {
308222f376Srpe	local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr
318222f376Srpe	set -A _c -- "$@"
328222f376Srpe	set -o noglob
338222f376Srpe
348222f376Srpe	case ${_c[_af]} in
358222f376Srpe	''|*([[:blank:]])'#'*)
368222f376Srpe		return
378222f376Srpe		;;
388222f376Srpe	inet)	((${#_c[*]} > 1)) || return
398222f376Srpe		[[ ${_c[_name]} == alias ]] && _mask=3 _bc=4
408222f376Srpe		[[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}"
418222f376Srpe		if [[ -n ${_c[_bc]} ]]; then
428222f376Srpe			_c[_bc]="broadcast ${_c[_bc]}"
438222f376Srpe			[[ ${_c[_bc]} == *NONE ]] && _c[_bc]=
448222f376Srpe		fi
458222f376Srpe		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
468222f376Srpe		;;
478222f376Srpe	inet6)	((${#_c[*]} > 1)) || return
488222f376Srpe		if [[ ${_c[_name]} == autoconf ]]; then
498222f376Srpe			_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
500113d951Srpe			V6_AUTOCONF=true
518222f376Srpe			return
528222f376Srpe		fi
538222f376Srpe		[[ ${_c[_name]} == alias ]] && _prefix=3
548222f376Srpe		[[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}"
558222f376Srpe		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
568222f376Srpe		;;
578222f376Srpe	dest)	((${#_c[*]} == 2)) && _daddr=${_c[1]} || return
588222f376Srpe		_prev=$((${#_cmds[*]} - 1))
598222f376Srpe		((_prev >= 0)) || return
608222f376Srpe		set -A _c -- ${_cmds[_prev]}
618222f376Srpe		_name=3
628222f376Srpe		[[ ${_c[_name]} == alias ]] && _name=4
638222f376Srpe		_c[_name]="${_c[_name]} $_daddr"
648222f376Srpe		_cmds[$_prev]="${_c[@]}"
658222f376Srpe		;;
668222f376Srpe	dhcp)	_c[0]=
678c1551d3Skrw		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]} up;dhclient $_if"
680113d951Srpe		V4_DHCPCONF=true
698222f376Srpe		;;
708222f376Srpe	'!'*)	_cmd=$(print -- "${_c[@]}" | sed 's/\$if/'$_if'/g')
718222f376Srpe		_cmds[${#_cmds[*]}]="${_cmd#!}"
728222f376Srpe		;;
738222f376Srpe	*)	_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
748222f376Srpe		;;
758222f376Srpe	esac
768222f376Srpe	unset _c
7779699d09Srpe	set +o noglob
788222f376Srpe}
798222f376Srpe
80d7d55851Srpe# Create interface $1 if it does not yet exist.
8180771ddaSrpe# Usage: ifcreate if1
82b6107460Sdlgifcreate() {
83b6107460Sdlg	local _if=$1
84b6107460Sdlg
85d7d55851Srpe	{ ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1
86b6107460Sdlg}
87b6107460Sdlg
88d7d55851Srpe# Create interfaces for network pseudo-devices referred to by hostname.if files.
8980771ddaSrpe# Usage: vifscreate
90b6107460Sdlgvifscreate() {
91d7d55851Srpe	local _vif _hn _if
92b6107460Sdlg
93d7d55851Srpe	for _vif in $(ifconfig -C); do
94375c217eSrpe		for _hn in /etc/hostname.${_vif}+([[:digit:]]); do
95b6107460Sdlg			[[ -f $_hn ]] || continue
96b6107460Sdlg			_if=${_hn#/etc/hostname.}
97b6107460Sdlg
98375c217eSrpe			if ! ifcreate $_if; then
997f358361Srpe				print -u2 "${0##*/}: create for '$_if' failed."
100375c217eSrpe			fi
101b6107460Sdlg		done
102b6107460Sdlg	done
103b6107460Sdlg}
104b6107460Sdlg
105e57a083bSrpe# Start a single interface.
106e57a083bSrpe# Usage: ifstart if1
107dfc209d0Smiodifstart() {
10878b420f3Stb	local _if=$1 _hn=/etc/hostname.$1 _cmds _i=0 _line _stat
1098222f376Srpe	set -A _cmds
11024811c97Srpe
111dfc209d0Smiod	# Interface names must be alphanumeric only.  We check to avoid
112dfc209d0Smiod	# configuring backup or temp files, and to catch the "*" case.
1138222f376Srpe	[[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return
114dfc209d0Smiod
115b7a96a2bSrpe	if [[ ! -f $_hn ]]; then
1167f358361Srpe		print -u2 "${0##*/}: $_hn: No such file or directory."
11749352c7bStodd		return
11849352c7bStodd	fi
1198222f376Srpe
120300d0407Srpe	# Not using stat(1), we can't rely on having /usr yet.
121b7a96a2bSrpe	set -A _stat -- $(ls -nL $_hn)
1221a0aef30Srpe	if [[ "${_stat[0]}${_stat[2]}${_stat[3]}" != *---00 ]]; then
1237f358361Srpe		print -u2 "WARNING: $_hn is insecure, fixing permissions."
124b7a96a2bSrpe		chmod -LR o-rwx $_hn
125b7a96a2bSrpe		chown -LR root:wheel $_hn
126bc53e65aSderaadt	fi
127dfc209d0Smiod
1288222f376Srpe	# Check for ifconfig'able interface, except if -n option is specified.
1298222f376Srpe	if ! $PRINT_ONLY; then
130b6107460Sdlg		ifcreate $_if || return
1312817040cStodd	fi
1328222f376Srpe
1338222f376Srpe	# Parse the hostname.if(5) file and fill _cmds array with interface
1348222f376Srpe	# configuration commands.
1358222f376Srpe	set -o noglob
13688c728ccSkn	while IFS= read -- _line; do
1378222f376Srpe		parse_hn_line $_line
138b7a96a2bSrpe	done <$_hn
1398222f376Srpe
1408222f376Srpe	# Apply the interface configuration commands stored in _cmds array.
1418222f376Srpe	while ((_i < ${#_cmds[*]})); do
1428222f376Srpe		if $PRINT_ONLY; then
1438222f376Srpe			print -r -- "${_cmds[_i]}"
1448222f376Srpe		else
1458222f376Srpe			eval "${_cmds[_i]}"
1468222f376Srpe		fi
1478222f376Srpe		((_i++))
1488222f376Srpe	done
1498222f376Srpe	unset _cmds
15079699d09Srpe	set +o noglob
151dfc209d0Smiod}
152dfc209d0Smiod
153dde523b1Srpe# Start multiple interfaces by driver name.
154dde523b1Srpe# Usage: ifmstart "em iwm" "trunk vlan"
155300d0407Srpe#   Start "$1" interfaces in order or all interfaces if empty.
156dde523b1Srpe#   Don't start "$2" interfaces. "$2" is optional.
1579ac6b043Stoddifmstart() {
158dde523b1Srpe	local _sifs=$1 _xifs=$2 _hn _if _sif _xif
159dde523b1Srpe
160dde523b1Srpe	for _sif in ${_sifs:-ALL}; do
161375c217eSrpe		for _hn in /etc/hostname.+([[:alpha:]])+([[:digit:]]); do
162375c217eSrpe			[[ -f $_hn ]] || continue
163dde523b1Srpe			_if=${_hn#/etc/hostname.}
1649ac6b043Stodd
165300d0407Srpe			# Skip unwanted ifs.
166dde523b1Srpe			for _xif in $_xifs; do
167dde523b1Srpe				[[ $_xif == ${_if%%[0-9]*} ]] && continue 2
1689ac6b043Stodd			done
1699ac6b043Stodd
170300d0407Srpe			# Start wanted ifs.
171dde523b1Srpe			[[ $_sif == @(ALL|${_if%%[0-9]*}) ]] && ifstart $_if
1729ac6b043Stodd		done
1739ac6b043Stodd	done
1749ac6b043Stodd}
1759ac6b043Stodd
17680771ddaSrpe# Parse /etc/mygate and add default routes for IPv4 and IPv6.
17705102370Smpi# Usage: defaultroute
17805102370Smpidefaultroute() {
179e9c30f15Stb	local _cmd;
180*4f9a4669Sderaadt	set -o noglob
181e9c30f15Stb
182*4f9a4669Sderaadt	stripcom /etc/mygate |
1830113d951Srpe	while read gw; do
184*4f9a4669Sderaadt		case $gw in
185*4f9a4669Sderaadt		'!'*)
186*4f9a4669Sderaadt			_cmd=$(print -- "$gw" | sed 's/\$if/'$_if'/g')
187*4f9a4669Sderaadt			_cmd="${_cmd#!}"
188*4f9a4669Sderaadt			;;
189*4f9a4669Sderaadt		*)
190*4f9a4669Sderaadt			if [[ $gw != @(*:*) ]]; then
191*4f9a4669Sderaadt				$V4_DHCPCONF && continue
192e9c30f15Stb				_cmd="route -qn add -host default $gw"
193*4f9a4669Sderaadt			elif [[ $gw == @(*:*) ]]; then
194*4f9a4669Sderaadt				$V6_AUTOCONF && continue
195e9c30f15Stb				_cmd="route -qn add -host -inet6 default $gw"
196*4f9a4669Sderaadt			fi
197*4f9a4669Sderaadt			;;
198*4f9a4669Sderaadt		esac
199e9c30f15Stb		if $PRINT_ONLY; then
200*4f9a4669Sderaadt			print -r -- "$_cmd"
201e9c30f15Stb		else
202*4f9a4669Sderaadt			$_cmd
203e9c30f15Stb		fi
20405102370Smpi	done
205*4f9a4669Sderaadt	set +o noglob
20605102370Smpi}
20705102370Smpi
20889f9479fStb# Make sure the invoking user has the right privileges.  Check for presence of
20989f9479fStb# id(1) to avoid problems with diskless setups.
21089f9479fStbif [[ -x /usr/bin/id ]] && (($(id -u) != 0)); then
21189f9479fStb	echo "${0##*/}: need root privileges"
21289f9479fStb	exit 1
21389f9479fStbfi
21489f9479fStb
215a035c1adSrpe# Get network related vars from rc.conf using the parsing routine from rc.subr.
216a035c1adSrpeFUNCS_ONLY=1 . /etc/rc.d/rc.subr
2178799e9c8Srobert_rc_parse_conf
2180dc37902Sangelos
2198222f376SrpePRINT_ONLY=false
2200113d951SrpeV4_DHCPCONF=false
2210113d951SrpeV6_AUTOCONF=false
2220113d951Srpe
2238222f376Srpewhile getopts ":n" opt; do
2248222f376Srpe	case $opt in
2258222f376Srpe	n)	PRINT_ONLY=true;;
2262511c2f6Srpe	*)	usage;;
2278222f376Srpe	esac
2288222f376Srpedone
2298222f376Srpeshift $((OPTIND-1))
2308222f376Srpe
2318222f376Srpe# Option -n is only supported if interface names are specified as parameters.
2322511c2f6Srpe$PRINT_ONLY && (($# == 0)) && usage
2338222f376Srpe
23480771ddaSrpe# Load key material for the generation of IPv6 Semantically Opaque Interface
23580771ddaSrpe# Identifiers (SOII) used for link local and SLAAC addresses.
23681acd49bSflorian$PRINT_ONLY || [[ ! -f /etc/soii.key ]] ||
23781acd49bSflorian	sysctl -q "net.inet6.ip6.soiikey=$(</etc/soii.key)"
23881acd49bSflorian
239dfc209d0Smiod# If we were invoked with a list of interface names, just reconfigure these
24005102370Smpi# interfaces (or bridges), add default routes and return.
2410a295e45Srpeif (($# > 0)); then
2420a295e45Srpe	for _if; do ifstart $_if; done
24305102370Smpi	defaultroute
244dfc209d0Smiod	return
245dfc209d0Smiodfi
246dfc209d0Smiod
247dfc209d0Smiod# Otherwise, process with the complete network initialization.
248dfc209d0Smiod
2494fbd02fcSsobrado# Set the address for the loopback interface.  Bringing the interface up,
2504fbd02fcSsobrado# automatically invokes the IPv6 address ::1.
251d216f73bShenningifconfig lo0 inet 127.0.0.1/8
25298c28033Skstailey
25380771ddaSrpe# IPv6 configuration.
2543d8fed7cSitojunif ifconfig lo0 inet6 >/dev/null 2>&1; then
2553d8fed7cSitojun	ip6kernel=YES
2563d8fed7cSitojun
257dfc209d0Smiod	# Disallow link-local unicast dest without outgoing scope identifiers.
258c3b5ca42Skn	route -qn add -inet6 fe80:: -prefixlen 10 ::1 -reject
25992aceabbSitojun
260dfc209d0Smiod	# Disallow site-local unicast dest without outgoing scope identifiers.
26192aceabbSitojun	# If you configure site-locals without scope id (it is permissible
26292aceabbSitojun	# config for routers that are not on scope boundary), you may want
26392aceabbSitojun	# to comment the line out.
264c3b5ca42Skn	route -qn add -inet6 fec0:: -prefixlen 10 ::1 -reject
26592aceabbSitojun
266dfc209d0Smiod	# Disallow "internal" addresses to appear on the wire.
267c3b5ca42Skn	route -qn add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject
26892aceabbSitojun
269dfc209d0Smiod	# Disallow packets to malicious 6to4 prefix.
270c3b5ca42Skn	route -qn add -inet6 2002:e000:: -prefixlen 20 ::1 -reject
271c3b5ca42Skn	route -qn add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject
272c3b5ca42Skn	route -qn add -inet6 2002:0000:: -prefixlen 24 ::1 -reject
273c3b5ca42Skn	route -qn add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject
27492aceabbSitojun
275a4ee3723Sitojun	# Disallow packets without scope identifier.
276c3b5ca42Skn	route -qn add -inet6 ff01:: -prefixlen 16 ::1 -reject
277c3b5ca42Skn	route -qn add -inet6 ff02:: -prefixlen 16 ::1 -reject
278a4ee3723Sitojun
27992aceabbSitojun	# Completely disallow packets to IPv4 compatible prefix.
280300d0407Srpe	#
28192aceabbSitojun	# This may conflict with RFC1933 under following circumstances:
28292aceabbSitojun	# (1) An IPv6-only KAME node tries to originate packets to IPv4
2835e268fadSderaadt	#     compatible destination.  The KAME node has no IPv4 compatible
28492aceabbSitojun	#     support.  Under RFC1933, it should transmit native IPv6
28592aceabbSitojun	#     packets toward IPv4 compatible destination, hoping it would
28692aceabbSitojun	#     reach a router that forwards the packet toward auto-tunnel
28792aceabbSitojun	#     interface.
2885e268fadSderaadt	# (2) An IPv6-only node originates a packet to an IPv4 compatible
28992aceabbSitojun	#     destination.  A KAME node is acting as an IPv6 router, and
29092aceabbSitojun	#     asked to forward it.
291300d0407Srpe	#
2925e268fadSderaadt	# Due to rare use of IPv4 compatible addresses, and security issues
29392aceabbSitojun	# with it, we disable it by default.
294c3b5ca42Skn	route -qn add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject
2953d8fed7cSitojunelse
2963d8fed7cSitojun	ip6kernel=NO
2973d8fed7cSitojunfi
2983d8fed7cSitojun
29980771ddaSrpe# Create all the pseudo interfaces up front.
300b6107460Sdlgvifscreate
301df930be7Sderaadt
3029ac6b043Stodd# Configure all the non-loopback interfaces which we know about, but
3034eb97611Sderaadt# do not start interfaces which must be delayed. Refer to hostname.if(5)
304f7df26a3Sjmcifmstart "" "aggr trunk svlan vlan carp pppoe tun tap gif etherip gre egre pflow wg"
30582c17b75Sitojun
306774508f4Sdlg# The aggr and trunk interfaces need to come up first in this list.
307f45bd3bdSmpf# The (s)vlan interfaces need to come up after trunk.
3084bdcd471Sbrad# Configure all the carp interfaces which we know about before default route.
309774508f4Sdlgifmstart "aggr trunk svlan vlan carp pppoe"
3104bdcd471Sbrad
31180771ddaSrpe# Set default routes for IPv4 and IPv6.
31205102370Smpidefaultroute
313cf3860a5Sderaadt
314745634aaSniklas# Multicast routing.
3156e0f151eSsthenif [[ $multicast != YES ]]; then
316705fcffdSreyk	route -qn delete 224.0.0.0/4 >/dev/null 2>&1
317f4b4b73bSderaadt	route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject >/dev/null
3186e0f151eSsthenfi
319dfc209d0Smiod
320300d0407Srpe# Reject 127/8 other than 127.0.0.1.
3218f8fdbefSderaadtroute -qn add -net 127 127.0.0.1 -reject >/dev/null
3228f8fdbefSderaadt
323b6107460Sdlg# Configure interfaces that rely on routing
324f7df26a3Sjmcifmstart "tun tap gif etherip gre egre pflow wg"
325b6107460Sdlg
3260a295e45Srpeif [[ $ip6kernel == YES ]]; then
32780771ddaSrpe	# Ensure IPv6 Duplicate Address Detection (DAD) is completed.
328c653ce7bSmarkus	count=0
3290a295e45Srpe	while ((count++ < 10 && $(sysctl -n net.inet6.ip6.dad_pending) != 0)); do
330c653ce7bSmarkus		sleep 1
331c653ce7bSmarkus	done
332089287c3Sdavidfi
333