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