xref: /dragonfly/etc/network.subr (revision 31524921)
1#
2# Copyright (c) 2003 The FreeBSD Project. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7# 1. Redistributions of source code must retain the above copyright
8#    notice, this list of conditions and the following disclaimer.
9# 2. Redistributions in binary form must reproduce the above copyright
10#    notice, this list of conditions and the following disclaimer in the
11#    documentation and/or other materials provided with the distribution.
12#
13# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
14# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16# ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
17# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23# SUCH DAMAGE.
24#
25# $FreeBSD: src/etc/network.subr,v 1.163 2005/06/30 04:52:47 brooks Exp $
26#
27
28#
29# Subroutines commonly used from network startup scripts.
30# Requires that rc.conf be loaded first.
31#
32
33# ifconfig_up if
34#	Evaluate ifconfig(8) arguments for interface $if and
35#	run ifconfig(8) with those arguments. It returns 0 if
36#	arguments were found and executed or 1 if the interface
37#	had no arguments.  Pseudo arguments DHCP and WPA are handled
38#	here.
39#
40ifconfig_up()
41{
42	_cfg=1
43
44	ifconfig_args=`ifconfig_getargs $1`
45	if [ -n "${ifconfig_args}" ]; then
46		ifconfig $1 ${ifconfig_args}
47		_cfg=0
48	fi
49
50	if wpaif $1; then
51		/etc/rc.d/wpa_supplicant start $1
52		_cfg=0		# XXX: not sure this should count
53	fi
54
55	if dhcpif $1; then
56		/etc/rc.d/dhclient start $1
57		_cfg=0
58	fi
59
60	return $_cfg
61}
62
63# ifconfig_down if
64#	Remove all inet entries from the $if interface. It returns
65#	0 if inet entries were found and removed. It returns 1 if
66#	no entries were found or they could not be removed.
67#
68ifconfig_down()
69{
70	[ -z "$1" ] && return 1
71	_ifs="^"
72	_cfg=1
73
74	inetList="`ifconfig $1 | grep 'inet ' | tr "\n" "$_ifs"`"
75
76	oldifs="$IFS"
77	IFS="$_ifs"
78	for _inet in $inetList ; do
79		# get rid of extraneous line
80		[ -z "$_inet" ] && break
81
82		_inet=`expr "$_inet" : '.*\(inet \([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*'`
83
84		IFS="$oldifs"
85		ifconfig $1 ${_inet} delete
86		IFS="$_ifs"
87		_cfg=0
88	done
89	IFS="$oldifs"
90
91	if wpaif $1; then
92		/etc/rc.d/wpa_supplicant stop $1
93	fi
94
95	if dhcpif $1; then
96		/etc/rc.d/dhclient stop $1
97		_cfg=0
98	fi
99
100	return $_cfg
101}
102
103# get_if_var if var [default]
104#	Return the value of the pseudo-hash corresponding to $if where
105#	$var is a string containg the sub-string "IF" which will be
106#	replaced with $if after the characters defined in _punct are
107#	replaced with '_'. If the variable is unset, replace it with
108#	$default if given.
109get_if_var()
110{
111	local _if _punct_c _punct _var _default prefix suffix
112
113	if [ $# -ne 2 -a $# -ne 3 ]; then
114		err 3 'USAGE: get_if_var name var [default]'
115	fi
116
117	_if=$1
118	_punct=". - / +"
119	for _punct_c in $_punct; do
120		_if=`ltr ${_if} ${_punct_c} '_'`
121	done
122	_var=$2
123	_default=$3
124
125	prefix=${_var%%IF*}
126	suffix=${_var##*IF}
127	eval echo \${${prefix}${_if}${suffix}-${_default}}
128}
129
130# _ifconfig_getargs if
131#	Echos the arguments for the supplied interface to stdout.
132#	returns 1 if empty.  In general, ifconfig_getargs should be used
133#	outside this file.
134_ifconfig_getargs()
135{
136	_ifn=$1
137	if [ -z "$_ifn" ]; then
138		return 1
139	fi
140
141	_args=`get_if_var $_ifn ifconfig_IF`
142	if [ -z "$_args" -a -n "${pccard_ifconfig}" ]; then
143		for _if in ${removable_interfaces} ; do
144			if [ "$_if" = "$_ifn" ] ; then
145				_args=${pccard_ifconfig}
146				break
147			fi
148		done
149	fi
150
151	echo $_args
152}
153
154# ifconfig_getargs if
155#	Takes the result from _ifconfig_getargs and removes pseudo
156#	args such as DHCP and WPA.
157ifconfig_getargs()
158{
159	_tmpargs=`_ifconfig_getargs $1`
160	if [ $? -eq 1 ]; then
161		return 1
162	fi
163	_args=
164
165	is_optarg=no
166	for _arg in $_tmpargs; do
167		if [ "$is_optarg" = "no" ]; then
168			case $_arg in
169			[Dd][Hh][Cc][Pp])
170				;;
171			[Ww][Pp][Aa])
172				;;
173			*)
174				_args="$_args $_arg"
175				case $_arg in
176				authmode)
177					is_optarg=yes
178					;;
179				esac
180				;;
181			esac
182		else
183			_args="$_args $_arg"
184			is_optarg=no
185		fi
186	done
187
188	echo $_args
189}
190
191# dhcpif if
192#	Returns 0 if the interface is a DHCP interface and 1 otherwise.
193dhcpif()
194{
195	_tmpargs=`_ifconfig_getargs $1`
196	for _arg in $_tmpargs; do
197		case $_arg in
198		[Dd][Hh][Cc][Pp])
199			return 0
200			;;
201		esac
202	done
203	return 1
204}
205
206# wpaif if
207#	Returns 0 if the interface is a WPA interface and 1 otherwise.
208wpaif()
209{
210	_tmpargs=`_ifconfig_getargs $1`
211	is_optarg=no
212	for _arg in $_tmpargs; do
213		if [ "$is_optarg" = "no" ]; then
214			case $_arg in
215			[Ww][Pp][Aa])
216				return 0
217				;;
218			authmode)
219				is_optarg=yes
220				;;
221			esac
222		else
223			is_optarg=no
224		fi
225	done
226	return 1
227}
228
229# ifalias_up if
230#	Configure aliases for network interface $if.
231#	It returns 0 if at least one alias was configured or
232#	1 if there were none.
233#
234ifalias_up()
235{
236	_ret=1
237	alias=0
238	while : ; do
239		ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
240		if [ -n "${ifconfig_args}" ]; then
241			ifconfig $1 ${ifconfig_args} alias
242			alias=$((${alias} + 1))
243			_ret=0
244		else
245			break
246		fi
247	done
248	return $_ret
249}
250
251#ifalias_down if
252#	Remove aliases for network interface $if.
253#	It returns 0 if at least one alias was removed or
254#	1 if there were none.
255#
256ifalias_down()
257{
258	_ret=1
259	alias=0
260	while : ; do
261		ifconfig_args=`get_if_var $1 ifconfig_IF_alias${alias}`
262		if [ -n "${ifconfig_args}" ]; then
263			ifconfig $1 ${ifconfig_args} -alias
264			alias=$((${alias} + 1))
265			_ret=0
266		else
267			break
268		fi
269	done
270	return $_ret
271}
272
273# ifscript_up if
274#	Evaluate a startup script for the $if interface.
275#	It returns 0 if a script was found and processed or
276#	1 if no script was found.
277#
278ifscript_up()
279{
280	if [ -r /etc/start_if.$1 ]; then
281		. /etc/start_if.$1
282		return 0
283	fi
284	return 1
285}
286
287# ifscript_down if
288#	Evaluate a shutdown script for the $if interface.
289#	It returns 0 if a script was found and processed or
290#	1 if no script was found.
291#
292ifscript_down()
293{
294	if [ -r /etc/stop_if.$1 ]; then
295		. /etc/stop_if.$1
296		return 0
297	fi
298	return 1
299}
300
301# Create cloneable interfaces.
302#
303clone_up()
304{
305	_prefix=
306	_list=
307	for ifn in ${cloned_interfaces}; do
308		ifconfig ${ifn} create
309		if [ $? -eq 0 ]; then
310			_list="${_list}${_prefix}${ifn}"
311			[ -z "$_prefix" ] && _prefix=' '
312		fi
313	done
314	debug "Cloned: ${_list}"
315}
316
317# Destroy cloned interfaces. Destroyed interfaces are echoed
318# to standard output.
319#
320clone_down()
321{
322	_prefix=
323	_list=
324	for ifn in ${cloned_interfaces}; do
325		ifconfig ${ifn} destroy
326		if [ $? -eq 0 ]; then
327			_list="${_list}${_prefix}${ifn}"
328			[ -z "$_prefix" ] && _prefix=' '
329		fi
330	done
331	debug "Destroyed clones: ${_list}"
332}
333
334gif_up() {
335	case ${gif_interfaces} in
336	[Nn][Oo] | '')
337		;;
338	*)
339		for i in ${gif_interfaces}; do
340			eval peers=\$gifconfig_$i
341			case ${peers} in
342			'')
343				continue
344				;;
345			*)
346				ifconfig $i create >/dev/null 2>&1
347				ifconfig $i tunnel ${peers}
348				ifconfig $i up
349				;;
350			esac
351		done
352		;;
353	esac
354}
355
356# ifnet_rename
357#	Rename all requested interfaces.
358#
359ifnet_rename()
360{
361
362	_ifn_list="`ifconfig -l`"
363	[ -z "$_ifn_list" ] && return 0
364	for _if in ${_ifn_list} ; do
365		_ifname=`get_if_var $_if ifconfig_IF_name`
366		if [ ! -z "$_ifname" ]; then
367			ifconfig $_if name $_ifname
368		fi
369	done
370	return 0
371}
372
373#
374# list_net_interfaces type
375#	List all network interfaces. The type of interface returned
376#	can be controlled by the type argument. The type
377#	argument can be any of the following:
378#		nodhcp - all interfaces, excluding DHCP configured interfaces
379#		dhcp   - list only DHCP configured interfaces
380#	If no argument is specified all network interfaces are output.
381#	Note that the list will include cloned interfaces if applicable.
382#	Cloned interfaces must already exist to have a chance to appear
383#	in the list if ${network_interfaces} is set to `auto'.
384#
385list_net_interfaces()
386{
387	type=$1
388
389	# Get a list of ALL the interfaces.  NOTE: cloned interfaces
390	# have already been configured so they should show up in the
391	# ifconfig -l output.
392	#
393	case ${network_interfaces} in
394	[Aa][Uu][Tt][Oo])
395		_autolist="`ifconfig -l`"
396		_lo=
397		for _if in ${_autolist} ; do
398			if [ "$_if" = "lo0" ]; then
399				_lo="lo0"
400			else
401				_tmplist="${_tmplist} ${_if}"
402			fi
403		done
404		_tmplist="${_lo} ${_tmplist}"
405		;;
406	*)
407		_tmplist="${network_interfaces} ${cloned_interfaces}"
408		;;
409	esac
410
411	if [ -z "$type" ]; then
412		echo $_tmplist
413		return 0
414	fi
415
416	# Separate out dhcp and non-dhcp interfaces
417	#
418	_aprefix=
419	_bprefix=
420	for _if in ${_tmplist} ; do
421		eval _ifarg="\$ifconfig_${_if}"
422		case "$_ifarg" in
423		[Dd][Hh][Cc][Pp])
424			_dhcplist="${_dhcplist}${_aprefix}${_if}"
425			[ -z "$_aprefix" ] && _aprefix=' '
426			;;
427		''|*)
428			_nodhcplist="${_nodhcplist}${_bprefix}${_if}"
429			[ -z "$_bprefix" ] && _bprefix=' '
430			;;
431		esac
432	done
433
434	case "$type" in
435	nodhcp)
436		echo $_nodhcplist
437		;;
438	dhcp)
439		echo $_dhcplist
440		;;
441	esac
442	return 0
443}
444
445hexdigit()
446{
447	if [ $1 -lt 10 ]; then
448		echo $1
449	else
450		case $1 in
451		10)	echo a ;;
452		11)	echo b ;;
453		12)	echo c ;;
454		13)	echo d ;;
455		14)	echo e ;;
456		15)	echo f ;;
457		esac
458	fi
459}
460
461hexprint()
462{
463	val=$1
464	str=''
465
466	dig=`hexdigit $((${val} & 15))`
467	str=${dig}${str}
468	val=$((${val} >> 4))
469	while [ ${val} -gt 0 ]; do
470		dig=`hexdigit $((${val} & 15))`
471		str=${dig}${str}
472		val=$((${val} >> 4))
473	done
474
475	echo ${str}
476}
477
478# Setup the interfaces for IPv6
479network6_interface_setup()
480{
481	interfaces=$*
482	rtsol_interfaces=''
483	case ${ipv6_gateway_enable} in
484	[Yy][Ee][Ss])
485		rtsol_available=no
486		;;
487	*)
488		rtsol_available=yes
489		;;
490	esac
491	for i in $interfaces; do
492		rtsol_interface=yes
493		prefix=`get_if_var $i ipv6_prefix_IF`
494		if [ -n "${prefix}" ]; then
495			rtsol_available=no
496			rtsol_interface=no
497			laddr=`network6_getladdr $i`
498			hostid=`expr "${laddr}" : 'fe80::\(.*\)%\(.*\)'`
499			for j in ${prefix}; do
500				address=$j\:${hostid}
501				ifconfig $i inet6 ${address} prefixlen 64 alias
502
503				case ${ipv6_gateway_enable} in
504				[Yy][Ee][Ss])
505					# subnet-router anycast address
506					# (rfc2373)
507					ifconfig $i inet6 $j:: prefixlen 64 \
508						alias anycast
509					;;
510				esac
511			done
512		fi
513		ipv6_ifconfig=`get_if_var $i ipv6_ifconfig_IF`
514		if [ -n "${ipv6_ifconfig}" ]; then
515			rtsol_available=no
516			rtsol_interface=no
517			ifconfig $i inet6 ${ipv6_ifconfig} alias
518		fi
519
520		if [ ${rtsol_available} = yes -a ${rtsol_interface} = yes ]
521		then
522			case ${i} in
523			lo0|gif[0-9]*|stf[0-9]*|faith[0-9]*|lp[0-9]*|sl[0-9]*|tun[0-9]*)
524				;;
525			*)
526				rtsol_interfaces="${rtsol_interfaces} ${i}"
527				;;
528			esac
529		else
530			ifconfig $i inet6
531		fi
532	done
533
534	if [ ${rtsol_available} = yes -a -n "${rtsol_interfaces}" ]; then
535		# Act as endhost - automatically configured.
536		# You can configure only single interface, as
537		# specification assumes that autoconfigured host has
538		# single interface only.
539		sysctl net.inet6.ip6.accept_rtadv=1
540		set ${rtsol_interfaces}
541		ifconfig $1 up
542		rtsol $1
543	fi
544
545	for i in $interfaces; do
546		alias=0
547		while : ; do
548			ipv6_ifconfig=`get_if_var $i ipv6_ifconfig_IF_alias${alias}`
549			if [ -z "${ipv6_ifconfig}" ]; then
550				break;
551			fi
552			ifconfig $i inet6 ${ipv6_ifconfig} alias
553			alias=$((${alias} + 1))
554		done
555	done
556}
557
558# Setup IPv6 to IPv4 mapping
559network6_stf_setup()
560{
561	case ${stf_interface_ipv4addr} in
562	[Nn][Oo] | '')
563		;;
564	*)
565		# assign IPv6 addr and interface route for 6to4 interface
566		stf_prefixlen=$((16+${stf_interface_ipv4plen:-0}))
567		OIFS="$IFS"
568		IFS=".$IFS"
569		set ${stf_interface_ipv4addr}
570		IFS="$OIFS"
571		hexfrag1=`hexprint $(($1*256 + $2))`
572		hexfrag2=`hexprint $(($3*256 + $4))`
573		ipv4_in_hexformat="${hexfrag1}:${hexfrag2}"
574		case ${stf_interface_ipv6_ifid} in
575		[Aa][Uu][Tt][Oo] | '')
576			for i in ${ipv6_network_interfaces}; do
577				laddr=`network6_getladdr ${i}`
578				case ${laddr} in
579				'')
580					;;
581				*)
582					break
583					;;
584				esac
585			done
586			stf_interface_ipv6_ifid=`expr "${laddr}" : \
587						      'fe80::\(.*\)%\(.*\)'`
588			case ${stf_interface_ipv6_ifid} in
589			'')
590				stf_interface_ipv6_ifid=0:0:0:1
591				;;
592			esac
593			;;
594		esac
595		ifconfig stf0 create >/dev/null 2>&1
596		ifconfig stf0 inet6 2002:${ipv4_in_hexformat}:${stf_interface_ipv6_slaid:-0}:${stf_interface_ipv6_ifid} \
597			prefixlen ${stf_prefixlen}
598		# disallow packets to malicious 6to4 prefix
599		route add -inet6 2002:e000:: -prefixlen 20 ::1 -reject
600		route add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject
601		route add -inet6 2002:0000:: -prefixlen 24 ::1 -reject
602		route add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject
603		;;
604	esac
605}
606
607# Setup static routes
608network6_static_routes_setup()
609{
610	# Set up any static routes.
611	case ${ipv6_defaultrouter} in
612	[Nn][Oo] | '')
613		;;
614	*)
615		ipv6_static_routes="default ${ipv6_static_routes}"
616		ipv6_route_default="default ${ipv6_defaultrouter}"
617		;;
618	esac
619	case ${ipv6_static_routes} in
620	[Nn][Oo] | '')
621		;;
622	*)
623		for i in ${ipv6_static_routes}; do
624			eval ipv6_route_args=\$ipv6_route_${i}
625			route add -inet6 ${ipv6_route_args}
626		done
627		;;
628	esac
629}
630
631# Setup faith
632network6_faith_setup()
633{
634	case ${ipv6_faith_prefix} in
635	[Nn][Oo] | '')
636		;;
637	*)
638		sysctl net.inet6.ip6.keepfaith=1
639		ifconfig faith0 create >/dev/null 2>&1
640		ifconfig faith0 up
641		for prefix in ${ipv6_faith_prefix}; do
642			prefixlen=`expr "${prefix}" : ".*/\(.*\)"`
643			case ${prefixlen} in
644			'')
645				prefixlen=96
646				;;
647			*)
648				prefix=`expr "${prefix}" : \
649					     "\(.*\)/${prefixlen}"`
650				;;
651			esac
652			route add -inet6 ${prefix} -prefixlen ${prefixlen} ::1
653			route change -inet6 ${prefix} -prefixlen ${prefixlen} \
654				-ifp faith0
655		done
656		;;
657	esac
658}
659
660# Install the "default interface" to kernel, which will be used
661# as the default route when there's no router.
662network6_default_interface_setup()
663{
664	# Choose IPv6 default interface if it is not clearly specified.
665	case ${ipv6_default_interface} in
666	'')
667		for i in ${ipv6_network_interfaces}; do
668			case $i in
669			lo0|faith[0-9]*)
670				continue
671				;;
672			esac
673			laddr=`network6_getladdr $i exclude_tentative`
674			case ${laddr} in
675			'')
676				;;
677			*)
678				ipv6_default_interface=$i
679				break
680				;;
681			esac
682		done
683		;;
684	esac
685
686	# Disallow unicast packets without outgoing scope identifiers,
687	# or route such packets to a "default" interface, if it is specified.
688	route add -inet6 fe80:: -prefixlen 10 ::1 -reject
689	case ${ipv6_default_interface} in
690	[Nn][Oo] | '')
691		route add -inet6 ff02:: -prefixlen 16 ::1 -reject
692		;;
693	*)
694		laddr=`network6_getladdr ${ipv6_default_interface}`
695		route add -inet6 ff02:: ${laddr} -prefixlen 16 -interface \
696			-cloning
697
698		# Disable installing the default interface with the
699		# case net.inet6.ip6.forwarding=0 and
700		# net.inet6.ip6.accept_rtadv=0, due to avoid conflict
701		# between the default router list and the manual
702		# configured default route.
703		case ${ipv6_gateway_enable} in
704		[Yy][Ee][Ss])
705			;;
706		*)
707			if [ `sysctl -n net.inet6.ip6.accept_rtadv` -eq 1 ]
708			then
709				ndp -I ${ipv6_default_interface}
710			fi
711			;;
712		esac
713		;;
714	esac
715}
716
717network6_getladdr()
718{
719	ifconfig $1 2>/dev/null | while read proto addr rest; do
720		case ${proto} in
721		inet6)
722			case ${addr} in
723			fe80::*)
724				if [ -z "$2" ]; then
725					echo ${addr}
726					return
727				fi
728				case ${rest} in
729				*tentative*)
730					continue
731					;;
732				*)
733					echo ${addr}
734					return
735				esac
736			esac
737		esac
738	done
739}
740