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