diff --git a/contrib/embeddable-wg-library/wireguard.c b/contrib/embeddable-wg-library/wireguard.c index c905b17..500f33d 100644 --- a/contrib/embeddable-wg-library/wireguard.c +++ b/contrib/embeddable-wg-library/wireguard.c @@ -62,7 +62,8 @@ enum wgdevice_attribute { enum wgpeer_flag { WGPEER_F_REMOVE_ME = 1U << 0, - WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1 + WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1, + WGPEER_F_HAS_ADVANCED_SECURITY = 1U << 3 }; enum wgpeer_attribute { WGPEER_A_UNSPEC, @@ -76,6 +77,7 @@ enum wgpeer_attribute { WGPEER_A_TX_BYTES, WGPEER_A_ALLOWEDIPS, WGPEER_A_PROTOCOL_VERSION, + WGPEER_A_ADVANCED_SECURITY, __WGPEER_A_LAST }; diff --git a/src/config.c b/src/config.c index 43b8f4a..f663b7d 100644 --- a/src/config.c +++ b/src/config.c @@ -447,6 +447,41 @@ static inline bool parse_uint32(uint32_t *device_value, const char *name, const return true; } +static inline bool parse_bool(bool *device_value, const char *name, const char *value) { + + if (!strlen(value)) { + fprintf(stderr, "Unable to parse empty string\n"); + return false; + } + + if (!strcasecmp(value, "off")) { + *device_value = false; + return true; + } + + if (!strcasecmp(value, "on")) { + *device_value = true; + return true; + } + + if (!char_is_digit(value[0])) + goto err; + + char *end; + uint32_t ret; + ret = strtoul(value, &end, 10); + + if (*end) { + fprintf(stderr, "Unable to parse %s: `%s'\n", name, value); + exit(1); + } + *device_value = ret != 0; + return true; +err: + fprintf(stderr, "Boolean value is neither on/off nor 0/1: `%s'\n", value); + return false; +} + static bool process_line(struct config_ctx *ctx, const char *line) { const char *value; @@ -540,6 +575,10 @@ static bool process_line(struct config_ctx *ctx, const char *line) ret = parse_key(ctx->last_peer->preshared_key, value); if (ret) ctx->last_peer->flags |= WGPEER_HAS_PRESHARED_KEY; + } else if (key_match("AdvancedSecurity")) { + ret = parse_bool(&ctx->last_peer->advanced_security, "AdvancedSecurity", value); + if (ret) + ctx->last_peer->flags |= WGPEER_HAS_ADVANCED_SECURITY; } else goto error; } else @@ -774,6 +813,12 @@ struct wgdevice *config_read_cmd(const char *argv[], int argc) peer->flags |= WGPEER_HAS_PRESHARED_KEY; argv += 2; argc -= 2; + } else if (!strcmp(argv[0], "advanced-security") && argc >= 2 && peer) { + if (!parse_bool(&peer->advanced_security, "AdvancedSecurity", argv[1])) + goto error; + peer->flags |= WGPEER_HAS_ADVANCED_SECURITY; + argv += 2; + argc -= 2; } else { fprintf(stderr, "Invalid argument: %s\n", argv[0]); goto error; diff --git a/src/containers.h b/src/containers.h index 20f8781..8f93bb5 100644 --- a/src/containers.h +++ b/src/containers.h @@ -7,6 +7,7 @@ #define CONTAINERS_H #include +#include #include #include #include @@ -43,7 +44,8 @@ enum { WGPEER_REPLACE_ALLOWEDIPS = 1U << 1, WGPEER_HAS_PUBLIC_KEY = 1U << 2, WGPEER_HAS_PRESHARED_KEY = 1U << 3, - WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4 + WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4, + WGPEER_HAS_ADVANCED_SECURITY = 1U << 5 }; struct wgpeer { @@ -62,6 +64,8 @@ struct wgpeer { uint64_t rx_bytes, tx_bytes; uint16_t persistent_keepalive_interval; + bool advanced_security; + struct wgallowedip *first_allowedip, *last_allowedip; struct wgpeer *next_peer; }; @@ -96,7 +100,7 @@ struct wgdevice { uint16_t listen_port; struct wgpeer *first_peer, *last_peer; - + uint16_t junk_packet_count; uint16_t junk_packet_min_size; uint16_t junk_packet_max_size; diff --git a/src/ipc-linux.h b/src/ipc-linux.h index 8626e1d..c6d9847 100644 --- a/src/ipc-linux.h +++ b/src/ipc-linux.h @@ -221,6 +221,11 @@ static int kernel_set_device(struct wgdevice *dev) goto toobig_peers; } } + if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) { + if (peer->advanced_security) + mnl_attr_put_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_ADVANCED_SECURITY, 0, NULL); + flags |= WGPEER_F_HAS_ADVANCED_SECURITY; + } if (flags) { if (!mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGPEER_A_FLAGS, flags)) goto toobig_peers; @@ -389,6 +394,25 @@ static int parse_peer(const struct nlattr *attr, void *data) if (!mnl_attr_validate(attr, MNL_TYPE_U64)) peer->tx_bytes = mnl_attr_get_u64(attr); break; + case WGPEER_A_FLAGS: + if (!mnl_attr_validate(attr, MNL_TYPE_U32)) { + uint32_t flags = mnl_attr_get_u32(attr); + + if (flags & WGPEER_F_HAS_ADVANCED_SECURITY && !(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) { + peer->flags |= WGPEER_HAS_ADVANCED_SECURITY; + peer->advanced_security = false; + } + } + break; + case WGPEER_A_ADVANCED_SECURITY: + if (!mnl_attr_validate(attr, MNL_TYPE_FLAG)) { + peer->advanced_security = true; + + if (!(peer->flags & WGPEER_HAS_ADVANCED_SECURITY)) { + peer->flags |= WGPEER_HAS_ADVANCED_SECURITY; + } + } + break; case WGPEER_A_ALLOWEDIPS: return mnl_attr_parse_nested(attr, parse_allowedips, peer); } diff --git a/src/ipc-uapi.h b/src/ipc-uapi.h index 4322160..250606c 100644 --- a/src/ipc-uapi.h +++ b/src/ipc-uapi.h @@ -73,6 +73,10 @@ static int userspace_set_device(struct wgdevice *dev) for_each_wgpeer(dev, peer) { key_to_hex(hex, peer->public_key); fprintf(f, "public_key=%s\n", hex); + if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) { + ret = -EINVAL; + goto out; + } if (peer->flags & WGPEER_REMOVE_ME) { fprintf(f, "remove=true\n"); continue; diff --git a/src/set.c b/src/set.c index 75560fd..8f749b1 100644 --- a/src/set.c +++ b/src/set.c @@ -18,7 +18,7 @@ int set_main(int argc, const char *argv[]) int ret = 1; if (argc < 3) { - fprintf(stderr, "Usage: %s %s [listen-port ] [fwmark ] [private-key ] [peer [remove] [preshared-key ] [endpoint :] [persistent-keepalive ] [allowed-ips /[,/]...] ]...\n", PROG_NAME, argv[0]); + fprintf(stderr, "Usage: %s %s [listen-port ] [fwmark ] [private-key ] [peer [remove] [preshared-key ] [endpoint :] [persistent-keepalive ] [allowed-ips /[,/] [advanced-security ]...] ]...\n", PROG_NAME, argv[0]); return 1; } diff --git a/src/showconf.c b/src/showconf.c index a66b6eb..424b2be 100644 --- a/src/showconf.c +++ b/src/showconf.c @@ -73,6 +73,9 @@ int showconf_main(int argc, const char *argv[]) key_to_base64(base64, peer->preshared_key); printf("PresharedKey = %s\n", base64); } + if (peer->flags & WGPEER_HAS_ADVANCED_SECURITY) { + printf("AdvancedSecurity = %s\n", peer->advanced_security ? "on" : "off"); + } if (peer->first_allowedip) printf("AllowedIPs = "); for_each_wgallowedip(peer, allowedip) { diff --git a/src/uapi/linux/linux/wireguard.h b/src/uapi/linux/linux/wireguard.h index afa4128..bb1c214 100644 --- a/src/uapi/linux/linux/wireguard.h +++ b/src/uapi/linux/linux/wireguard.h @@ -111,6 +111,9 @@ * most recent protocol will be used when * this is unset. Otherwise, must be set * to 1. + * WGPEER_A_ADVANCED_SECURITY: flag indicating that advanced security + * techniques provided by AmneziaWG should + * be used. * 0: NLA_NESTED * ... * ... @@ -174,6 +177,7 @@ enum wgpeer_flag { WGPEER_F_REMOVE_ME = 1U << 0, WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1, WGPEER_F_UPDATE_ONLY = 1U << 2, + WGPEER_F_HAS_ADVANCED_SECURITY = 1U << 3, __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS | WGPEER_F_UPDATE_ONLY }; @@ -189,6 +193,7 @@ enum wgpeer_attribute { WGPEER_A_TX_BYTES, WGPEER_A_ALLOWEDIPS, WGPEER_A_PROTOCOL_VERSION, + WGPEER_A_ADVANCED_SECURITY, __WGPEER_A_LAST }; #define WGPEER_A_MAX (__WGPEER_A_LAST - 1)