Merge branch 'vendor/GCC47'
[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
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.
157 ifconfig_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.
193 dhcpif()
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.
208 wpaif()
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 #
234 ifalias_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 #
256 ifalias_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 #
278 ifscript_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 #
292 ifscript_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 #
303 clone_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 #
320 clone_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
334 gif_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 #
359 ifnet_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 #
385 list_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
445 hexdigit()
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
461 hexprint()
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
479 network6_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
559 network6_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
608 network6_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
632 network6_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.
662 network6_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
717 network6_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 }