1451640b7SAaron LI#!/bin/sh 2451640b7SAaron LI# 3451640b7SAaron LI# Copyright (c) 2024 The DragonFly Project. All rights reserved. 4451640b7SAaron LI# 5451640b7SAaron LI# This code is derived from software contributed to The DragonFly Project 6451640b7SAaron LI# by Aaron LI <aly@aaronly.me> 7451640b7SAaron LI# 8451640b7SAaron LI# Redistribution and use in source and binary forms, with or without 9451640b7SAaron LI# modification, are permitted provided that the following conditions 10451640b7SAaron LI# are met: 11451640b7SAaron LI# 12451640b7SAaron LI# 1. Redistributions of source code must retain the above copyright 13451640b7SAaron LI# notice, this list of conditions and the following disclaimer. 14451640b7SAaron LI# 2. Redistributions in binary form must reproduce the above copyright 15451640b7SAaron LI# notice, this list of conditions and the following disclaimer in 16451640b7SAaron LI# the documentation and/or other materials provided with the 17451640b7SAaron LI# distribution. 18451640b7SAaron LI# 3. Neither the name of The DragonFly Project nor the names of its 19451640b7SAaron LI# contributors may be used to endorse or promote products derived 20451640b7SAaron LI# from this software without specific, prior written permission. 21451640b7SAaron LI# 22451640b7SAaron LI# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23451640b7SAaron LI# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24451640b7SAaron LI# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25451640b7SAaron LI# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26451640b7SAaron LI# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27451640b7SAaron LI# INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28451640b7SAaron LI# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29451640b7SAaron LI# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30451640b7SAaron LI# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31451640b7SAaron LI# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32451640b7SAaron LI# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33451640b7SAaron LI# SUCH DAMAGE. 34451640b7SAaron LI# 35451640b7SAaron LI 36451640b7SAaron LI# PROVIDE: wg wireguard 37451640b7SAaron LI# REQUIRE: NETWORKING 38451640b7SAaron LI# BEFORE: DAEMON 39451640b7SAaron LI 40451640b7SAaron LI# uncomment to show extra debug logs 41451640b7SAaron LI#WG_DEBUG=yes 42451640b7SAaron LI# uncomment to not actually execute the commands 43451640b7SAaron LI#WG_DRYRUN=yes 44451640b7SAaron LI 45451640b7SAaron LI. /etc/rc.subr 46451640b7SAaron LI 47451640b7SAaron LIname="wg" 48451640b7SAaron LIrcvar=$(set_rcvar) 49451640b7SAaron LIstart_cmd="${name}_start" 50451640b7SAaron LIstop_cmd="${name}_stop" 51451640b7SAaron LIstatus_cmd="${name}_status" 52451640b7SAaron LIextra_commands="status" 53451640b7SAaron LI 54451640b7SAaron LI# usage: wg_run cmd ... 55451640b7SAaron LIwg_run() 56451640b7SAaron LI{ 57451640b7SAaron LI if [ -n "${WG_DRYRUN}" ]; then 58451640b7SAaron LI printf "[+] %s\n" "$*" 59451640b7SAaron LI return 60451640b7SAaron LI fi 61451640b7SAaron LI debug "[+] $*" 62451640b7SAaron LI "$@" 63451640b7SAaron LI} 64451640b7SAaron LI 65451640b7SAaron LI# similar to wg_run(), but exit if the command fails. 66451640b7SAaron LIwg_must_run() 67451640b7SAaron LI{ 68451640b7SAaron LI wg_run "$@" 69451640b7SAaron LI local ret=$? 70451640b7SAaron LI if [ ${ret} -ne 0 ]; then 71451640b7SAaron LI err ${ret} "return code: ${ret}, command was: $*" 72451640b7SAaron LI fi 73451640b7SAaron LI} 74451640b7SAaron LI 75451640b7SAaron LI# usage: wg_load_config <conffile> 76451640b7SAaron LIwg_load_config() 77451640b7SAaron LI{ 78451640b7SAaron LI local conffile=$1 79451640b7SAaron LI local ifname=$(basename ${conffile} .conf) 80451640b7SAaron LI 81451640b7SAaron LI debug "loading [${ifname}] configs from file: ${conffile}" 82451640b7SAaron LI local configs=$(awk -v ifname="${ifname}" -v debugvar="${WG_DEBUG}" ' 83451640b7SAaron LI BEGIN { 84451640b7SAaron LI SUBSEP = "_" 85451640b7SAaron LI 86451640b7SAaron LI # conversion table for hex2dec() 87451640b7SAaron LI xdigits = "0123456789abcdef" 88451640b7SAaron LI for (i = 0; i < length(xdigits); i++) { 89451640b7SAaron LI k = substr(xdigits, i + 1, 1) 90451640b7SAaron LI decv[k] = i 91451640b7SAaron LI decv[toupper(k)] = i 92451640b7SAaron LI } 93451640b7SAaron LI } 94451640b7SAaron LI 95451640b7SAaron LI function debug(msg) { 96451640b7SAaron LI if (!debugvar) 97451640b7SAaron LI return 98451640b7SAaron LI printf("wg [%s]: DEBUG: %s\n", ifname, msg) > "/dev/stderr" 99451640b7SAaron LI } 100451640b7SAaron LI function info(msg) { 101451640b7SAaron LI printf("wg [%s]: INFO: %s\n", ifname, msg) > "/dev/stderr" 102451640b7SAaron LI } 103451640b7SAaron LI function warn(msg) { 104451640b7SAaron LI printf("wg [%s]: WARNING: %s\n", ifname, msg) > "/dev/stderr" 105451640b7SAaron LI } 106451640b7SAaron LI function error(code, msg) { 107451640b7SAaron LI printf("wg [%s]: ERROR: %s\n", ifname, msg) > "/dev/stderr" 108451640b7SAaron LI exit code 109451640b7SAaron LI } 110451640b7SAaron LI function hex2dec(x, v) { 111451640b7SAaron LI # The 0x prefix is optional. 112451640b7SAaron LI v = 0 113451640b7SAaron LI for (i = 1; i <= length(x); i++) 114451640b7SAaron LI v = 16 * v + decv[substr(x, i, 1)] 115451640b7SAaron LI return v 116451640b7SAaron LI } 117451640b7SAaron LI function fix_integer(v) { 118451640b7SAaron LI if (v == "off") 119451640b7SAaron LI return 0 120451640b7SAaron LI else if (v ~ /^0[xX][[:xdigit:]]+$/) 121451640b7SAaron LI return hex2dec(v) 122451640b7SAaron LI else 123451640b7SAaron LI return v + 0 124451640b7SAaron LI } 125451640b7SAaron LI function fix_boolean(v) { 126451640b7SAaron LI v = tolower(v) 127451640b7SAaron LI if (v == "1" || v == "true" || v == "on" || v == "yes") 128451640b7SAaron LI return "true" 129451640b7SAaron LI else 130451640b7SAaron LI return "false" 131451640b7SAaron LI } 132451640b7SAaron LI function fix_endpoint(v) { 133451640b7SAaron LI if (v ~ /^\[/) { 134451640b7SAaron LI # Assume IPv6: [ipv6]:port 135451640b7SAaron LI sub(/\[/, "", v) 136451640b7SAaron LI sub(/\]:/, " ", v) 137451640b7SAaron LI } else { 138451640b7SAaron LI # Assume IPv4 or domain: ipv4:port, domain:port 139451640b7SAaron LI sub(/:/, " ", v) 140451640b7SAaron LI } 141451640b7SAaron LI return v 142451640b7SAaron LI } 143451640b7SAaron LI function fix_address(v, n, a) { 144451640b7SAaron LI # Comma-separated IPv4/IPv6, with optional CIDR masks 145451640b7SAaron LI n = split(v, addrs, /[, ]+/) 146451640b7SAaron LI v = "" 147451640b7SAaron LI for (i = 1; i <= n; i++) { 148451640b7SAaron LI a = addrs[i] 149451640b7SAaron LI if (!index(a, "/")) { 150451640b7SAaron LI if (index(a, ":")) 151451640b7SAaron LI a = a "/128" 152451640b7SAaron LI else 153451640b7SAaron LI a = a "/32" 154451640b7SAaron LI } 155451640b7SAaron LI v = v " " a 156451640b7SAaron LI } 157451640b7SAaron LI return v 158451640b7SAaron LI } 159451640b7SAaron LI function fix_aips(v, n) { 160451640b7SAaron LI # Comma-separated IPv4/IPv6 with CIDR masks 161451640b7SAaron LI n = split(v, aips, /[, ]+/) 162451640b7SAaron LI v = "" 163451640b7SAaron LI for (i = 1; i <= n; i++) 164451640b7SAaron LI v = v " " aips[i] 165451640b7SAaron LI return v 166451640b7SAaron LI } 167451640b7SAaron LI function trim(s) { 168451640b7SAaron LI gsub(/^[ \t]+|[ \t]+$/, "", s) 169451640b7SAaron LI return s 170451640b7SAaron LI } 171451640b7SAaron LI function quote(s) { 172451640b7SAaron LI # NOTE: \047 is the single quote. 173451640b7SAaron LI gsub(/\047/, "\047\\\047\047", s) 174f43226ddSAaron LI return "\047" s "\047" 175451640b7SAaron LI } 176451640b7SAaron LI 177451640b7SAaron LI NF == 0 || $1 ~ /^[#;]/ { 178451640b7SAaron LI next 179451640b7SAaron LI } 180451640b7SAaron LI $1 ~ /^\[/ { 181451640b7SAaron LI section = tolower($1) 182451640b7SAaron LI if (section == "[interface]") { 183451640b7SAaron LI is_interface = 1 184451640b7SAaron LI is_peer = 0 185451640b7SAaron LI } else if (section == "[peer]") { 186451640b7SAaron LI is_interface = 0 187451640b7SAaron LI is_peer = 1 188451640b7SAaron LI peer_count++ 189451640b7SAaron LI } else { 190451640b7SAaron LI is_interface = 0 191451640b7SAaron LI is_peer = 0 192451640b7SAaron LI warn(sprintf("unknown section: %s", section)) 193451640b7SAaron LI } 194451640b7SAaron LI next 195451640b7SAaron LI } 196451640b7SAaron LI !(is_interface || is_peer) { 197451640b7SAaron LI warn(sprintf("skip unknown %s: %s", section, $0)) 198451640b7SAaron LI next 199451640b7SAaron LI } 200451640b7SAaron LI $0 !~ /^[ \t]*[[:alnum:]]+[ \t]*=[ \t]*[^ \t].*$/ { 201451640b7SAaron LI warn(sprintf("skip invalid line: %s", $0)) 202451640b7SAaron LI next 203451640b7SAaron LI } 204451640b7SAaron LI { 205451640b7SAaron LI match($0, /^[ \t]*[[:alnum:]]+[ \t]*=/) 206451640b7SAaron LI key = trim(tolower(substr($0, 1, RLENGTH - 1))) 207451640b7SAaron LI value = trim(substr($0, RLENGTH + 1)) 208451640b7SAaron LI if (key == "" || value == "") 209451640b7SAaron LI error(1, "code bug") # already skipped; cannot happen 210451640b7SAaron LI 211451640b7SAaron LI # Join split lines. 212451640b7SAaron LI while (value ~ /\\$/) { 213451640b7SAaron LI if ((getline vline) <= 0) { 214451640b7SAaron LI warn(sprintf("incomplete value of |%s|: %s", 215451640b7SAaron LI key, value)) 216451640b7SAaron LI break 217451640b7SAaron LI } 218451640b7SAaron LI value = substr(value, 1, length(value) - 1) 219451640b7SAaron LI value = value " " trim(vline) 220451640b7SAaron LI } 221451640b7SAaron LI 222451640b7SAaron LI if (is_interface) { 223451640b7SAaron LI debug(sprintf("interface: |%s| = |%s|", key, value)) 224451640b7SAaron LI if (key == "description" || key == "privatekey" || 225451640b7SAaron LI key == "listenport" || key == "mtu") { 226451640b7SAaron LI interface[key] = value 227451640b7SAaron LI } else if (key == "cookie" || key == "fwmark") { 228451640b7SAaron LI key = "cookie" 229451640b7SAaron LI interface[key] = fix_integer(value) 230451640b7SAaron LI } else if (key == "address") { 231451640b7SAaron LI old = interface[key] 232451640b7SAaron LI interface[key] = old " " fix_address(value) 233451640b7SAaron LI } else if (key == "preup" || key == "postup" || 234451640b7SAaron LI key == "predown" || key == "postdown") { 235451640b7SAaron LI gsub(/%i/, ifname, value) 236451640b7SAaron LI n = ++interface[key "_count"] 237451640b7SAaron LI interface[key n] = value 238451640b7SAaron LI } else { 239451640b7SAaron LI info(sprintf("ignore unsupported interface " \ 240451640b7SAaron LI "config: %s = %s", key, value)) 241451640b7SAaron LI next 242451640b7SAaron LI } 243451640b7SAaron LI } else { 244451640b7SAaron LI debug(sprintf("peer[%d]: |%s| = |%s|", 245451640b7SAaron LI peer_count, key, value)) 246451640b7SAaron LI if (key == "description" || key == "publickey" || 247451640b7SAaron LI key == "presharedkey") { 248451640b7SAaron LI peers[peer_count, key] = value 249451640b7SAaron LI } else if (key == "endpoint") { 250451640b7SAaron LI peers[peer_count, key] = fix_endpoint(value) 251451640b7SAaron LI } else if (key == "allowedips") { 252451640b7SAaron LI old = peers[peer_count, key] 253451640b7SAaron LI peers[peer_count, key] = old " " fix_aips(value) 254451640b7SAaron LI } else if (key == "persistentkeepalive") { 255451640b7SAaron LI peers[peer_count, key] = fix_integer(value) 256451640b7SAaron LI } else if (key == "enabled") { 257451640b7SAaron LI peers[peer_count, key] = fix_boolean(value) 258451640b7SAaron LI } else { 259451640b7SAaron LI info(sprintf("ignore unsupported peer " \ 260451640b7SAaron LI "config: %s = %s", key, value)) 261451640b7SAaron LI next 262451640b7SAaron LI } 263451640b7SAaron LI } 264451640b7SAaron LI } 265451640b7SAaron LI 266451640b7SAaron LI END { 267451640b7SAaron LI for (key in interface) 268451640b7SAaron LI printf("_wg_interface_%s=%s;\n", 269451640b7SAaron LI key, quote(interface[key])) 270451640b7SAaron LI 2719c070710SAaron LI peer_count += 0 # fix empty value to be 0 272451640b7SAaron LI printf("_wg_peer_count=%s;\n", quote(peer_count)) 273451640b7SAaron LI for (key in peers) 274451640b7SAaron LI printf("_wg_peer%s=%s;\n", key, quote(peers[key])) 275451640b7SAaron LI }' "${conffile}") || exit $? 276451640b7SAaron LI 277451640b7SAaron LI local msg=$(printf "eval configs: {{{\n%s\n}}}\n" "${configs}") 278451640b7SAaron LI debug "${msg}" 279451640b7SAaron LI 280451640b7SAaron LI eval "${configs}" 281451640b7SAaron LI} 282451640b7SAaron LI 283451640b7SAaron LI# usage: wg_set_interface <ifname> 284451640b7SAaron LIwg_set_interface() 285451640b7SAaron LI{ 286451640b7SAaron LI local ifname=$1 287451640b7SAaron LI 288451640b7SAaron LI local privkey=${_wg_interface_privatekey} 289451640b7SAaron LI local port=${_wg_interface_listenport} 290451640b7SAaron LI local cookie=${_wg_interface_cookie} 291451640b7SAaron LI 292451640b7SAaron LI local args= 293451640b7SAaron LI if [ -z "${privkey}" ]; then 294451640b7SAaron LI err 1 "interface is missing the private key" 295451640b7SAaron LI else 296451640b7SAaron LI args="wgkey ${privkey}" 297451640b7SAaron LI fi 298451640b7SAaron LI if [ -n "${port}" ]; then 299451640b7SAaron LI args="${args} wgport ${port}" 300451640b7SAaron LI fi 301451640b7SAaron LI if [ -n "${cookie}" ]; then 302451640b7SAaron LI args="${args} wgcookie ${cookie}" 303451640b7SAaron LI fi 304451640b7SAaron LI wg_must_run ifconfig ${ifname} ${args} 305451640b7SAaron LI 306451640b7SAaron LI local addrs=${_wg_interface_address} 307451640b7SAaron LI local addr af 308451640b7SAaron LI for addr in ${addrs}; do 309451640b7SAaron LI case ${addr} in 310451640b7SAaron LI *:*) 311451640b7SAaron LI af=inet6 312451640b7SAaron LI ;; 313451640b7SAaron LI *) 314451640b7SAaron LI af=inet 315451640b7SAaron LI ;; 316451640b7SAaron LI esac 317451640b7SAaron LI wg_run ifconfig ${ifname} ${af} ${addr} alias 318451640b7SAaron LI done 319451640b7SAaron LI 320451640b7SAaron LI local descr=${_wg_interface_description} 321451640b7SAaron LI if [ -n "${descr}" ]; then 322451640b7SAaron LI wg_run ifconfig ${ifname} description "${descr}" 323451640b7SAaron LI fi 324451640b7SAaron LI 325451640b7SAaron LI local mtu=${_wg_interface_mtu} 326451640b7SAaron LI if [ -n "${mtu}" ]; then 327451640b7SAaron LI wg_run ifconfig ${ifname} mtu ${mtu} 328451640b7SAaron LI fi 329451640b7SAaron LI} 330451640b7SAaron LI 331451640b7SAaron LI# usage: wg_set_peer <ifname> <peerid> 332451640b7SAaron LIwg_set_peer() 333451640b7SAaron LI{ 334451640b7SAaron LI local ifname=$1 335451640b7SAaron LI local peerid=$2 336451640b7SAaron LI 337451640b7SAaron LI local enabled 338451640b7SAaron LI eval 'enabled="${_wg_'${peerid}'_enabled}"' 339451640b7SAaron LI if [ "${enabled}" = "false" ]; then 340451640b7SAaron LI info "peer [${peerid}] is disabled" 341451640b7SAaron LI return 342451640b7SAaron LI fi 343451640b7SAaron LI 344451640b7SAaron LI local publickey 345451640b7SAaron LI eval 'publickey="${_wg_'${peerid}'_publickey}"' 346451640b7SAaron LI if [ -z "${publickey}" ]; then 347451640b7SAaron LI warn "peer [${peerid}] is missing the public key" 348451640b7SAaron LI return 349451640b7SAaron LI fi 350451640b7SAaron LI local cmd="ifconfig ${ifname} wgpeer ${publickey}" 351451640b7SAaron LI 352451640b7SAaron LI local descr 353451640b7SAaron LI eval 'descr="${_wg_'${peerid}'_description}"' 354451640b7SAaron LI if [ -n "${descr}" ]; then 355451640b7SAaron LI wg_run ${cmd} wgdescription "${descr}" 356451640b7SAaron LI fi 357451640b7SAaron LI 358451640b7SAaron LI local psk endpoint pka aips 359451640b7SAaron LI eval 'psk="${_wg_'${peerid}'_presharedkey}"' 360451640b7SAaron LI eval 'endpoint="${_wg_'${peerid}'_endpoint}"' 361451640b7SAaron LI eval 'pka="${_wg_'${peerid}'_persistentkeepalive}"' 362451640b7SAaron LI eval 'aips="${_wg_'${peerid}'_allowedips}"' 363451640b7SAaron LI 364451640b7SAaron LI local args= aip 365451640b7SAaron LI if [ -n "${psk}" ]; then 366451640b7SAaron LI args="${args} wgpsk ${psk}" 367451640b7SAaron LI fi 368451640b7SAaron LI if [ -n "${endpoint}" ]; then 369451640b7SAaron LI args="${args} wgendpoint ${endpoint}" 370451640b7SAaron LI fi 371451640b7SAaron LI if [ -n "${pka}" ]; then 372451640b7SAaron LI args="${args} wgpka ${pka}" 373451640b7SAaron LI fi 374451640b7SAaron LI # All allowed IPs must be configured at once. 375451640b7SAaron LI for aip in ${aips}; do 376451640b7SAaron LI args="${args} wgaip ${aip}" 377451640b7SAaron LI done 378451640b7SAaron LI wg_run ${cmd} ${args} 379451640b7SAaron LI} 380451640b7SAaron LI 381451640b7SAaron LI# usage: wg_exec_hook <preup|postup|predown|postdown> 382451640b7SAaron LIwg_exec_hook() 383451640b7SAaron LI{ 384451640b7SAaron LI local hook=$1 385451640b7SAaron LI local count 386451640b7SAaron LI 387451640b7SAaron LI case ${hook} in 388451640b7SAaron LI preup|postup|predown|postdown) 389451640b7SAaron LI eval 'count="${_wg_interface_'${hook}'_count:-0}"' 390451640b7SAaron LI ;; 391451640b7SAaron LI *) 392451640b7SAaron LI err 1 "unknown hook: ${hook}" 393451640b7SAaron LI ;; 394451640b7SAaron LI esac 395451640b7SAaron LI 396451640b7SAaron LI debug "executing [${hook}] hook (${count} actions) ..." 397451640b7SAaron LI 398451640b7SAaron LI local i=1 cmd ret 399451640b7SAaron LI while [ ${i} -le ${count} ]; do 400451640b7SAaron LI eval 'cmd="${_wg_interface_'${hook}${i}'}"' 401451640b7SAaron LI wg_run sh -c "${cmd}" 402451640b7SAaron LI ret=$? 403451640b7SAaron LI if [ ${ret} -ne 0 ]; then 404451640b7SAaron LI warn "return code: ${ret}, command was: sh -c '${cmd}'" 405451640b7SAaron LI fi 406451640b7SAaron LI i=$((i + 1)) 407451640b7SAaron LI done 408451640b7SAaron LI} 409451640b7SAaron LI 410451640b7SAaron LI# usage: wg_start_interface <ifname> 411451640b7SAaron LIwg_start_interface() 412451640b7SAaron LI{ 413451640b7SAaron LI local ifname=$1 414451640b7SAaron LI info "starting interface [${ifname}] ..." 415451640b7SAaron LI 416e1be3f08SAaron LI local conffile="${wg_config_dir}/${ifname}.conf" 417451640b7SAaron LI if [ ! -r "${conffile}" ]; then 418451640b7SAaron LI err 1 "cannot read config file: ${conffile}" 419451640b7SAaron LI fi 420451640b7SAaron LI 421451640b7SAaron LI wg_load_config "${conffile}" 422451640b7SAaron LI 423451640b7SAaron LI wg_exec_hook preup 424451640b7SAaron LI 425451640b7SAaron LI local cmd 426*212e48ceSAntonio Huete Jimenez if expr "${ifname}" : 'wg[0-9][0-9]*$' > /dev/null; then 427451640b7SAaron LI cmd="ifconfig ${ifname} create" 428451640b7SAaron LI else 429451640b7SAaron LI cmd="ifconfig wg create name ${ifname}" 430451640b7SAaron LI fi 431451640b7SAaron LI wg_must_run ${cmd} > /dev/null 432451640b7SAaron LI 433451640b7SAaron LI wg_set_interface ${ifname} 434451640b7SAaron LI 435451640b7SAaron LI local i=1 436451640b7SAaron LI while [ ${i} -le ${_wg_peer_count:-0} ]; do 437451640b7SAaron LI wg_set_peer ${ifname} "peer${i}" 438451640b7SAaron LI i=$((i + 1)) 439451640b7SAaron LI done 440451640b7SAaron LI 441451640b7SAaron LI wg_run ifconfig ${ifname} up 442451640b7SAaron LI 443451640b7SAaron LI wg_exec_hook postup 444451640b7SAaron LI 445451640b7SAaron LI info "interface [${ifname}] started." 446451640b7SAaron LI} 447451640b7SAaron LI 448451640b7SAaron LI# usage: wg_stop_interface <ifname> 449451640b7SAaron LIwg_stop_interface() 450451640b7SAaron LI{ 451451640b7SAaron LI local ifname=$1 452451640b7SAaron LI info "stopping interface [${ifname}] ..." 453451640b7SAaron LI 454e1be3f08SAaron LI local conffile="${wg_config_dir}/${ifname}.conf" 455451640b7SAaron LI if [ ! -r "${conffile}" ]; then 456451640b7SAaron LI err 1 "cannot read config file: ${conffile}" 457451640b7SAaron LI fi 458451640b7SAaron LI 459451640b7SAaron LI wg_load_config "${conffile}" 460451640b7SAaron LI 461451640b7SAaron LI wg_exec_hook predown 462451640b7SAaron LI 463451640b7SAaron LI wg_run ifconfig ${ifname} down 464451640b7SAaron LI wg_run ifconfig ${ifname} destroy 465451640b7SAaron LI 466451640b7SAaron LI wg_exec_hook postdown 467451640b7SAaron LI 468451640b7SAaron LI info "interface [${ifname}] stopped." 469451640b7SAaron LI} 470451640b7SAaron LI 471451640b7SAaron LIwg_start() 472451640b7SAaron LI{ 473451640b7SAaron LI local ifname 474451640b7SAaron LI for ifname in ${wg_interfaces}; do 475451640b7SAaron LI if [ "${ifname}" = "wg" ]; then 476451640b7SAaron LI warn "skip invalid interface name: ${ifname}" 477451640b7SAaron LI continue 478451640b7SAaron LI fi 479451640b7SAaron LI if ifconfig -n ${ifname} >/dev/null 2>&1; then 480451640b7SAaron LI warn "interface [${ifname}] already exists." 481451640b7SAaron LI continue 482451640b7SAaron LI fi 483451640b7SAaron LI # Use a sub-shell to avoid mixing the configurations of 484451640b7SAaron LI # different interfaces. 485451640b7SAaron LI ( wg_start_interface ${ifname} ) 486451640b7SAaron LI done 487451640b7SAaron LI} 488451640b7SAaron LI 489451640b7SAaron LIwg_stop() 490451640b7SAaron LI{ 491451640b7SAaron LI local ifname 492451640b7SAaron LI for ifname in ${wg_interfaces}; do 493451640b7SAaron LI if ! ifconfig -n ${ifname} >/dev/null 2>&1; then 494451640b7SAaron LI warn "interface [${ifname}] does not exist." 495451640b7SAaron LI continue 496451640b7SAaron LI fi 497451640b7SAaron LI ( wg_stop_interface ${ifname} ) 498451640b7SAaron LI done 499451640b7SAaron LI} 500451640b7SAaron LI 501451640b7SAaron LIwg_status() 502451640b7SAaron LI{ 503451640b7SAaron LI local ifname 504451640b7SAaron LI for ifname in ${wg_interfaces}; do 505451640b7SAaron LI wg_run ifconfig -n ${ifname} 506451640b7SAaron LI done 507451640b7SAaron LI} 508451640b7SAaron LI 509451640b7SAaron LIload_rc_config ${name} 510451640b7SAaron LI 511451640b7SAaron LIcmd=$1 512451640b7SAaron LIshift 513451640b7SAaron LIif [ $# -gt 0 ]; then 514451640b7SAaron LI wg_interfaces="$@" 515451640b7SAaron LIfi 516451640b7SAaron LIdebug "interfaces: ${wg_interfaces}" 517451640b7SAaron LI 518451640b7SAaron LIrun_rc_command "${cmd}" 519