1df930be7Sderaadt#!/bin/sh - 2df930be7Sderaadt# 3*ac570418Skn# $OpenBSD: netstart,v 1.228 2022/11/05 12:03:58 kn Exp $ 45116749bSrpe 55116749bSrpe# Turn off Strict Bourne shell mode. 65116749bSrpeset +o sh 78fc5e153Smillert 82511c2f6Srpe# Show usage of the netstart script and exit. 92511c2f6Srpeusage() { 10*ac570418Skn print -u2 "usage: sh $0 [-n] [interface ...]" 112511c2f6Srpe exit 1 122511c2f6Srpe} 132511c2f6Srpe 145176db26Skn# Test the first argument against the remaining ones, return success on a match. 155176db26Sknisin() { 165176db26Skn local _a=$1 _b 175176db26Skn 185176db26Skn shift 195176db26Skn for _b; do 205176db26Skn [[ $_a == "$_b" ]] && return 0 215176db26Skn done 225176db26Skn return 1 235176db26Skn} 245176db26Skn 259ed80bb0Skn# Echo file $1 to stdout. Skip comment lines. Strip leading and trailing 26952fbff6Srpe# whitespace if IFS is set. 27e57a083bSrpe# Usage: stripcom /path/to/file 288fc5e153Smillertstripcom() { 29e57a083bSrpe local _file=$1 _line 30e57a083bSrpe 31e57a083bSrpe [[ -f $_file ]] || return 32e57a083bSrpe 33e57a083bSrpe while read _line; do 34e57a083bSrpe [[ -n ${_line%%#*} ]] && print -r -- "$_line" 35e57a083bSrpe done <$_file 368fc5e153Smillert} 3704e0ac27Smillert 388222f376Srpe# Parse and "unpack" a hostname.if(5) line given as positional parameters. 398222f376Srpe# Fill the _cmds array with the resulting interface configuration commands. 408222f376Srpeparse_hn_line() { 41a872b7aeSkrw local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr _dhcp _i 428222f376Srpe set -A _c -- "$@" 438222f376Srpe set -o noglob 448222f376Srpe 458222f376Srpe case ${_c[_af]} in 468222f376Srpe ''|*([[:blank:]])'#'*) 478222f376Srpe return 488222f376Srpe ;; 498222f376Srpe inet) ((${#_c[*]} > 1)) || return 5039d47095Sflorian if [[ ${_c[_name]} == autoconf ]]; then 5139d47095Sflorian _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 52816e0240Ssthen V4_AUTOCONF=true 5339d47095Sflorian return 5439d47095Sflorian fi 558222f376Srpe [[ ${_c[_name]} == alias ]] && _mask=3 _bc=4 568222f376Srpe [[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}" 578222f376Srpe if [[ -n ${_c[_bc]} ]]; then 588222f376Srpe _c[_bc]="broadcast ${_c[_bc]}" 598222f376Srpe [[ ${_c[_bc]} == *NONE ]] && _c[_bc]= 608222f376Srpe fi 618222f376Srpe _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 628222f376Srpe ;; 638222f376Srpe inet6) ((${#_c[*]} > 1)) || return 648222f376Srpe if [[ ${_c[_name]} == autoconf ]]; then 658222f376Srpe _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 660113d951Srpe V6_AUTOCONF=true 678222f376Srpe return 688222f376Srpe fi 698222f376Srpe [[ ${_c[_name]} == alias ]] && _prefix=3 708222f376Srpe [[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}" 718222f376Srpe _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 728222f376Srpe ;; 738222f376Srpe dest) ((${#_c[*]} == 2)) && _daddr=${_c[1]} || return 748222f376Srpe _prev=$((${#_cmds[*]} - 1)) 758222f376Srpe ((_prev >= 0)) || return 768222f376Srpe set -A _c -- ${_cmds[_prev]} 778222f376Srpe _name=3 788222f376Srpe [[ ${_c[_name]} == alias ]] && _name=4 798222f376Srpe _c[_name]="${_c[_name]} $_daddr" 808222f376Srpe _cmds[$_prev]="${_c[@]}" 818222f376Srpe ;; 822555728fSflorian dhcp) _cmds[${#_cmds[*]}]="ifconfig $_if inet autoconf" 832555728fSflorian V4_AUTOCONF=true 848222f376Srpe ;; 858222f376Srpe '!'*) _cmd=$(print -- "${_c[@]}" | sed 's/\$if/'$_if'/g') 868222f376Srpe _cmds[${#_cmds[*]}]="${_cmd#!}" 878222f376Srpe ;; 888222f376Srpe *) _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 898222f376Srpe ;; 908222f376Srpe esac 918222f376Srpe unset _c 9279699d09Srpe set +o noglob 938222f376Srpe} 948222f376Srpe 95d7d55851Srpe# Create interface $1 if it does not yet exist. 9680771ddaSrpe# Usage: ifcreate if1 97b6107460Sdlgifcreate() { 98b6107460Sdlg local _if=$1 99b6107460Sdlg 10009ec2297Sbluhm if $PRINT_ONLY; then 10109ec2297Sbluhm print -r -- "{ ifconfig $_if || ifconfig $_if create; }" 10209ec2297Sbluhm else 103d7d55851Srpe { ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1 10409ec2297Sbluhm fi 105b6107460Sdlg} 106b6107460Sdlg 107d7d55851Srpe# Create interfaces for network pseudo-devices referred to by hostname.if files. 1085176db26Skn# Optionally, limit creation to given interfaces only. 1095176db26Skn# Usage: vifscreate [if ...] 110b6107460Sdlgvifscreate() { 111d7d55851Srpe local _vif _hn _if 112b6107460Sdlg 113d7d55851Srpe for _vif in $(ifconfig -C); do 114375c217eSrpe for _hn in /etc/hostname.${_vif}+([[:digit:]]); do 115b6107460Sdlg [[ -f $_hn ]] || continue 116b6107460Sdlg _if=${_hn#/etc/hostname.} 117b6107460Sdlg 11837db1d1cSbluhm # loopback for routing domain is created by kernel 11937db1d1cSbluhm [[ -n ${_if##lo[1-9]*} ]] || continue 12037db1d1cSbluhm 1215176db26Skn if (($# > 0)) && ! isin $_if "$@"; then 1225176db26Skn continue 1235176db26Skn fi 1245176db26Skn 125375c217eSrpe if ! ifcreate $_if; then 1267f358361Srpe print -u2 "${0##*/}: create for '$_if' failed." 127375c217eSrpe fi 128b6107460Sdlg done 129b6107460Sdlg done 130b6107460Sdlg} 131b6107460Sdlg 132e57a083bSrpe# Start a single interface. 133e57a083bSrpe# Usage: ifstart if1 134dfc209d0Smiodifstart() { 13578b420f3Stb local _if=$1 _hn=/etc/hostname.$1 _cmds _i=0 _line _stat 1368222f376Srpe set -A _cmds 13724811c97Srpe 138dfc209d0Smiod # Interface names must be alphanumeric only. We check to avoid 139dfc209d0Smiod # configuring backup or temp files, and to catch the "*" case. 1408222f376Srpe [[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return 141dfc209d0Smiod 142b7a96a2bSrpe if [[ ! -f $_hn ]]; then 1437f358361Srpe print -u2 "${0##*/}: $_hn: No such file or directory." 14449352c7bStodd return 14549352c7bStodd fi 1468222f376Srpe 147300d0407Srpe # Not using stat(1), we can't rely on having /usr yet. 148b7a96a2bSrpe set -A _stat -- $(ls -nL $_hn) 1491a0aef30Srpe if [[ "${_stat[0]}${_stat[2]}${_stat[3]}" != *---00 ]]; then 1507f358361Srpe print -u2 "WARNING: $_hn is insecure, fixing permissions." 151b7a96a2bSrpe chmod -LR o-rwx $_hn 152b7a96a2bSrpe chown -LR root:wheel $_hn 153bc53e65aSderaadt fi 154dfc209d0Smiod 1558222f376Srpe # Check for ifconfig'able interface, except if -n option is specified. 156b6107460Sdlg ifcreate $_if || return 1578222f376Srpe 1588222f376Srpe # Parse the hostname.if(5) file and fill _cmds array with interface 1598222f376Srpe # configuration commands. 1608222f376Srpe set -o noglob 16188c728ccSkn while IFS= read -- _line; do 1628222f376Srpe parse_hn_line $_line 163b7a96a2bSrpe done <$_hn 1648222f376Srpe 1658222f376Srpe # Apply the interface configuration commands stored in _cmds array. 1668222f376Srpe while ((_i < ${#_cmds[*]})); do 1678222f376Srpe if $PRINT_ONLY; then 1688222f376Srpe print -r -- "${_cmds[_i]}" 1698222f376Srpe else 1708222f376Srpe eval "${_cmds[_i]}" 1718222f376Srpe fi 1728222f376Srpe ((_i++)) 1738222f376Srpe done 1748222f376Srpe unset _cmds 17579699d09Srpe set +o noglob 176dfc209d0Smiod} 177dfc209d0Smiod 178dde523b1Srpe# Start multiple interfaces by driver name. 179dde523b1Srpe# Usage: ifmstart "em iwm" "trunk vlan" 180300d0407Srpe# Start "$1" interfaces in order or all interfaces if empty. 181dde523b1Srpe# Don't start "$2" interfaces. "$2" is optional. 1829ac6b043Stoddifmstart() { 183dde523b1Srpe local _sifs=$1 _xifs=$2 _hn _if _sif _xif 184dde523b1Srpe 185dde523b1Srpe for _sif in ${_sifs:-ALL}; do 186375c217eSrpe for _hn in /etc/hostname.+([[:alpha:]])+([[:digit:]]); do 187375c217eSrpe [[ -f $_hn ]] || continue 188dde523b1Srpe _if=${_hn#/etc/hostname.} 1899ac6b043Stodd 190300d0407Srpe # Skip unwanted ifs. 191dde523b1Srpe for _xif in $_xifs; do 192dde523b1Srpe [[ $_xif == ${_if%%[0-9]*} ]] && continue 2 1939ac6b043Stodd done 1949ac6b043Stodd 195300d0407Srpe # Start wanted ifs. 196dde523b1Srpe [[ $_sif == @(ALL|${_if%%[0-9]*}) ]] && ifstart $_if 1979ac6b043Stodd done 1989ac6b043Stodd done 1999ac6b043Stodd} 2009ac6b043Stodd 20180771ddaSrpe# Parse /etc/mygate and add default routes for IPv4 and IPv6. 20205102370Smpi# Usage: defaultroute 20305102370Smpidefaultroute() { 2040df984aaStb local _cmd _v4set=false _v6set=false; 2054f9a4669Sderaadt set -o noglob 206e9c30f15Stb 2074f9a4669Sderaadt stripcom /etc/mygate | 2080113d951Srpe while read gw; do 2094f9a4669Sderaadt case $gw in 2104f9a4669Sderaadt '!'*) 2110df984aaStb _cmd=$(print -- "$gw") 2124f9a4669Sderaadt _cmd="${_cmd#!}" 2134f9a4669Sderaadt ;; 2140df984aaStb !(*:*)) 215816e0240Ssthen ($_v4set || $V4_AUTOCONF) && continue 216e9c30f15Stb _cmd="route -qn add -host default $gw" 2170df984aaStb _v4set=true 2180df984aaStb ;; 2190df984aaStb *) 2200df984aaStb ($_v6set || $V6_AUTOCONF) && continue 221e9c30f15Stb _cmd="route -qn add -host -inet6 default $gw" 2220df984aaStb _v6set=true 2234f9a4669Sderaadt ;; 2244f9a4669Sderaadt esac 225e9c30f15Stb if $PRINT_ONLY; then 2264f9a4669Sderaadt print -r -- "$_cmd" 227e9c30f15Stb else 2284f9a4669Sderaadt $_cmd 229e9c30f15Stb fi 23005102370Smpi done 2314f9a4669Sderaadt set +o noglob 23205102370Smpi} 23305102370Smpi 23409ec2297Sbluhm# add all the routes needed for IPv6 23509ec2297Sbluhmip6routes() { 23609ec2297Sbluhm local _i=0 23709ec2297Sbluhm set -A _cmds 23809ec2297Sbluhm 23909ec2297Sbluhm # Disallow link-local unicast dest without outgoing scope identifiers. 24009ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 fe80:: -prefixlen 10 ::1 -reject" 24109ec2297Sbluhm 24209ec2297Sbluhm # Disallow site-local unicast dest without outgoing scope identifiers. 24309ec2297Sbluhm # If you configure site-locals without scope id (it is permissible 24409ec2297Sbluhm # config for routers that are not on scope boundary), you may want 24509ec2297Sbluhm # to comment the line out. 24609ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 fec0:: -prefixlen 10 ::1 -reject" 24709ec2297Sbluhm 24809ec2297Sbluhm # Disallow "internal" addresses to appear on the wire. 24909ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject" 25009ec2297Sbluhm 25109ec2297Sbluhm # Disallow packets to malicious 6to4 prefix. 25209ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:e000:: -prefixlen 20 ::1 -reject" 25309ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject" 25409ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:0000:: -prefixlen 24 ::1 -reject" 25509ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject" 25609ec2297Sbluhm 25709ec2297Sbluhm # Disallow packets without scope identifier. 25809ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ff01:: -prefixlen 16 ::1 -reject" 25909ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ff02:: -prefixlen 16 ::1 -reject" 26009ec2297Sbluhm 26109ec2297Sbluhm # Completely disallow packets to IPv4 compatible prefix. 26209ec2297Sbluhm # 26309ec2297Sbluhm # This may conflict with RFC1933 under following circumstances: 26409ec2297Sbluhm # (1) An IPv6-only KAME node tries to originate packets to IPv4 26509ec2297Sbluhm # compatible destination. The KAME node has no IPv4 compatible 26609ec2297Sbluhm # support. Under RFC1933, it should transmit native IPv6 26709ec2297Sbluhm # packets toward IPv4 compatible destination, hoping it would 26809ec2297Sbluhm # reach a router that forwards the packet toward auto-tunnel 26909ec2297Sbluhm # interface. 27009ec2297Sbluhm # (2) An IPv6-only node originates a packet to an IPv4 compatible 27109ec2297Sbluhm # destination. A KAME node is acting as an IPv6 router, and 27209ec2297Sbluhm # asked to forward it. 27309ec2297Sbluhm # 27409ec2297Sbluhm # Due to rare use of IPv4 compatible addresses, and security issues 27509ec2297Sbluhm # with it, we disable it by default. 27609ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject" 27709ec2297Sbluhm 27809ec2297Sbluhm # Apply the interface configuration commands stored in _cmds array. 27909ec2297Sbluhm _i=0 28009ec2297Sbluhm while ((_i < ${#_cmds[*]})); do 28109ec2297Sbluhm if $PRINT_ONLY; then 28209ec2297Sbluhm print -r -- "${_cmds[_i]}" 28309ec2297Sbluhm else 28409ec2297Sbluhm eval "${_cmds[_i]}" 28509ec2297Sbluhm fi 28609ec2297Sbluhm ((_i++)) 28709ec2297Sbluhm done 28809ec2297Sbluhm unset _cmds 28909ec2297Sbluhm} 29009ec2297Sbluhm 291f96b97a3Sflorian# wait for autoconf interfaces 292f96b97a3Sflorianwait_autoconf_default() { 2937c2e177aSkn local _count=0 2947c2e177aSkn 295f96b97a3Sflorian if ifconfig | grep -q ': flags=.*<.*AUTOCONF.*>'; then 2967c2e177aSkn while ((_count++ < 20)); do 297f96b97a3Sflorian route -n show | grep -q ^default && break 298f96b97a3Sflorian sleep .5 299f96b97a3Sflorian done 300f96b97a3Sflorian fi 301f96b97a3Sflorian} 302f96b97a3Sflorian 3037c2e177aSkn# Ensure IPv6 Duplicate Address Detection (DAD) is completed. 3047c2e177aSknwait_dad() { 3057c2e177aSkn local _count=0 3067c2e177aSkn 3077c2e177aSkn while ((_count++ < 10 && $(sysctl -n net.inet6.ip6.dad_pending) != 0)); do 3087c2e177aSkn sleep 1 3097c2e177aSkn done 3107c2e177aSkn} 3117c2e177aSkn 31289f9479fStb# Make sure the invoking user has the right privileges. Check for presence of 31389f9479fStb# id(1) to avoid problems with diskless setups. 31489f9479fStbif [[ -x /usr/bin/id ]] && (($(id -u) != 0)); then 31589f9479fStb echo "${0##*/}: need root privileges" 31689f9479fStb exit 1 31789f9479fStbfi 31889f9479fStb 319a035c1adSrpe# Get network related vars from rc.conf using the parsing routine from rc.subr. 320a035c1adSrpeFUNCS_ONLY=1 . /etc/rc.d/rc.subr 3218799e9c8Srobert_rc_parse_conf 3220dc37902Sangelos 3238222f376SrpePRINT_ONLY=false 324816e0240SsthenV4_AUTOCONF=false 3250113d951SrpeV6_AUTOCONF=false 326751bfb17SknIP6KERNEL=false 3270113d951Srpe 3288222f376Srpewhile getopts ":n" opt; do 3298222f376Srpe case $opt in 3308222f376Srpe n) PRINT_ONLY=true;; 3312511c2f6Srpe *) usage;; 3328222f376Srpe esac 3338222f376Srpedone 3348222f376Srpeshift $((OPTIND-1)) 3358222f376Srpe 336751bfb17Sknif ifconfig lo0 inet6 >/dev/null 2>&1; then 337751bfb17Skn IP6KERNEL=true 338751bfb17Sknfi 339751bfb17Skn 34080771ddaSrpe# Load key material for the generation of IPv6 Semantically Opaque Interface 341ab2ae2f8Skn# Identifiers (SOII) used for SLAAC addresses. 342577f3075Sknif $IP6KERNEL && ! $PRINT_ONLY; then 343577f3075Skn [[ -f /etc/soii.key ]] && 34481acd49bSflorian sysctl -q "net.inet6.ip6.soiikey=$(</etc/soii.key)" 345577f3075Sknfi 34681acd49bSflorian 347dfc209d0Smiod# If we were invoked with a list of interface names, just reconfigure these 34805102370Smpi# interfaces (or bridges), add default routes and return. 3495176db26Skn# Create virtual interfaces upfront to make ifconfig commands depending on 3505176db26Skn# other interfaces, e.g. "patch", work regardless of in which order interface 3515176db26Skn# names were specified. 3520a295e45Srpeif (($# > 0)); then 3535176db26Skn vifscreate "$@" 3540a295e45Srpe for _if; do ifstart $_if; done 35505102370Smpi defaultroute 356dfc209d0Smiod return 357dfc209d0Smiodfi 358dfc209d0Smiod 359dfc209d0Smiod# Otherwise, process with the complete network initialization. 360dfc209d0Smiod 3614fbd02fcSsobrado# Set the address for the loopback interface. Bringing the interface up, 3624fbd02fcSsobrado# automatically invokes the IPv6 address ::1. 36309ec2297Sbluhmif $PRINT_ONLY; then 36409ec2297Sbluhm print -r -- "ifconfig lo0 inet 127.0.0.1/8" 36509ec2297Sbluhmelse 366d216f73bShenning ifconfig lo0 inet 127.0.0.1/8 36709ec2297Sbluhmfi 36898c28033Skstailey 3691943041aSknif $IP6KERNEL && ! $PRINT_ONLY; then 3701943041aSkn ip6routes 3711943041aSknfi 3721943041aSkn 37380771ddaSrpe# Create all the pseudo interfaces up front. 374b6107460Sdlgvifscreate 375df930be7Sderaadt 3769ac6b043Stodd# Configure all the non-loopback interfaces which we know about, but 3774eb97611Sderaadt# do not start interfaces which must be delayed. Refer to hostname.if(5) 378eba597afSdlgifmstart "" "aggr trunk svlan vlan carp pppoe tun tap gif etherip gre egre nvgre eoip vxlan pflow wg" 37982c17b75Sitojun 380774508f4Sdlg# The aggr and trunk interfaces need to come up first in this list. 381f45bd3bdSmpf# The (s)vlan interfaces need to come up after trunk. 3824bdcd471Sbrad# Configure all the carp interfaces which we know about before default route. 383774508f4Sdlgifmstart "aggr trunk svlan vlan carp pppoe" 3844bdcd471Sbrad 38580771ddaSrpe# Set default routes for IPv4 and IPv6. 38605102370Smpidefaultroute 387cf3860a5Sderaadt 388745634aaSniklas# Multicast routing. 3896e0f151eSsthenif [[ $multicast != YES ]]; then 39009ec2297Sbluhm if $PRINT_ONLY; then 39109ec2297Sbluhm print -r -- "route -qn delete 224.0.0.0/4" 39209ec2297Sbluhm print -r -- "route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject" 39309ec2297Sbluhm else 39409ec2297Sbluhm route -qn delete 224.0.0.0/4 39509ec2297Sbluhm route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject 39609ec2297Sbluhm fi 3976e0f151eSsthenfi 398dfc209d0Smiod 399300d0407Srpe# Reject 127/8 other than 127.0.0.1. 40009ec2297Sbluhmif $PRINT_ONLY; then 40109ec2297Sbluhm print -r -- "route -qn add -net 127 127.0.0.1 -reject" 40209ec2297Sbluhmelse 40309ec2297Sbluhm route -qn add -net 127 127.0.0.1 -reject 40409ec2297Sbluhmfi 4058f8fdbefSderaadt 406f96b97a3Sflorian# If interface autoconf exists, pause a little for at least one default route 40791d26677Skn$PRINT_ONLY || wait_autoconf_default 408f96b97a3Sflorian 409b6107460Sdlg# Configure interfaces that rely on routing 410eba597afSdlgifmstart "tun tap gif etherip gre egre nvgre eoip vxlan pflow wg" 411b6107460Sdlg 4127c2e177aSknif $IP6KERNEL && ! $PRINT_ONLY; then 4137c2e177aSkn wait_dad 414089287c3Sdavidfi 415