freebsd-skq/libexec/rc/network.subr
eugen 645d0bb86c network.subr: improve configuration of cloned gif(4) interfaces
ifconfig(8) syntax allows to specify only single address_family,
so we need additional invocation of ifconfig to support configuration
of cloned gif interface that may use different address families
for its internal and external addresses.

Also, ifconfig(8) does not allow to omit "inet6" keyword for address family
specifying IPv6 addresses as outer addresses of the interface.

Also, address_family is not "parameter" and it has to go before parameters
including "tunnel" keyword, so "ifconfig gif0 tunnel inet6 $oip1 $oip2" would be
wrong syntax and only "ifconfig gif0 inet6 tunnel $oip1 $oip2" is right.

With this change, the following works:

gifconfig_gif0="inet6 2a00::1 2a01::1"
ifconfig_gif0="inet 10.0.0.1 10.0.0.2 netmask 255.255.255.252"

MFC after:	2 weeks
2019-04-05 22:45:08 +00:00

1774 lines
36 KiB
Plaintext

#
# Copyright (c) 2003 The FreeBSD Project. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
IFCONFIG_CMD="/sbin/ifconfig"
: ${netif_ipexpand_max:=2048}
#
# Subroutines commonly used from network startup scripts.
# Requires that rc.conf be loaded first.
#
# ifn_start ifn
# Bring up and configure an interface. If some configuration is
# applied, print the interface configuration.
#
ifn_start()
{
local ifn cfg
ifn="$1"
cfg=1
[ -z "$ifn" ] && err 1 "ifn_start called without an interface"
ifscript_up ${ifn} && cfg=0
ifconfig_up ${ifn} && cfg=0
if ! noafif $ifn; then
afexists inet && ipv4_up ${ifn} && cfg=0
afexists inet6 && ipv6_up ${ifn} && cfg=0
fi
childif_create ${ifn} && cfg=0
return $cfg
}
# ifn_stop ifn
# Shutdown and de-configure an interface. If action is taken,
# print the interface name.
#
ifn_stop()
{
local ifn cfg
ifn="$1"
cfg=1
[ -z "$ifn" ] && err 1 "ifn_stop called without an interface"
if ! noafif $ifn; then
afexists inet6 && ipv6_down ${ifn} && cfg=0
afexists inet && ipv4_down ${ifn} && cfg=0
fi
ifconfig_down ${ifn} && cfg=0
ifscript_down ${ifn} && cfg=0
childif_destroy ${ifn} && cfg=0
return $cfg
}
# ifn_vnetup ifn
# Move ifn to the specified vnet jail.
#
ifn_vnetup()
{
ifn_vnet0 $1 vnet
}
# ifn_vnetdown ifn
# Reclaim ifn from the specified vnet jail.
#
ifn_vnetdown()
{
ifn_vnet0 $1 -vnet
}
# ifn_vnet0 ifn action
# Helper function for ifn_vnetup and ifn_vnetdown.
#
ifn_vnet0()
{
local _ifn _cfg _action _vnet
_ifn="$1"
_action="$2"
_cfg=1
if _vnet=$(vnetif $_ifn); then
${IFCONFIG_CMD} $_ifn $_action $_vnet && _cfg=0
fi
return $_cfg
}
# ifconfig_up if
# Evaluate ifconfig(8) arguments for interface $if and
# run ifconfig(8) with those arguments. It returns 0 if
# arguments were found and executed or 1 if the interface
# had no arguments. Pseudo arguments DHCP and WPA are handled
# here.
#
ifconfig_up()
{
local _cfg _ifconfig_descr _ipv6_opts ifconfig_args
_cfg=1
# Make sure lo0 always comes up.
if [ "$1" = "lo0" ]; then
_cfg=0
fi
# inet6 specific
if ! noafif $1 && afexists inet6; then
if checkyesno ipv6_activate_all_interfaces; then
_ipv6_opts="-ifdisabled"
elif [ "$1" != "lo0" ]; then
_ipv6_opts="ifdisabled"
fi
# backward compatibility: $ipv6_enable
case $ipv6_enable in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
case $1 in
bridge[0-9]*)
# No accept_rtadv by default on if_bridge(4)
# to avoid a conflict with the member
# interfaces.
;;
*)
if ! checkyesno ipv6_gateway_enable; then
_ipv6_opts="${_ipv6_opts} accept_rtadv"
fi
;;
esac
;;
esac
case $ipv6_cpe_wanif in
$1)
_ipv6_opts="${_ipv6_opts} -no_radr accept_rtadv"
;;
esac
if [ -n "${_ipv6_opts}" ]; then
${IFCONFIG_CMD} $1 inet6 ${_ipv6_opts}
fi
fi
# ifconfig_IF
ifconfig_args=`ifconfig_getargs $1`
if [ -n "${ifconfig_args}" ]; then
eval ${IFCONFIG_CMD} $1 ${ifconfig_args}
_cfg=0
fi
# inet6 specific
if ! noafif $1 && afexists inet6; then
# ifconfig_IF_ipv6
ifconfig_args=`ifconfig_getargs $1 ipv6`
if [ -n "${ifconfig_args}" ]; then
# backward compatibility: inet6 keyword
case "${ifconfig_args}" in
:*|[0-9a-fA-F]*:*)
warn "\$ifconfig_$1_ipv6 needs leading" \
"\"inet6\" keyword for an IPv6 address."
ifconfig_args="inet6 ${ifconfig_args}"
;;
esac
${IFCONFIG_CMD} $1 inet6 -ifdisabled
eval ${IFCONFIG_CMD} $1 ${ifconfig_args}
_cfg=0
fi
# $ipv6_prefix_IF will be handled in
# ipv6_prefix_hostid_addr_common().
ifconfig_args=`get_if_var $1 ipv6_prefix_IF`
if [ -n "${ifconfig_args}" ]; then
${IFCONFIG_CMD} $1 inet6 -ifdisabled
_cfg=0
fi
# backward compatibility: $ipv6_ifconfig_IF
ifconfig_args=`get_if_var $1 ipv6_ifconfig_IF`
if [ -n "${ifconfig_args}" ]; then
warn "\$ipv6_ifconfig_$1 is obsolete." \
" Use ifconfig_$1_ipv6 instead."
${IFCONFIG_CMD} $1 inet6 -ifdisabled
eval ${IFCONFIG_CMD} $1 inet6 ${ifconfig_args}
_cfg=0
fi
fi
ifalias $1 link alias
ifalias $1 ether alias
_ifconfig_descr=`get_if_var $1 ifconfig_IF_descr`
if [ -n "${_ifconfig_descr}" ]; then
${IFCONFIG_CMD} $1 description "${_ifconfig_descr}"
fi
if wpaif $1; then
/etc/rc.d/wpa_supplicant start $1
_cfg=0 # XXX: not sure this should count
elif hostapif $1; then
/etc/rc.d/hostapd start $1
_cfg=0
elif [ ${_cfg} -eq 0 ]; then
${IFCONFIG_CMD} $1 up
fi
if ! noafif $1 && afexists inet6; then
ipv6_accept_rtadv_up $1 && _cfg=0
fi
if dhcpif $1; then
if [ $_cfg -ne 0 ] ; then
${IFCONFIG_CMD} $1 up
fi
if syncdhcpif $1; then
/etc/rc.d/dhclient start $1
fi
_cfg=0
fi
return $_cfg
}
# ifconfig_down if
# returns 1 if wpa_supplicant or dhclient was stopped or
# the interface exists.
#
ifconfig_down()
{
local _cfg
_cfg=1
if wpaif $1; then
/etc/rc.d/wpa_supplicant stop $1
_cfg=0
elif hostapif $1; then
/etc/rc.d/hostapd stop $1
_cfg=0
elif dhcpif $1; then
/etc/rc.d/dhclient stop $1
_cfg=0
fi
if ifexists $1; then
${IFCONFIG_CMD} $1 down
_cfg=0
fi
return $_cfg
}
# get_if_var if var [default]
# Return the value of the pseudo-hash corresponding to $if where
# $var is a string containg the sub-string "IF" which will be
# replaced with $if after the characters defined in _punct are
# replaced with '_'. If the variable is unset, replace it with
# $default if given.
get_if_var()
{
local _if _punct _punct_c _var _default prefix suffix
if [ $# -ne 2 -a $# -ne 3 ]; then
err 3 'USAGE: get_if_var name var [default]'
fi
_if=$1
_punct=".-/+"
ltr ${_if} "${_punct}" '_' _if
_var=$2
_default=$3
prefix=${_var%%IF*}
suffix=${_var##*IF}
eval echo \${${prefix}${_if}${suffix}-${_default}}
}
# _ifconfig_getargs if [af]
# Prints the arguments for the supplied interface to stdout.
# Returns 1 if empty. In general, ifconfig_getargs should be used
# outside this file.
_ifconfig_getargs()
{
local _ifn _af
_ifn=$1
_af=${2+_$2}
if [ -z "$_ifn" ]; then
return 1
fi
get_if_var $_ifn ifconfig_IF$_af "$ifconfig_DEFAULT"
}
# ifconfig_getargs if [af]
# Takes the result from _ifconfig_getargs and removes pseudo
# args such as DHCP and WPA.
ifconfig_getargs()
{
local _tmpargs _arg _args _vnet
_tmpargs=`_ifconfig_getargs $1 $2`
if [ $? -eq 1 ]; then
return 1
fi
_args=
_vnet=0
for _arg in $_tmpargs; do
case $_arg:$_vnet in
[Dd][Hh][Cc][Pp]:0) ;;
[Nn][Oo][Aa][Uu][Tt][Oo]:0) ;;
[Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;;
[Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp]:0) ;;
[Ww][Pp][Aa]:0) ;;
[Hh][Oo][Ss][Tt][Aa][Pp]:0) ;;
vnet:0) _vnet=1 ;;
*:1) _vnet=0 ;;
*:0)
_args="$_args $_arg"
;;
esac
done
echo $_args
}
# autoif
# Returns 0 if the interface should be automatically configured at
# boot time and 1 otherwise.
autoif()
{
local _tmpargs _arg
_tmpargs=`_ifconfig_getargs $1`
for _arg in $_tmpargs; do
case $_arg in
[Nn][Oo][Aa][Uu][Tt][Oo])
return 1
;;
esac
done
return 0
}
# dhcpif if
# Returns 0 if the interface is a DHCP interface and 1 otherwise.
dhcpif()
{
local _tmpargs _arg
_tmpargs=`_ifconfig_getargs $1`
case $1 in
lo[0-9]*|\
stf[0-9]*|\
lp[0-9]*|\
sl[0-9]*)
return 1
;;
esac
if noafif $1; then
return 1
fi
for _arg in $_tmpargs; do
case $_arg in
[Dd][Hh][Cc][Pp])
return 0
;;
[Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
return 0
;;
[Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
return 0
;;
esac
done
return 1
}
# syncdhcpif
# Returns 0 if the interface should be configured synchronously and
# 1 otherwise.
syncdhcpif()
{
local _tmpargs _arg
_tmpargs=`_ifconfig_getargs $1`
if noafif $1; then
return 1
fi
for _arg in $_tmpargs; do
case $_arg in
[Nn][Oo][Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
return 1
;;
[Ss][Yy][Nn][Cc][Dd][Hh][Cc][Pp])
return 0
;;
esac
done
checkyesno synchronous_dhclient
}
# wpaif if
# Returns 0 if the interface is a WPA interface and 1 otherwise.
wpaif()
{
local _tmpargs _arg
_tmpargs=`_ifconfig_getargs $1`
for _arg in $_tmpargs; do
case $_arg in
[Ww][Pp][Aa])
return 0
;;
esac
done
return 1
}
# hostapif if
# Returns 0 if the interface is a HOSTAP interface and 1 otherwise.
hostapif()
{
local _tmpargs _arg
_tmpargs=`_ifconfig_getargs $1`
for _arg in $_tmpargs; do
case $_arg in
[Hh][Oo][Ss][Tt][Aa][Pp])
return 0
;;
esac
done
return 1
}
# vnetif if
# Returns 0 and echo jail if "vnet" keyword is specified on the
# interface, and 1 otherwise.
vnetif()
{
local _tmpargs _arg _vnet
_tmpargs=`_ifconfig_getargs $1`
_vnet=0
for _arg in $_tmpargs; do
case $_arg:$_vnet in
vnet:0) _vnet=1 ;;
*:1) echo $_arg; return 0 ;;
esac
done
return 1
}
# afexists af
# Returns 0 if the address family is enabled in the kernel
# 1 otherwise.
afexists()
{
local _af
_af=$1
case ${_af} in
inet|inet6)
check_kern_features ${_af}
;;
link|ether)
return 0
;;
*)
err 1 "afexists(): Unsupported address family: $_af"
;;
esac
}
# noafif if
# Returns 0 if the interface has no af configuration and 1 otherwise.
noafif()
{
local _if
_if=$1
case $_if in
pflog[0-9]*|\
pfsync[0-9]*|\
usbus[0-9]*|\
an[0-9]*|\
ath[0-9]*|\
ipw[0-9]*|\
ipfw[0-9]*|\
iwi[0-9]*|\
iwn[0-9]*|\
ral[0-9]*|\
wi[0-9]*|\
wl[0-9]*|\
wpi[0-9]*)
return 0
;;
esac
return 1
}
# ipv6if if
# Returns 0 if the interface should be configured for IPv6 and
# 1 otherwise.
ipv6if()
{
local _if _tmpargs i
_if=$1
if ! afexists inet6; then
return 1
fi
# lo0 is always IPv6-enabled
case $_if in
lo0)
return 0
;;
esac
case "${ipv6_network_interfaces}" in
$_if|"$_if "*|*" $_if"|*" $_if "*|[Aa][Uu][Tt][Oo])
# True if $ifconfig_IF_ipv6 is defined.
_tmpargs=`_ifconfig_getargs $_if ipv6`
if [ -n "${_tmpargs}" ]; then
return 0
fi
# True if $ipv6_prefix_IF is defined.
_tmpargs=`get_if_var $_if ipv6_prefix_IF`
if [ -n "${_tmpargs}" ]; then
return 0
fi
# backward compatibility: True if $ipv6_ifconfig_IF is defined.
_tmpargs=`get_if_var $_if ipv6_ifconfig_IF`
if [ -n "${_tmpargs}" ]; then
return 0
fi
;;
esac
return 1
}
# ipv6_autoconfif if
# Returns 0 if the interface should be configured for IPv6 with
# Stateless Address Configuration; 1 otherwise.
ipv6_autoconfif()
{
local _if _tmpargs _arg
_if=$1
case $_if in
lo[0-9]*|\
stf[0-9]*|\
lp[0-9]*|\
sl[0-9]*)
return 1
;;
esac
if noafif $_if; then
return 1
fi
if ! ipv6if $_if; then
return 1
fi
if checkyesno ipv6_gateway_enable; then
return 1
fi
_tmpargs=`get_if_var $_if ipv6_prefix_IF`
if [ -n "${_tmpargs}" ]; then
return 1
fi
# backward compatibility: $ipv6_enable
case $ipv6_enable in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
if checkyesno ipv6_gateway_enable; then
return 1
fi
case $1 in
bridge[0-9]*)
# No accept_rtadv by default on if_bridge(4)
# to avoid a conflict with the member
# interfaces.
return 1
;;
*)
return 0
;;
esac
;;
esac
_tmpargs=`_ifconfig_getargs $_if ipv6`
for _arg in $_tmpargs; do
case $_arg in
accept_rtadv)
return 0
;;
esac
done
# backward compatibility: $ipv6_ifconfig_IF
_tmpargs=`get_if_var $_if ipv6_ifconfig_IF`
for _arg in $_tmpargs; do
case $_arg in
accept_rtadv)
return 0
;;
esac
done
return 1
}
# ifexists if
# Returns 0 if the interface exists and 1 otherwise.
ifexists()
{
[ -z "$1" ] && return 1
${IFCONFIG_CMD} -n $1 > /dev/null 2>&1
}
# ipv4_up if
# add IPv4 addresses to the interface $if
ipv4_up()
{
local _if _ret
_if=$1
_ret=1
# Add 127.0.0.1/8 to lo0 unless otherwise specified.
if [ "${_if}" = "lo0" ]; then
ifconfig_args=`get_if_var ${_if} ifconfig_IF`
if [ -z "${ifconfig_args}" ]; then
${IFCONFIG_CMD} ${_if} inet 127.0.0.1/8 alias
fi
fi
ifalias ${_if} inet alias && _ret=0
return $_ret
}
# ipv6_up if
# add IPv6 addresses to the interface $if
ipv6_up()
{
local _if _ret
_if=$1
_ret=1
if ! ipv6if $_if; then
return 0
fi
ifalias ${_if} inet6 alias && _ret=0
ipv6_prefix_hostid_addr_common ${_if} alias && _ret=0
return $_ret
}
# ipv4_down if
# remove IPv4 addresses from the interface $if
ipv4_down()
{
local _if _ifs _ret inetList oldifs _inet
_if=$1
_ifs="^"
_ret=1
ifalias ${_if} inet -alias && _ret=0
inetList="`${IFCONFIG_CMD} ${_if} | grep 'inet ' | tr "\n\t" "$_ifs"`"
oldifs="$IFS"
IFS="$_ifs"
for _inet in $inetList ; do
# get rid of extraneous line
case $_inet in
inet\ *) ;;
*) continue ;;
esac
_inet=`expr "$_inet" : '.*\(inet \([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*'`
IFS="$oldifs"
${IFCONFIG_CMD} ${_if} ${_inet} delete
IFS="$_ifs"
_ret=0
done
IFS="$oldifs"
return $_ret
}
# ipv6_down if
# remove IPv6 addresses from the interface $if
ipv6_down()
{
local _if _ifs _ret inetList oldifs _inet6
_if=$1
_ifs="^"
_ret=1
if ! ipv6if $_if; then
return 0
fi
ipv6_accept_rtadv_down ${_if} && _ret=0
ipv6_prefix_hostid_addr_common ${_if} -alias && _ret=0
ifalias ${_if} inet6 -alias && _ret=0
inetList="`${IFCONFIG_CMD} ${_if} | grep 'inet6 ' | tr "\n\t" "$_ifs"`"
oldifs="$IFS"
IFS="$_ifs"
for _inet6 in $inetList ; do
# get rid of extraneous line
case $_inet6 in
inet6\ *) ;;
*) continue ;;
esac
_inet6=`expr "$_inet6" : '.*\(inet6 \([0-9a-f:]*\)\).*'`
IFS="$oldifs"
${IFCONFIG_CMD} ${_if} ${_inet6} -alias
IFS="$_ifs"
_ret=0
done
IFS="$oldifs"
return $_ret
}
# ifalias if af action
# Configure or remove aliases for network interface $if.
# It returns 0 if at least one alias was configured or
# removed, or 1 if there were none.
#
ifalias()
{
local _ret
_ret=1
afexists $2 || return $_ret
case "$2" in
inet|inet6|link|ether)
ifalias_af_common $1 $2 $3 && _ret=0
;;
esac
return $_ret
}
# ifalias_expand_addr af action addr
# Expand address range ("N-M") specification in addr.
# "addr" must not include an address-family keyword.
# The results will include an address-family keyword.
#
ifalias_expand_addr()
{
local _af _action
_af=$1
_action=$2
shift 2
afexists $_af || return
ifalias_expand_addr_$_af $_action $*
}
# ifalias_expand_addr_inet action addr
# Helper function for ifalias_expand_addr(). Handles IPv4.
#
ifalias_expand_addr_inet()
{
local _action _arg _cidr _cidr_addr _exargs
local _ipaddr _plen _range _iphead _iptail _iplow _iphigh _ipcount
local _retstr _c
_action=$1
_arg=$2
shift 2
_exargs=$*
_retstr=
case $_action:$_arg:$_exargs in
*:*--*) return ;; # invalid
tmp:*[0-9]-[0-9]*:*) # to be expanded
_action="alias"
;;
*:*[0-9]-[0-9]*:*) # to be expanded
;;
tmp:*:*netmask*) # already expanded w/ netmask option
echo ${_arg%/[0-9]*} $_exargs && return
;;
tmp:*:*) # already expanded w/o netmask option
echo $_arg $_exargs && return
;;
*:*:*netmask*) # already expanded w/ netmask option
echo inet ${_arg%/[0-9]*} $_exargs && return
;;
*:*:*) # already expanded w/o netmask option
echo inet $_arg $_exargs && return
;;
esac
for _cidr in $_arg; do
_ipaddr=${_cidr%%/*}
_plen=${_cidr##*/}
# When subnet prefix length is not specified, use /32.
case $_plen in
$_ipaddr) _plen=32 ;; # "/" character not found
esac
OIFS=$IFS
IFS=. set -- $_ipaddr
_range=
_iphead=
_iptail=
for _c in $@; do
case $_range:$_c in
:[0-9]*-[0-9]*)
_range=$_c
;;
:*)
_iphead="${_iphead}${_iphead:+.}${_c}"
;;
*:*)
_iptail="${_iptail}${_iptail:+.}${_c}"
;;
esac
done
IFS=$OIFS
_iplow=${_range%-*}
_iphigh=${_range#*-}
# clear netmask when removing aliases
if [ "$_action" = "-alias" ]; then
_plen=""
fi
_ipcount=$_iplow
while [ "$_ipcount" -le "$_iphigh" ]; do
_retstr="${_retstr} ${_iphead}${_iphead:+.}${_ipcount}${_iptail:+.}${_iptail}${_plen:+/}${_plen}"
if [ $_ipcount -gt $(($_iplow + $netif_ipexpand_max)) ]; then
warn "Range specification is too large (${_iphead}${_iphead:+.}${_iplow}${_iptail:+.}${_iptail}-${_iphead}${_iphead:+.}${_iphigh}${_iptail:+.}${_iptail}). ${_iphead}${_iphead:+.}${_iplow}${_iptail:+.}${_iptail}-${_iphead}${_iphead:+.}${_ipcount}${_iptail:+.}${_iptail} was processed. Increase \$netif_ipexpand_max in rc.conf."
break
else
_ipcount=$(($_ipcount + 1))
fi
# Forcibly set /32 for remaining aliases.
_plen=32
done
done
for _c in $_retstr; do
ifalias_expand_addr_inet $_action $_c $_exargs
done
}
# ifalias_expand_addr_inet6 action addr
# Helper function for ifalias_expand_addr(). Handles IPv6.
#
ifalias_expand_addr_inet6()
{
local _action _arg _cidr _cidr_addr _exargs
local _ipaddr _plen _ipleft _ipright _iplow _iphigh _ipcount
local _ipv4part
local _retstr _c
_action=$1
_arg=$2
shift 2
_exargs=$*
_retstr=
case $_action:$_arg:$_exargs in
*:*--*:*) return ;; # invalid
tmp:*[0-9a-zA-Z]-[0-9a-zA-Z]*:*)# to be expanded
_action="alias"
;;
*:*[0-9a-zA-Z]-[0-9a-zA-Z]*:*) # to be expanded
;;
tmp:*:*prefixlen*) # already expanded w/ prefixlen option
echo ${_arg%/[0-9]*} $_exargs && return
;;
tmp:*:*) # already expanded w/o prefixlen option
echo $_arg $_exargs && return
;;
*:*:*prefixlen*) # already expanded w/ prefixlen option
echo inet6 ${_arg%/[0-9]*} $_exargs && return
;;
*:*:*) # already expanded w/o prefixlen option
echo inet6 $_arg $_exargs && return
;;
esac
for _cidr in $_arg; do
_ipaddr="${_cidr%%/*}"
_plen="${_cidr##*/}"
case $_action:$_ipaddr:$_cidr in
-alias:*:*) unset _plen ;;
*:$_cidr:$_ipaddr) unset _plen ;;
esac
if [ "${_ipaddr%:*.*.*.*}" = "$_ipaddr" ]; then
# Handle !v4mapped && !v4compat addresses.
# The default prefix length is 64.
case $_ipaddr:$_cidr in
$_cidr:$_ipaddr) _plen="64" ;;
esac
_ipleft=${_ipaddr%-*}
_ipright=${_ipaddr#*-}
_iplow=${_ipleft##*:}
_iphigh=${_ipright%%:*}
_ipleft=${_ipleft%:*}
_ipright=${_ipright#*:}
if [ "$_iphigh" = "$_ipright" ]; then
unset _ipright
else
_ipright=:$_ipright
fi
if [ -n "$_iplow" -a -n "$_iphigh" ]; then
_iplow=$((0x$_iplow))
_iphigh=$((0x$_iphigh))
_ipcount=$_iplow
while [ $_ipcount -le $_iphigh ]; do
_r=`printf "%s:%04x%s%s" \
$_ipleft $_ipcount $_ipright \
${_plen:+/}$_plen`
_retstr="$_retstr $_r"
if [ $_ipcount -gt $(($_iplow + $netif_ipexpand_max)) ]
then
warn "Range specification is too large $(printf '(%s:%x%s-%s:%x%s)' "$_ipleft" "$_iplow" "$_ipright" "$_ipleft" "$_iphigh" "$_ipright"). $(printf '%s:%x%s-%s:%x%s' "$_ipleft" "$_iplow" "$_ipright" "$_ipleft" "$_ipcount" "$_ipright") was processed. Increase \$netif_ipexpand_max in rc.conf."
break
else
_ipcount=$(($_ipcount + 1))
fi
done
else
_retstr="${_ipaddr}${_plen:+/}${_plen}"
fi
for _c in $_retstr; do
ifalias_expand_addr_inet6 $_action $_c $_exargs
done
else
# v4mapped/v4compat should handle as an IPv4 alias
_ipv4part=${_ipaddr##*:}
# Adjust prefix length if any. If not, set the
# default prefix length as 32.
case $_ipaddr:$_cidr in
$_cidr:$_ipaddr) _plen=32 ;;
*) _plen=$(($_plen - 96)) ;;
esac
_retstr=`ifalias_expand_addr_inet \
tmp ${_ipv4part}${_plen:+/}${_plen}`
for _c in $_retstr; do
ifalias_expand_addr_inet $_action $_c $_exargs
done
fi
done
}
# ifalias_af_common_handler if af action args
# Helper function for ifalias_af_common().
#
ifalias_af_common_handler()
{
local _ret _if _af _action _args _c _tmpargs
_ret=1
_if=$1
_af=$2
_action=$3
shift 3
_args=$*
case $_args in
${_af}\ *) ;;
*) return ;;
esac
# link(ether) does not support address removal.
case $_af:$_action in
link:-alias|ether:-alias) return ;;
esac
_tmpargs=
for _c in $_args; do
case $_c in
${_af})
case $_tmpargs in
${_af}\ *[0-9a-fA-F]-*)
ifalias_af_common_handler $_if $_af $_action \
`ifalias_expand_addr $_af $_action ${_tmpargs#${_af}\ }`
;;
${_af}\ *)
${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
;;
esac
_tmpargs=$_af
;;
*)
_tmpargs="$_tmpargs $_c"
;;
esac
done
# Process the last component if any.
if [ -n "$_tmpargs}" ]; then
case $_tmpargs in
${_af}\ *[0-9a-fA-F]-*)
ifalias_af_common_handler $_if $_af $_action \
`ifalias_expand_addr $_af $_action ${_tmpargs#${_af}\ }`
;;
${_af}\ *)
${IFCONFIG_CMD} $_if $_tmpargs $_action && _ret=0
;;
esac
fi
return $_ret
}
# ifalias_af_common if af action
# Helper function for ifalias().
#
ifalias_af_common()
{
local _ret _if _af _action alias ifconfig_args _aliasn _c _tmpargs _iaf
local _vif _punct=".-/+"
_ret=1
_aliasn=
_if=$1
_af=$2
_action=$3
# Normalize $_if before using it in a pattern to list_vars()
ltr "$_if" "$_punct" "_" _vif
# ifconfig_IF_aliasN which starts with $_af
for alias in `list_vars ifconfig_${_vif}_alias[0-9]\* |
sort_lite -nk1.$((9+${#_vif}+7))`
do
eval ifconfig_args=\"\$$alias\"
_iaf=
case $ifconfig_args in
inet\ *) _iaf=inet ;;
inet6\ *) _iaf=inet6 ;;
link\ *) _iaf=link ;;
ether\ *) _iaf=ether ;;
esac
case ${_af}:${_action}:${_iaf}:"${ifconfig_args}" in
${_af}:*:${_af}:*)
_aliasn="$_aliasn $ifconfig_args"
;;
${_af}:*:"":"")
break
;;
inet:alias:"":*)
_aliasn="$_aliasn inet $ifconfig_args"
warn "\$${alias} needs leading" \
"\"inet\" keyword for an IPv4 address."
esac
done
# backward compatibility: ipv6_ifconfig_IF_aliasN.
case $_af in
inet6)
for alias in `list_vars ipv6_ifconfig_${_vif}_alias[0-9]\* |
sort_lite -nk1.$((14+${#_vif}+7))`
do
eval ifconfig_args=\"\$$alias\"
case ${_action}:"${ifconfig_args}" in
*:"")
break
;;
alias:*)
_aliasn="${_aliasn} inet6 ${ifconfig_args}"
warn "\$${alias} is obsolete. " \
"Use ifconfig_${_vif}_aliasN instead."
;;
esac
done
esac
# backward compatibility: ipv4_addrs_IF.
for _tmpargs in `get_if_var $_if ipv4_addrs_IF`; do
_aliasn="$_aliasn inet $_tmpargs"
done
# Handle ifconfig_IF_aliases, ifconfig_IF_aliasN, and the others.
_tmpargs=
for _c in `get_if_var $_if ifconfig_IF_aliases` $_aliasn; do
case $_c in
inet|inet6|link|ether)
case $_tmpargs in
${_af}\ *)
eval ifalias_af_common_handler $_if $_af $_action $_tmpargs && _ret=0
;;
esac
_tmpargs=$_c
;;
*)
_tmpargs="$_tmpargs $_c"
esac
done
# Process the last component
case $_tmpargs in
${_af}\ *)
ifalias_af_common_handler $_if $_af $_action $_tmpargs && _ret=0
;;
esac
return $_ret
}
# ipv6_prefix_hostid_addr_common if action
# Add or remove IPv6 prefix + hostid addr on the interface $if
#
ipv6_prefix_hostid_addr_common()
{
local _if _action prefix j
_if=$1
_action=$2
prefix=`get_if_var ${_if} ipv6_prefix_IF`
if [ -n "${prefix}" ]; then
for j in ${prefix}; do
# The default prefixlen is 64.
plen=${j#*/}
case $j:$plen in
$plen:$j) plen=64 ;;
*) j=${j%/*} ;;
esac
# Normalize the last part by removing ":"
j=${j%::*}
j=${j%:}
${IFCONFIG_CMD} ${_if} inet6 $j:: \
prefixlen $plen eui64 ${_action}
# if I am a router, add subnet router
# anycast address (RFC 2373).
if checkyesno ipv6_gateway_enable; then
${IFCONFIG_CMD} ${_if} inet6 $j:: \
prefixlen $plen ${_action} anycast
fi
done
fi
}
# ipv6_accept_rtadv_up if
# Enable accepting Router Advertisement and send Router
# Solicitation message
ipv6_accept_rtadv_up()
{
if ipv6_autoconfif $1; then
${IFCONFIG_CMD} $1 inet6 accept_rtadv up
if [ -x /sbin/rtsol ]; then
/sbin/rtsol ${rtsol_flags} $1
fi
return 0
fi
return 1
}
# ipv6_accept_rtadv_down if
# Disable accepting Router Advertisement
ipv6_accept_rtadv_down()
{
if ipv6_autoconfif $1; then
${IFCONFIG_CMD} $1 inet6 -accept_rtadv
fi
}
# ifscript_up if
# Evaluate a startup script for the $if interface.
# It returns 0 if a script was found and processed or
# 1 if no script was found.
#
ifscript_up()
{
if [ -r /etc/start_if.$1 ]; then
. /etc/start_if.$1
return 0
else
return 1
fi
}
# ifscript_down if
# Evaluate a shutdown script for the $if interface.
# It returns 0 if a script was found and processed or
# 1 if no script was found.
#
ifscript_down()
{
if [ -r /etc/stop_if.$1 ]; then
. /etc/stop_if.$1
return 0
else
return 1
fi
}
# wlan_up
# Create IEEE802.11 interfaces.
#
wlan_up()
{
local _list _iflist parent child_wlans child create_args debug_flags
_list=
_iflist=$*
# Parse wlans_$parent="$child ..."
for parent in `set | sed -nE 's/wlans_([a-z]+[0-9]+)=.*/\1/p'`; do
child_wlans=`get_if_var $parent wlans_IF`
for child in ${child_wlans}; do
create_args="wlandev $parent `get_if_var $child create_args_IF`"
debug_flags="`get_if_var $child wlandebug_IF`"
case $_iflist in
""|$child|$child\ *|*\ $child\ *|*\ $child) ;;
*) continue ;;
esac
# Skip if ${child} already exists.
if ${IFCONFIG_CMD} $child > /dev/null 2>&1; then
continue
fi
if expr $child : 'wlan[0-9][0-9]*$' >/dev/null 2>&1; then
${IFCONFIG_CMD} $child create ${create_args} && cfg=0
else
${IFCONFIG_CMD} wlan create ${create_args} name $child && cfg=0
fi
if [ $? -eq 0 ]; then
_list="$_list $child"
fi
if [ -n "${debug_flags}" ]; then
wlandebug -i $child ${debug_flags}
fi
done
done
if [ -n "${_list# }" ]; then
echo "Created wlan(4) interfaces: ${_list# }."
fi
debug "Created wlan(4)s: ${_list# }"
}
# wlan_down
# Destroy IEEE802.11 interfaces.
#
wlan_down()
{
local _list _iflist parent child_wlans child
_list=
_iflist=$*
# Parse wlans_$parent="$child ..."
for parent in `set | sed -nE 's/wlans_([a-z]+[0-9]+)=.*/\1/p'`; do
child_wlans=`get_if_var $parent wlans_IF`
for child in ${child_wlans}; do
case $_iflist in
""|$child|$child\ *|*\ $child\ *|*\ $child) ;;
*) continue ;;
esac
# Skip if ${child} doesn't exists.
if ! ${IFCONFIG_CMD} $child > /dev/null 2>&1; then
continue
fi
${IFCONFIG_CMD} -n ${child} destroy
if [ $? -eq 0 ]; then
_list="$_list $child"
fi
done
done
if [ -n "${_list# }" ]; then
echo "Destroyed wlan(4) interfaces: ${_list# }."
fi
debug "Destroyed wlan(4)s: ${_list# }"
}
# clone_up
# Create cloneable interfaces.
#
clone_up()
{
local _list ifn ifopt _iflist _inet6 _n tmpargs
_list=
_iflist=$*
# create_args_IF
for ifn in ${cloned_interfaces}; do
# Parse ifn:ifopt.
OIFS=$IFS; IFS=:; set -- $ifn; ifn=$1; ifopt=$2; IFS=$OIFS
case $_iflist in
""|$ifn|$ifn\ *|*\ $ifn\ *|*\ $ifn) ;;
*) continue ;;
esac
case $ifn in
epair[0-9]*)
# epair(4) uses epair[0-9] for creation and
# epair[0-9][ab] for configuration.
#
# Skip if ${ifn}a or ${ifn}b already exist.
if ${IFCONFIG_CMD} ${ifn}a > /dev/null 2>&1; then
continue
elif ${IFCONFIG_CMD} ${ifn}b > /dev/null 2>&1; then
continue
fi
${IFCONFIG_CMD} ${ifn} create \
`get_if_var ${ifn} create_args_IF`
if [ $? -eq 0 ]; then
_list="$_list ${ifn}a ${ifn}b"
fi
;;
*)
# Skip if ${ifn} already exists.
if ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then
continue
fi
${IFCONFIG_CMD} ${ifn} create \
`get_if_var ${ifn} create_args_IF`
if [ $? -eq 0 ]; then
_list="$_list $ifn"
fi
esac
done
if [ -n "$gif_interfaces" ]; then
warn "\$gif_interfaces is obsolete. Use \$cloned_interfaces instead."
fi
for ifn in ${gif_interfaces}; do
# Parse ifn:ifopt.
OIFS=$IFS; IFS=:; set -- $ifn; ifn=$1; ifopt=$2; IFS=$OIFS
case $_iflist in
""|$ifn|$ifn\ *|*\ $ifn\ *|*\ $ifn) ;;
*) continue ;;
esac
# Skip if ifn already exists.
if ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then
continue
fi
case $ifn in
gif[0-9]*)
${IFCONFIG_CMD} $ifn create
;;
*)
_n=$(${IFCONFIG_CMD} gif create)
${IFCONFIG_CMD} $_n name $ifn
;;
esac
if [ $? -eq 0 ]; then
_list="$_list $ifn"
tmpargs=$(get_if_var $ifn gifconfig_IF)
_inet6=''
case "$tmpargs" in
'')
;;
inet6[[:space:]]*)
tmpargs=${tmpargs#inet6}
_inet6=inet6
# FALLTHROUGH
;&
*)
${IFCONFIG_CMD} $ifn $_inet6 tunnel $tmpargs
;;
esac
fi
done
if [ -n "${_list# }" ]; then
echo "Created clone interfaces: ${_list# }."
fi
debug "Cloned: ${_list# }"
}
# clone_down
# Destroy cloned interfaces. Destroyed interfaces are echoed to
# standard output.
#
clone_down()
{
local _list ifn _difn ifopt _iflist _sticky
_list=
_iflist=$*
: ${cloned_interfaces_sticky:=NO}
if checkyesno cloned_interfaces_sticky; then
_sticky=1
else
_sticky=0
fi
for ifn in ${cloned_interfaces} ${gif_interfaces}; do
# Parse ifn:ifopt.
OIFS=$IFS; IFS=:; set -- $ifn; ifn=$1; ifopt=$2; IFS=$OIFS
case $ifopt:$_sticky in
sticky:*) continue ;; # :sticky => not destroy
nosticky:*) ;; # :nosticky => destroy
*:1) continue ;; # global sticky knob == 1
esac
case $_iflist in
""|$ifn|$ifn\ *|*\ $ifn\ *|*\ $ifn) ;;
*) continue ;;
esac
case $ifn in
epair[0-9]*)
# Note: epair(4) uses epair[0-9] for removal and
# epair[0-9][ab] for configuration.
#
# Skip if both of ${ifn}a and ${ifn}b do not exist.
if ${IFCONFIG_CMD} ${ifn}a > /dev/null 2>&1; then
_difn=${ifn}a
elif ${IFCONFIG_CMD} ${ifn}b > /dev/null 2>&1; then
_difn=${ifn}b
else
continue
fi
${IFCONFIG_CMD} -n $_difn destroy
if [ $? -eq 0 ]; then
_list="$_list ${ifn}a ${ifn}b"
fi
;;
*)
# Skip if ifn does not exist.
if ! ${IFCONFIG_CMD} $ifn > /dev/null 2>&1; then
continue
fi
${IFCONFIG_CMD} -n ${ifn} destroy
if [ $? -eq 0 ]; then
_list="$_list $ifn"
fi
;;
esac
done
if [ -n "${_list# }" ]; then
echo "Destroyed clone interfaces: ${_list# }."
fi
debug "Destroyed clones: ${_list# }"
}
# childif_create
# Create and configure child interfaces. Return 0 if child
# interfaces are created.
#
childif_create()
{
local cfg child child_vlans create_args debug_flags ifn i
cfg=1
ifn=$1
# Create vlan interfaces
child_vlans=`get_if_var $ifn vlans_IF`
if [ -n "${child_vlans}" ]; then
load_kld if_vlan
fi
for child in ${child_vlans}; do
if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
child="${ifn}.${child}"
create_args=`get_if_var $child create_args_IF`
${IFCONFIG_CMD} $child create ${create_args} && cfg=0
else
create_args="vlandev $ifn `get_if_var $child create_args_IF`"
if expr $child : 'vlan[0-9][0-9]*$' >/dev/null 2>&1; then
${IFCONFIG_CMD} $child create ${create_args} && cfg=0
else
i=`${IFCONFIG_CMD} vlan create ${create_args}`
${IFCONFIG_CMD} $i name $child && cfg=0
fi
fi
if autoif $child; then
ifn_start $child
fi
done
return ${cfg}
}
# childif_destroy
# Destroy child interfaces.
#
childif_destroy()
{
local cfg child child_vlans ifn
cfg=1
child_vlans=`get_if_var $ifn vlans_IF`
for child in ${child_vlans}; do
if expr $child : '[1-9][0-9]*$' >/dev/null 2>&1; then
child="${ifn}.${child}"
fi
if ! ifexists $child; then
continue
fi
${IFCONFIG_CMD} -n $child destroy && cfg=0
done
return ${cfg}
}
# ng_mkpeer
# Create netgraph nodes.
#
ng_mkpeer()
{
ngctl -f - 2> /dev/null <<EOF
mkpeer $*
msg dummy nodeinfo
EOF
}
# ng_create_one
# Create netgraph nodes.
#
ng_create_one()
{
local t
ng_mkpeer $* | while read line; do
t=`expr "${line}" : '.* name="\([a-z]*[0-9]*\)" .*'`
if [ -n "${t}" ]; then
echo ${t}
return
fi
done
}
# ifnet_rename [ifname]
# Rename interfaces if ifconfig_IF_name is defined.
#
ifnet_rename()
{
local _if _ifname
# ifconfig_IF_name
for _if in ${*:-$(${IFCONFIG_CMD} -l)}; do
_ifname=`get_if_var $_if ifconfig_IF_name`
if [ ! -z "$_ifname" ]; then
${IFCONFIG_CMD} $_if name $_ifname
fi
done
return 0
}
# list_net_interfaces type
# List all network interfaces. The type of interface returned
# can be controlled by the type argument. The type
# argument can be any of the following:
# nodhcp - all interfaces, excluding DHCP configured interfaces
# dhcp - list only DHCP configured interfaces
# noautoconf - all interfaces, excluding IPv6 Stateless
# Address Autoconf configured interfaces
# autoconf - list only IPv6 Stateless Address Autoconf
# configured interfaces
# If no argument is specified all network interfaces are output.
# Note that the list will include cloned interfaces if applicable.
# Cloned interfaces must already exist to have a chance to appear
# in the list if ${network_interfaces} is set to `auto'.
#
list_net_interfaces()
{
local type _tmplist _list _autolist _lo _if
type=$1
# Get a list of ALL the interfaces and make lo0 first if it's there.
#
_tmplist=
case ${network_interfaces} in
[Aa][Uu][Tt][Oo])
_autolist="`${IFCONFIG_CMD} -l`"
_lo=
for _if in ${_autolist} ; do
if autoif $_if; then
if [ "$_if" = "lo0" ]; then
_lo="lo0 "
else
_tmplist="${_tmplist} ${_if}"
fi
fi
done
_tmplist="${_lo}${_tmplist# }"
;;
*)
for _if in ${network_interfaces} ${cloned_interfaces}; do
# epair(4) uses epair[0-9] for creation and
# epair[0-9][ab] for configuration.
case $_if in
epair[0-9]*)
_tmplist="$_tmplist ${_if}a ${_if}b"
;;
*)
_tmplist="$_tmplist $_if"
;;
esac
done
#
# lo0 is effectively mandatory, so help prevent foot-shooting
#
case "$_tmplist" in
lo0|'lo0 '*|*' lo0'|*' lo0 '*)
# This is fine, do nothing
_tmplist="${_tmplist# }"
;;
*)
_tmplist="lo0 ${_tmplist# }"
;;
esac
;;
esac
_list=
case "$type" in
nodhcp)
for _if in ${_tmplist} ; do
if ! dhcpif $_if && \
[ -n "`_ifconfig_getargs $_if`" ]; then
_list="${_list# } ${_if}"
fi
done
;;
dhcp)
for _if in ${_tmplist} ; do
if dhcpif $_if; then
_list="${_list# } ${_if}"
fi
done
;;
noautoconf)
for _if in ${_tmplist} ; do
if ! ipv6_autoconfif $_if && \
[ -n "`_ifconfig_getargs $_if ipv6`" ]; then
_list="${_list# } ${_if}"
fi
done
;;
autoconf)
for _if in ${_tmplist} ; do
if ipv6_autoconfif $_if; then
_list="${_list# } ${_if}"
fi
done
;;
*)
_list=${_tmplist}
;;
esac
echo $_list
return 0
}
# get_default_if -address_family
# Get the interface of the default route for the given address family.
# The -address_family argument must be suitable passing to route(8).
#
get_default_if()
{
local routeget oldifs defif line
defif=
oldifs="$IFS"
IFS="
"
for line in `route -n get $1 default 2>/dev/null`; do
case $line in
*interface:*)
defif=${line##*: }
;;
esac
done
IFS=${oldifs}
echo $defif
}
# hexdigit arg
# Echo decimal number $arg (single digit) in hexadecimal format.
hexdigit()
{
printf '%x\n' "$1"
}
# hexprint arg
# Echo decimal number $arg (multiple digits) in hexadecimal format.
hexprint()
{
printf '%x\n' "$1"
}
is_wired_interface()
{
local media
case `${IFCONFIG_CMD} $1 2>/dev/null` in
*media:?Ethernet*) media=Ethernet ;;
esac
test "$media" = "Ethernet"
}
# network6_getladdr if [flag]
# Echo link-local address from $if if any.
# If flag is defined, tentative ones will be excluded.
network6_getladdr()
{
local _if _flag proto addr rest
_if=$1
_flag=$2
${IFCONFIG_CMD} $_if 2>/dev/null | while read proto addr rest; do
case "${proto}/${addr}/${_flag}/${rest}" in
inet6/fe80::*//*)
echo ${addr}
;;
inet6/fe80:://*tentative*) # w/o flag
sleep `${SYSCTL_N} net.inet6.ip6.dad_count`
network6_getladdr $_if $_flags
;;
inet6/fe80::/*/*tentative*) # w/ flag
echo ${addr}
;;
*)
continue
;;
esac
return
done
}