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