Skip to content

Commit 491d58a

Browse files
committed
Basic SunOS support
1 parent 5efe8dd commit 491d58a

File tree

3 files changed

+111
-49
lines changed

3 files changed

+111
-49
lines changed

contrib/smf/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
WireGuard for SMF
2+
=================
3+
4+
The example `wg-quick.xml` file may be used for running wg-quick(8)
5+
using SMF.
6+
7+
Usage
8+
-----
9+
10+
Choose a name for your wg-quick config. It can be pretty much any simple string.
11+
It will be used for naming your config file and your SMF service instance name.
12+
The underlying tun device will be allocated dynamically.
13+
14+
Create `/etc/wireguard/<something>.conf`
15+
16+
```
17+
# svccfg import wg-quick.xml
18+
# svccfg -s svc:/vpn/wg-quick add something
19+
# svcadm enable wg-quick:something
20+
```
21+
22+
Helpful references
23+
------------------
24+
25+
- https://blogs.warwick.ac.uk/chrismay/entry/solaris_smf_manifest/
26+
- (archive) https://web.archive.org/web/20210613085120/https://blogs.warwick.ac.uk/chrismay/entry/solaris_smf_manifest/
27+
- https://github.com/omniosorg/omnios-extra/blob/800489a/build/wireguard-tools/files/wg-quick.xml
28+
- https://github.com/TritonDataCenter/pkgsrc-extra/blob/4423c14/wireguard-tools/files/smf/manifest.xml

contrib/smf/wg-quick.xml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0"?>
2+
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
3+
<service_bundle type="manifest" name="export">
4+
<service name="vpn/wg-quick" type="service" version="0">
5+
<!--instance name="default" enabled="false" -->
6+
<dependency name="network" grouping="require_all" restart_on="error" type="service">
7+
<service_fmri value="svc:/milestone/network:default"/>
8+
</dependency>
9+
<dependency name="filesystem" grouping="require_all" restart_on="error" type="service">
10+
<service_fmri value="svc:/system/filesystem/local"/>
11+
</dependency>
12+
<exec_method name="start" type="method" exec="/usr/local/bin/wg-quick up %i" timeout_seconds="180">
13+
<method_context>
14+
<method_credential group="root" user="root"/>
15+
<method_environment>
16+
<envvar name="WG_QUICK_USERSPACE_IMPLEMENTATION" value="/usr/local/sbin/wireguard"/>
17+
</method_environment>
18+
</method_context>
19+
</exec_method>
20+
<exec_method name="stop" type="method" exec="/usr/local/bin/wg-quick down %i" timeout_seconds="180">
21+
<method_context>
22+
<method_credential group="root" user="root"/>
23+
<method_environment>
24+
<envvar name="WG_QUICK_USERSPACE_IMPLEMENTATION" value="/usr/local/sbin/wireguard"/>
25+
</method_environment>
26+
</method_context>
27+
</exec_method>
28+
<property_group name="application" type="application"/>
29+
<property_group name="startd" type="framework">
30+
<propval name="duration" type="astring" value="contract"/>
31+
<propval name="ignore_error" type="astring" value="core,signal"/>
32+
</property_group>
33+
<!-- /instance -->
34+
<stability value="Evolving"/>
35+
<template>
36+
<common_name>
37+
<loctext xml:lang="C">WireGuard via wg-quick(8)</loctext>
38+
</common_name>
39+
</template>
40+
</service>
41+
</service_bundle>

src/wg-quick/sunos.bash

Lines changed: 42 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
#!/usr/local/bin/bash
1+
#!/usr/bin/env bash
22
# SPDX-License-Identifier: GPL-2.0
33
#
4-
# Copyright (C) 2015-2020 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
4+
# Copyright (C) 2015-2023 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
55
#
66

77
set -e -o pipefail
88
shopt -s extglob
99
export LC_ALL=C
1010

11-
exec 3>&2
1211
SELF="$(readlink -f "${BASH_SOURCE[0]}")"
1312
export PATH="${SELF%/*}:$PATH"
1413

@@ -29,7 +28,7 @@ PROGRAM="${0##*/}"
2928
ARGS=( "$@" )
3029

3130
cmd() {
32-
echo "[#] $*" >&3
31+
echo "[#] $*" >&2
3332
"$@"
3433
}
3534

@@ -45,7 +44,7 @@ parse_options() {
4544
[[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist"
4645
[[ $CONFIG_FILE =~ (^|/)([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] || die "The config file must be a valid interface name, followed by .conf"
4746
CONFIG_FILE="$(readlink -f "$CONFIG_FILE")"
48-
((($(stat -f '0%#p' "$CONFIG_FILE") & $(stat -f '0%#p' "${CONFIG_FILE%/*}") & 0007) == 0)) || echo "Warning: \`$CONFIG_FILE' is world accessible" >&2
47+
((($(stat -c '0%#a' "$CONFIG_FILE") & $(stat -c '0%#a' "${CONFIG_FILE%/*}") & 0007) == 0)) || echo "Warning: \`$CONFIG_FILE' is world accessible" >&2
4948
INTERFACE="${BASH_REMATCH[2]}"
5049
shopt -s nocasematch
5150
while read -r line || [[ -n $line ]]; do
@@ -83,37 +82,32 @@ read_bool() {
8382
}
8483

8584
auto_su() {
86-
[[ $UID == 0 ]] || exec doas -- "$BASH" -- "$SELF" "${ARGS[@]}"
85+
# Other platforms appear to escalate priviliges silently.
86+
# We will just require root permissions.
87+
[[ $UID == 0 ]] || die "must be run as root"
8788
}
8889

89-
9090
get_real_interface() {
91-
local interface line
92-
while IFS= read -r line; do
93-
if [[ $line =~ ^([a-z]+[0-9]+):\ .+ ]]; then
94-
interface="${BASH_REMATCH[1]}"
95-
continue
96-
fi
97-
if [[ $interface == wg* && $line =~ ^\ description:\ wg-quick:\ (.+) && ${BASH_REMATCH[1]} == "$INTERFACE" ]]; then
98-
REAL_INTERFACE="$interface"
99-
return 0
100-
fi
101-
done < <(ifconfig)
102-
return 1
91+
local interface diff
92+
wg show interfaces >/dev/null
93+
[[ -f "/var/run/wireguard/$INTERFACE.name" ]] || return 1
94+
interface="$(< "/var/run/wireguard/$INTERFACE.name")"
95+
[[ -n $interface && -S "/var/run/wireguard/$interface.sock" ]] || return 1
96+
diff=$(( $(stat -c %Y "/var/run/wireguard/$interface.sock" 2>/dev/null || echo 200) - $(stat -c %Y "/var/run/wireguard/$INTERFACE.name" 2>/dev/null || echo 100) ))
97+
[[ $diff -ge 2 || $diff -le -2 ]] && return 1
98+
REAL_INTERFACE="$interface"
99+
echo "[+] Interface for $INTERFACE is $REAL_INTERFACE" >&2
100+
return 0
103101
}
104102

105103
add_if() {
106-
while true; do
107-
local -A existing_ifs="( $(wg show interfaces | sed 's/\([^ ]*\)/[\1]=1/g') )"
108-
local index ret
109-
for ((index=0; index <= 2147483647; ++index)); do [[ -v existing_ifs[wg$index] ]] || break; done
110-
if ret="$(cmd ifconfig wg$index create description "wg-quick: $INTERFACE" 2>&1)"; then
111-
REAL_INTERFACE="wg$index"
112-
return 0
113-
fi
114-
[[ $ret == *"ifconfig: SIOCIFCREATE: File exists"* ]] && continue
115-
echo "$ret" >&3
116-
return 1
104+
export WG_TUN_NAME_FILE="/var/run/wireguard/$INTERFACE.name"
105+
mkdir -p "/var/run/wireguard/"
106+
cmd "${WG_QUICK_USERSPACE_IMPLEMENTATION:-wireguard-go}" tun
107+
cmd sleep 0.1
108+
get_real_interface
109+
until ipadm show-if $REAL_INTERFACE 2>/dev/null | grep -q $REAL_INTERFACE; do
110+
cmd sleep 0.1
117111
done
118112
}
119113

@@ -143,12 +137,18 @@ del_routes() {
143137
}
144138

145139
del_if() {
140+
local addr
146141
unset_dns
147-
[[ -n $REAL_INTERFACE ]] && cmd ifconfig $REAL_INTERFACE destroy
142+
[[ -n $REAL_INTERFACE ]] && ipadm show-addr -p -o addrobj | grep $REAL_INTERFACE/ | while read addr; do
143+
cmd ipadm delete-addr $addr
144+
done
145+
[[ -z $REAL_INTERFACE ]] || cmd rm -f "/var/run/wireguard/$REAL_INTERFACE.sock"
146+
cmd rm -f "/var/run/wireguard/$INTERFACE.name"
148147
}
149148

150149
up_if() {
151-
cmd ifconfig "$REAL_INTERFACE" up
150+
# Due to illumos tun driver quirks there is nothing to do here.
151+
true
152152
}
153153

154154
add_addr() {
@@ -160,7 +160,9 @@ add_addr() {
160160
family=inet
161161
[[ -n $FIRSTADDR4 ]] || FIRSTADDR4="${1%/*}"
162162
fi
163-
cmd ifconfig "$REAL_INTERFACE" $family "$1" alias
163+
# cleanup just in case
164+
ipadm delete-addr "$REAL_INTERFACE/$2" &>/dev/null || true
165+
cmd ipadm create-addr -t -T static -a "local=$1,remote=$1" "$REAL_INTERFACE/$2"
164166
}
165167

166168
set_mtu() {
@@ -283,25 +285,14 @@ monitor_daemon() {
283285

284286
set_dns() {
285287
[[ ${#DNS[@]} -gt 0 ]] || return 0
286-
287-
# TODO: add exclusive support for nameservers
288-
if pgrep -qx unwind; then
289-
echo "[!] WARNING: unwind will leak DNS queries" >&2
290-
elif pgrep -qx resolvd; then
291-
echo "[!] WARNING: resolvd may leak DNS queries" >&2
292-
else
293-
echo "[+] resolvd is not running, DNS will not be configured" >&2
294-
return 0
295-
fi
296-
297288
cmd cp /etc/resolv.conf "/etc/resolv.conf.wg-quick-backup.$INTERFACE"
298-
[[ ${#DNS_SEARCH[@]} -eq 0 ]] || cmd printf 'search %s\n' "${DNS_SEARCH[*]}" > /etc/resolv.conf
299-
route nameserver ${REAL_INTERFACE} ${DNS[@]}
289+
{ cmd printf 'nameserver %s\n' "${DNS[@]}"
290+
[[ ${#DNS_SEARCH[@]} -eq 0 ]] || cmd printf 'search %s\n' "${DNS_SEARCH[*]}"
291+
} > /etc/resolv.conf
300292
}
301293

302294
unset_dns() {
303295
[[ -f "/etc/resolv.conf.wg-quick-backup.$INTERFACE" ]] || return 0
304-
route nameserver ${REAL_INTERFACE}
305296
cmd mv "/etc/resolv.conf.wg-quick-backup.$INTERFACE" /etc/resolv.conf
306297
}
307298

@@ -415,14 +406,16 @@ cmd_usage() {
415406

416407
cmd_up() {
417408
local i
409+
local n=0
418410
get_real_interface && die "\`$INTERFACE' already exists as \`$REAL_INTERFACE'"
419411
trap 'del_if; del_routes; exit' INT TERM EXIT
420412
execute_hooks "${PRE_UP[@]}"
421413
add_if
422-
set_config
423414
for i in "${ADDRESSES[@]}"; do
424-
add_addr "$i"
415+
add_addr "$i" "$INTERFACE$n"
416+
n=$((n + 1))
425417
done
418+
set_config
426419
set_mtu
427420
up_if
428421
set_dns

0 commit comments

Comments
 (0)