netstart revision 1.194
1#!/bin/sh -
2#
3#	$OpenBSD: netstart,v 1.194 2018/02/19 23:42:29 rpe Exp $
4
5# Turn off Strict Bourne shell mode.
6set +o sh
7
8# Echo file $1 to stdout. Skip comment lines and delete everything
9# after the first '#' from other lines. Strip leading and trailing
10# whitespace if IFS is set.
11# Usage: stripcom /path/to/file
12stripcom() {
13	local _file=$1 _line
14
15	[[ -f $_file ]] || return
16
17	while read _line; do
18		[[ -n ${_line%%#*} ]] && print -r -- "$_line"
19	done <$_file
20}
21
22# Parse and "unpack" a hostname.if(5) line given as positional parameters.
23# Fill the _cmds array with the resulting interface configuration commands.
24parse_hn_line() {
25	local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr
26	set -A _c -- "$@"
27	set -o noglob
28
29	case ${_c[_af]} in
30	''|*([[:blank:]])'#'*)
31		return
32		;;
33	inet)	((${#_c[*]} > 1)) || return
34		[[ ${_c[_name]} == alias ]] && _mask=3 _bc=4
35		[[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}"
36		if [[ -n ${_c[_bc]} ]]; then
37			_c[_bc]="broadcast ${_c[_bc]}"
38			[[ ${_c[_bc]} == *NONE ]] && _c[_bc]=
39		fi
40		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
41		;;
42	inet6)	((${#_c[*]} > 1)) || return
43		if [[ ${_c[_name]} == autoconf ]]; then
44			_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
45			V6_AUTOCONF=true
46			return
47		fi
48		[[ ${_c[_name]} == alias ]] && _prefix=3
49		[[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}"
50		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
51		;;
52	dest)	((${#_c[*]} == 2)) && _daddr=${_c[1]} || return
53		_prev=$((${#_cmds[*]} - 1))
54		((_prev >= 0)) || return
55		set -A _c -- ${_cmds[_prev]}
56		_name=3
57		[[ ${_c[_name]} == alias ]] && _name=4
58		_c[_name]="${_c[_name]} $_daddr"
59		_cmds[$_prev]="${_c[@]}"
60		;;
61	dhcp)	_c[0]=
62		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]} down;dhclient $_if"
63		V4_DHCPCONF=true
64		;;
65	'!'*)	_cmd=$(print -- "${_c[@]}" | sed 's/\$if/'$_if'/g')
66		_cmds[${#_cmds[*]}]="${_cmd#!}"
67		;;
68	*)	_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
69		;;
70	esac
71	unset _c
72	set +o noglob
73}
74
75# Create interface $1 if it does not yet exist.
76ifcreate() {
77	local _if=$1
78
79	{ ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1
80}
81
82# Create interfaces for network pseudo-devices referred to by hostname.if files.
83vifscreate() {
84	local _vif _hn _if
85
86	for _vif in $(ifconfig -C); do
87		for _hn in /etc/hostname.${_vif}+([[:digit:]]); do
88			[[ -f $_hn ]] || continue
89			_if=${_hn#/etc/hostname.}
90
91			if ! ifcreate $_if; then
92				print -u2 "${0##*/}: create for '$_if' failed."
93			fi
94		done
95	done
96}
97
98# Start a single interface.
99# Usage: ifstart if1
100ifstart() {
101	local _if=$1 _hn=/etc/hostname.$1 _cmds _i=0 _line _stat
102	set -A _cmds
103
104	# Interface names must be alphanumeric only.  We check to avoid
105	# configuring backup or temp files, and to catch the "*" case.
106	[[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return
107
108	if [[ ! -f $_hn ]]; then
109		print -u2 "${0##*/}: $_hn: No such file or directory."
110		return
111	fi
112
113	# Not using stat(1), we can't rely on having /usr yet.
114	set -A _stat -- $(ls -nL $_hn)
115	if [[ "${_stat[0]}${_stat[2]}${_stat[3]}" != *---00 ]]; then
116		print -u2 "WARNING: $_hn is insecure, fixing permissions."
117		chmod -LR o-rwx $_hn
118		chown -LR root:wheel $_hn
119	fi
120
121	# Check for ifconfig'able interface, except if -n option is specified.
122	if ! $PRINT_ONLY; then
123		ifcreate $_if || return
124	fi
125
126	# Parse the hostname.if(5) file and fill _cmds array with interface
127	# configuration commands.
128	set -o noglob
129	while IFS= read -- _line; do
130		parse_hn_line $_line
131	done <$_hn
132
133	# Apply the interface configuration commands stored in _cmds array.
134	while ((_i < ${#_cmds[*]})); do
135		if $PRINT_ONLY; then
136			print -r -- "${_cmds[_i]}"
137		else
138			eval "${_cmds[_i]}"
139		fi
140		((_i++))
141	done
142	unset _cmds
143	set +o noglob
144}
145
146# Start multiple interfaces by driver name.
147# Usage: ifmstart "em iwm" "trunk vlan"
148#   Start "$1" interfaces in order or all interfaces if empty.
149#   Don't start "$2" interfaces. "$2" is optional.
150ifmstart() {
151	local _sifs=$1 _xifs=$2 _hn _if _sif _xif
152
153	for _sif in ${_sifs:-ALL}; do
154		for _hn in /etc/hostname.+([[:alpha:]])+([[:digit:]]); do
155			[[ -f $_hn ]] || continue
156			_if=${_hn#/etc/hostname.}
157
158			# Skip unwanted ifs.
159			for _xif in $_xifs; do
160				[[ $_xif == ${_if%%[0-9]*} ]] && continue 2
161			done
162
163			# Start wanted ifs.
164			[[ $_sif == @(ALL|${_if%%[0-9]*}) ]] && ifstart $_if
165		done
166	done
167}
168
169# Parse /etc/mygate and add default routes for IPv4 and IPv6
170# Usage: defaultroute
171defaultroute() {
172	local _cmd;
173
174	! $V4_DHCPCONF && stripcom /etc/mygate |
175	while read gw; do
176		[[ $gw == @(*:*) ]] && continue
177		_cmd="route -qn add -host default $gw"
178		if $PRINT_ONLY; then
179			print -r -- "$_cmd" && break
180		else
181			$_cmd && break
182		fi
183	done
184	! $V6_AUTOCONF && stripcom /etc/mygate |
185	while read gw; do
186		[[ $gw == !(*:*) ]] && continue
187		_cmd="route -qn add -host -inet6 default $gw"
188		if $PRINT_ONLY; then
189			print -r -- "$_cmd" && break
190		else
191			$_cmd && break
192		fi
193	done
194}
195
196# Get network related vars from rc.conf using the parsing routine from rc.subr.
197FUNCS_ONLY=1 . /etc/rc.d/rc.subr
198_rc_parse_conf
199
200PRINT_ONLY=false
201USAGE="USAGE: ${0##*/} [-n] [interface ...]"
202V4_DHCPCONF=false
203V6_AUTOCONF=false
204
205while getopts ":n" opt; do
206	case $opt in
207	n)	PRINT_ONLY=true;;
208	*)	print -u2 "$USAGE"; exit 1;;
209	esac
210done
211shift $((OPTIND-1))
212
213# Option -n is only supported if interface names are specified as parameters.
214if $PRINT_ONLY && (($# == 0)); then
215	print -u2 "Missing parameters.\n$USAGE"
216	exit 1
217fi
218
219$PRINT_ONLY || [[ ! -f /etc/soii.key ]] ||
220	sysctl -q "net.inet6.ip6.soiikey=$(</etc/soii.key)"
221
222# If we were invoked with a list of interface names, just reconfigure these
223# interfaces (or bridges), add default routes and return.
224if (($# > 0)); then
225	for _if; do ifstart $_if; done
226	defaultroute
227	return
228fi
229
230# Otherwise, process with the complete network initialization.
231
232# /etc/myname contains my symbolic name.
233[[ -f /etc/myname ]] && hostname "$(stripcom /etc/myname)"
234
235# Set the address for the loopback interface.  Bringing the interface up,
236# automatically invokes the IPv6 address ::1.
237ifconfig lo0 inet 127.0.0.1/8
238
239if ifconfig lo0 inet6 >/dev/null 2>&1; then
240	# IPv6 configurations.
241	ip6kernel=YES
242
243	# Disallow link-local unicast dest without outgoing scope identifiers.
244	route -qn add -inet6 fe80:: -prefixlen 10 ::1 -reject >/dev/null
245
246	# Disallow site-local unicast dest without outgoing scope identifiers.
247	# If you configure site-locals without scope id (it is permissible
248	# config for routers that are not on scope boundary), you may want
249	# to comment the line out.
250	route -qn add -inet6 fec0:: -prefixlen 10 ::1 -reject >/dev/null
251
252	# Disallow "internal" addresses to appear on the wire.
253	route -qn add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject >/dev/null
254
255	# Disallow packets to malicious 6to4 prefix.
256	route -qn add -inet6 2002:e000:: -prefixlen 20 ::1 -reject >/dev/null
257	route -qn add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject >/dev/null
258	route -qn add -inet6 2002:0000:: -prefixlen 24 ::1 -reject >/dev/null
259	route -qn add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject >/dev/null
260
261	# Disallow packets without scope identifier.
262	route -qn add -inet6 ff01:: -prefixlen 16 ::1 -reject >/dev/null
263	route -qn add -inet6 ff02:: -prefixlen 16 ::1 -reject >/dev/null
264
265	# Completely disallow packets to IPv4 compatible prefix.
266	#
267	# This may conflict with RFC1933 under following circumstances:
268	# (1) An IPv6-only KAME node tries to originate packets to IPv4
269	#     compatible destination.  The KAME node has no IPv4 compatible
270	#     support.  Under RFC1933, it should transmit native IPv6
271	#     packets toward IPv4 compatible destination, hoping it would
272	#     reach a router that forwards the packet toward auto-tunnel
273	#     interface.
274	# (2) An IPv6-only node originates a packet to an IPv4 compatible
275	#     destination.  A KAME node is acting as an IPv6 router, and
276	#     asked to forward it.
277	#
278	# Due to rare use of IPv4 compatible addresses, and security issues
279	# with it, we disable it by default.
280	route -qn add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject >/dev/null
281else
282	ip6kernel=NO
283fi
284
285# Create all the pseudo interfaces up front
286vifscreate
287
288# Configure all the non-loopback interfaces which we know about, but
289# do not start interfaces which must be delayed. Refer to hostname.if(5)
290ifmstart "" "trunk svlan vlan carp pppoe tun tap gif etherip gre egre mobileip pflow"
291
292# The trunk interfaces need to come up first in this list.
293# The (s)vlan interfaces need to come up after trunk.
294# Configure all the carp interfaces which we know about before default route.
295ifmstart "trunk svlan vlan carp pppoe"
296
297# Look for default routes in /etc/mygate.
298defaultroute
299
300# Multicast routing.
301if [[ $multicast != YES ]]; then
302	route -qn delete 224.0.0.0/4 >/dev/null 2>&1
303	route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject >/dev/null
304fi
305
306# Reject 127/8 other than 127.0.0.1.
307route -qn add -net 127 127.0.0.1 -reject >/dev/null
308
309# Configure interfaces that rely on routing
310ifmstart "tun tap gif etherip gre egre mobileip pflow"
311
312if [[ $ip6kernel == YES ]]; then
313	# This is to make sure DAD is completed before going further.
314	count=0
315	while ((count++ < 10 && $(sysctl -n net.inet6.ip6.dad_pending) != 0)); do
316		sleep 1
317	done
318fi
319