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