diff options
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/config.c | 23 | ||||
-rw-r--r-- | src/containers.h | 5 | ||||
-rw-r--r-- | src/ipc-freebsd.h | 7 | ||||
-rw-r--r-- | src/ipc-linux.h | 8 | ||||
-rw-r--r-- | src/ipc-openbsd.h | 5 | ||||
-rw-r--r-- | src/ipc-uapi.h | 2 | ||||
-rw-r--r-- | src/ipc-windows.h | 6 | ||||
-rw-r--r-- | src/man/wg-quick.8 | 2 | ||||
-rw-r--r-- | src/man/wg.8 | 8 | ||||
-rw-r--r-- | src/set.c | 2 | ||||
-rw-r--r-- | src/setconf.c | 43 | ||||
-rw-r--r-- | src/show.c | 4 | ||||
-rw-r--r-- | src/uapi/linux/linux/wireguard.h | 9 | ||||
-rw-r--r-- | src/version.h | 2 | ||||
-rw-r--r-- | src/wg-quick/android.c | 2 | ||||
-rwxr-xr-x | src/wg-quick/darwin.bash | 13 | ||||
-rwxr-xr-x | src/wg-quick/freebsd.bash | 13 | ||||
-rwxr-xr-x | src/wg-quick/linux.bash | 27 | ||||
-rwxr-xr-x | src/wg-quick/openbsd.bash | 13 |
20 files changed, 135 insertions, 61 deletions
diff --git a/src/Makefile b/src/Makefile index 0533910..1c4b3f6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -39,7 +39,7 @@ PLATFORM ?= $(shell uname -s | tr '[:upper:]' '[:lower:]') CFLAGS ?= -O3 ifneq ($(wildcard uapi/$(PLATFORM)/.),) -CFLAGS += -idirafter uapi/$(PLATFORM) +CFLAGS += -isystem uapi/$(PLATFORM) endif CFLAGS += -std=gnu99 -D_GNU_SOURCE CFLAGS += -Wall -Wextra diff --git a/src/config.c b/src/config.c index 81ccb47..6b8aa58 100644 --- a/src/config.c +++ b/src/config.c @@ -337,6 +337,20 @@ static bool validate_netmask(struct wgallowedip *allowedip) return true; } +static inline void parse_ip_prefix(struct wgpeer *peer, uint32_t *flags, char **mask) +{ + /* If the IP is prefixed with either '+' or '-' consider this an + * incremental change. Disable WGPEER_REPLACE_ALLOWEDIPS. */ + switch ((*mask)[0]) { + case '-': + *flags |= WGALLOWEDIP_REMOVE_ME; + /* fall through */ + case '+': + peer->flags &= ~WGPEER_REPLACE_ALLOWEDIPS; + ++(*mask); + } +} + static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **last_allowedip, const char *value) { struct wgallowedip *allowedip = *last_allowedip, *new_allowedip; @@ -353,10 +367,18 @@ static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **la } sep = mutable; while ((mask = strsep(&sep, ","))) { + uint32_t flags = 0; unsigned long cidr; char *end, *ip; + parse_ip_prefix(peer, &flags, &mask); + saved_entry = strdup(mask); + if (!saved_entry) { + perror("strdup"); + free(mutable); + return false; + } ip = strsep(&mask, "/"); new_allowedip = calloc(1, sizeof(*new_allowedip)); @@ -387,6 +409,7 @@ static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **la else goto err; new_allowedip->cidr = cidr; + new_allowedip->flags = flags; if (!validate_netmask(new_allowedip)) fprintf(stderr, "Warning: AllowedIP has nonzero host part: %s/%s\n", ip, mask); diff --git a/src/containers.h b/src/containers.h index a82e8dd..8fd813a 100644 --- a/src/containers.h +++ b/src/containers.h @@ -28,6 +28,10 @@ struct timespec64 { int64_t tv_nsec; }; +enum { + WGALLOWEDIP_REMOVE_ME = 1U << 0, +}; + struct wgallowedip { uint16_t family; union { @@ -35,6 +39,7 @@ struct wgallowedip { struct in6_addr ip6; }; uint8_t cidr; + uint32_t flags; struct wgallowedip *next_allowedip; }; diff --git a/src/ipc-freebsd.h b/src/ipc-freebsd.h index fa74edd..58e5e71 100644 --- a/src/ipc-freebsd.h +++ b/src/ipc-freebsd.h @@ -15,7 +15,7 @@ static int get_dgram_socket(void) { static int sock = -1; if (sock < 0) - sock = socket(AF_INET, SOCK_DGRAM, 0); + sock = socket(AF_LOCAL, SOCK_DGRAM, 0); return sock; } @@ -307,6 +307,11 @@ static int kernel_set_device(struct wgdevice *dev) nvl_aips[j] = nvlist_create(0); if (!nvl_aips[j]) goto err_peer; + if (aip->flags) { + //TODO: implement me + ret = -EOPNOTSUPP; + goto err_peer; + } nvlist_add_number(nvl_aips[j], "cidr", aip->cidr); if (aip->family == AF_INET) nvlist_add_binary(nvl_aips[j], "ipv4", &aip->ip4, sizeof(aip->ip4)); diff --git a/src/ipc-linux.h b/src/ipc-linux.h index 5883ffe..01247f1 100644 --- a/src/ipc-linux.h +++ b/src/ipc-linux.h @@ -228,6 +228,8 @@ again: } if (!mnl_attr_put_u8_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_CIDR_MASK, allowedip->cidr)) goto toobig_allowedips; + if (allowedip->flags && !mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FLAGS, allowedip->flags)) + goto toobig_allowedips; mnl_attr_nest_end(nlh, allowedip_nest); allowedip_nest = NULL; } @@ -479,6 +481,12 @@ static int kernel_get_device(struct wgdevice **device, const char *iface) struct nlmsghdr *nlh; struct mnlg_socket *nlg; + /* libmnl doesn't check the buffer size, so enforce that before using. */ + if (strlen(iface) >= IFNAMSIZ) { + errno = ENAMETOOLONG; + return -ENAMETOOLONG; + } + try_again: ret = 0; *device = calloc(1, sizeof(**device)); diff --git a/src/ipc-openbsd.h b/src/ipc-openbsd.h index 03fbdb5..6bb231e 100644 --- a/src/ipc-openbsd.h +++ b/src/ipc-openbsd.h @@ -252,6 +252,11 @@ static int kernel_set_device(struct wgdevice *dev) aip_count = 0; wg_aip = &wg_peer->p_aips[0]; for_each_wgallowedip(peer, aip) { + if (aip->flags) { + //TODO: implement me + errno = EOPNOTSUPP; + goto out; + } wg_aip->a_af = aip->family; wg_aip->a_cidr = aip->cidr; diff --git a/src/ipc-uapi.h b/src/ipc-uapi.h index f582916..1d8a271 100644 --- a/src/ipc-uapi.h +++ b/src/ipc-uapi.h @@ -89,7 +89,7 @@ static int userspace_set_device(struct wgdevice *dev) continue; } else continue; - fprintf(f, "allowed_ip=%s/%d\n", ip, allowedip->cidr); + fprintf(f, "allowed_ip=%s%s/%d\n", (allowedip->flags & WGALLOWEDIP_REMOVE_ME) ? "-" : "", ip, allowedip->cidr); } } fprintf(f, "\n"); diff --git a/src/ipc-windows.h b/src/ipc-windows.h index d237fc9..a71911e 100644 --- a/src/ipc-windows.h +++ b/src/ipc-windows.h @@ -418,6 +418,12 @@ static int kernel_set_device(struct wgdevice *dev) aip_count = 0; wg_aip = (void *)wg_peer + sizeof(WG_IOCTL_PEER); for_each_wgallowedip(peer, aip) { + if (aip->flags) { + //TODO: implement me + errno = EOPNOTSUPP; + goto out; + } + wg_aip->AddressFamily = aip->family; wg_aip->Cidr = aip->cidr; diff --git a/src/man/wg-quick.8 b/src/man/wg-quick.8 index b84eb64..bc9e145 100644 --- a/src/man/wg-quick.8 +++ b/src/man/wg-quick.8 @@ -168,7 +168,7 @@ sockets, which bypass Netfilter.) When IPv6 is in use, additional similar lines Or, perhaps it is desirable to store private keys in encrypted form, such as through use of .BR pass (1): - \fBPostUp = wg set %i private-key <(pass WireGuard/private-keys/%i)\fP + \fBPreUp = wg set %i private-key <(pass WireGuard/private-keys/%i)\fP .br For use on a server, the following is a more complicated example involving multiple peers: diff --git a/src/man/wg.8 b/src/man/wg.8 index 7984539..a0fc04c 100644 --- a/src/man/wg.8 +++ b/src/man/wg.8 @@ -55,7 +55,7 @@ transfer-rx, transfer-tx, persistent-keepalive. Shows the current configuration of \fI<interface>\fP in the format described by \fICONFIGURATION FILE FORMAT\fP below. .TP -\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]... +\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI[+|-]<ip1>/<cidr1>\fP[,\fI[+|-]<ip2>/<cidr2>\fP]...] ]... Sets configuration values for the specified \fI<interface>\fP. Multiple \fIpeer\fPs may be specified, and if the \fIremove\fP argument is given for a peer, that peer is removed, not configured. If \fIlisten-port\fP @@ -72,7 +72,11 @@ the device. The use of \fIpreshared-key\fP is optional, and may be omitted; it adds an additional layer of symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance. If \fIallowed-ips\fP is specified, but the value is the empty string, all -allowed ips are removed from the peer. The use of \fIpersistent-keepalive\fP +allowed ips are removed from the peer. By default, \fIallowed-ips\fP replaces +a peer's allowed ips. If + or - is prepended to any of the ips then +the update is incremental; ips prefixed with '+' or '' are added to the peer's +allowed ips if not present while ips prefixed with '-' are removed if present. +The use of \fIpersistent-keepalive\fP is optional and is by default off; setting it to 0 or "off" disables it. Otherwise it represents, in seconds, between 1 and 65535 inclusive, how often to send an authenticated empty packet to the peer, for the purpose of keeping @@ -18,7 +18,7 @@ int set_main(int argc, const char *argv[]) int ret = 1; if (argc < 3) { - fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]); + fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips [+|-]<ip1>/<cidr1>[,[+|-]<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]); return 1; } diff --git a/src/setconf.c b/src/setconf.c index 1c5b138..4f830a4 100644 --- a/src/setconf.c +++ b/src/setconf.c @@ -13,15 +13,15 @@ #include "ipc.h" #include "subcommands.h" -struct pubkey_origin { - uint8_t *pubkey; +struct peer_origin { + struct wgpeer *peer; bool from_file; }; -static int pubkey_cmp(const void *first, const void *second) +static int peer_cmp(const void *first, const void *second) { - const struct pubkey_origin *a = first, *b = second; - int ret = memcmp(a->pubkey, b->pubkey, WG_KEY_LEN); + const struct peer_origin *a = first, *b = second; + int ret = memcmp(a->peer->public_key, b->peer->public_key, WG_KEY_LEN); if (ret) return ret; return a->from_file - b->from_file; @@ -31,7 +31,7 @@ static bool sync_conf(struct wgdevice *file) { struct wgdevice *runtime; struct wgpeer *peer; - struct pubkey_origin *pubkeys; + struct peer_origin *peers; size_t peer_count = 0, i = 0; if (!file->first_peer) @@ -55,46 +55,51 @@ static bool sync_conf(struct wgdevice *file) for_each_wgpeer(runtime, peer) ++peer_count; - pubkeys = calloc(peer_count, sizeof(*pubkeys)); - if (!pubkeys) { + peers = calloc(peer_count, sizeof(*peers)); + if (!peers) { free_wgdevice(runtime); - perror("Public key allocation"); + perror("Peer list allocation"); return false; } for_each_wgpeer(file, peer) { - pubkeys[i].pubkey = peer->public_key; - pubkeys[i].from_file = true; + peers[i].peer = peer; + peers[i].from_file = true; ++i; } for_each_wgpeer(runtime, peer) { - pubkeys[i].pubkey = peer->public_key; - pubkeys[i].from_file = false; + peers[i].peer = peer; + peers[i].from_file = false; ++i; } - qsort(pubkeys, peer_count, sizeof(*pubkeys), pubkey_cmp); + qsort(peers, peer_count, sizeof(*peers), peer_cmp); for (i = 0; i < peer_count; ++i) { - if (pubkeys[i].from_file) + if (peers[i].from_file) continue; - if (i == peer_count - 1 || !pubkeys[i + 1].from_file || memcmp(pubkeys[i].pubkey, pubkeys[i + 1].pubkey, WG_KEY_LEN)) { + if (i == peer_count - 1 || !peers[i + 1].from_file || memcmp(peers[i].peer->public_key, peers[i + 1].peer->public_key, WG_KEY_LEN)) { peer = calloc(1, sizeof(struct wgpeer)); if (!peer) { free_wgdevice(runtime); - free(pubkeys); + free(peers); perror("Peer allocation"); return false; } peer->flags = WGPEER_REMOVE_ME; - memcpy(peer->public_key, pubkeys[i].pubkey, WG_KEY_LEN); + memcpy(peer->public_key, peers[i].peer->public_key, WG_KEY_LEN); peer->next_peer = file->first_peer; file->first_peer = peer; if (!file->last_peer) file->last_peer = peer; + } else if (i < peer_count - 1 && peers[i + 1].from_file && + (peers[i].peer->flags & WGPEER_HAS_PRESHARED_KEY) && !(peers[i + 1].peer->flags & WGPEER_HAS_PRESHARED_KEY) && + !memcmp(peers[i].peer->public_key, peers[i + 1].peer->public_key, WG_KEY_LEN)) { + memset(peers[i + 1].peer->preshared_key, 0, WG_KEY_LEN); + peers[i + 1].peer->flags |= WGPEER_HAS_PRESHARED_KEY; } } free_wgdevice(runtime); - free(pubkeys); + free(peers); return true; } @@ -312,9 +312,9 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int else printf("off\n"); } else if (!strcmp(param, "endpoints")) { - if (with_interface) - printf("%s\t", device->name); for_each_wgpeer(device, peer) { + if (with_interface) + printf("%s\t", device->name); printf("%s\t", key(peer->public_key)); if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) printf("%s\n", endpoint(&peer->endpoint.addr)); diff --git a/src/uapi/linux/linux/wireguard.h b/src/uapi/linux/linux/wireguard.h index 0efd52c..6ca266a 100644 --- a/src/uapi/linux/linux/wireguard.h +++ b/src/uapi/linux/linux/wireguard.h @@ -101,6 +101,10 @@ * WGALLOWEDIP_A_FAMILY: NLA_U16 * WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr * WGALLOWEDIP_A_CIDR_MASK: NLA_U8 + * WGALLOWEDIP_A_FLAGS: NLA_U32, WGALLOWEDIP_F_REMOVE_ME if + * the specified IP should be removed; + * otherwise, this IP will be added if + * it is not already present. * 0: NLA_NESTED * ... * 0: NLA_NESTED @@ -184,11 +188,16 @@ enum wgpeer_attribute { }; #define WGPEER_A_MAX (__WGPEER_A_LAST - 1) +enum wgallowedip_flag { + WGALLOWEDIP_F_REMOVE_ME = 1U << 0, + __WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME +}; enum wgallowedip_attribute { WGALLOWEDIP_A_UNSPEC, WGALLOWEDIP_A_FAMILY, WGALLOWEDIP_A_IPADDR, WGALLOWEDIP_A_CIDR_MASK, + WGALLOWEDIP_A_FLAGS, __WGALLOWEDIP_A_LAST }; #define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1) diff --git a/src/version.h b/src/version.h index c3ca131..0a7ef8d 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1,3 @@ #ifndef WIREGUARD_TOOLS_VERSION -#define WIREGUARD_TOOLS_VERSION "1.0.20210914" +#define WIREGUARD_TOOLS_VERSION "1.0.20250521" #endif diff --git a/src/wg-quick/android.c b/src/wg-quick/android.c index 1263ee4..3ed05e5 100644 --- a/src/wg-quick/android.c +++ b/src/wg-quick/android.c @@ -1047,7 +1047,7 @@ static void set_routes(const char *iface, unsigned int netid) static void set_config(const char *iface, const char *config) { FILE *config_writer; - _cleanup_free_ char *cmd = concat("wg setconf ", iface, " /proc/self/fd/0", NULL); + _cleanup_free_ char *cmd = concat("wg addconf ", iface, " /proc/self/fd/0", NULL); int ret; printf("[#] %s\n", cmd); diff --git a/src/wg-quick/darwin.bash b/src/wg-quick/darwin.bash index 8e46818..1b7fe5e 100755 --- a/src/wg-quick/darwin.bash +++ b/src/wg-quick/darwin.bash @@ -62,6 +62,7 @@ parse_options() { stripped="${line%%\#*}" key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}" value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}" + unstripped_value="${line#*=}"; unstripped_value="${unstripped_value##*([[:space:]])}"; unstripped_value="${unstripped_value%%*([[:space:]])}" [[ $key == "["* ]] && interface_section=0 [[ $key == "[Interface]" ]] && interface_section=1 if [[ $interface_section -eq 1 ]]; then @@ -72,10 +73,10 @@ parse_options() { [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v ) done; continue ;; Table) TABLE="$value"; continue ;; - PreUp) PRE_UP+=( "$value" ); continue ;; - PreDown) PRE_DOWN+=( "$value" ); continue ;; - PostUp) POST_UP+=( "$value" ); continue ;; - PostDown) POST_DOWN+=( "$value" ); continue ;; + PreUp) PRE_UP+=( "$unstripped_value" ); continue ;; + PreDown) PRE_DOWN+=( "$unstripped_value" ); continue ;; + PostUp) POST_UP+=( "$unstripped_value" ); continue ;; + PostDown) POST_DOWN+=( "$unstripped_value" ); continue ;; SaveConfig) read_bool SAVE_CONFIG "$value"; continue ;; esac fi @@ -369,7 +370,7 @@ add_route() { } set_config() { - cmd wg setconf "$REAL_INTERFACE" <(echo "$WG_CONFIG") + cmd wg addconf "$REAL_INTERFACE" <(echo "$WG_CONFIG") } save_config() { @@ -452,8 +453,8 @@ cmd_up() { local i get_real_interface && die "\`$INTERFACE' already exists as \`$REAL_INTERFACE'" trap 'del_if; del_routes; exit' INT TERM EXIT - execute_hooks "${PRE_UP[@]}" add_if + execute_hooks "${PRE_UP[@]}" set_config for i in "${ADDRESSES[@]}"; do add_addr "$i" diff --git a/src/wg-quick/freebsd.bash b/src/wg-quick/freebsd.bash index b529ab2..aeae18d 100755 --- a/src/wg-quick/freebsd.bash +++ b/src/wg-quick/freebsd.bash @@ -80,6 +80,7 @@ parse_options() { stripped="${line%%\#*}" key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}" value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}" + unstripped_value="${line#*=}"; unstripped_value="${unstripped_value##*([[:space:]])}"; unstripped_value="${unstripped_value%%*([[:space:]])}" [[ $key == "["* ]] && interface_section=0 [[ $key == "[Interface]" ]] && interface_section=1 if [[ $interface_section -eq 1 ]]; then @@ -90,10 +91,10 @@ parse_options() { [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v ) done; continue ;; Table) TABLE="$value"; continue ;; - PreUp) PRE_UP+=( "$value" ); continue ;; - PreDown) PRE_DOWN+=( "$value" ); continue ;; - PostUp) POST_UP+=( "$value" ); continue ;; - PostDown) POST_DOWN+=( "$value" ); continue ;; + PreUp) PRE_UP+=( "$unstripped_value" ); continue ;; + PreDown) PRE_DOWN+=( "$unstripped_value" ); continue ;; + PostUp) POST_UP+=( "$unstripped_value" ); continue ;; + PostDown) POST_DOWN+=( "$unstripped_value" ); continue ;; SaveConfig) read_bool SAVE_CONFIG "$value"; continue ;; esac fi @@ -337,7 +338,7 @@ add_route() { } set_config() { - echo "$WG_CONFIG" | cmd wg setconf "$INTERFACE" /dev/stdin + echo "$WG_CONFIG" | cmd wg addconf "$INTERFACE" /dev/stdin } save_config() { @@ -420,8 +421,8 @@ cmd_up() { local i [[ -z $(ifconfig "$INTERFACE" 2>/dev/null) ]] || die "\`$INTERFACE' already exists" trap 'del_if; del_routes; clean_temp; exit' INT TERM EXIT - execute_hooks "${PRE_UP[@]}" add_if + execute_hooks "${PRE_UP[@]}" set_config for i in "${ADDRESSES[@]}"; do add_addr "$i" diff --git a/src/wg-quick/linux.bash b/src/wg-quick/linux.bash index 69e5bef..34fa5f9 100755 --- a/src/wg-quick/linux.bash +++ b/src/wg-quick/linux.bash @@ -51,6 +51,7 @@ parse_options() { stripped="${line%%\#*}" key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}" value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}" + unstripped_value="${line#*=}"; unstripped_value="${unstripped_value##*([[:space:]])}"; unstripped_value="${unstripped_value%%*([[:space:]])}" [[ $key == "["* ]] && interface_section=0 [[ $key == "[Interface]" ]] && interface_section=1 if [[ $interface_section -eq 1 ]]; then @@ -61,10 +62,10 @@ parse_options() { [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v ) done; continue ;; Table) TABLE="$value"; continue ;; - PreUp) PRE_UP+=( "$value" ); continue ;; - PreDown) PRE_DOWN+=( "$value" ); continue ;; - PostUp) POST_UP+=( "$value" ); continue ;; - PostDown) POST_DOWN+=( "$value" ); continue ;; + PreUp) PRE_UP+=( "$unstripped_value" ); continue ;; + PreDown) PRE_DOWN+=( "$unstripped_value" ); continue ;; + PostUp) POST_UP+=( "$unstripped_value" ); continue ;; + PostDown) POST_DOWN+=( "$unstripped_value" ); continue ;; SaveConfig) read_bool SAVE_CONFIG "$value"; continue ;; esac fi @@ -87,7 +88,7 @@ auto_su() { add_if() { local ret - if ! cmd ip link add "$INTERFACE" type wireguard; then + if ! cmd ip link add dev "$INTERFACE" type wireguard; then ret=$? [[ -e /sys/module/wireguard ]] || ! command -v "${WG_QUICK_USERSPACE_IMPLEMENTATION:-wireguard-go}" >/dev/null && exit $ret echo "[!] Missing WireGuard kernel module. Falling back to slow userspace implementation." >&2 @@ -123,7 +124,7 @@ add_addr() { } set_mtu_up() { - local mtu=0 endpoint output + local mtu=2147483647 endpoint output if [[ -n $MTU ]]; then cmd ip link set mtu "$MTU" up dev "$INTERFACE" return @@ -131,18 +132,18 @@ set_mtu_up() { while read -r _ endpoint; do [[ $endpoint =~ ^\[?([a-z0-9:.]+)\]?:[0-9]+$ ]] || continue output="$(ip route get "${BASH_REMATCH[1]}" || true)" - [[ ( $output =~ mtu\ ([0-9]+) || ( $output =~ dev\ ([^ ]+) && $(ip link show dev "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) ) ) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}" + [[ ( $output =~ mtu\ ([0-9]+) || ( $output =~ dev\ ([^ ]+) && $(ip link show dev "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) ) ) && ${BASH_REMATCH[1]} -lt $mtu ]] && mtu="${BASH_REMATCH[1]}" done < <(wg show "$INTERFACE" endpoints) - if [[ $mtu -eq 0 ]]; then + if [[ $mtu -eq 2147483647 ]]; then read -r output < <(ip route show default || true) || true - [[ ( $output =~ mtu\ ([0-9]+) || ( $output =~ dev\ ([^ ]+) && $(ip link show dev "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) ) ) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}" + [[ ( $output =~ mtu\ ([0-9]+) || ( $output =~ dev\ ([^ ]+) && $(ip link show dev "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) ) ) && ${BASH_REMATCH[1]} -lt $mtu ]] && mtu="${BASH_REMATCH[1]}" fi - [[ $mtu -gt 0 ]] || mtu=1500 + [[ $mtu -gt 0 && $mtu -lt 2147483647 ]] || mtu=1500 cmd ip link set mtu $(( mtu - 80 )) up dev "$INTERFACE" } resolvconf_iface_prefix() { - [[ -f /etc/resolvconf/interface-order ]] || return 0 + [[ -f /etc/resolvconf/interface-order && ! -L $(type -P resolvconf) ]] || return 0 local iface while read -r iface; do [[ $iface =~ ^([A-Za-z0-9-]+)\*$ ]] || continue @@ -248,7 +249,7 @@ add_default() { } set_config() { - cmd wg setconf "$INTERFACE" <(echo "$WG_CONFIG") + cmd wg addconf "$INTERFACE" <(echo "$WG_CONFIG") } save_config() { @@ -327,8 +328,8 @@ cmd_up() { local i [[ -z $(ip link show dev "$INTERFACE" 2>/dev/null) ]] || die "\`$INTERFACE' already exists" trap 'del_if; exit' INT TERM EXIT - execute_hooks "${PRE_UP[@]}" add_if + execute_hooks "${PRE_UP[@]}" set_config for i in "${ADDRESSES[@]}"; do add_addr "$i" diff --git a/src/wg-quick/openbsd.bash b/src/wg-quick/openbsd.bash index 2adfe46..19b9909 100755 --- a/src/wg-quick/openbsd.bash +++ b/src/wg-quick/openbsd.bash @@ -52,6 +52,7 @@ parse_options() { stripped="${line%%\#*}" key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}" value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}" + unstripped_value="${line#*=}"; unstripped_value="${unstripped_value##*([[:space:]])}"; unstripped_value="${unstripped_value%%*([[:space:]])}" [[ $key == "["* ]] && interface_section=0 [[ $key == "[Interface]" ]] && interface_section=1 if [[ $interface_section -eq 1 ]]; then @@ -62,10 +63,10 @@ parse_options() { [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v ) done; continue ;; Table) TABLE="$value"; continue ;; - PreUp) PRE_UP+=( "$value" ); continue ;; - PreDown) PRE_DOWN+=( "$value" ); continue ;; - PostUp) POST_UP+=( "$value" ); continue ;; - PostDown) POST_DOWN+=( "$value" ); continue ;; + PreUp) PRE_UP+=( "$unstripped_value" ); continue ;; + PreDown) PRE_DOWN+=( "$unstripped_value" ); continue ;; + PostUp) POST_UP+=( "$unstripped_value" ); continue ;; + PostDown) POST_DOWN+=( "$unstripped_value" ); continue ;; SaveConfig) read_bool SAVE_CONFIG "$value"; continue ;; esac fi @@ -337,7 +338,7 @@ add_route() { } set_config() { - cmd wg setconf "$REAL_INTERFACE" <(echo "$WG_CONFIG") + cmd wg addconf "$REAL_INTERFACE" <(echo "$WG_CONFIG") } save_config() { @@ -417,8 +418,8 @@ cmd_up() { local i get_real_interface && die "\`$INTERFACE' already exists as \`$REAL_INTERFACE'" trap 'del_if; del_routes; exit' INT TERM EXIT - execute_hooks "${PRE_UP[@]}" add_if + execute_hooks "${PRE_UP[@]}" set_config for i in "${ADDRESSES[@]}"; do add_addr "$i" |