├── .gitignore ├── Makefile ├── README.md ├── netctl └── netctl.8 /.gitignore: -------------------------------------------------------------------------------- 1 | # -*- mode: gitignore; -*- 2 | *~ 3 | \#*\# 4 | .\#* 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | 3 | install: 4 | cp netctl "$(PREFIX)/sbin/" 5 | cp netctl.8 "$(PREFIX)/man/man8/" 6 | mkdir -p /etc/hostname.d/nwids 7 | 8 | remove: 9 | rm -f "$(PREFIX)/sbin/netctl" 10 | rm -f "$(PREFIX)/man/man8/netctl.8" 11 | 12 | lint: 13 | mandoc -T lint netctl.8 14 | 15 | man: 16 | mandoc netctl.8 | less 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About netctl 2 | ============ 3 | 4 | `netctl` is a utility to manage network locations, interface 5 | configuration files, and to start, stop, or restart interfaces on 6 | OpenBSD. 7 | 8 | `netctl` is not a replacement for `ifconfig(8)` or `netstart(8)`. It's 9 | utility to make managing locations easier. `netstart` and `ifconfig` 10 | still do the work. `netctl` makes the user's life, especially portable 11 | users, easier. 12 | 13 | 14 | Features 15 | -------- 16 | + Create, delete and switch between **locations** (including restarting 17 | **interfaces**) 18 | + Enable and disable **configurations**. 19 | + Start, stop and restart **interfaces**. 20 | + Detect and join known wireless networks (**waps**). 21 | + Scan for wireless access points. 22 | + List **locations**, **configurations**, **interfaces**, and **waps**. 23 | 24 | See the man page for further details. 25 | 26 | 27 | Install 28 | ------- 29 | 30 | There's no installer for `netctl` at the moment. `doas make install` 31 | will install to **/usr/local** unless you override the PREFIX 32 | variable. 33 | 34 | `make install` will also create **/etc/hostname.d/** and 35 | **/etc/hostname.d/nwids/** 36 | 37 | 38 | Locations 39 | --------- 40 | 41 | `netctl` works by symlinking **hostname.if** files in location 42 | directories to **/etc/hostname.if** so that the normal `netstart(8)` 43 | code can do what it already does well. 44 | 45 | `netctl` will create **location** directories for you by calling `doas 46 | netctl create location_name`. `netctl` will **not** at this time 47 | create the **hostname.if** files. They have to be created the same 48 | ways as documented in `hostname.if(5)`. See the `man` page for more 49 | details. 50 | 51 | 52 | Auto Detecting and Joining Networks 53 | ----------------------------------- 54 | 55 | Auto detecting and joining requires some setup. `netctl` will not 56 | connect to wireless access points that are not known. To create a 57 | *known* wap, a standard wireless **hostname.if** file should be 58 | created in **/etc/hostname.d/nwids**. *E.g.,* 59 | 60 | ``` 61 | $ cat /etc/hostname.d/nwids/Silly\ Wap.nwid 62 | nwid "Silly Wap" 63 | wpakey '$w@pau7h99' 64 | dhcp 65 | ``` 66 | 67 | The filename **must** be the same as the **nwid** in the file which 68 | **must** match the **ESSID** of the wireless access point. Any valid 69 | configuration directive `ifconfig(8)` will accept may be placed in the 70 | file. 71 | 72 | Executing `doas netctl -a start iwm0` will cause `netctl` to scan the 73 | local network (with `ifconfig iwm0 scan`) and attempt to match the 74 | results with the names of the **nwids** found by `ls`-ing 75 | **/etc/hostname.d/nwids**. 76 | 77 | **N.B.** `ifconfig scan` is called with *each* wlan device unless one 78 | is specified after the **start** parameter. 79 | 80 | 81 | Auto Detecting and Joining Networks When Resuming 82 | ------------------------------------------------- 83 | 84 | `netctl` is not a daemon so it doesn't know when a computer has 85 | resumed from sleep. `apmd(8)` does know and will call a script called 86 | **resume** if it exists in **/etc/apm** and is executable. 87 | 88 | A simple script like the following will work where the script is 89 | called **suspend** and the other scripts are symlinked to it (see the 90 | **man** page for `apmd(8)`): 91 | 92 | ``` 93 | #!/bin/sh 94 | 95 | cmd="${0##*([[:blank:]])/etc/apm/}" 96 | case "${cmd}" in 97 | powerup|resume) 98 | /usr/local/bin/netctl -a restart 99 | ;; 100 | *) 101 | ;; 102 | esac 103 | ``` 104 | 105 | 106 | TODO 107 | ---- 108 | 109 | + Add boot time detecting and joining wireless networks 110 | + Create hostname.if files in locations 111 | 112 | 113 | Maybe TODO 114 | ---------- 115 | + Set and get values in hostname.if files. *E.g.,* 116 | ``` 117 | $ doas netctl get home nwid 118 | "Silly Wap" 119 | 120 | $ doas netctl set home nwid "My WAP Name" 121 | 122 | $ doas netctl set home dhcp on 123 | ``` 124 | 125 | 126 | Comments on Boot Time Configuration 127 | -------- 128 | 129 | `netctl` is written in pure shell (using no commands outside of shell, 130 | **/bin** and **/sbin**), so that it can run at boot time when **/usr** 131 | may not be mounted yet. 132 | 133 | I think I can get automated location switching working at boot time. I 134 | already have code from an earlier project that will match wap scans to 135 | the correct configuration. I'm rewriting it in pure shell and 136 | integrating it for use during boot. 137 | 138 | 139 | Copyright and License 140 | --------------------- 141 | 142 | Copyright (c) 2017 Aaron Poffenberger 143 | 144 | Permission to use, copy, modify, and distribute this software for any 145 | purpose with or without fee is hereby granted, provided that the above 146 | copyright notice and this permission notice appear in all copies. 147 | 148 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 149 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 150 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 151 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 152 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 153 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 154 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 155 | 156 | Updates and Suggestions 157 | ----------------------- 158 | 159 | Let me know by `Issue` or email if you find bugs or have suggestions. 160 | -------------------------------------------------------------------------------- /netctl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # $OpenBSD$ 4 | # 5 | # Copyright (c) 2017 Aaron Poffenberger 6 | # 7 | # Permission to use, copy, modify, and distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # cmd OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS cmd, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | # Turn off Strict Bourne shell mode. 21 | set +o sh 22 | 23 | readonly __progname="netctl" 24 | readonly TRUE=0 25 | readonly FALSE=1 26 | readonly HN_DIR=${HN_DIR:-/etc/hostname.d} 27 | 28 | # Log an error 29 | # Usage: log_err msg [exit code] 30 | # Cheerfully copied from rc.subr(8) 31 | # Copyright (c) 2010, 2011, 2014-2017 Antoine Jacoutot 32 | # Copyright (c) 2010, 2011 Ingo Schwarze 33 | # Copyright (c) 2010, 2011, 2014 Robert Nagy 34 | log_err() { 35 | [ -n "${1}" ] && echo "${1}" 1>&2 36 | [ -n "${2}" ] && exit "${2}" || exit 1 37 | } 38 | 39 | # Log a warning 40 | # Usage: log_err msg [exit code] 41 | log_warning() { 42 | log_msg "${1}" 1>&2 43 | } 44 | 45 | # Log a message 46 | # Usage: log_msg msg [right justify length] 47 | log_msg() { 48 | local -R${2:-0} _msg="${1}" 49 | 50 | [ -n "${_msg}" ] && echo "${_msg}" 51 | } 52 | 53 | # Log a message to stdout or stderr 54 | # Usage: usage [2] 55 | usage() { 56 | echo \ 57 | "usage: netctl [-h] 58 | netctl ls [lsarg ...] 59 | netctl create|delete location ... 60 | netctl [-dr] switch location [interface ...] 61 | netctl enable|disable [configuration ...] 62 | netctl [-a] start|restart [interface ...] 63 | netctl stop [interface ...] 64 | netctl [-v] scan [interface ...]" 1>&${1:-1} 65 | } 66 | 67 | # Get interface configuration 68 | # Expects variables to be typeset/local from calling fn 69 | # Usage: get_if_conf if1 70 | get_if_conf() { 71 | # use co-process to preserve values set in while loop 72 | ifconfig $1 |& 73 | while IFS=' ' read -r -p _l; do 74 | _key=${_l%%*([[:blank:]])*(:) *} 75 | _val=${_l##*([[:blank:]])*${_key}*(:)*([[:blank:]])} 76 | 77 | [[ ${_key} == 'groups' ]] && _groups=${_val} 78 | [[ ${_key} == 'media' ]] && _media=${_val} 79 | [[ ${_key} == 'status' ]] && _status=${_val} 80 | [[ ${_key} == 'ieee80211' ]] && _ieee80211=${_val} 81 | [[ ${_key} == 'inet' ]] && _inet=${_val} 82 | [[ ${_key} == 'inet6' ]] && _inet6=${_val} 83 | done 84 | } 85 | 86 | # Get interfaces 87 | # Expects variable _ifs to be typeset/local from calling fn 88 | # Usage: get_ifs if1 89 | get_ifs() { 90 | local _if _excl_keys 91 | # exclude network pseudo-devices 92 | set -A _pseudo_devices $(ifconfig -C) 93 | 94 | # use co-process to preserve values set in while loop 95 | ifconfig $1 |& 96 | while IFS=' ' read -r -p _l; do 97 | [[ "${_l}" == *:\ flags* ]] || continue 98 | 99 | _if=${_l%%*([[:blank:]])*():*} 100 | 101 | [ -z "${_if}" ] && continue 102 | 103 | #_if=${_l%%*([[:blank:]])*():*} 104 | 105 | # exclude if-type (san _if num) in pseudo-devices 106 | [[ " ${_pseudo_devices[*]}0 " \ 107 | == *" ${_if%%*([[:digit:]])} "* ]] && 108 | continue 109 | 110 | _ifs[${#_ifs[*]}]="${_if}" 111 | done 112 | 113 | [ -n "${_ifs}" ] || return 1 114 | } 115 | 116 | get_locations() { 117 | local _l 118 | 119 | ls -p "${HN_DIR}" |& 120 | # use co-process to preserve values set in while loop 121 | while IFS=' ' read -r -p _l ; do 122 | # skip known nwids, not a location 123 | [[ "${_l}" == *nwids* ]] && continue 124 | # skip files 125 | [[ "${_l}" == *([[:blank:]])*/ ]] || continue 126 | _locations[${#_locations[*]}]="${_l%%/}" 127 | done 128 | } 129 | 130 | get_configurations() { 131 | local _l _location 132 | 133 | _location="$1" 134 | 135 | ls -p "${HN_DIR}/${_location}" |& 136 | # use co-process to preserve values set in while loop 137 | while IFS=' ' read -r -p _l ; do 138 | # skip directories 139 | [[ "${_l}" == *([[:blank:]])*[!/] ]] || continue 140 | 141 | _configurations[${#_configurations[*]}]="${_l}" 142 | done 143 | } 144 | 145 | # Restart interface 146 | # Usage: if_restart if1 147 | if_restart() { 148 | echo if_restart 149 | if_stop $1 && if_start $1 150 | } 151 | 152 | # Start interface 153 | # Usage: if_start if1 154 | if_start() { 155 | local _if 156 | 157 | _if=$1 158 | ([ ${dryrun} -eq 1 ] && 159 | log_msg "/bin/sh /etc/netstart -p ${_if}") || 160 | /bin/sh /etc/netstart ${_if} 161 | } 162 | 163 | # Stop interface 164 | # Usage: if_stop if1 165 | if_stop() { 166 | local _options _groups _media _status _ieee80211 _inet _inet6 \ 167 | _key _wlan_keys _inet_keys _mode_keys _if 168 | 169 | set -A _wlan_keys -- join nwid chan mode nwkey powersave wpakey wpa 170 | 171 | _if=$1 172 | get_if_conf ${_if} 173 | 174 | # remove mode if the interface is wireless 175 | [ -n "${_ieee80211}" ] && _options="${_options} -mode" 176 | 177 | for _key in ${_wlan_keys[*]} ; do 178 | [[ "${_ieee80211}" == *"${_key}"* ]] && 179 | _options="${_options} -${_key}" 180 | done 181 | 182 | [ -n "${_inet}" ] && _options="${_options} -inet" 183 | [ -n "${_inet6}" ] && _options="${_options} -inet6" 184 | 185 | [ ${dryrun} -eq 1 ] && 186 | log_msg "ifconfig ${_if} ${_options} down delete" || 187 | (ifconfig ${_if} ${_options} down && 188 | ifconfig ${_if} ${_options} down) 189 | } 190 | 191 | # Create link from configuration to /etc/hostname.if 192 | # Usage: link_configuration if from to 193 | link_configuration() { 194 | local _if _from _to 195 | 196 | _if=$1 197 | _from="${2}" 198 | _to="${3}" 199 | 200 | [ ! -f "${_to}" ] && 201 | [ -f "/etc/hostname.${_if}.disabled" ] && 202 | _to="/etc/hostname.${_if}.disabled" 203 | 204 | [ ! -f "${_from}" ] && 205 | [ ${delete} -eq 1 ] && 206 | rm -f "${_to}" && 207 | return 208 | 209 | [ -f "${_from}" ] && 210 | cd /etc/ && 211 | ln -fs "${_from##/etc/}" "${_to}" && 212 | log_msg "Switch ${_if}" || 213 | log_warning "No configuration for ${_if}" 214 | 215 | [ -f "${_to}" ] && 216 | [ ${restart} -eq 1 ] && 217 | if_restart ${_if} 218 | } 219 | 220 | ls_locations() { 221 | local _l _locations 222 | set -A _locations 223 | 224 | get_locations 225 | 226 | log_msg "Locations:" 227 | for _l in "${_locations[@]}" ; do 228 | log_msg "\t${_l}" 229 | done 230 | 231 | unset _l _locations 232 | } 233 | 234 | ls_configurations() { 235 | local _c _configurations _l _locations 236 | set -A _locations 237 | set -A _configurations 238 | 239 | [[ -n "$@" ]] && set -A _locations "$@" || 240 | get_locations 241 | 242 | log_msg "Configurations:" 243 | for _l in "${_locations[@]}" ; do 244 | get_configurations "${_l}" 245 | 246 | log_msg "\t${_l}:" 247 | for _c in "${_configurations[@]}" ; do 248 | log_msg "\t\t${_c}" 249 | done 250 | 251 | set -A _configurations 252 | done 253 | 254 | 255 | unset _c _configurations _l _locations 256 | } 257 | 258 | ls_interfaces() { 259 | local _if _ifs 260 | set -A _ifs 261 | 262 | get_ifs 263 | 264 | log_msg "Interfaces:" 265 | for _if in "${_ifs[@]}" ; do 266 | log_msg "\t${_if}" 267 | done 268 | 269 | unset _if _ifs 270 | } 271 | 272 | ls_waps() { 273 | local _nwid _path _paths 274 | set -A _paths -- ${HN_DIR}/nwids/*.nwid 275 | log_msg "Wireless access points (known waps):" 276 | for _path in "${_paths[@]}" ; do 277 | _nwid=${_path##*([[:blank:]])${HN_DIR}/nwids/} 278 | _nwid=${_nwid%%.nwid} 279 | log_msg "\t${_nwid}" 280 | done 281 | 282 | unset _nwid _path _paths 283 | } 284 | 285 | # Get interface details 286 | # Expects variable _nwids to be typeset/local from calling fn 287 | # Usage: scan if1 288 | scan() { 289 | local _nwid _i _iselem _if _verbose 290 | 291 | _if=$1 292 | _verbose=$2 293 | # use co-process to preserve values set in while loop 294 | ifconfig ${_if} scan |& 295 | while IFS=' ' read -r -p _l ; do 296 | [[ "${_l}" == *([[:blank::]])nwid* ]] || continue 297 | 298 | [[ "${_verbose:-0}" -eq 1 ]] && 299 | _nwids[${#_nwids[*]}] \ 300 | ="${_l%%*([[:blank:]])*()% *}%" && 301 | continue 302 | 303 | [[ "${_verbose:-0}" -eq 2 ]] && 304 | _nwids[${#_nwids[*]}]="${_l}" && 305 | continue 306 | 307 | _nwid=${_l%%*([[:blank:]])*()chan *} 308 | _nwid=${_nwid##*nwid *()} 309 | 310 | [[ ${_nwid} == '""' ]] && continue 311 | 312 | 313 | _iselem=0 && _i=0 314 | while ((_i < ${#_nwids[*]})) ; do 315 | [[ "${_nwids[_i]}" == "${_nwid}" ]] && 316 | _iselem=1 && break 317 | ((_i++)) 318 | done 319 | [ ${_iselem} -eq 0 ] && _nwids[${#_nwids[*]}]="${_nwid}" 320 | done 321 | 322 | [ -n "${_nwids}" ] || return 1 323 | } 324 | 325 | # Match scanned access points with first known wap 326 | # Usage: wap_match if1 327 | wap_match() { 328 | local _if _nwids _nwid _path _paths _wap _waps 329 | set -A _paths -- ${HN_DIR}/nwids/*.nwid 330 | 331 | _if=$1 332 | 333 | [ -z "${_paths}" ] && 334 | log_warning "No known waps found." && 335 | return 1 336 | 337 | for _path in "${_paths[@]}" ; do 338 | _wap=${_path##*([[:blank:]])${HN_DIR}/nwids/} 339 | _wap=${_wap%%.nwid} 340 | _waps[${#_waps[*]}]="${_wap}" 341 | done 342 | 343 | scan ${_if} 344 | for _nwid in "${_nwids[@]}" ; do 345 | _nwid=${_nwid##\"} 346 | _nwid=${_nwid%%\"} 347 | [[ " ${_waps[*]} " == *" ${_nwid} "* ]] && 348 | log_msg "Found '${_nwid}'" && 349 | _match="${HN_DIR}/nwids/${_nwid}.nwid" && 350 | return 351 | done 352 | } 353 | 354 | typeset -i autowap=0 delete=0 dryrun=0 restart=0 verbose=0 355 | while getopts :adhnqrv opt ; do 356 | case ${opt} in 357 | a) 358 | autowap=1;; 359 | d) 360 | delete=1;; 361 | h) 362 | usage 363 | exit 364 | ;; 365 | n) 366 | dryrun=1;; 367 | q) 368 | quiet=1;; 369 | r) 370 | restart=1;; 371 | v) 372 | ((verbose++)) 373 | cmd="scan";; 374 | :) 375 | log_msg "${__progname}: option requires an argument -- ${OPTARG}" 376 | usage 2 377 | exit 378 | ;; 379 | \?) 380 | log_msg "${__progname}: invalid option -- ${OPTARG}" 381 | usage 2 382 | exit 383 | ;; 384 | esac 385 | done 386 | shift $(( OPTIND - 1 )) 387 | cmd=$1 388 | 389 | case ${cmd} in 390 | ls) 391 | shift 1 392 | lsarg="$1" 393 | [[ -z "$@" ]] && usage 2 && exit 394 | shift 1 395 | lsparms="$@" 396 | [[ ${lsarg} == @(all|locations|configurations\ 397 | |interfaces|waps) ]] || 398 | usage 2 399 | ;; 400 | create) 401 | shift 1 402 | locations="$@" 403 | ;; 404 | delete) 405 | shift 1 406 | locations="$@" 407 | ;; 408 | switch) 409 | shift 1 410 | location="$1" 411 | [ -d "${HN_DIR}/${location}" ] || usage 2 412 | [[ -z "$@" ]] && usage 2 && exit 413 | shift 1 414 | ifs="$@" 415 | get_ifs ${ifs} # throws its own errors 416 | ifs="${_ifs[@]}" 417 | ;; 418 | enable|disable|stop) 419 | shift 1 420 | ifs="$@" 421 | get_ifs ${ifs} # throws its own errors 422 | ifs="${_ifs[@]}" 423 | ;; 424 | start|restart) 425 | shift 1 426 | ifs="$@" 427 | if [ ${autowap} -eq 1 ] && [ -z "${ifs}" ] ; then 428 | get_ifs wlan # throws its own errors 429 | ifs="${_ifs[@]}" 430 | elif [ ${autowap} -eq 1 ] && [ -n "${ifs}" ] ; then 431 | # Check whether ${ifs} are in wlan group 432 | get_ifs wlan # throws its own errors 433 | for _if in ${ifs} ; do 434 | [[ " ${_ifs} " == *" ${_if} "* ]] && 435 | continue 436 | log_err "${_if} not in wlan group" 3 437 | done 438 | else 439 | get_ifs ${ifs} # throws its own errors 440 | ifs="${_ifs[@]}" 441 | fi 442 | ;; 443 | scan) 444 | shift 1 445 | ifs="$@" 446 | get_ifs "${ifs:-wlan}" # throws its own errors 447 | ifs="${_ifs[@]}" 448 | ;; 449 | *) 450 | usage 2 451 | exit 452 | ;; 453 | esac 454 | 455 | case ${cmd} in 456 | ls) 457 | case ${lsarg} in 458 | all) 459 | ls_locations 460 | ls_configurations 461 | ls_interfaces 462 | ls_waps 463 | ;; 464 | locations) 465 | ls_locations 466 | ;; 467 | configurations) 468 | ls_configurations ${lsparms};; 469 | interfaces) 470 | ls_interfaces;; 471 | waps) 472 | ls_waps;; 473 | *) 474 | usage 2 475 | ;; 476 | esac 477 | ;; 478 | create) 479 | for _loc in ${locations} ; do 480 | mkdir -p "${HN_DIR}/${_loc}" && continue 481 | log_warning "Unable to create location ${_loc}" 482 | done 483 | ;; 484 | delete) 485 | for _loc in ${locations} ; do 486 | rm -rf "${HN_DIR}/${_loc}" && continue 487 | log_warning "Unable to delete location ${_loc}" 488 | done 489 | ;; 490 | switch) 491 | for _if in ${ifs} ; do 492 | _from="${HN_DIR}/${location}/hostname.${_if}" 493 | _to="/etc/hostname.${_if}" 494 | link_configuration ${_if} "${_from}" "${_to}" 495 | done 496 | ;; 497 | enable) 498 | for _if in ${ifs} ; do 499 | _from="/etc/hostname.${_if}.disabled" 500 | _to="/etc/hostname.${_if}" 501 | [ -f "${_from}" ] || continue 502 | 503 | [ -f "${_from}" ] && ! [ -f "${_to}" ] && 504 | mv "${_from}" "${_to}" && 505 | continue 506 | 507 | log_warning "Unable to enable ${_if}" 508 | done 509 | ;; 510 | disable) 511 | for _if in ${ifs} ; do 512 | _from="/etc/hostname.${_if}" 513 | _to="/etc/hostname.${_if}.disabled" 514 | [ -f "${_from}" ] || continue 515 | 516 | [ -f "${_from}" ] && 517 | mv "${_from}" "${_to}" && 518 | continue 519 | 520 | log_warning "Unable to disable ${_if}" 521 | done 522 | ;; 523 | start|restart) 524 | local _match _groups _media _status _ieee80211 \ 525 | _inet _inet6 526 | set -A _match 527 | 528 | for _if in ${ifs} ; do 529 | get_if_conf ${_if} 530 | # if _if status == "no network" scanning fails 531 | # stop the interface and reset 532 | [[ "${_status}" == 'no network' ]] && 533 | log_warning "Stopping ${_if} ..." && 534 | if_stop ${_if} 535 | # wap_match ${_if} 536 | # [ -n "${_match}" ] || return 537 | _to="/etc/hostname.${_if}" 538 | #link_configuration ${_if} "${_match}" "${_to}" 539 | if_restart ${_if} 540 | ifconfig ${_if} 541 | done 542 | ;; 543 | stop) 544 | for _if in ${ifs} ; do 545 | if_stop ${_if} 546 | done 547 | ;; 548 | scan) 549 | local _nwids 550 | set -A _nwids 551 | for _if in ${ifs} ; do 552 | log_msg "${_if}:" 553 | scan ${_if} ${verbose} 554 | for _nwid in "${_nwids[@]}" ; do 555 | log_msg "\t${_nwid}" 556 | done 557 | done 558 | ;; 559 | *) 560 | usage 2 561 | ;; 562 | esac 563 | -------------------------------------------------------------------------------- /netctl.8: -------------------------------------------------------------------------------- 1 | .\" $OpenBSD$ 2 | .\" 3 | .\" Copyright (c) 2017 Aaron Poffenberger 4 | .\" 5 | .\" Permission to use, copy, modify, and distribute this software for any 6 | .\" purpose with or without fee is hereby granted, provided that the above 7 | .\" copyright notice and this permission notice appear in all copies. 8 | .\" 9 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | .\" 17 | .Dd $Mdocdate: Sep 23 2017 $ 18 | .Dt NETCTL 8 19 | .Os 20 | .Sh NAME 21 | .Nm netctl 22 | .Nd configure and control hostname.if definitions 23 | .Sh SYNOPSIS 24 | .Nm netctl 25 | .Op Fl h 26 | .Nm netctl 27 | .Cm ls 28 | .Op Ar lsarg ... 29 | .Nm netctl 30 | .Cm create|delete 31 | .Ar location ... 32 | .Nm netctl 33 | .Op Fl dr 34 | .Cm switch 35 | .Ar location 36 | .Op Ar interface ... 37 | .Nm netctl 38 | .Cm enable|disable 39 | .Op Ar configuration ... 40 | .Nm netctl 41 | .Op Fl a 42 | .Cm start|restart 43 | .Op Ar interface ... 44 | .Nm netctl 45 | .Cm stop 46 | .Op Ar interface ... 47 | .Nm netctl 48 | .Op Fl v 49 | .Cm scan 50 | .Op Ar interface ... 51 | .Sh DESCRIPTION 52 | The 53 | .Nm 54 | utility is used to manage network locations, interface configuration 55 | files, and to start, stop, or restart interfaces. 56 | .Pp 57 | .Nm 58 | works with 59 | .Xr ifconfig 8 60 | and 61 | .Xr netstart 8 . 62 | It does not replace them. 63 | .Pp 64 | The following options are available: 65 | .Bl -tag -width Ds 66 | .It Fl h 67 | Help message. 68 | .It Cm ls Op Ar lsarg ... 69 | Display a list of locations, configurations, interfaces and known wireless access points matching 70 | .Ar lsarg , 71 | which can be one of: 72 | .Bl -tag -width "interfaces" -offset indent -compact 73 | .It Cm all 74 | all locations, configurations and interfaces 75 | .It Cm configurations Op Ar location ... 76 | all configurations for the current 77 | .Ar location 78 | or locations 79 | .It Cm interfaces 80 | all interfaces (exluding pseudo-devices) 81 | .It Cm locations 82 | all locations 83 | .It Cm waps 84 | all known (configured) wireless access points 85 | .El 86 | .It Ar location 87 | The 88 | .Ar location 89 | parameter is the name of a collection of related 90 | .Ar interface 91 | configuration files. 92 | .Pp 93 | .Nm 94 | locations are stored as directories in 95 | .Pa /etc/hostname.d . 96 | See 97 | .Sx FILES . 98 | .Pp 99 | .Sy N.B . 100 | May not include network pseudo-devices. 101 | .It Ar configuration 102 | The 103 | .Ar configuration 104 | parameter is a 105 | .Xr hostname.if 5 106 | file in a 107 | .Ar location 108 | directory. 109 | See 110 | .Sx FILES . 111 | .It Ar interface 112 | The 113 | .Ar interface 114 | parameter is an interface 115 | .Dq name unit 116 | as defined in 117 | .Xr ifconfig 8 118 | which includes groups. 119 | .El 120 | .Sh LOCATION 121 | The following commands are available for working with network locations: 122 | .Bl -tag -width Ds 123 | .It Cm create Ar location ... 124 | Create one or more locations. 125 | .It Cm delete Ar location ... 126 | Delete one or more locations. 127 | .Pp 128 | .Sy N.B . 129 | Deletes all 130 | .Ar interface 131 | .Ar configuration 132 | files in 133 | .Ar location . 134 | .It Oo Fl dr Oc Cm switch Ar location Oo Ar interface ... Oc 135 | Switch to 136 | .Ar location . 137 | .It Fl d 138 | Delete 139 | .Pa /etc/hostname.if 140 | not found in 141 | .Ar location . 142 | .Pp 143 | .Sy N.B . 144 | Does not affect actual interface. 145 | Removes symlink from previous location. 146 | Otherwise the symlink to the previous location configuration is left in place. 147 | .Pp 148 | .Sy Default : 149 | leave in place. 150 | .It Fl r 151 | Restart the interface(s) after switching. 152 | .El 153 | .Sh CONFIGURATION 154 | The following commands are available for working with interface configurations: 155 | .Bl -tag -width Ds 156 | .It Cm enable Ar configuration ... 157 | Enable an interface 158 | .Ar configuration . 159 | .It Cm disable Ar configuration ... 160 | Disable an interface 161 | .Ar configuration . 162 | .El 163 | .Sh INTERFACE 164 | The following commands are available for working with interfaces: 165 | .Bl -tag -width Ds 166 | .It Oo Fl a Oc Cm start Op Ar interface ... 167 | Start one or more interfaces. 168 | .It Fl a 169 | If the interface is in the wlan group, try to connect to a known wireless access point. 170 | .It Cm stop Op Ar interface ... 171 | Stop one or more interfaces. 172 | .It Oo Fl a Oc Cm restart Op Ar interface ... 173 | Restart one or more interfaces. 174 | .It Fl a 175 | If the interface is in the wlan group, try to connect to a known wireless access point. 176 | .It Oo Fl v Oc Cm scan Op Ar interface ... 177 | Scan for wireless access point with one or more interfaces. 178 | .It Fl v 179 | Verbose scan. 180 | .It Fl vv 181 | Detailed scan (Same as 182 | .Cm ifconfig Ar if Ar scan Ns 183 | ). 184 | .El 185 | .Sh ENVIRONMENT 186 | .Bl -tag -width MANPATHX 187 | .It Ev HN_DIR 188 | Directory to find 189 | .Ar location 190 | directories and interface configuration files. 191 | .El 192 | .Sh FILES 193 | .Bl -tag -width "/etc/hostname.d/nwids/NAME.nwid" -compact 194 | .It Pa /etc/hostname.d 195 | default 196 | .Ar location 197 | directory. 198 | .Pp 199 | .It Pa /etc/hostname.d/*/hostname.XXX 200 | interface-specific 201 | .Ar configuration 202 | files by location. 203 | .Pp 204 | .It Pa /etc/hostname.d/nwids 205 | default location for known wireless access point 206 | .Ar configuration 207 | files. 208 | .Pp 209 | .It Pa /etc/hostname.d/nwids/NAME.nwid 210 | .Ar configuration 211 | files for known wireless access points named for the access point (including spaces). 212 | .El 213 | .Sh EXAMPLES 214 | Create new location: 215 | .Bd -literal -offset indent 216 | $ doas netctl create home 217 | .Ed 218 | .Pp 219 | Start 220 | .Ar em0 : 221 | .Bd -literal -offset indent 222 | $ doas netctl start em0 223 | .Ed 224 | .Pp 225 | Start 226 | .Ar iwm 227 | and connect to known wireless access point: 228 | .Bd -literal -offset indent 229 | $ doas netctl -a start iwm0 230 | Found "Silly Wap" 231 | Switch iwm0 232 | iwm0: no link ..... got link 233 | iwm0: DHCPREQUEST to 255.255.255.255 234 | iwm0: DHCPREQUEST to 255.255.255.255 235 | iwm0: DHCPACK from 192.168.1.1 (00:00:00:00:00:00) 236 | iwm0: bound to 192.168.1.41 -- renewal in 3600 seconds 237 | .Ed 238 | .Pp 239 | Switch location and restart all interfaces: 240 | .Bd -literal -offset indent 241 | netctl -r switch home 242 | .Ed 243 | .Pp 244 | Switch location and restart 245 | .Ar iwm0 : 246 | .Bd -literal -offset indent 247 | $ doas netctl -r switch home iwm0 248 | .Ed 249 | .Pp 250 | Switch location and remove unconfigured interfaces: 251 | .Bd -literal -offset indent 252 | $ ls /etc/hostname.{em,iwm}0 253 | /etc/hostname.em0@ /etc/hostname.iwm0@ 254 | 255 | $ ls /etc/hostname.d/work 256 | /etc/hostname.d/work/hostname.iwm0 257 | 258 | $ doas netctl -d switch work 259 | 260 | $ ls /etc/hostname.{em,iwm}0 261 | /etc/hostname.iwm0@ 262 | .Ed 263 | .Pp 264 | Scan for wireless access points with 265 | .Ar iwm0 : 266 | .Bd -literal -offset indent 267 | $ doas netctl -v scan iwm0 268 | iwm0: 269 | supersecurewap 270 | notsosecurewap 271 | "Silly Wap" 272 | .Ed 273 | .Pp 274 | Simple integration with 275 | .Xr apmd 8 276 | might look like: 277 | .Bd -literal -offset indent 278 | $ ls -l 279 | lrwxr-xr-x 1 root wheel 7 Sep 20 16:23 powerup@ -> suspend 280 | lrwxr-xr-x 1 root wheel 7 Sep 20 16:23 resume@ -> suspend 281 | -rwxr--r-- 1 root wheel 225 Sep 27 20:41 suspend* 282 | 283 | $ cat /etc/apm/suspend 284 | #!/bin/sh 285 | 286 | cmd="${0##*([[:blank:]])/etc/apm/}" 287 | case "${cmd}" in 288 | powerup|resume) 289 | /usr/local/bin/netctl -a restart 290 | ;; 291 | *) 292 | ;; 293 | esac 294 | .Ed 295 | .Sh DIAGNOSTICS 296 | .Nm 297 | utility always exits 0. 298 | .Sh SEE ALSO 299 | .Xr hostname.if 5 , 300 | .Xr apmd 8 , 301 | .Xr ifconfig 8 , 302 | .Xr netstart 8 303 | .Sh HISTORY 304 | .Nm 305 | is a new utility but it draws inspiration and style from 306 | .Xr rcctl 8 307 | and 308 | .Xr netstart 8 . 309 | .Pp 310 | A great deal of credit is due to Antoine Jacoutot, Ingo Schwarze, and 311 | Robert Nagy for their work on 312 | .Xr rcctl 8 313 | and 314 | .Xr netstart 8 . 315 | .Sh AUTHORS 316 | .An -nosplit 317 | The 318 | .Nm 319 | utility was written by 320 | .An Aaron Poffenberger Aq Mt akp@hypernote.com . 321 | .Sh BUGS 322 | .Nm 323 | should prevent users from running commands that require superuser. 324 | .Nm 325 | should al work with some network pseudo-devices like 326 | .Xr trunk 4 . 327 | --------------------------------------------------------------------------------