netstart revision 1.218
1#!/bin/sh - 2# 3# $OpenBSD: netstart,v 1.218 2022/06/26 09:36:13 florian Exp $ 4 5# Turn off Strict Bourne shell mode. 6set +o sh 7 8# Show usage of the netstart script and exit. 9usage() { 10 print -u2 "usage: ${0##*/} [[-n] interface ...]" 11 exit 1 12} 13 14# Echo file $1 to stdout. Skip comment lines. Strip leading and trailing 15# whitespace if IFS is set. 16# Usage: stripcom /path/to/file 17stripcom() { 18 local _file=$1 _line 19 20 [[ -f $_file ]] || return 21 22 while read _line; do 23 [[ -n ${_line%%#*} ]] && print -r -- "$_line" 24 done <$_file 25} 26 27# Parse and "unpack" a hostname.if(5) line given as positional parameters. 28# Fill the _cmds array with the resulting interface configuration commands. 29parse_hn_line() { 30 local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr _dhcp _i 31 set -A _c -- "$@" 32 set -o noglob 33 34 case ${_c[_af]} in 35 ''|*([[:blank:]])'#'*) 36 return 37 ;; 38 inet) ((${#_c[*]} > 1)) || return 39 if [[ ${_c[_name]} == autoconf ]]; then 40 _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 41 V4_AUTOCONF=true 42 return 43 fi 44 [[ ${_c[_name]} == alias ]] && _mask=3 _bc=4 45 [[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}" 46 if [[ -n ${_c[_bc]} ]]; then 47 _c[_bc]="broadcast ${_c[_bc]}" 48 [[ ${_c[_bc]} == *NONE ]] && _c[_bc]= 49 fi 50 _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 51 ;; 52 inet6) ((${#_c[*]} > 1)) || return 53 if [[ ${_c[_name]} == autoconf ]]; then 54 _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 55 V6_AUTOCONF=true 56 return 57 fi 58 [[ ${_c[_name]} == alias ]] && _prefix=3 59 [[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}" 60 _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 61 ;; 62 dest) ((${#_c[*]} == 2)) && _daddr=${_c[1]} || return 63 _prev=$((${#_cmds[*]} - 1)) 64 ((_prev >= 0)) || return 65 set -A _c -- ${_cmds[_prev]} 66 _name=3 67 [[ ${_c[_name]} == alias ]] && _name=4 68 _c[_name]="${_c[_name]} $_daddr" 69 _cmds[$_prev]="${_c[@]}" 70 ;; 71 dhcp) _cmds[${#_cmds[*]}]="ifconfig $_if inet autoconf" 72 V4_AUTOCONF=true 73 ;; 74 '!'*) _cmd=$(print -- "${_c[@]}" | sed 's/\$if/'$_if'/g') 75 _cmds[${#_cmds[*]}]="${_cmd#!}" 76 ;; 77 *) _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}" 78 ;; 79 esac 80 unset _c 81 set +o noglob 82} 83 84# Create interface $1 if it does not yet exist. 85# Usage: ifcreate if1 86ifcreate() { 87 local _if=$1 88 89 if $PRINT_ONLY; then 90 print -r -- "{ ifconfig $_if || ifconfig $_if create; }" 91 else 92 { ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1 93 fi 94} 95 96# Create interfaces for network pseudo-devices referred to by hostname.if files. 97# Usage: vifscreate 98vifscreate() { 99 local _vif _hn _if 100 101 for _vif in $(ifconfig -C); do 102 for _hn in /etc/hostname.${_vif}+([[:digit:]]); do 103 [[ -f $_hn ]] || continue 104 _if=${_hn#/etc/hostname.} 105 106 # loopback for routing domain is created by kernel 107 [[ -n ${_if##lo[1-9]*} ]] || continue 108 109 if ! ifcreate $_if; then 110 print -u2 "${0##*/}: create for '$_if' failed." 111 fi 112 done 113 done 114} 115 116# Start a single interface. 117# Usage: ifstart if1 118ifstart() { 119 local _if=$1 _hn=/etc/hostname.$1 _cmds _i=0 _line _stat 120 set -A _cmds 121 122 # Interface names must be alphanumeric only. We check to avoid 123 # configuring backup or temp files, and to catch the "*" case. 124 [[ $_if != +([[:alpha:]])+([[:digit:]]) ]] && return 125 126 if [[ ! -f $_hn ]]; then 127 print -u2 "${0##*/}: $_hn: No such file or directory." 128 return 129 fi 130 131 # Not using stat(1), we can't rely on having /usr yet. 132 set -A _stat -- $(ls -nL $_hn) 133 if [[ "${_stat[0]}${_stat[2]}${_stat[3]}" != *---00 ]]; then 134 print -u2 "WARNING: $_hn is insecure, fixing permissions." 135 chmod -LR o-rwx $_hn 136 chown -LR root:wheel $_hn 137 fi 138 139 # Check for ifconfig'able interface, except if -n option is specified. 140 ifcreate $_if || return 141 142 # Parse the hostname.if(5) file and fill _cmds array with interface 143 # configuration commands. 144 set -o noglob 145 while IFS= read -- _line; do 146 parse_hn_line $_line 147 done <$_hn 148 149 # Apply the interface configuration commands stored in _cmds array. 150 while ((_i < ${#_cmds[*]})); do 151 if $PRINT_ONLY; then 152 print -r -- "${_cmds[_i]}" 153 else 154 eval "${_cmds[_i]}" 155 fi 156 ((_i++)) 157 done 158 unset _cmds 159 set +o noglob 160} 161 162# Start multiple interfaces by driver name. 163# Usage: ifmstart "em iwm" "trunk vlan" 164# Start "$1" interfaces in order or all interfaces if empty. 165# Don't start "$2" interfaces. "$2" is optional. 166ifmstart() { 167 local _sifs=$1 _xifs=$2 _hn _if _sif _xif 168 169 for _sif in ${_sifs:-ALL}; do 170 for _hn in /etc/hostname.+([[:alpha:]])+([[:digit:]]); do 171 [[ -f $_hn ]] || continue 172 _if=${_hn#/etc/hostname.} 173 174 # Skip unwanted ifs. 175 for _xif in $_xifs; do 176 [[ $_xif == ${_if%%[0-9]*} ]] && continue 2 177 done 178 179 # Start wanted ifs. 180 [[ $_sif == @(ALL|${_if%%[0-9]*}) ]] && ifstart $_if 181 done 182 done 183} 184 185# Parse /etc/mygate and add default routes for IPv4 and IPv6. 186# Usage: defaultroute 187defaultroute() { 188 local _cmd _v4set=false _v6set=false; 189 set -o noglob 190 191 stripcom /etc/mygate | 192 while read gw; do 193 case $gw in 194 '!'*) 195 _cmd=$(print -- "$gw") 196 _cmd="${_cmd#!}" 197 ;; 198 !(*:*)) 199 ($_v4set || $V4_AUTOCONF) && continue 200 _cmd="route -qn add -host default $gw" 201 _v4set=true 202 ;; 203 *) 204 ($_v6set || $V6_AUTOCONF) && continue 205 _cmd="route -qn add -host -inet6 default $gw" 206 _v6set=true 207 ;; 208 esac 209 if $PRINT_ONLY; then 210 print -r -- "$_cmd" 211 else 212 $_cmd 213 fi 214 done 215 set +o noglob 216} 217 218# add all the routes needed for IPv6 219ip6routes() { 220 local _i=0 221 set -A _cmds 222 223 # Disallow link-local unicast dest without outgoing scope identifiers. 224 _cmds[_i++]="route -qn add -inet6 fe80:: -prefixlen 10 ::1 -reject" 225 226 # Disallow site-local unicast dest without outgoing scope identifiers. 227 # If you configure site-locals without scope id (it is permissible 228 # config for routers that are not on scope boundary), you may want 229 # to comment the line out. 230 _cmds[_i++]="route -qn add -inet6 fec0:: -prefixlen 10 ::1 -reject" 231 232 # Disallow "internal" addresses to appear on the wire. 233 _cmds[_i++]="route -qn add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject" 234 235 # Disallow packets to malicious 6to4 prefix. 236 _cmds[_i++]="route -qn add -inet6 2002:e000:: -prefixlen 20 ::1 -reject" 237 _cmds[_i++]="route -qn add -inet6 2002:7f00:: -prefixlen 24 ::1 -reject" 238 _cmds[_i++]="route -qn add -inet6 2002:0000:: -prefixlen 24 ::1 -reject" 239 _cmds[_i++]="route -qn add -inet6 2002:ff00:: -prefixlen 24 ::1 -reject" 240 241 # Disallow packets without scope identifier. 242 _cmds[_i++]="route -qn add -inet6 ff01:: -prefixlen 16 ::1 -reject" 243 _cmds[_i++]="route -qn add -inet6 ff02:: -prefixlen 16 ::1 -reject" 244 245 # Completely disallow packets to IPv4 compatible prefix. 246 # 247 # This may conflict with RFC1933 under following circumstances: 248 # (1) An IPv6-only KAME node tries to originate packets to IPv4 249 # compatible destination. The KAME node has no IPv4 compatible 250 # support. Under RFC1933, it should transmit native IPv6 251 # packets toward IPv4 compatible destination, hoping it would 252 # reach a router that forwards the packet toward auto-tunnel 253 # interface. 254 # (2) An IPv6-only node originates a packet to an IPv4 compatible 255 # destination. A KAME node is acting as an IPv6 router, and 256 # asked to forward it. 257 # 258 # Due to rare use of IPv4 compatible addresses, and security issues 259 # with it, we disable it by default. 260 _cmds[_i++]="route -qn add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject" 261 262 # Apply the interface configuration commands stored in _cmds array. 263 _i=0 264 while ((_i < ${#_cmds[*]})); do 265 if $PRINT_ONLY; then 266 print -r -- "${_cmds[_i]}" 267 else 268 eval "${_cmds[_i]}" 269 fi 270 ((_i++)) 271 done 272 unset _cmds 273} 274 275# wait for autoconf interfaces 276wait_autoconf_default() { 277 if ifconfig | grep -q ': flags=.*<.*AUTOCONF.*>'; then 278 count=0 279 while ((count++ < 20)); do 280 route -n show | grep -q ^default && break 281 sleep .5 282 done 283 fi 284} 285 286# Make sure the invoking user has the right privileges. Check for presence of 287# id(1) to avoid problems with diskless setups. 288if [[ -x /usr/bin/id ]] && (($(id -u) != 0)); then 289 echo "${0##*/}: need root privileges" 290 exit 1 291fi 292 293# Get network related vars from rc.conf using the parsing routine from rc.subr. 294FUNCS_ONLY=1 . /etc/rc.d/rc.subr 295_rc_parse_conf 296 297PRINT_ONLY=false 298V4_AUTOCONF=false 299V6_AUTOCONF=false 300 301while getopts ":n" opt; do 302 case $opt in 303 n) PRINT_ONLY=true;; 304 *) usage;; 305 esac 306done 307shift $((OPTIND-1)) 308 309# Load key material for the generation of IPv6 Semantically Opaque Interface 310# Identifiers (SOII) used for link local and SLAAC addresses. 311$PRINT_ONLY || [[ ! -f /etc/soii.key ]] || 312 sysctl -q "net.inet6.ip6.soiikey=$(</etc/soii.key)" 313 314# If we were invoked with a list of interface names, just reconfigure these 315# interfaces (or bridges), add default routes and return. 316if (($# > 0)); then 317 for _if; do ifstart $_if; done 318 defaultroute 319 return 320fi 321 322# Otherwise, process with the complete network initialization. 323 324# Set the address for the loopback interface. Bringing the interface up, 325# automatically invokes the IPv6 address ::1. 326if $PRINT_ONLY; then 327 print -r -- "ifconfig lo0 inet 127.0.0.1/8" 328else 329 ifconfig lo0 inet 127.0.0.1/8 330fi 331 332# IPv6 configuration. 333if ifconfig lo0 inet6 >/dev/null 2>&1; then 334 ip6kernel=YES 335 ip6routes 336else 337 ip6kernel=NO 338fi 339 340# Create all the pseudo interfaces up front. 341vifscreate 342 343# Configure all the non-loopback interfaces which we know about, but 344# do not start interfaces which must be delayed. Refer to hostname.if(5) 345ifmstart "" "aggr trunk svlan vlan carp pppoe tun tap gif etherip gre egre nvgre eoip vxlan pflow wg" 346 347# The aggr and trunk interfaces need to come up first in this list. 348# The (s)vlan interfaces need to come up after trunk. 349# Configure all the carp interfaces which we know about before default route. 350ifmstart "aggr trunk svlan vlan carp pppoe" 351 352# Set default routes for IPv4 and IPv6. 353defaultroute 354 355# Multicast routing. 356if [[ $multicast != YES ]]; then 357 if $PRINT_ONLY; then 358 print -r -- "route -qn delete 224.0.0.0/4" 359 print -r -- "route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject" 360 else 361 route -qn delete 224.0.0.0/4 362 route -qn add -net 224.0.0.0/4 -interface 127.0.0.1 -reject 363 fi 364fi 365 366# Reject 127/8 other than 127.0.0.1. 367if $PRINT_ONLY; then 368 print -r -- "route -qn add -net 127 127.0.0.1 -reject" 369else 370 route -qn add -net 127 127.0.0.1 -reject 371fi 372 373# If interface autoconf exists, pause a little for at least one default route 374wait_autoconf_default 375 376# Configure interfaces that rely on routing 377ifmstart "tun tap gif etherip gre egre nvgre eoip vxlan pflow wg" 378 379if [[ $ip6kernel == YES ]]; then 380 # Ensure IPv6 Duplicate Address Detection (DAD) is completed. 381 count=0 382 while ((count++ < 10 && $(sysctl -n net.inet6.ip6.dad_pending) != 0)); do 383 sleep 1 384 done 385fi 386