1df930be7Sderaadt#!/bin/sh - 2df930be7Sderaadt# 3*37db1d1cSbluhm# $OpenBSD: netstart,v 1.216 2021/09/02 19:38:20 bluhm Exp $ 45116749bSrpe 55116749bSrpe# Turn off Strict Bourne shell mode. 65116749bSrpeset +o sh 78fc5e153Smillert 82511c2f6Srpe# Show usage of the netstart script and exit. 92511c2f6Srpeusage() { 102511c2f6Srpe print -u2 "usage: ${0##*/} [[-n] interface ...]" 112511c2f6Srpe exit 1 122511c2f6Srpe} 132511c2f6Srpe 149ed80bb0Skn# Echo file $1 to stdout. Skip comment lines. Strip leading and trailing 15952fbff6Srpe# whitespace if IFS is set. 16e57a083bSrpe# Usage: stripcom /path/to/file 178fc5e153Smillertstripcom() { 18e57a083bSrpe local _file=$1 _line 19e57a083bSrpe 20e57a083bSrpe [[ -f $_file ]] || return 21e57a083bSrpe 22e57a083bSrpe while read _line; do 23e57a083bSrpe [[ -n ${_line%%#*} ]] && print -r -- "$_line" 24e57a083bSrpe done <$_file 258fc5e153Smillert} 2604e0ac27Smillert 278222f376Srpe# Parse and "unpack" a hostname.if(5) line given as positional parameters. 288222f376Srpe# Fill the _cmds array with the resulting interface configuration commands. 298222f376Srpeparse_hn_line() { 30a872b7aeSkrw local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr _dhcp _i 318222f376Srpe set -A _c -- "$@" 328222f376Srpe set -o noglob 338222f376Srpe 348222f376Srpe case ${_c[_af]} in 358222f376Srpe ''|*([[:blank:]])'#'*) 368222f376Srpe return 378222f376Srpe ;; 388222f376Srpe inet) ((${#_c[*]} > 1)) || return 3939d47095Sflorian if [[ ${_c[_name]} == autoconf ]]; then 4039d47095Sflorian _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 41816e0240Ssthen V4_AUTOCONF=true 4239d47095Sflorian return 4339d47095Sflorian fi 448222f376Srpe [[ ${_c[_name]} == alias ]] && _mask=3 _bc=4 458222f376Srpe [[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}" 468222f376Srpe if [[ -n ${_c[_bc]} ]]; then 478222f376Srpe _c[_bc]="broadcast ${_c[_bc]}" 488222f376Srpe [[ ${_c[_bc]} == *NONE ]] && _c[_bc]= 498222f376Srpe fi 508222f376Srpe _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 518222f376Srpe ;; 528222f376Srpe inet6) ((${#_c[*]} > 1)) || return 538222f376Srpe if [[ ${_c[_name]} == autoconf ]]; then 548222f376Srpe _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 550113d951Srpe V6_AUTOCONF=true 568222f376Srpe return 578222f376Srpe fi 588222f376Srpe [[ ${_c[_name]} == alias ]] && _prefix=3 598222f376Srpe [[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}" 608222f376Srpe _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 618222f376Srpe ;; 628222f376Srpe dest) ((${#_c[*]} == 2)) && _daddr=${_c[1]} || return 638222f376Srpe _prev=$((${#_cmds[*]} - 1)) 648222f376Srpe ((_prev >= 0)) || return 658222f376Srpe set -A _c -- ${_cmds[_prev]} 668222f376Srpe _name=3 678222f376Srpe [[ ${_c[_name]} == alias ]] && _name=4 688222f376Srpe _c[_name]="${_c[_name]} $_daddr" 698222f376Srpe _cmds[$_prev]="${_c[@]}" 708222f376Srpe ;; 712555728fSflorian dhcp) _cmds[${#_cmds[*]}]="ifconfig $_if inet autoconf" 722555728fSflorian V4_AUTOCONF=true 738222f376Srpe ;; 748222f376Srpe '!'*) _cmd=$(print -- "${_c[@]}" | sed 's/\$if/'$_if'/g') 758222f376Srpe _cmds[${#_cmds[*]}]="${_cmd#!}" 768222f376Srpe ;; 778222f376Srpe *) _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 788222f376Srpe ;; 798222f376Srpe esac 808222f376Srpe unset _c 8179699d09Srpe set +o noglob 828222f376Srpe} 838222f376Srpe 84d7d55851Srpe# Create interface $1 if it does not yet exist. 8580771ddaSrpe# Usage: ifcreate if1 86b6107460Sdlgifcreate() { 87b6107460Sdlg local _if=$1 88b6107460Sdlg 8909ec2297Sbluhm if $PRINT_ONLY; then 9009ec2297Sbluhm print -r -- "{ ifconfig $_if || ifconfig $_if create; }" 9109ec2297Sbluhm else 92d7d55851Srpe { ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1 9309ec2297Sbluhm fi 94b6107460Sdlg} 95b6107460Sdlg 96d7d55851Srpe# Create interfaces for network pseudo-devices referred to by hostname.if files. 9780771ddaSrpe# Usage: vifscreate 98b6107460Sdlgvifscreate() { 99d7d55851Srpe local _vif _hn _if 100b6107460Sdlg 101d7d55851Srpe for _vif in $(ifconfig -C); do 102375c217eSrpe for _hn in /etc/hostname.${_vif}+([[:digit:]]); do 103b6107460Sdlg [[ -f $_hn ]] || continue 104b6107460Sdlg _if=${_hn#/etc/hostname.} 105b6107460Sdlg 106*37db1d1cSbluhm # loopback for routing domain is created by kernel 107*37db1d1cSbluhm [[ -n ${_if##lo[1-9]*} ]] || continue 108*37db1d1cSbluhm 109375c217eSrpe if ! ifcreate $_if; then 1107f358361Srpe print -u2 "${0##*/}: create for '$_if' failed." 111375c217eSrpe fi 112b6107460Sdlg done 113b6107460Sdlg done 114b6107460Sdlg} 115b6107460Sdlg 116e57a083bSrpe# Start a single interface. 117e57a083bSrpe# Usage: ifstart if1 118dfc209d0Smiodifstart() { 11978b420f3Stb local _if=$1 _hn=/etc/hostname.$1 _cmds _i=0 _line _stat 1208222f376Srpe set -A _cmds 12124811c97Srpe 122dfc209d0Smiod # Interface names must be alphanumeric only. We check to avoid 123dfc209d0Smiod # configuring backup or temp files, and to catch the "*" case. 1248222f376Srpe [[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return 125dfc209d0Smiod 126b7a96a2bSrpe if [[ ! -f $_hn ]]; then 1277f358361Srpe print -u2 "${0##*/}: $_hn: No such file or directory." 12849352c7bStodd return 12949352c7bStodd fi 1308222f376Srpe 131300d0407Srpe # Not using stat(1), we can't rely on having /usr yet. 132b7a96a2bSrpe set -A _stat -- $(ls -nL $_hn) 1331a0aef30Srpe if [[ "${_stat[0]}${_stat[2]}${_stat[3]}" != *---00 ]]; then 1347f358361Srpe print -u2 "WARNING: $_hn is insecure, fixing permissions." 135b7a96a2bSrpe chmod -LR o-rwx $_hn 136b7a96a2bSrpe chown -LR root:wheel $_hn 137bc53e65aSderaadt fi 138dfc209d0Smiod 1398222f376Srpe # Check for ifconfig'able interface, except if -n option is specified. 140b6107460Sdlg ifcreate $_if || return 1418222f376Srpe 1428222f376Srpe # Parse the hostname.if(5) file and fill _cmds array with interface 1438222f376Srpe # configuration commands. 1448222f376Srpe set -o noglob 14588c728ccSkn while IFS= read -- _line; do 1468222f376Srpe parse_hn_line $_line 147b7a96a2bSrpe done <$_hn 1488222f376Srpe 1498222f376Srpe # Apply the interface configuration commands stored in _cmds array. 1508222f376Srpe while ((_i < ${#_cmds[*]})); do 1518222f376Srpe if $PRINT_ONLY; then 1528222f376Srpe print -r -- "${_cmds[_i]}" 1538222f376Srpe else 1548222f376Srpe eval "${_cmds[_i]}" 1558222f376Srpe fi 1568222f376Srpe ((_i++)) 1578222f376Srpe done 1588222f376Srpe unset _cmds 15979699d09Srpe set +o noglob 160dfc209d0Smiod} 161dfc209d0Smiod 162dde523b1Srpe# Start multiple interfaces by driver name. 163dde523b1Srpe# Usage: ifmstart "em iwm" "trunk vlan" 164300d0407Srpe# Start "$1" interfaces in order or all interfaces if empty. 165dde523b1Srpe# Don't start "$2" interfaces. "$2" is optional. 1669ac6b043Stoddifmstart() { 167dde523b1Srpe local _sifs=$1 _xifs=$2 _hn _if _sif _xif 168dde523b1Srpe 169dde523b1Srpe for _sif in ${_sifs:-ALL}; do 170375c217eSrpe for _hn in /etc/hostname.+([[:alpha:]])+([[:digit:]]); do 171375c217eSrpe [[ -f $_hn ]] || continue 172dde523b1Srpe _if=${_hn#/etc/hostname.} 1739ac6b043Stodd 174300d0407Srpe # Skip unwanted ifs. 175dde523b1Srpe for _xif in $_xifs; do 176dde523b1Srpe [[ $_xif == ${_if%%[0-9]*} ]] && continue 2 1779ac6b043Stodd done 1789ac6b043Stodd 179300d0407Srpe # Start wanted ifs. 180dde523b1Srpe [[ $_sif == @(ALL|${_if%%[0-9]*}) ]] && ifstart $_if 1819ac6b043Stodd done 1829ac6b043Stodd done 1839ac6b043Stodd} 1849ac6b043Stodd 18580771ddaSrpe# Parse /etc/mygate and add default routes for IPv4 and IPv6. 18605102370Smpi# Usage: defaultroute 18705102370Smpidefaultroute() { 1880df984aaStb local _cmd _v4set=false _v6set=false; 1894f9a4669Sderaadt set -o noglob 190e9c30f15Stb 1914f9a4669Sderaadt stripcom /etc/mygate | 1920113d951Srpe while read gw; do 1934f9a4669Sderaadt case $gw in 1944f9a4669Sderaadt '!'*) 1950df984aaStb _cmd=$(print -- "$gw") 1964f9a4669Sderaadt _cmd="${_cmd#!}" 1974f9a4669Sderaadt ;; 1980df984aaStb !(*:*)) 199816e0240Ssthen ($_v4set || $V4_AUTOCONF) && continue 200e9c30f15Stb _cmd="route -qn add -host default $gw" 2010df984aaStb _v4set=true 2020df984aaStb ;; 2030df984aaStb *) 2040df984aaStb ($_v6set || $V6_AUTOCONF) && continue 205e9c30f15Stb _cmd="route -qn add -host -inet6 default $gw" 2060df984aaStb _v6set=true 2074f9a4669Sderaadt ;; 2084f9a4669Sderaadt esac 209e9c30f15Stb if $PRINT_ONLY; then 2104f9a4669Sderaadt print -r -- "$_cmd" 211e9c30f15Stb else 2124f9a4669Sderaadt $_cmd 213e9c30f15Stb fi 21405102370Smpi done 2154f9a4669Sderaadt set +o noglob 21605102370Smpi} 21705102370Smpi 21809ec2297Sbluhm# add all the routes needed for IPv6 21909ec2297Sbluhmip6routes() { 22009ec2297Sbluhm local _i=0 22109ec2297Sbluhm set -A _cmds 22209ec2297Sbluhm 22309ec2297Sbluhm # Disallow link-local unicast dest without outgoing scope identifiers. 22409ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 fe80:: -prefixlen 10 ::1 -reject" 22509ec2297Sbluhm 22609ec2297Sbluhm # Disallow site-local unicast dest without outgoing scope identifiers. 22709ec2297Sbluhm # If you configure site-locals without scope id (it is permissible 22809ec2297Sbluhm # config for routers that are not on scope boundary), you may want 22909ec2297Sbluhm # to comment the line out. 23009ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 fec0:: -prefixlen 10 ::1 -reject" 23109ec2297Sbluhm 23209ec2297Sbluhm # Disallow "internal" addresses to appear on the wire. 23309ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject" 23409ec2297Sbluhm 23509ec2297Sbluhm # Disallow packets to malicious 6to4 prefix. 23609ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:e000:: -prefixlen 20 ::1 -reject" 23709ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject" 23809ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:0000:: -prefixlen 24 ::1 -reject" 23909ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject" 24009ec2297Sbluhm 24109ec2297Sbluhm # Disallow packets without scope identifier. 24209ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ff01:: -prefixlen 16 ::1 -reject" 24309ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ff02:: -prefixlen 16 ::1 -reject" 24409ec2297Sbluhm 24509ec2297Sbluhm # Completely disallow packets to IPv4 compatible prefix. 24609ec2297Sbluhm # 24709ec2297Sbluhm # This may conflict with RFC1933 under following circumstances: 24809ec2297Sbluhm # (1) An IPv6-only KAME node tries to originate packets to IPv4 24909ec2297Sbluhm # compatible destination. The KAME node has no IPv4 compatible 25009ec2297Sbluhm # support. Under RFC1933, it should transmit native IPv6 25109ec2297Sbluhm # packets toward IPv4 compatible destination, hoping it would 25209ec2297Sbluhm # reach a router that forwards the packet toward auto-tunnel 25309ec2297Sbluhm # interface. 25409ec2297Sbluhm # (2) An IPv6-only node originates a packet to an IPv4 compatible 25509ec2297Sbluhm # destination. A KAME node is acting as an IPv6 router, and 25609ec2297Sbluhm # asked to forward it. 25709ec2297Sbluhm # 25809ec2297Sbluhm # Due to rare use of IPv4 compatible addresses, and security issues 25909ec2297Sbluhm # with it, we disable it by default. 26009ec2297Sbluhm _cmds[_i++]="route -qn add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject" 26109ec2297Sbluhm 26209ec2297Sbluhm # Apply the interface configuration commands stored in _cmds array. 26309ec2297Sbluhm _i=0 26409ec2297Sbluhm while ((_i < ${#_cmds[*]})); do 26509ec2297Sbluhm if $PRINT_ONLY; then 26609ec2297Sbluhm print -r -- "${_cmds[_i]}" 26709ec2297Sbluhm else 26809ec2297Sbluhm eval "${_cmds[_i]}" 26909ec2297Sbluhm fi 27009ec2297Sbluhm ((_i++)) 27109ec2297Sbluhm done 27209ec2297Sbluhm unset _cmds 27309ec2297Sbluhm} 27409ec2297Sbluhm 27589f9479fStb# Make sure the invoking user has the right privileges. Check for presence of 27689f9479fStb# id(1) to avoid problems with diskless setups. 27789f9479fStbif [[ -x /usr/bin/id ]] && (($(id -u) != 0)); then 27889f9479fStb echo "${0##*/}: need root privileges" 27989f9479fStb exit 1 28089f9479fStbfi 28189f9479fStb 282a035c1adSrpe# Get network related vars from rc.conf using the parsing routine from rc.subr. 283a035c1adSrpeFUNCS_ONLY=1 . /etc/rc.d/rc.subr 2848799e9c8Srobert_rc_parse_conf 2850dc37902Sangelos 2868222f376SrpePRINT_ONLY=false 287816e0240SsthenV4_AUTOCONF=false 2880113d951SrpeV6_AUTOCONF=false 2890113d951Srpe 2908222f376Srpewhile getopts ":n" opt; do 2918222f376Srpe case $opt in 2928222f376Srpe n) PRINT_ONLY=true;; 2932511c2f6Srpe *) usage;; 2948222f376Srpe esac 2958222f376Srpedone 2968222f376Srpeshift $((OPTIND-1)) 2978222f376Srpe 29880771ddaSrpe# Load key material for the generation of IPv6 Semantically Opaque Interface 29980771ddaSrpe# Identifiers (SOII) used for link local and SLAAC addresses. 30081acd49bSflorian$PRINT_ONLY || [[ ! -f /etc/soii.key ]] || 30181acd49bSflorian sysctl -q "net.inet6.ip6.soiikey=$(</etc/soii.key)" 30281acd49bSflorian 303dfc209d0Smiod# If we were invoked with a list of interface names, just reconfigure these 30405102370Smpi# interfaces (or bridges), add default routes and return. 3050a295e45Srpeif (($# > 0)); then 3060a295e45Srpe for _if; do ifstart $_if; done 30705102370Smpi defaultroute 308dfc209d0Smiod return 309dfc209d0Smiodfi 310dfc209d0Smiod 311dfc209d0Smiod# Otherwise, process with the complete network initialization. 312dfc209d0Smiod 3134fbd02fcSsobrado# Set the address for the loopback interface. Bringing the interface up, 3144fbd02fcSsobrado# automatically invokes the IPv6 address ::1. 31509ec2297Sbluhmif $PRINT_ONLY; then 31609ec2297Sbluhm print -r -- "ifconfig lo0 inet 127.0.0.1/8" 31709ec2297Sbluhmelse 318d216f73bShenning ifconfig lo0 inet 127.0.0.1/8 31909ec2297Sbluhmfi 32098c28033Skstailey 32180771ddaSrpe# IPv6 configuration. 3223d8fed7cSitojunif ifconfig lo0 inet6 >/dev/null 2>&1; then 3233d8fed7cSitojun ip6kernel=YES 32409ec2297Sbluhm ip6routes 3253d8fed7cSitojunelse 3263d8fed7cSitojun ip6kernel=NO 3273d8fed7cSitojunfi 3283d8fed7cSitojun 32980771ddaSrpe# Create all the pseudo interfaces up front. 330b6107460Sdlgvifscreate 331df930be7Sderaadt 3329ac6b043Stodd# Configure all the non-loopback interfaces which we know about, but 3334eb97611Sderaadt# do not start interfaces which must be delayed. Refer to hostname.if(5) 334f7df26a3Sjmcifmstart "" "aggr trunk svlan vlan carp pppoe tun tap gif etherip gre egre pflow wg" 33582c17b75Sitojun 336774508f4Sdlg# The aggr and trunk interfaces need to come up first in this list. 337f45bd3bdSmpf# The (s)vlan interfaces need to come up after trunk. 3384bdcd471Sbrad# Configure all the carp interfaces which we know about before default route. 339774508f4Sdlgifmstart "aggr trunk svlan vlan carp pppoe" 3404bdcd471Sbrad 34180771ddaSrpe# Set default routes for IPv4 and IPv6. 34205102370Smpidefaultroute 343cf3860a5Sderaadt 344745634aaSniklas# Multicast routing. 3456e0f151eSsthenif [[ $multicast != YES ]]; then 34609ec2297Sbluhm if $PRINT_ONLY; then 34709ec2297Sbluhm print -r -- "route -qn delete 224.0.0.0/4" 34809ec2297Sbluhm print -r -- "route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject" 34909ec2297Sbluhm else 35009ec2297Sbluhm route -qn delete 224.0.0.0/4 35109ec2297Sbluhm route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject 35209ec2297Sbluhm fi 3536e0f151eSsthenfi 354dfc209d0Smiod 355300d0407Srpe# Reject 127/8 other than 127.0.0.1. 35609ec2297Sbluhmif $PRINT_ONLY; then 35709ec2297Sbluhm print -r -- "route -qn add -net 127 127.0.0.1 -reject" 35809ec2297Sbluhmelse 35909ec2297Sbluhm route -qn add -net 127 127.0.0.1 -reject 36009ec2297Sbluhmfi 3618f8fdbefSderaadt 362b6107460Sdlg# Configure interfaces that rely on routing 363f7df26a3Sjmcifmstart "tun tap gif etherip gre egre pflow wg" 364b6107460Sdlg 3650a295e45Srpeif [[ $ip6kernel == YES ]]; then 36680771ddaSrpe # Ensure IPv6 Duplicate Address Detection (DAD) is completed. 367c653ce7bSmarkus count=0 3680a295e45Srpe while ((count++ < 10 && $(sysctl -n net.inet6.ip6.dad_pending) != 0)); do 369c653ce7bSmarkus sleep 1 370c653ce7bSmarkus done 371089287c3Sdavidfi 372