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