Compare commits

...

15 commits

Author SHA1 Message Date
Iurii Egorov
c0b400c6df Update wg-json to support AmneziaWG parameters 2024-10-01 16:02:42 +03:00
Iurii Egorov
f69cd16056 Auth notifications for unknown peers 2024-09-15 21:29:49 +03:00
Iurii Egorov
dafa38e4b0 Support for legacy clients 2024-09-03 14:48:33 +03:00
pokamest
e42813caac
Merge pull request #12 from RomikB/pipe_rebranding
unsafe rebranding: change pipe name for windows
2024-05-06 09:53:51 -07:00
RomikB
776a1b5e19 unsafe rebranding: change pipe name for windows 2024-05-05 10:31:44 +02:00
pokamest
d33c4b6936
Merge pull request #11 from amnezia-vpn/fix/android
Fix android.c
2024-03-16 13:45:39 +00:00
albexk
2fdea58d2b Fix android.c 2024-03-16 14:33:02 +03:00
tiaga
6eb1abfa4f
Merge pull request #10 from amnezia-vpn/update_actions
Improve pipeline
2024-02-13 20:18:12 +07:00
tiaga
eb9ef8a1fd Improve pipeline
- rename `wg.exe` to `awg.exe`
- set release name automatically
2024-02-13 20:16:15 +07:00
tiaga
da1e7bcea3
Merge pull request #9 from amnezia-vpn/update_linux_build
Update linux-build.yml
2024-02-13 07:07:51 +07:00
AlexanderGalkov
ff229c0c82
Update linux-build.yml
Signed-off-by: AlexanderGalkov <143902290+AlexanderGalkov@users.noreply.github.com>
2024-02-12 22:46:26 +07:00
pokamest
af245c000e
Merge pull request #8 from amnezia-vpn/fix/android
Fix missing brackets and package name
2024-02-11 09:08:09 -08:00
albexk
7b234cf29b Fix missing brackets and package name 2024-02-11 19:20:52 +03:00
tiaga
c1148485e0
Merge pull request #7 from AlexanderGalkov/test
Update linux-build.yml
2024-02-04 01:42:40 +07:00
AlexanderGalkov
5e05aab557
Update linux-build.yml
Signed-off-by: AlexanderGalkov <143902290+AlexanderGalkov@users.noreply.github.com>
2024-02-03 18:29:28 +07:00
18 changed files with 515 additions and 47 deletions

View file

@ -19,8 +19,8 @@ jobs:
cd src &&
make &&
mkdir build &&
cp wg ./build/wg &&
cp wg-quick/linux.bash ./build/wg-quick
cp wg ./build/awg &&
cp wg-quick/linux.bash ./build/awg-quick
- name: Upload artifact
uses: actions/upload-artifact@v4
@ -43,11 +43,43 @@ jobs:
cd src &&
make &&
mkdir build &&
cp wg ./build/wg &&
cp wg-quick/linux.bash ./build/wg-quick
cp wg ./build/awg &&
cp wg-quick/linux.bash ./build/awg-quick
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: alpine-3.19-amneziawg-tools
path: ./src/build
GitHub-Release:
name: GitHub Release
needs: [Build-for-Ubuntu, Build-for-Alpine]
strategy:
matrix:
include:
- os: "ubuntu"
release: "22.04"
- os: "alpine"
release: "3.19"
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Calculate checksums
run: for file in $(find ./${{ matrix.os }}-${{ matrix.release }}-amneziawg-tools/ -type f); do openssl dgst -sha256 -r "$file" | awk '{print $1}' > "${file}.sha256"; done
- name: Zip files
run: zip -r ${{ matrix.os }}-${{ matrix.release }}-amneziawg-tools.zip ${{ matrix.os }}-${{ matrix.release }}-amneziawg-tools
- name: Upload binaries to Release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./${{ matrix.os }}-${{ matrix.release }}-amneziawg-tools.zip
tag: ${{ github.ref }}
release_name: ${{ github.ref_name }}
overwrite: true
file_glob: true

View file

@ -52,5 +52,6 @@ jobs:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: windows-amneziawg-tools.zip
tag: ${{ github.ref }}
release_name: ${{ github.ref_name }}
overwrite: true
file_glob: true

View file

@ -46,7 +46,7 @@ if exist .deps/prepared goto :build
del src\*.exe src\*.o src\wincompat\*.o src\wincompat\*.lib 2> NUL
set LDFLAGS=-s
make --no-print-directory -C src PLATFORM=windows CC=%~2-w64-mingw32-gcc WINDRES=%~2-w64-mingw32-windres V=1 RUNSTATEDIR= SYSTEMDUNITDIR= -j%NUMBER_OF_PROCESSORS% || exit /b 1
move /Y src\wg.exe "%~1\wg.exe" > NUL || exit /b 1
move /Y src\wg.exe "%~1\awg.exe" > NUL || exit /b 1
goto :eof
:error

View file

@ -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
};

View file

@ -2,20 +2,30 @@
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
# Copyright (C) 2024 Amnezia VPN. All Rights Reserved.
exec < <(exec wg show all dump)
exec < <(exec awg show all dump)
printf '{'
while read -r -d $'\t' device; do
if [[ $device != "$last_device" ]]; then
[[ -z $last_device ]] && printf '\n' || printf '%s,\n' "$end"
last_device="$device"
read -r private_key public_key listen_port fwmark
read -r private_key public_key listen_port jc jmin jmax s1 s2 h1 h2 h3 h4 fwmark
printf '\t"%s": {' "$device"
delim=$'\n'
[[ $private_key == "(none)" ]] || { printf '%s\t\t"privateKey": "%s"' "$delim" "$private_key"; delim=$',\n'; }
[[ $public_key == "(none)" ]] || { printf '%s\t\t"publicKey": "%s"' "$delim" "$public_key"; delim=$',\n'; }
[[ $listen_port == "0" ]] || { printf '%s\t\t"listenPort": %u' "$delim" $(( $listen_port )); delim=$',\n'; }
[[ $jc == "0" ]] || { printf '%s\t\t"jc": %u' "$delim" $(( $jc )); delim=$',\n'; }
[[ $jmin == "0" ]] || { printf '%s\t\t"jmin": %u' "$delim" $(( $jmin )); delim=$',\n'; }
[[ $jmax == "0" ]] || { printf '%s\t\t"jmax": %u' "$delim" $(( $jmax )); delim=$',\n'; }
[[ $s1 == "0" ]] || { printf '%s\t\t"s1": %u' "$delim" $(( $s1 )); delim=$',\n'; }
[[ $s2 == "0" ]] || { printf '%s\t\t"s2": %u' "$delim" $(( $s2 )); delim=$',\n'; }
[[ $h1 == "1" ]] || { printf '%s\t\t"h1": %u' "$delim" $(( $h1 )); delim=$',\n'; }
[[ $h2 == "2" ]] || { printf '%s\t\t"h2": %u' "$delim" $(( $h2 )); delim=$',\n'; }
[[ $h3 == "3" ]] || { printf '%s\t\t"h3": %u' "$delim" $(( $h3 )); delim=$',\n'; }
[[ $h4 == "4" ]] || { printf '%s\t\t"h4": %u' "$delim" $(( $h4 )); delim=$',\n'; }
[[ $fwmark == "off" ]] || { printf '%s\t\t"fwmark": %u' "$delim" $(( $fwmark )); delim=$',\n'; }
printf '%s\t\t"peers": {' "$delim"; end=$'\n\t\t}\n\t}'
delim=$'\n'

View file

@ -0,0 +1,24 @@
=== Dynamic peers authentication example ===
This example shows how to utilize netlink's multicast notifications
in AmneziaWG kernel module to provide dynamic peer authentication.
To compile it, you must install some pre-requisites:
```shell
apt-get install build-essential pkg-config libnl-3-dev libnl-genl-3-dev
```
After that, build example with the following command:
```shell
gcc notification-listener.c $(pkg-config --cflags --libs libnl-3.0 libnl-genl-3.0) -o notification-listener
```
Bring up AWG interface with `awg-quick` as usually, edit `accounts.csv` file accordingly to your needs and then run:
```shell
sudo ./notification-listener ./approve.sh ./accounts.csv
```
### **PLEASE NOTE: THIS EXAMPLE AS WELL AS OVERALL DYNAMIC AUTHENTICATION MECHANISM AND LEGACY CLIENTS' SUPPORT IN AMNEZIAWG IS SPONSORED BY [WINDSCRIBE LIMITED](https://windscribe.com)**

View file

@ -0,0 +1,2 @@
Public Key,Allowed Ips,PSK
/Ca5004uiLJVBqSPaBUKg5zBszO9qbzEUCWmVkelkjY=,"10.8.1.10/32",E37VXqGtGvwftop/uFsbZcIO76Ox1kMmB6Sz/JoIw2I=
1 Public Key Allowed Ips PSK
2 /Ca5004uiLJVBqSPaBUKg5zBszO9qbzEUCWmVkelkjY= 10.8.1.10/32 E37VXqGtGvwftop/uFsbZcIO76Ox1kMmB6Sz/JoIw2I=

View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
ACCOUNTS_FILE=$1
INTERFACE_NAME=$2
PUBLIC_KEY=$3
ENDPOINT=$4
ADVANCED_SECURITY=$5
ACCOUNT_STR=`grep "${PUBLIC_KEY}" "${ACCOUNTS_FILE}"`
if [ "${ACCOUNT_STR}" == "" ]; then
echo "Public key not found in accounts file!"
exit 255
fi
ACCOUNT=(${ACCOUNT_STR//,/ })
ALLOWED_IPS=$(echo ${ACCOUNT[1]}|tr -d '"')
PSK=$(echo ${ACCOUNT[2]}|tr -d '"')
PSK_FILE=$(tempfile)
echo "${PSK}" > "${PSK_FILE}"
awg set "${INTERFACE_NAME}" peer "${PUBLIC_KEY}" allowed-ips "${ALLOWED_IPS}" endpoint "${ENDPOINT}" allowed-ips "${ALLOWED_IPS}" preshared-key "${PSK_FILE}" advanced-security "${ADVANCED_SECURITY}"
EXIT_CODE=$?
rm -f "{$PSK_FILE}"
exit ${EXIT_CODE}

View file

@ -0,0 +1,263 @@
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "../../src/uapi/linux/linux/wireguard.h"
#define prerr(...) fprintf(stderr, "Error: " __VA_ARGS__)
#define WG_KEY_LEN 32
#define WG_KEY_LEN_BASE64 ((((WG_KEY_LEN) + 2) / 3) * 4 + 1)
static struct nl_sock *sk = NULL;
static char **cb_argv;
static int cb_argc;
static int cleanup_and_exit(int ret)
{
if (sk != NULL)
nl_socket_free(sk);
exit(ret);
}
static void signal_handler(int sig)
{
cleanup_and_exit(EXIT_SUCCESS);
}
static inline void encode_base64(char dest[static 4], const uint8_t src[static 3])
{
const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
for (unsigned int i = 0; i < 4; ++i)
dest[i] = input[i] + 'A'
+ (((25 - input[i]) >> 8) & 6)
- (((51 - input[i]) >> 8) & 75)
- (((61 - input[i]) >> 8) & 15)
+ (((62 - input[i]) >> 8) & 3);
}
void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN])
{
unsigned int i;
for (i = 0; i < WG_KEY_LEN / 3; ++i)
encode_base64(&base64[i * 4], &key[i * 3]);
encode_base64(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
base64[WG_KEY_LEN_BASE64 - 2] = '=';
base64[WG_KEY_LEN_BASE64 - 1] = '\0';
}
static char *key(const uint8_t key[static WG_KEY_LEN])
{
static char base64[WG_KEY_LEN_BASE64];
key_to_base64(base64, key);
return base64;
}
static char *endpoint(const struct sockaddr *addr)
{
char host[4096 + 1];
char service[512 + 1];
static char buf[sizeof(host) + sizeof(service) + 4];
int ret;
socklen_t addr_len = 0;
memset(buf, 0, sizeof(buf));
if (addr->sa_family == AF_INET)
addr_len = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6)
addr_len = sizeof(struct sockaddr_in6);
ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST);
if (ret) {
strncpy(buf, gai_strerror(ret), sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
} else
snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service);
return buf;
}
static int get_ifname(struct nlattr *tb[], char **ifname)
{
if (tb[WGDEVICE_A_IFNAME] == NULL)
return -1;
*ifname = nla_data(tb[WGDEVICE_A_IFNAME]);
return 0;
}
static int get_pubkey(struct nlattr *peer[], char **pubkey)
{
if (peer[WGPEER_A_PUBLIC_KEY] == NULL)
return -1;
*pubkey = key(nla_data(peer[WGPEER_A_PUBLIC_KEY]));
return 0;
}
static int get_endpoint(struct nlattr *peer[], char **endpoint_ip)
{
if (peer[WGPEER_A_ENDPOINT] == NULL)
return -1;
*endpoint_ip = endpoint(nla_data(peer[WGPEER_A_ENDPOINT]));
return 0;
}
static int run_callback(char *ifname, char *pubkey, char *endpoint_ip, bool advanced_security)
{
char** new_argv = malloc((cb_argc + 2) * sizeof *new_argv);
new_argv[0] = cb_argv[1];
for (int i = 2; i < cb_argc - 3; i++) {
new_argv[i - 1] = cb_argv[i];
}
new_argv[cb_argc - 4] = ifname;
new_argv[cb_argc - 3] = pubkey;
new_argv[cb_argc - 2] = endpoint_ip;
new_argv[cb_argc - 1] = (advanced_security ? "on\0" : "off\0");
new_argv[cb_argc] = NULL;
int child_pid = fork(), ret;
if (child_pid < 0) {
prerr("failed to spawn child process: %d\n", child_pid);
return child_pid;
} else if (child_pid == 0) {
execv(cb_argv[1], new_argv);
exit(0);
} else {
waitpid(child_pid, &ret, 0);
}
free(new_argv);
return ret;
}
static int netlink_callback(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
struct genlmsghdr *gnlh = nlmsg_data(ret_hdr);
struct nlattr *tb[WGDEVICE_A_MAX + 1];
struct nlattr *peer[WGPEER_A_MAX + 1];
nla_parse(tb, WGDEVICE_A_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
char *ifname, *pubkey, *endpoint_ip;
bool advanced_security = false;
int cb_ret;
switch (gnlh->cmd) {
case WG_CMD_UNKNOWN_PEER:
if (get_ifname(tb, &ifname) < 0) {
prerr("unknown interface name!\n");
return NL_SKIP;
}
if (nla_parse_nested(peer, WGPEER_A_MAX, tb[WGDEVICE_A_PEER], NULL)) {
prerr("failed to parse nested peer!\n");
return NL_SKIP;
}
if (get_pubkey(peer, &pubkey)) {
prerr("invalid public key!\n");
return NL_SKIP;
}
if (get_endpoint(peer, &endpoint_ip)) {
prerr("invalid endpoint!\n");
return NL_SKIP;
}
if (nla_get_flag(peer[WGPEER_A_ADVANCED_SECURITY])) {
advanced_security = true;
}
if (cb_ret = run_callback(ifname, pubkey, endpoint_ip, advanced_security)) {
prerr("failed to execute callback script: %d!\n", cb_ret);
return NL_SKIP;
}
printf("Callback executed successfully.\n");
break;
default:
return NL_SKIP;
}
return 0;
}
int main(int argc, char *argv[])
{
int ret;
int sk_fd;
fd_set rfds;
if (argc < 2) {
prerr("usage: %s <callback>\n", argv[0]);
cleanup_and_exit(EXIT_FAILURE);
}
cb_argc = argc + 3;
cb_argv = argv;
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
sk = nl_socket_alloc();
if (sk == NULL) {
prerr("unable to allocate Netlink socket!\n");
exit(EXIT_FAILURE);
}
ret = genl_connect(sk);
if (ret < 0) {
prerr("no connect %d!\n", ret);
cleanup_and_exit(EXIT_FAILURE);
}
printf("Netlink socket connected.\n");
ret = genl_ctrl_resolve_grp(sk, WG_GENL_NAME, WG_MULTICAST_GROUP_AUTH);
if (ret < 0) {
prerr("auth group not found %d!\n", ret);
cleanup_and_exit(EXIT_FAILURE);
}
ret = nl_socket_add_membership(sk, ret);
if (ret < 0) {
prerr("unable to join multicast group %d!\n", ret);
cleanup_and_exit(EXIT_FAILURE);
}
nl_socket_disable_seq_check(sk);
ret = nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, netlink_callback, NULL);
if (ret < 0) {
prerr("unable to register callback %d!\n", ret);
cleanup_and_exit(EXIT_FAILURE);
}
while (1) {
FD_ZERO(&rfds);
sk_fd = nl_socket_get_fd(sk);
FD_SET(sk_fd, &rfds);
ret = select(sk_fd + 1, &rfds, NULL, NULL, NULL);
if (ret < 0)
break;
ret = nl_recvmsgs_default(sk);
if (ret < 0) {
prerr("error receiving message %d!\n", ret);
cleanup_and_exit(EXIT_FAILURE);
}
}
cleanup_and_exit(EXIT_FAILURE);
}

View file

@ -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;

View file

@ -7,6 +7,7 @@
#define CONTAINERS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
@ -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;

View file

@ -221,6 +221,11 @@ again:
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);
}

View file

@ -26,7 +26,7 @@ static FILE *userspace_interface_file(const char *iface)
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes))
goto err;
snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\WireGuard\\%s", iface);
snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\AmneziaWG\\%s", iface);
pipe_handle = CreateFileA(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (pipe_handle == INVALID_HANDLE_VALUE)
goto err;
@ -62,7 +62,7 @@ static bool userspace_has_wireguard_interface(const char *iface)
if (have_cached_interfaces)
return hashtable_find_entry(&cached_interfaces, iface) != NULL;
snprintf(fname, sizeof(fname), "ProtectedPrefix\\Administrators\\WireGuard\\%s", iface);
snprintf(fname, sizeof(fname), "ProtectedPrefix\\Administrators\\AmneziaWG\\%s", iface);
find_handle = FindFirstFile("\\\\.\\pipe\\*", &find_data);
if (find_handle == INVALID_HANDLE_VALUE)
return -EIO;
@ -78,7 +78,7 @@ static bool userspace_has_wireguard_interface(const char *iface)
static int userspace_get_wireguard_interfaces(struct string_list *list)
{
static const char prefix[] = "ProtectedPrefix\\Administrators\\WireGuard\\";
static const char prefix[] = "ProtectedPrefix\\Administrators\\AmneziaWG\\";
WIN32_FIND_DATA find_data;
HANDLE find_handle;
char *iface;

View file

@ -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;

View file

@ -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>] [advanced-security <on|off>]...] ]...\n", PROG_NAME, argv[0]);
return 1;
}

View file

@ -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) {

View file

@ -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
* ...
* ...
@ -126,6 +129,25 @@
* of a peer, it likely should not be specified in subsequent fragments.
*
* If an error occurs, NLMSG_ERROR will reply containing an errno.
*
* WG_CMD_UNKNOWN_PEER
* ----------------------
*
* This command is sent on the multicast group WG_MULTICAST_GROUP_AUTH
* when the initiation message received from a peer with an unknown public
* key.
* The kernel will send a single message containing the
* following tree of nested items:
*
* WGDEVICE_A_IFINDEX: NLA_U32
* WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1
* WGDEVICE_A_PEER: NLA_NESTED
* WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
* WGPEER_A_ENDPOINT: NLA_MIN_LEN(struct sockaddr), struct sockaddr_in or struct sockaddr_in6
* WGPEER_A_ADVANCED_SECURITY: flag indicating that advanced security
* techniques provided by AmneziaWG should
* be used.
*
*/
#ifndef _WG_UAPI_WIREGUARD_H
@ -136,9 +158,12 @@
#define WG_KEY_LEN 32
#define WG_MULTICAST_GROUP_AUTH "auth"
enum wg_cmd {
WG_CMD_GET_DEVICE,
WG_CMD_SET_DEVICE,
WG_CMD_UNKNOWN_PEER,
__WG_CMD_MAX
};
#define WG_CMD_MAX (__WG_CMD_MAX - 1)
@ -166,6 +191,7 @@ enum wgdevice_attribute {
WGDEVICE_A_H2,
WGDEVICE_A_H3,
WGDEVICE_A_H4,
WGDEVICE_A_PEER,
__WGDEVICE_A_LAST
};
#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1)
@ -174,6 +200,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 +216,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)

View file

@ -27,11 +27,11 @@
#include <sys/param.h>
#include <sys/system_properties.h>
#ifndef WG_PACKAGE_NAME
#define WG_PACKAGE_NAME "com.wireguard.android"
#ifndef AWG_PACKAGE_NAME
#define AWG_PACKAGE_NAME "org.amnezia.awg"
#endif
#ifndef WG_CONFIG_SEARCH_PATHS
#define WG_CONFIG_SEARCH_PATHS "/data/misc/wireguard /data/data/" WG_PACKAGE_NAME "/files"
#ifndef AWG_CONFIG_SEARCH_PATHS
#define AWG_CONFIG_SEARCH_PATHS "/data/misc/amneziawg /data/data/" AWG_PACKAGE_NAME "/files"
#endif
#define _printf_(x, y) __attribute__((format(printf, x, y)))
@ -636,7 +636,7 @@ static void add_if(const char *iface)
if (is_asecurity_on)
cmd("amneziawg-go %s", iface);
else
cmd("ip link add %s type wireguard", iface);
cmd("ip link add %s type amneziawg", iface);
}
static void del_if(const char *iface)
@ -648,7 +648,7 @@ static void del_if(const char *iface)
regmatch_t matches[2];
char *netid = NULL;
_cleanup_free_ char *rule_regex = concat("0xc([0-9a-f]+)/0xcffff lookup ", iface, NULL);
_cleanup_free_ char *iptables_regex = concat("^-A (.* --comment \"wireguard rule ", iface, "\"[^\n]*)\n*$", NULL);
_cleanup_free_ char *iptables_regex = concat("^-A (.* --comment \"amneziawg rule ", iface, "\"[^\n]*)\n*$", NULL);
xregcomp(&rule_reg, rule_regex, REG_EXTENDED);
xregcomp(&iptables_reg, iptables_regex, REG_EXTENDED);
@ -684,7 +684,7 @@ static bool should_block_ipv6(const char *iface)
DEFINE_CMD(c);
bool has_ipv6 = false, has_all_none = true;
for (char *endpoint = cmd_ret(&c, "wg show %s endpoints", iface); endpoint; endpoint = cmd_ret(&c, NULL)) {
for (char *endpoint = cmd_ret(&c, "awg show %s endpoints", iface); endpoint; endpoint = cmd_ret(&c, NULL)) {
char *start = strchr(endpoint, '\t');
if (!start)
@ -705,7 +705,7 @@ static uint16_t determine_listen_port(const char *iface)
char *value;
cmd("ip link set up dev %s", iface);
value = cmd_ret(&c, "wg show %s listen-port", iface);
value = cmd_ret(&c, "awg show %s listen-port", iface);
if (!value)
goto set_back_down;
listen_port = strtoul(value, NULL, 10);
@ -725,12 +725,12 @@ static void up_if(unsigned int *netid, const char *iface, uint16_t listen_port)
while (*netid < 4096)
*netid = random() & 0xfffe;
cmd("wg set %s fwmark 0x20000", iface);
cmd("iptables -I OUTPUT 1 -m mark --mark 0x20000 -j ACCEPT -m comment --comment \"wireguard rule %s\"", iface);
cmd("ip6tables -I OUTPUT 1 -m mark --mark 0x20000 -j ACCEPT -m comment --comment \"wireguard rule %s\"", iface);
cmd("awg set %s fwmark 0x20000", iface);
cmd("iptables -I OUTPUT 1 -m mark --mark 0x20000 -j ACCEPT -m comment --comment \"amneziawg rule %s\"", iface);
cmd("ip6tables -I OUTPUT 1 -m mark --mark 0x20000 -j ACCEPT -m comment --comment \"amneziawg rule %s\"", iface);
if (listen_port) {
cmd("iptables -I INPUT 1 -p udp --dport %u -j ACCEPT -m comment --comment \"wireguard rule %s\"", listen_port, iface);
cmd("ip6tables -I INPUT 1 -p udp --dport %u -j %s -m comment --comment \"wireguard rule %s\"", listen_port, should_block_ipv6(iface) ? "DROP" : "ACCEPT", iface);
cmd("iptables -I INPUT 1 -p udp --dport %u -j ACCEPT -m comment --comment \"amneziawg rule %s\"", listen_port, iface);
cmd("ip6tables -I INPUT 1 -p udp --dport %u -j %s -m comment --comment \"amneziawg rule %s\"", listen_port, should_block_ipv6(iface) ? "DROP" : "ACCEPT", iface);
}
cmd("ip link set up dev %s", iface);
cndc(sdk_version < 31 ? "network create %u vpn 1 1" : "network create %u vpn 1", *netid);
@ -1011,7 +1011,7 @@ static void set_mtu(const char *iface, unsigned int mtu)
if (endpoint_mtu == -1)
endpoint_mtu = 1500;
for (char *endpoint = cmd_ret(&c_endpoints, "wg show %s endpoints", iface); endpoint; endpoint = cmd_ret(&c_endpoints, NULL)) {
for (char *endpoint = cmd_ret(&c_endpoints, "awg show %s endpoints", iface); endpoint; endpoint = cmd_ret(&c_endpoints, NULL)) {
if (regexec(&regex_endpoint, endpoint, ARRAY_SIZE(matches), matches, 0))
continue;
endpoint[matches[1].rm_eo] = '\0';
@ -1034,7 +1034,7 @@ static void set_routes(const char *iface, unsigned int netid)
{
DEFINE_CMD(c);
for (char *allowedips = cmd_ret(&c, "wg show %s allowed-ips", iface); allowedips; allowedips = cmd_ret(&c, NULL)) {
for (char *allowedips = cmd_ret(&c, "awg show %s allowed-ips", iface); allowedips; allowedips = cmd_ret(&c, NULL)) {
char *start = strchr(allowedips, '\t');
if (!start)
@ -1051,7 +1051,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("awg setconf ", iface, " /proc/self/fd/0", NULL);
int ret;
printf("[#] %s\n", cmd);
@ -1074,13 +1074,13 @@ static void broadcast_change(void)
{
const char *pkg = getenv("CALLING_PACKAGE");
if (!pkg || strcmp(pkg, WG_PACKAGE_NAME))
cmd("am broadcast -a com.wireguard.android.action.REFRESH_TUNNEL_STATES " WG_PACKAGE_NAME);
if (!pkg || strcmp(pkg, AWG_PACKAGE_NAME))
cmd("am broadcast -a org.amnezia.awg.action.REFRESH_TUNNEL_STATES " AWG_PACKAGE_NAME);
}
static void print_search_paths(FILE *file, const char *prefix)
{
_cleanup_free_ char *paths = strdup(WG_CONFIG_SEARCH_PATHS);
_cleanup_free_ char *paths = strdup(AWG_CONFIG_SEARCH_PATHS);
for (char *path = strtok(paths, " "); path; path = strtok(NULL, " "))
fprintf(file, "%s%s\n", prefix, path);
@ -1094,7 +1094,7 @@ static void cmd_usage(const char *program)
" followed by `.conf'. Otherwise, INTERFACE is an interface name, with\n"
" configuration found at:\n\n", program);
print_search_paths(stdout, " - ");
printf( "\n It is to be readable by wg(8)'s `setconf' sub-command, with the exception\n"
printf( "\n It is to be readable by awg(8)'s `setconf' sub-command, with the exception\n"
" of the following additions to the [Interface] section, which are handled by\n"
" this program:\n\n"
" - Address: may be specified one or more times and contains one or more\n"
@ -1103,7 +1103,7 @@ static void cmd_usage(const char *program)
" - DNS: an optional DNS server to use while the device is up.\n"
" - ExcludedApplications: optional blacklist of applications to exclude from the tunnel.\n\n"
" - IncludedApplications: optional whitelist of applications to include in the tunnel.\n\n"
" See wg-quick(8) for more info and examples.\n");
" See awg-quick(8) for more info and examples.\n");
}
static char *cleanup_iface = NULL;
@ -1151,7 +1151,7 @@ static void cmd_down(const char *iface)
DEFINE_CMD(c);
bool found = false;
char *ifaces = cmd_ret(&c, "wg show interfaces");
char *ifaces = cmd_ret(&c, "awg show interfaces");
if (ifaces) {
for (char *eiface = strtok(ifaces, " \n"); eiface; eiface = strtok(NULL, " \n")) {
if (!strcmp(iface, eiface)) {
@ -1161,7 +1161,7 @@ static void cmd_down(const char *iface)
}
}
if (!found) {
fprintf(stderr, "Error: %s is not a WireGuard interface\n", iface);
fprintf(stderr, "Error: %s is not a AmneziaWG interface\n", iface);
exit(EMEDIUMTYPE);
}
@ -1175,7 +1175,7 @@ static void parse_options(char **iface, char **config, unsigned int *mtu, char *
_cleanup_fclose_ FILE *file = NULL;
_cleanup_free_ char *line = NULL;
_cleanup_free_ char *filename = NULL;
_cleanup_free_ char *paths = strdup(WG_CONFIG_SEARCH_PATHS);
_cleanup_free_ char *paths = strdup(AWG_CONFIG_SEARCH_PATHS);
_cleanup_regfree_ regex_t regex_iface = { 0 }, regex_conf = { 0 };
regmatch_t matches[2];
struct stat sbuf;
@ -1260,23 +1260,23 @@ static void parse_options(char **iface, char **config, unsigned int *mtu, char *
} else if (!strncasecmp(clean, "MTU=", 4) && j > 4) {
*mtu = atoi(clean + 4);
continue;
} else if (!strncasecmp(clean, "Jc=", 3) && j > 4 {
} else if (!strncasecmp(clean, "Jc=", 3) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "Jmin=", 5) && j > 4 {
} else if (!strncasecmp(clean, "Jmin=", 5) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "Jmax=", 5) && j > 4 {
} else if (!strncasecmp(clean, "Jmax=", 5) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "S1=", 3) && j > 4 {
} else if (!strncasecmp(clean, "S1=", 3) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "S2=", 3) && j > 4 {
} else if (!strncasecmp(clean, "S2=", 3) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "H1=", 3) && j > 4 {
} else if (!strncasecmp(clean, "H1=", 3) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "H2=", 3) && j > 4 {
} else if (!strncasecmp(clean, "H2=", 3) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "H3=", 3) && j > 4 {
} else if (!strncasecmp(clean, "H3=", 3) && j > 4) {
is_asecurity_on = true;
} else if (!strncasecmp(clean, "H4=", 3) && j > 4 {
} else if (!strncasecmp(clean, "H4=", 3) && j > 4) {
is_asecurity_on = true;
}
}