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