├── COPYING ├── README.md ├── amneziawg-dkms.spec ├── debian ├── amneziawg-dkms.postinst ├── changelog ├── clean ├── compat ├── control ├── copyright ├── files ├── gbp.conf ├── rules ├── source │ └── format └── watch ├── kernel-tree-scripts ├── cleanup-sources.sh ├── create-patch.sh ├── filter-compat-defines.sh ├── jury-rig.sh └── prepare-sources.sh └── src ├── Kbuild ├── Kconfig ├── Makefile ├── allowedips.c ├── allowedips.h ├── compat ├── Kbuild.include ├── checksum │ └── checksum_partial_compat.h ├── compat-asm.h ├── compat.h ├── dst_cache │ ├── dst_cache.c │ └── include │ │ └── net │ │ └── dst_cache.h ├── dstmetadata │ └── include │ │ └── net │ │ └── dst_metadata.h ├── fpu-x86 │ └── include │ │ └── asm │ │ └── fpu │ │ └── api.h ├── intel-family-x86 │ └── include │ │ └── asm │ │ └── intel-family.h ├── memneq │ ├── include.h │ └── memneq.c ├── neon-arm │ └── include │ │ └── asm │ │ └── neon.h ├── ptr_ring │ └── include │ │ └── linux │ │ └── ptr_ring.h ├── simd-asm │ └── include │ │ └── asm │ │ └── simd.h ├── simd │ └── include │ │ └── linux │ │ └── simd.h ├── siphash │ ├── include │ │ └── linux │ │ │ └── siphash.h │ └── siphash.c ├── skb_array │ └── include │ │ └── linux │ │ └── skb_array.h ├── udp_tunnel │ ├── include │ │ └── net │ │ │ └── udp_tunnel.h │ ├── udp_tunnel.c │ └── udp_tunnel_partial_compat.h └── version │ └── linux │ └── version.h ├── cookie.c ├── cookie.h ├── crypto ├── Kbuild.include ├── include │ └── zinc │ │ ├── blake2s.h │ │ ├── chacha20.h │ │ ├── chacha20poly1305.h │ │ ├── curve25519.h │ │ └── poly1305.h ├── zinc.h └── zinc │ ├── blake2s │ ├── blake2s-x86_64-glue.c │ ├── blake2s-x86_64.S │ └── blake2s.c │ ├── chacha20 │ ├── chacha20-arm-glue.c │ ├── chacha20-arm.pl │ ├── chacha20-arm64.pl │ ├── chacha20-mips-glue.c │ ├── chacha20-mips.S │ ├── chacha20-unrolled-arm.S │ ├── chacha20-x86_64-glue.c │ ├── chacha20-x86_64.pl │ └── chacha20.c │ ├── chacha20poly1305.c │ ├── curve25519 │ ├── curve25519-arm-glue.c │ ├── curve25519-arm.S │ ├── curve25519-fiat32.c │ ├── curve25519-hacl64.c │ ├── curve25519-x86_64-glue.c │ ├── curve25519-x86_64.c │ └── curve25519.c │ ├── poly1305 │ ├── poly1305-arm-glue.c │ ├── poly1305-arm.pl │ ├── poly1305-arm64.pl │ ├── poly1305-donna32.c │ ├── poly1305-donna64.c │ ├── poly1305-mips-glue.c │ ├── poly1305-mips.S │ ├── poly1305-mips64.pl │ ├── poly1305-x86_64-glue.c │ ├── poly1305-x86_64.pl │ └── poly1305.c │ └── selftest │ ├── blake2s.c │ ├── chacha20.c │ ├── chacha20poly1305.c │ ├── curve25519.c │ ├── poly1305.c │ └── run.h ├── device.c ├── device.h ├── dkms.conf ├── main.c ├── messages.h ├── netlink.c ├── netlink.h ├── noise.c ├── noise.h ├── patches ├── 000-initial-amneziawg.patch ├── 001-legacy-clients-support.patch ├── 002-unknown-peers-notifications.patch ├── 003-fix-for-non-linear-skb.patch ├── 005-bogus-endpoints-parameter.patch ├── 006-bogus-endpoints-prefixes.patch └── 007-random-bytes-fix.patch ├── peer.c ├── peer.h ├── peerlookup.c ├── peerlookup.h ├── queueing.c ├── queueing.h ├── ratelimiter.c ├── ratelimiter.h ├── receive.c ├── selftest ├── allowedips.c ├── counter.c └── ratelimiter.c ├── send.c ├── socket.c ├── socket.h ├── tests ├── debug.mk ├── netns.sh └── qemu │ ├── Makefile │ ├── arch │ ├── aarch64.config │ ├── aarch64_be.config │ ├── arm.config │ ├── armeb.config │ ├── i686.config │ ├── m68k.config │ ├── mips.config │ ├── mips64.config │ ├── mips64el.config │ ├── mipsel.config │ ├── powerpc.config │ ├── powerpc64le.config │ └── x86_64.config │ ├── debug.config │ ├── init.c │ └── kernel.config ├── timers.c ├── timers.h ├── uapi └── wireguard.h └── version.h /README.md: -------------------------------------------------------------------------------- 1 | # AmneziaWG kernel module 2 | 3 | ## Table of contents 4 | 5 | - [Installation](#installation) 6 | - [Ubuntu](#ubuntu) 7 | - [Debian](#debian) 8 | - [Linux Mint](#linux-mint) 9 | - [RHEL/CentOS/SUSE/Fedora Core](#rhelcentossusefedora-core) 10 | - [Manual build](#manual-build) 11 | - [Configuration](#configuration) 12 | - [Troubleshooting](#troubleshooting) 13 | - [License](#license) 14 | 15 | ## Installation 16 | 17 | ### Ubuntu 18 | 19 | Open `Terminal` and proceed with following instructions: 20 | 21 | 1. (Optionally) Upgrade your system to latest packages including latest available kernel by running `apt-get full-upgrade`. 22 | After kernel upgrade reboot is required. 23 | 2. Ensure that you have source repositories configured for APT - run `vi /etc/apt/sources.list` and make sure that there is 24 | at least one line starting with `deb-src` is present and uncommented. 25 | 3. Install pre-requisites - run `sudo apt install -y software-properties-common python3-launchpadlib gnupg2 linux-headers-$(uname -r)`. 26 | 4. Run `sudo add-apt-repository ppa:amnezia/ppa`. 27 | 5. Finally execute `sudo apt-get install -y amneziawg`. 28 | 29 | ### Debian 30 | 31 | Open `Terminal` and do next steps: 32 | 33 | 1. (Optionally) Upgrade your system to latest packages including latest available kernel by running `apt-get full-upgrade`. 34 | After kernel upgrade reboot is required. 35 | 2. Ensure that you have source repositories configured for APT - run `vi /etc/apt/sources.list` and make sure that there is 36 | at least one line starting with `deb-src` is present and uncommented. 37 | 3. Execute following commands: 38 | ```shell 39 | sudo apt install -y software-properties-common python3-launchpadlib gnupg2 linux-headers-$(uname -r) 40 | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 57290828 41 | echo "deb https://ppa.launchpadcontent.net/amnezia/ppa/ubuntu focal main" | sudo tee -a /etc/apt/sources.list 42 | echo "deb-src https://ppa.launchpadcontent.net/amnezia/ppa/ubuntu focal main" | sudo tee -a /etc/apt/sources.list 43 | sudo apt-get update 44 | sudo apt-get install -y amneziawg 45 | ``` 46 | 47 | ### Linux Mint 48 | 49 | Open `Software Sources` and make sure that `Source code repositories` (under `Optional Sources`) are enabled. 50 | 51 | Proceed to `PPAs` section and add `ppa:amnezia/ppa` PPA repository, after that save configuration and rebuild `apt` cache. 52 | 53 | After that, open `Terminal` and run: 54 | 55 | ```shell 56 | sudo apt-get install -y amneziawg 57 | ``` 58 | 59 | ### RHEL/CentOS/SUSE/Fedora Core 60 | 61 | *If you use release that doesn't have DKMS support out of the box, you may need to install [EPEL](https://docs.fedoraproject.org/en-US/epel/#_quickstart) first.* 62 | 63 | Open `Terminal` and run: 64 | 65 | ```shell 66 | sudo dnf copr enable amneziavpn/amneziawg 67 | sudo dnf install amneziawg-dkms amneziawg-tools 68 | ``` 69 | 70 | Before installation it is strictly recommended to upgrade your system kernel to the latest available version and perform 71 | the reboot afterwards. 72 | 73 | ## Manual build 74 | 75 | You may need to install kernel headers and/or build essentials packages before running following steps. 76 | 77 | 1. In Terminal: 78 | ```shell 79 | git clone https://github.com/amnezia-vpn/amneziawg-linux-kernel-module.git 80 | cd amneziawg-linux-kernel-module/src 81 | ``` 82 | 83 | 2. Now, if you run modern Linux with kernel version 5.6+, you need to download your kernel's source from anywhere possible 84 | and link resulting tree to `kernel` symlink: 85 | 86 | ```shell 87 | ln -s /path/to/kernel/source kernel 88 | ``` 89 | 90 | Please note to find and provide full kernel sourcetree, not only headers. **If you run on legacy kernel (<5.6), you do not need to perform this step.** 91 | 92 | 3. Now perform build and installation: 93 | ```shell 94 | make 95 | sudo make install 96 | ``` 97 | 98 | Or on a capable system you may want to use DKMS for this: 99 | ```shell 100 | sudo make dkms-install 101 | sudo dkms add -m amneziawg -v 1.0.0 102 | sudo dkms build -m amneziawg -v 1.0.0 103 | sudo dkms install -m amneziawg -v 1.0.0 104 | ``` 105 | 106 | ## Configuration 107 | 108 | > [!IMPORTANT] 109 | > All parameters should be the same between Client and Server, except Jc - it can vary. 110 | 111 | - Jc — 1 ≤ Jc ≤ 128; recommended range is from 3 to 10 inclusive 112 | - Jmin — Jmin < Jmax; recommended value is 50 113 | - Jmax — Jmin < Jmax ≤ 1280; recommended value is 1000 114 | - S1 — S1 < 1280; S1 + 56 ≠ S2; recommended range is from 15 to 150 inclusive 115 | - S2 — S2 < 1280; recommended range is from 15 to 150 inclusive 116 | - H1/H2/H3/H4 — must be unique among each other; recommended range is from 5 to 2147483647 inclusive 117 | 118 | ## Troubleshooting 119 | 120 | > [!TIP] 121 | > Please check [Ubuntu Server documentation](https://documentation.ubuntu.com/server/how-to/wireguard-vpn/troubleshooting) for more troubleshooting steps. 122 | 123 | ### Enable debug logging 124 | 125 | To get more details, you can enable the dynamic debug feature for the module: 126 | 127 | ```shell 128 | echo "module amneziawg +p" | sudo tee /sys/kernel/debug/dynamic_debug/control 129 | ``` 130 | 131 | This will log messages to dmesg, which can be watched live with: 132 | ```shell 133 | dmesg -wT 134 | ``` 135 | 136 | ### Low space on `/tmp` filesystem 137 | 138 | Most installation instructions above assume that you have enough space in system's `/tmp` partition (as setup script needs 139 | to manipulate with kernel's sourcetree which is pretty huge). 140 | 141 | If you can not afford enough space in your `/tmp`, you may override temporary dir by setting `AWG_TEMP_DIR` environment variable 142 | before the installation: 143 | 144 | ```shell 145 | export AWG_TEMP_DIR="/home/ubuntu/tmp" 146 | ``` 147 | 148 | This setting should persist for future and will not require repeating. 149 | 150 | ### Kernel sourcetree could not be found automatically 151 | 152 | In some rare cases, setup script may not find your kernel's sourcetree automatically. You may find appropriate sources by yourself 153 | then and link them to DKMS module sources, e.g. 154 | 155 | ```shell 156 | ln -s /path/to/your/kernel/sources /usr/src/amneziawg-1.0.0/kernel 157 | ``` 158 | 159 | Reinstall the package thereafter and you should get everything working. 160 | 161 | Should you upgrade your kernel in the future, please remember that you may also need refresh sourcetree and update symlinks. 162 | 163 | ## License 164 | 165 | This project is released under the [GPLv2](COPYING). 166 | -------------------------------------------------------------------------------- /debian/amneziawg-dkms.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | #DEBHELPER# 5 | 6 | case "$1" in 7 | install) 8 | ;; 9 | 10 | configure|reconfigure) 11 | # Get the version of the current loaded module: 12 | old_version="$(cat /sys/module/amneziawg/version 2>/dev/null)" || exit 0 13 | # Get the version of the latest available module: 14 | new_version="$(modinfo -F version amneziawg 2>/dev/null)" || exit 0 15 | # See if the new one is actually newer: 16 | dpkg --compare-versions "$old_version" lt "$new_version" || exit 0 17 | # Trigger an update notification that recommends a reboot: 18 | touch /run/reboot-required || true 19 | grep -Fqsx amneziawg-dkms /run/reboot-required.pkgs || \ 20 | echo amneziawg-dkms >> /run/reboot-required.pkgs || true 21 | ;; 22 | *) 23 | ;; 24 | esac 25 | 26 | exit 0 -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | amneziawg-linux-kmod (1.0.0) unstable; urgency=medium 2 | 3 | * Initial release 4 | 5 | -- unidentified attacker Fri, 01 Dec 2023 11:11:00 +0300 6 | -------------------------------------------------------------------------------- /debian/clean: -------------------------------------------------------------------------------- 1 | src/crypto/zinc/chacha20/chacha20-x86_64.S 2 | src/crypto/zinc/poly1305/poly1305-x86_64.S 3 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: amneziawg-linux-kmod 2 | Section: net 3 | Priority: optional 4 | Maintainer: unidentified attacker 5 | Build-Depends: 6 | debhelper, 7 | dkms 8 | Standards-Version: 4.5.1 9 | Homepage: https://amnezia.org 10 | Vcs-Git: https://github.com/amnezia-vpn/awg-linux-kernel-module.git 11 | Vcs-Browser: https://github.com/amnezia-vpn/awg-linux-kernel-module 12 | Rules-Requires-Root: no 13 | 14 | Package: amneziawg-dkms 15 | Architecture: all 16 | Section: kernel 17 | Depends: 18 | ${misc:Depends}, 19 | ${perl:Depends}, 20 | Recommends: 21 | amneziawg (>= 0.0.20191219), 22 | amneziawg-tools (>= 0.0.20191219), 23 | Description: fast, modern, secure kernel VPN tunnel (DKMS version) 24 | WireGuard is a novel VPN that runs inside the Linux Kernel and uses 25 | state-of-the-art cryptography (the "Noise" protocol). It aims to be 26 | faster, simpler, leaner, and more useful than IPSec, while avoiding 27 | the massive headache. It intends to be considerably more performant 28 | than OpenVPN. WireGuard is designed as a general purpose VPN for 29 | running on embedded interfaces and super computers alike, fit for 30 | many different circumstances. It runs over UDP. 31 | . 32 | This package uses DKMS to automatically build the wireguard kernel 33 | module. 34 | -------------------------------------------------------------------------------- /debian/files: -------------------------------------------------------------------------------- 1 | amneziawg-dkms_1.0.0_all.deb kernel optional 2 | amneziawg-linux-kmod_1.0.0_amd64.buildinfo net optional 3 | -------------------------------------------------------------------------------- /debian/gbp.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | debian-branch = debian/master 3 | upstream-tag = v%(version)s 4 | 5 | [buildpackage] 6 | compression = xz -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export DH_VERBOSE = 1 4 | 5 | include /usr/share/dpkg/default.mk 6 | 7 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 8 | export DEB_VERSION_UPSTREAM 9 | 10 | AMNEZIAWG_ARGS = V=1 11 | 12 | %: 13 | dh $@ --with dkms 14 | 15 | override_dh_auto_install: 16 | $(MAKE) -C src DESTDIR=`pwd`/debian/amneziawg-dkms DKMSDIR=/usr/src/amneziawg-$(DEB_VERSION_UPSTREAM) dkms-install 17 | 18 | override_dh_dkms: 19 | dh_dkms -p amneziawg-dkms -- src/dkms.conf 20 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | opts=mode=git,pgpmode=gittag \ 3 | https://github.com/amnezia-vpn/awg-linux-kernel-module.git \ 4 | refs/tags/v?([\d\.]+) 5 | 6 | -------------------------------------------------------------------------------- /kernel-tree-scripts/cleanup-sources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | AWG_TEMP_DIR="$(cat /var/lib/amnezia/amneziawg/.tempdir 2>/dev/null)" 4 | PREFIX=${AWG_TEMP_DIR:-/tmp} 5 | WORKDIR="${PREFIX}/amneziawg" 6 | 7 | [ -e kernel ] && rm -f kernel 8 | [ -d "${WORKDIR}" ] && rm -rf "${WORKDIR}" -------------------------------------------------------------------------------- /kernel-tree-scripts/create-patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: GPL-2.0 3 | # 4 | # Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 5 | 6 | shopt -s globstar 7 | 8 | WG="$(readlink -f "$(dirname "$(readlink -f "$0")")/../src/")" 9 | 10 | for i in "$WG"/**/{*.c,*.h,*.S,*.pl,*.include} "$WG/Kbuild" "$WG/Kconfig"; do 11 | [[ $i == "$WG/tests/"* ]] && continue 12 | diff -u /dev/null "$i" | sed "s:${WG}:b/net/wireguard:;s:Kbuild:Makefile:" 13 | done 14 | 15 | cat <<_EOF 16 | --- a/net/Kconfig 17 | +++ b/net/Kconfig 18 | @@ -85,2 +85,3 @@ config INET 19 | if INET 20 | +source "net/wireguard/Kconfig" 21 | source "net/ipv4/Kconfig" 22 | --- a/net/Makefile 23 | +++ b/net/Makefile 24 | @@ -16,2 +16,3 @@ 25 | obj-\$(CONFIG_NETFILTER) += netfilter/ 26 | +obj-\$(CONFIG_WIREGUARD) += wireguard/ 27 | obj-\$(CONFIG_INET) += ipv4/ 28 | _EOF 29 | -------------------------------------------------------------------------------- /kernel-tree-scripts/filter-compat-defines.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: GPL-2.0 3 | # 4 | # Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 5 | 6 | silent=0 7 | level=0 8 | ifs=( ) 9 | 10 | while IFS= read -r line; do 11 | if [[ $line =~ ^[[:space:]]*(#if.*) ]]; then 12 | ifs[level++]=0 13 | if [[ ${BASH_REMATCH[1]} == "#ifndef COMPAT_CANNOT_"* ]]; then 14 | ifs[level-1]=-1 15 | continue 16 | elif [[ ${BASH_REMATCH[1]} == "#ifdef COMPAT_CANNOT_"* ]]; then 17 | ifs[level-1]=1 18 | ((++silent)) 19 | continue 20 | fi 21 | elif [[ $line =~ ^[[:space:]]*#else && ${ifs[level-1]} -ne 0 ]]; then 22 | ((ifs[level-1]*=-1)) 23 | ((silent+=ifs[level-1])) 24 | continue 25 | elif [[ $line =~ ^[[:space:]]*#endif ]]; then 26 | ((--level)) 27 | [[ ${ifs[level]} -eq 1 ]] && ((--silent)) 28 | [[ ${ifs[level]} -ne 0 ]] && continue 29 | fi 30 | [[ $silent -eq 0 ]] && printf '%s\n' "$line" 31 | done < "$1" | clang-format -style="{ColumnLimit: 10000}" 32 | -------------------------------------------------------------------------------- /kernel-tree-scripts/jury-rig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: GPL-2.0 3 | # 4 | # Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 5 | 6 | K="$1" 7 | WG="$(readlink -f "$(dirname "$(readlink -f "$0")")/../src/")" 8 | 9 | if [[ ! -e $K/net/Kconfig ]]; then 10 | echo "You must specify the location of kernel sources as the first argument." >&2 11 | exit 1 12 | fi 13 | 14 | ln -sfT "$WG" "$K/net/wireguard" 15 | sed -i "/^obj-\\\$(CONFIG_NETFILTER).*+=/a obj-\$(CONFIG_WIREGUARD) += wireguard/" "$K/net/Makefile" 16 | sed -i "/^if INET\$/a source \"net/wireguard/Kconfig\"" "$K/net/Kconfig" 17 | -------------------------------------------------------------------------------- /kernel-tree-scripts/prepare-sources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | KERNEL_VERSION=$1 4 | 5 | is_modern_kernel() { 6 | local modern=$(echo $KERNEL_VERSION | awk 'BEGIN{ FS="."}; 7 | { if ($1 < 5) { print "N"; } 8 | else if ($1 == 5) { 9 | if ($2 <= 5) { print "N"; } 10 | else { print "Y"; } 11 | } 12 | else { print "Y"; } 13 | }') 14 | 15 | if [ "$modern" = "N" ]; then 16 | return 1 17 | fi 18 | } 19 | 20 | cd_first () { 21 | local prefix=$1 22 | local first=$(find ./${prefix}* -maxdepth 0 -type d 2>/dev/null | sort | head -n 1) 23 | [ "${first}" != "" ] && cd "${first}" || exit 255 24 | } 25 | 26 | if ! is_modern_kernel; then 27 | echo "Legacy kernel - using the compat sources" 28 | exit 0 29 | fi 30 | 31 | if [ -e kernel/drivers/net/wireguard/main.c ] && [ -e kernel/include/uapi/linux/wireguard.h ]; then 32 | echo "Kernel sources are already prepared, skipping" 33 | exit 0 34 | fi 35 | 36 | if ! which apt-get > /dev/null 2>&1 && \ 37 | ! which dnf > /dev/null 2>&1 && \ 38 | ! which yum > /dev/null 2>&1; then 39 | echo "You need to download sources on your own and make a symbolic link to /usr/src/amneziawg-1.0.0/kernel:" 40 | echo "" 41 | echo " ln -s /path/to/kernel/source /usr/src/amneziawg-1.0.0/kernel" 42 | echo "" 43 | echo "Otherwise it is not possible to obtain kernel sources on your system automatically" 44 | exit 1 45 | fi 46 | 47 | DISTRO_FLAVOR=$(cat /etc/*-release 2>/dev/null | grep -E ^ID_LIKE= | sed 's/ID_LIKE=//' | sed 's/"//g') 48 | DISTRO_FLAVOR=${DISTRO_FLAVOR:-$(cat /etc/*-release 2>/dev/null | grep -E ^ID= | sed 's/ID=//' | sed 's/"//g')} 49 | 50 | if [ "${AWG_TEMP_DIR}" != "" ]; then 51 | mkdir -p /var/lib/amnezia/amneziawg 52 | echo "${AWG_TEMP_DIR}" > /var/lib/amnezia/amneziawg/.tempdir 53 | elif [ -f /var/lib/amnezia/amneziawg/.tempdir ]; then 54 | AWG_TEMP_DIR="$(cat /var/lib/amnezia/amneziawg/.tempdir)" 55 | fi 56 | 57 | PREFIX=${AWG_TEMP_DIR:-/tmp} 58 | WORKDIR="${PREFIX}/amneziawg" 59 | 60 | [ -d "${WORKDIR}" ] && rm -rf "${WORKDIR}" 61 | mkdir -p "${WORKDIR}" 62 | pushd "${WORKDIR}" > /dev/null 2>&1 || exit 1 63 | 64 | echo "Downloading source for Linux kernel version ${KERNEL_VERSION}" 65 | 66 | if [[ "${DISTRO_FLAVOR}" =~ debian ]]; then 67 | export DEBIAN_FRONTEND=noninteractive 68 | VERSION_MAIN="${KERNEL_VERSION%+*}" 69 | VERSION_SUFFIX="${KERNEL_VERSION#*+}" 70 | ac=$(apt-cache search --names-only linux-image "${VERSION_MAIN}" "${VERSION_SUFFIX}" unsigned 2>/dev/null|head -n 1) 71 | [ "${ac}" == "" ] && ac=$(apt-cache search --names-only linux-image "${VERSION_MAIN}" "${VERSION_SUFFIX}" 2>/dev/null|head -n 1) 72 | if [ "${ac}" == "" ]; then 73 | echo "Could not find suitable image for your Linux distribution!" 74 | exit 255 75 | fi 76 | 77 | PACKAGE_NAME="${ac% - *}" 78 | PACKAGE_VERSION=$(apt-cache madison "${PACKAGE_NAME}"|grep Sources|head -n 1|awk '{ print $3; }') 79 | echo "Downloading as $(whoami)" 80 | apt-get -yq -o APT::Sandbox::User="$(whoami)" source "${PACKAGE_NAME}=${PACKAGE_VERSION}" 81 | cd_first 82 | else 83 | yumdownloader --source kernel 84 | [ -f "${HOME}/.rpmmacros" ] && mv "${HOME}/.rpmmacros" "${HOME}/.rpmmacros.orig" 85 | echo "%_topdir $(pwd)" > "${HOME}/.rpmmacros" 86 | rpm -ivh "$(ls *.rpm)" 87 | cd SPECS || exit 255 88 | rpmbuild -bp --target="$(uname -m)" --nodeps kernel.spec 89 | rm -rf "${HOME}/.rpmmacros" 90 | [ -f "${HOME}/.rpmmacros.orig" ] && mv "${HOME}/.rpmmacros.orig" "${HOME}/.rpmmacros" 91 | cd ../BUILD || exit 255 92 | cd_first 93 | cd_first linux 94 | fi 95 | 96 | KERNEL_PATH="$(pwd)" 97 | popd > /dev/null 2>&1 || exit 1 98 | [ -e kernel ] && rm -f kernel 99 | ln -s "${KERNEL_PATH}" kernel 100 | -------------------------------------------------------------------------------- /src/Kbuild: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | 5 | AWG_MODERN_KERNEL := $(shell [ $(VERSION) -gt 5 -o \( $(VERSION) -eq 5 -a $(PATCHLEVEL) -gt 5 \) ] && echo true) 6 | 7 | ccflags-y := -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt' 8 | ccflags-y += -Wframe-larger-than=2048 9 | ccflags-$(CONFIG_AMNEZIAWG_DEBUG) += -DDEBUG -g 10 | ccflags-$(if $(WIREGUARD_VERSION),y,) += -D'WIREGUARD_VERSION="$(WIREGUARD_VERSION)"' 11 | ccflags-$(if $(OMIT_ENDPOINTS),y,) += -D'OMIT_ENDPOINTS="$(OMIT_ENDPOINTS)"' 12 | 13 | amneziawg-y := main.o noise.o device.o peer.o timers.o queueing.o send.o receive.o socket.o peerlookup.o allowedips.o ratelimiter.o cookie.o netlink.o 14 | 15 | ifndef AWG_MODERN_KERNEL 16 | include $(src)/crypto/Kbuild.include 17 | include $(src)/compat/Kbuild.include 18 | endif 19 | 20 | obj-$(if $(KBUILD_EXTMOD),m,$(CONFIG_AMNEZIAWG)) := amneziawg.o 21 | -------------------------------------------------------------------------------- /src/Kconfig: -------------------------------------------------------------------------------- 1 | config AMNEZIAWG 2 | tristate "IP: AmneziaWG secure network tunnel" 3 | depends on NET && INET 4 | depends on IPV6 || !IPV6 5 | select NET_UDP_TUNNEL 6 | select DST_CACHE 7 | select CRYPTO 8 | select CRYPTO_ALGAPI 9 | select VFP 10 | select VFPv3 if CPU_V7 11 | select NEON if CPU_V7 12 | select KERNEL_MODE_NEON if CPU_V7 13 | default m 14 | help 15 | WireGuard is a secure, fast, and easy to use replacement for IPsec 16 | that uses modern cryptography and clever networking tricks. It's 17 | designed to be fairly general purpose and abstract enough to fit most 18 | use cases, while at the same time remaining extremely simple to 19 | configure. See www.wireguard.com for more info. 20 | 21 | It's safe to say Y or M here, as the driver is very lightweight and 22 | is only in use when an administrator chooses to add an interface. 23 | 24 | config AMNEZIAWG_DEBUG 25 | bool "Debugging checks and verbose messages" 26 | depends on AMNEZIAWG 27 | help 28 | This will write log messages for handshake and other events 29 | that occur for a WireGuard interface. It will also perform some 30 | extra validation checks and unit tests at various points. This is 31 | only useful for debugging. 32 | 33 | Say N here unless you know what you're doing. 34 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | 5 | WIREGUARD_VERSION = 1.0.0 6 | OMIT_ENDPOINTS ?= 7 | 8 | KERNELRELEASE ?= $(shell uname -r) 9 | KERNELDIR ?= /lib/modules/$(KERNELRELEASE)/build 10 | PREFIX ?= /usr 11 | DESTDIR ?= 12 | SRCDIR ?= $(PREFIX)/src 13 | DKMSDIR ?= $(SRCDIR)/amneziawg-$(WIREGUARD_VERSION) 14 | DEPMOD ?= depmod 15 | DEPMODBASEDIR ?= / 16 | 17 | PWD := $(shell pwd) 18 | 19 | all: apply-patches module 20 | debug: apply-patches module-debug 21 | 22 | rwildcard=$(foreach d,$(if $3,$(filter-out $3,$(wildcard $1*)),$(wildcard $1*)),$(call rwildcard,$d/,$2,$3) $(filter $(subst *,%,$2),$d)) 23 | 24 | KERNEL_SOURCE_DIR := $(PWD)/kernel 25 | WG_SOURCE_DIR := $(KERNEL_SOURCE_DIR)/drivers/net/wireguard 26 | 27 | define MODERN_KERNEL_CHECK_COMMAND 28 | echo $(KERNELRELEASE) | awk 'BEGIN{ FS="."}; 29 | { if ($$1 < 5) { print "N"; } 30 | else if ($$1 == 5) { 31 | if ($$2 <= 5) { print "N"; } 32 | else { print "Y"; } 33 | } 34 | else { print "Y"; } 35 | }' 36 | endef 37 | export MODERN_KERNEL_CHECK_COMMAND 38 | 39 | ifeq ($(shell $(MODERN_KERNEL_CHECK_COMMAND)),Y) 40 | define MODERN_KERNEL_SOURCES_NOT_FOUND_ERROR 41 | 42 | You're running a modern Linux Kernel (version $(KERNELRELEASE)). 43 | 44 | In order to build AmneziaWG kernel module for this kernel you must obtain sources of your kernel 45 | by yourself and make a symlink to them into this directory: 46 | 47 | ln -s kernel 48 | 49 | After that please run make script again 50 | endef 51 | export MODERN_KERNEL_SOURCES_NOT_FOUND_ERROR 52 | 53 | GENERATED_SOURCES_DIR := $(PWD)/generated 54 | TARGET_BUILD_DIR := $(GENERATED_SOURCES_DIR) 55 | 56 | FILE_LIST := $(if $(strip $(realpath $(WG_SOURCE_DIR))),$(call rwildcard,$(WG_SOURCE_DIR)/,*.c *.h *.S *.pl *.include,)) 57 | SOURCE_FILES := $(filter-out Makefile main.c wireguard.mod.c tests/%,$(foreach f,$(FILE_LIST),$(subst $(WG_SOURCE_DIR)/,,$(f)))) 58 | NEEDED_SOURCES := $(addprefix $(GENERATED_SOURCES_DIR)/,main.c uapi/wireguard.h Kbuild Kconfig $(SOURCE_FILES)) 59 | 60 | apply-patches: $(NEEDED_SOURCES) $(GENERATED_SOURCES_DIR)/.patches.stamp 61 | 62 | $(GENERATED_SOURCES_DIR)/.patches.stamp: $(sort $(wildcard $(PWD)/patches/*.patch)) 63 | CWD=$$(pwd); \ 64 | cd $(GENERATED_SOURCES_DIR); \ 65 | for patch in $^; do \ 66 | patch -F3 -t -p0 -i $$patch; \ 67 | done; \ 68 | cd $$CWD; \ 69 | date > $(GENERATED_SOURCES_DIR)/.patches.stamp 70 | 71 | $(GENERATED_SOURCES_DIR)/K%: $(PWD)/K% 72 | @install -d $(@D) && install -m 0644 $^ $@ 73 | 74 | $(GENERATED_SOURCES_DIR)/uapi/wireguard.h: $(KERNEL_SOURCE_DIR)/include/uapi/linux/wireguard.h 75 | @install -d $(@D) && install -m 0644 $^ $@ 76 | 77 | $(GENERATED_SOURCES_DIR)/%: $(WG_SOURCE_DIR)/% 78 | @install -d $(@D) && install -m 0644 $^ $@ 79 | 80 | $(KERNEL_SOURCE_DIR)/%: 81 | $(error $(MODERN_KERNEL_SOURCES_NOT_FOUND_ERROR)) 82 | else 83 | TARGET_BUILD_DIR := $(PWD) 84 | 85 | apply-patches: 86 | @: 87 | endif 88 | 89 | ifneq ($(V),1) 90 | MAKEFLAGS += --no-print-directory 91 | endif 92 | 93 | module: 94 | @$(MAKE) -C $(KERNELDIR) M=$(TARGET_BUILD_DIR) WIREGUARD_VERSION="$(WIREGUARD_VERSION)" OMIT_ENDPOINTS="$(OMIT_ENDPOINTS)" modules 95 | [ "$(TARGET_BUILD_DIR)" != "$(PWD)" ] && cp $(TARGET_BUILD_DIR)/amneziawg.ko $(PWD)/amneziawg.ko || true 96 | 97 | module-debug: 98 | @$(MAKE) -C $(KERNELDIR) M=$(TARGET_BUILD_DIR) V=1 CONFIG_AMNEZIAWG_DEBUG=y WIREGUARD_VERSION="$(WIREGUARD_VERSION)" OMIT_ENDPOINTS="$(OMIT_ENDPOINTS)" modules 99 | [ "$(TARGET_BUILD_DIR)" != "$(PWD)" ] && cp $(TARGET_BUILD_DIR)/amneziawg.ko $(PWD)/amneziawg.ko || true 100 | 101 | clean: 102 | @$(MAKE) -C $(KERNELDIR) M=$(PWD) clean 103 | [ "$(TARGET_BUILD_DIR)" != "$(PWD)" ] && rm -rf $(TARGET_BUILD_DIR) || true 104 | 105 | module-install: 106 | @$(MAKE) -C $(KERNELDIR) M=$(TARGET_BUILD_DIR) WIREGUARD_VERSION="$(WIREGUARD_VERSION)" OMIT_ENDPOINTS="$(OMIT_ENDPOINTS)" modules_install 107 | $(DEPMOD) -b "$(DEPMODBASEDIR)" -a $(KERNELRELEASE) 108 | 109 | install: module-install 110 | 111 | DKMS_SOURCES := Makefile Kbuild Kconfig dkms.conf $(call rwildcard,,*.c *.h *.S *.pl *.include *.patch,amneziawg.mod.c kernel/% tests/%) 112 | dkms-install: $(DKMS_SOURCES) 113 | @$(foreach f,$(DKMS_SOURCES),install -v -m0644 -D $(f) $(DESTDIR)$(DKMSDIR)/$(f);) 114 | @install -v -m 0755 ../kernel-tree-scripts/prepare-sources.sh "$(DESTDIR)$(DKMSDIR)/prepare-sources.sh" 115 | @install -v -m 0755 ../kernel-tree-scripts/cleanup-sources.sh "$(DESTDIR)$(DKMSDIR)/cleanup-sources.sh" 116 | [ "$(realpath $(WG_SOURCE_DIR))" != "" ] && ln -s "$(KERNEL_SOURCE_DIR)" "$(DESTDIR)$(DKMSDIR)/kernel" || true 117 | 118 | style: 119 | $(KERNELDIR)/scripts/checkpatch.pl -f --max-line-length=4000 --codespell --color=always $(filter-out wireguard.mod.c,$(wildcard *.c)) $(wildcard *.h) $(wildcard selftest/*.c) 120 | 121 | check: clean 122 | scan-build --html-title=wireguard-linux-compat -maxloop 100 --view --keep-going $(MAKE) module CONFIG_WIREGUARD_DEBUG=y C=2 CF="-D__CHECK_ENDIAN__" 123 | 124 | coccicheck: clean 125 | @$(MAKE) -C $(KERNELDIR) M=$(TARGET_BUILD_DIR) CONFIG_WIREGUARD_DEBUG=y coccicheck MODE=report 126 | 127 | cloc: 128 | @cloc --skip-uniqueness --by-file --extract-with="$$(readlink -f ../kernel-tree-scripts/filter-compat-defines.sh) >FILE< > \$$(basename >FILE<)" $(filter-out wireguard.mod.c,$(wildcard *.c)) $(wildcard *.h) 129 | 130 | -include tests/debug.mk 131 | 132 | .PHONY: all module module-debug apply-patches module-install install dkms-install clean cloc check style 133 | -------------------------------------------------------------------------------- /src/allowedips.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_ALLOWEDIPS_H 7 | #define _WG_ALLOWEDIPS_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | struct wg_peer; 14 | 15 | struct allowedips_node { 16 | struct wg_peer __rcu *peer; 17 | struct allowedips_node __rcu *bit[2]; 18 | u8 cidr, bit_at_a, bit_at_b, bitlen; 19 | u8 bits[16] __aligned(__alignof(u64)); 20 | 21 | /* Keep rarely used members at bottom to be beyond cache line. */ 22 | unsigned long parent_bit_packed; 23 | union { 24 | struct list_head peer_list; 25 | struct rcu_head rcu; 26 | }; 27 | }; 28 | 29 | struct allowedips { 30 | struct allowedips_node __rcu *root4; 31 | struct allowedips_node __rcu *root6; 32 | u64 seq; 33 | } __aligned(4); /* We pack the lower 2 bits of &root, but m68k only gives 16-bit alignment. */ 34 | 35 | void wg_allowedips_init(struct allowedips *table); 36 | void wg_allowedips_free(struct allowedips *table, struct mutex *mutex); 37 | int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip, 38 | u8 cidr, struct wg_peer *peer, struct mutex *lock); 39 | int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip, 40 | u8 cidr, struct wg_peer *peer, struct mutex *lock); 41 | void wg_allowedips_remove_by_peer(struct allowedips *table, 42 | struct wg_peer *peer, struct mutex *lock); 43 | /* The ip input pointer should be __aligned(__alignof(u64))) */ 44 | int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr); 45 | 46 | /* These return a strong reference to a peer: */ 47 | struct wg_peer *wg_allowedips_lookup_dst(struct allowedips *table, 48 | struct sk_buff *skb); 49 | struct wg_peer *wg_allowedips_lookup_src(struct allowedips *table, 50 | struct sk_buff *skb); 51 | 52 | #ifdef DEBUG 53 | bool wg_allowedips_selftest(void); 54 | #endif 55 | 56 | int wg_allowedips_slab_init(void); 57 | void wg_allowedips_slab_uninit(void); 58 | 59 | #endif /* _WG_ALLOWEDIPS_H */ 60 | -------------------------------------------------------------------------------- /src/compat/Kbuild.include: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | 5 | kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) 6 | 7 | ccflags-y += -include $(kbuild-dir)/compat/compat.h 8 | asflags-y += -include $(kbuild-dir)/compat/compat-asm.h 9 | LINUXINCLUDE := -DCOMPAT_VERSION=$(VERSION) -DCOMPAT_PATCHLEVEL=$(PATCHLEVEL) -DCOMPAT_SUBLEVEL=$(SUBLEVEL) -I$(kbuild-dir)/compat/version $(LINUXINCLUDE) 10 | 11 | ifeq ($(wildcard $(srctree)/include/linux/ptr_ring.h),) 12 | ccflags-y += -I$(kbuild-dir)/compat/ptr_ring/include 13 | endif 14 | 15 | ifeq ($(wildcard $(srctree)/include/linux/skb_array.h),) 16 | ccflags-y += -I$(kbuild-dir)/compat/skb_array/include 17 | endif 18 | 19 | ifeq ($(wildcard $(srctree)/include/linux/siphash.h),) 20 | ccflags-y += -I$(kbuild-dir)/compat/siphash/include 21 | amneziawg-y += compat/siphash/siphash.o 22 | endif 23 | 24 | ifeq ($(wildcard $(srctree)/include/net/dst_cache.h),) 25 | ccflags-y += -I$(kbuild-dir)/compat/dst_cache/include 26 | amneziawg-y += compat/dst_cache/dst_cache.o 27 | endif 28 | 29 | ifeq ($(wildcard $(srctree)/arch/x86/include/asm/intel-family.h)$(CONFIG_X86),y) 30 | ccflags-y += -I$(kbuild-dir)/compat/intel-family-x86/include 31 | endif 32 | 33 | ifeq ($(wildcard $(srctree)/arch/x86/include/asm/fpu/api.h)$(CONFIG_X86),y) 34 | ccflags-y += -I$(kbuild-dir)/compat/fpu-x86/include 35 | endif 36 | 37 | ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/simd.h)$(shell grep -s -F "generic-y += simd.h" "$(srctree)/arch/$(SRCARCH)/Kbuild" "$(srctree)/arch/$(SRCARCH)/Makefile"),) 38 | ccflags-y += -I$(kbuild-dir)/compat/simd-asm/include 39 | endif 40 | 41 | ifeq ($(wildcard $(srctree)/include/linux/simd.h),) 42 | ccflags-y += -I$(kbuild-dir)/compat/simd/include 43 | endif 44 | 45 | ifeq ($(wildcard $(srctree)/include/net/udp_tunnel.h),) 46 | ccflags-y += -I$(kbuild-dir)/compat/udp_tunnel/include 47 | amneziawg-y += compat/udp_tunnel/udp_tunnel.o 48 | endif 49 | 50 | ifeq ($(shell grep -s -F "int crypto_memneq" "$(srctree)/include/crypto/algapi.h"),) 51 | ccflags-y += -include $(kbuild-dir)/compat/memneq/include.h 52 | amneziawg-y += compat/memneq/memneq.o 53 | endif 54 | 55 | ifeq ($(shell grep -s -F "addr_gen_mode" "$(srctree)/include/linux/ipv6.h"),) 56 | ccflags-y += -DCOMPAT_CANNOT_USE_DEV_CNF 57 | endif 58 | 59 | ifdef CONFIG_HZ 60 | ifeq ($(wildcard $(CURDIR)/include/generated/timeconst.h),) 61 | ccflags-y += $(shell bash -c '((a=$(CONFIG_HZ), b=1000000)); while ((b > 0)); do ((t=b, b=a%b, a=t)); done; echo "-DHZ_TO_USEC_NUM=$$((1000000/a)) -DHZ_TO_USEC_DEN=$$(($(CONFIG_HZ)/a))";') 62 | endif 63 | endif 64 | 65 | ifeq ($(wildcard $(srctree)/arch/arm/include/asm/neon.h)$(CONFIG_ARM),y) 66 | ccflags-y += -I$(kbuild-dir)/compat/neon-arm/include 67 | endif 68 | ifeq ($(wildcard $(srctree)/arch/arm64/include/asm/neon.h)$(CONFIG_ARM64),y) 69 | ccflags-y += -I$(kbuild-dir)/compat/neon-arm/include 70 | endif 71 | 72 | ifeq ($(wildcard $(srctree)/include/net/dst_metadata.h),) 73 | ccflags-y += -I$(kbuild-dir)/compat/dstmetadata/include 74 | endif 75 | 76 | ifeq ($(CONFIG_X86_64),y) 77 | ifeq ($(ssse3_instr),) 78 | ssse3_instr := $(call as-instr,pshufb %xmm0$(comma)%xmm0,-DCONFIG_AS_SSSE3=1) 79 | ccflags-y += $(ssse3_instr) 80 | asflags-y += $(ssse3_instr) 81 | endif 82 | ifeq ($(avx_instr),) 83 | avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1) 84 | ccflags-y += $(avx_instr) 85 | asflags-y += $(avx_instr) 86 | endif 87 | ifeq ($(avx2_instr),) 88 | avx2_instr := $(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1) 89 | ccflags-y += $(avx2_instr) 90 | asflags-y += $(avx2_instr) 91 | endif 92 | ifeq ($(avx512_instr),) 93 | avx512_instr := $(call as-instr,vpmovm2b %k1$(comma)%zmm5,-DCONFIG_AS_AVX512=1) 94 | ccflags-y += $(avx512_instr) 95 | asflags-y += $(avx512_instr) 96 | endif 97 | ifeq ($(bmi2_instr),) 98 | bmi2_instr :=$(call as-instr,mulx %rax$(comma)%rax$(comma)%rax,-DCONFIG_AS_BMI2=1) 99 | ccflags-y += $(bmi2_instr) 100 | asflags-y += $(bmi2_instr) 101 | endif 102 | ifeq ($(adx_instr),) 103 | adx_instr :=$(call as-instr,adcx %rax$(comma)%rax,-DCONFIG_AS_ADX=1) 104 | ccflags-y += $(adx_instr) 105 | asflags-y += $(adx_instr) 106 | endif 107 | endif 108 | 109 | ifneq ($(shell grep -s -F "\#define LINUX_PACKAGE_ID \" Debian " "$(CURDIR)/include/generated/package.h"),) 110 | ccflags-y += -DISDEBIAN 111 | endif 112 | -------------------------------------------------------------------------------- /src/compat/checksum/checksum_partial_compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define IP6_MF 0x0001 13 | #define IP6_OFFSET 0xFFF8 14 | static inline int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len, unsigned int max) 15 | { 16 | if (skb_headlen(skb) >= len) 17 | return 0; 18 | if (max > skb->len) 19 | max = skb->len; 20 | if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) 21 | return -ENOMEM; 22 | if (skb_headlen(skb) < len) 23 | return -EPROTO; 24 | return 0; 25 | } 26 | #define MAX_IP_HDR_LEN 128 27 | static inline int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) 28 | { 29 | unsigned int off; 30 | bool fragment; 31 | int err; 32 | fragment = false; 33 | err = skb_maybe_pull_tail(skb, sizeof(struct iphdr), MAX_IP_HDR_LEN); 34 | if (err < 0) 35 | goto out; 36 | if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) 37 | fragment = true; 38 | off = ip_hdrlen(skb); 39 | err = -EPROTO; 40 | if (fragment) 41 | goto out; 42 | switch (ip_hdr(skb)->protocol) { 43 | case IPPROTO_TCP: 44 | err = skb_maybe_pull_tail(skb, 45 | off + sizeof(struct tcphdr), 46 | MAX_IP_HDR_LEN); 47 | if (err < 0) 48 | goto out; 49 | 50 | if (!skb_partial_csum_set(skb, off, 51 | offsetof(struct tcphdr, check))) { 52 | err = -EPROTO; 53 | goto out; 54 | } 55 | 56 | if (recalculate) 57 | tcp_hdr(skb)->check = 58 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, 59 | ip_hdr(skb)->daddr, 60 | skb->len - off, 61 | IPPROTO_TCP, 0); 62 | break; 63 | case IPPROTO_UDP: 64 | err = skb_maybe_pull_tail(skb, 65 | off + sizeof(struct udphdr), 66 | MAX_IP_HDR_LEN); 67 | if (err < 0) 68 | goto out; 69 | 70 | if (!skb_partial_csum_set(skb, off, 71 | offsetof(struct udphdr, check))) { 72 | err = -EPROTO; 73 | goto out; 74 | } 75 | 76 | if (recalculate) 77 | udp_hdr(skb)->check = 78 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, 79 | ip_hdr(skb)->daddr, 80 | skb->len - off, 81 | IPPROTO_UDP, 0); 82 | break; 83 | default: 84 | goto out; 85 | } 86 | err = 0; 87 | out: 88 | return err; 89 | } 90 | #define MAX_IPV6_HDR_LEN 256 91 | #define OPT_HDR(type, skb, off) \ 92 | (type *)(skb_network_header(skb) + (off)) 93 | static inline int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) 94 | { 95 | int err; 96 | u8 nexthdr; 97 | unsigned int off; 98 | unsigned int len; 99 | bool fragment; 100 | bool done; 101 | fragment = false; 102 | done = false; 103 | off = sizeof(struct ipv6hdr); 104 | err = skb_maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); 105 | if (err < 0) 106 | goto out; 107 | nexthdr = ipv6_hdr(skb)->nexthdr; 108 | len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); 109 | while (off <= len && !done) { 110 | switch (nexthdr) { 111 | case IPPROTO_DSTOPTS: 112 | case IPPROTO_HOPOPTS: 113 | case IPPROTO_ROUTING: { 114 | struct ipv6_opt_hdr *hp; 115 | 116 | err = skb_maybe_pull_tail(skb, off + sizeof(struct ipv6_opt_hdr), MAX_IPV6_HDR_LEN); 117 | if (err < 0) 118 | goto out; 119 | hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); 120 | nexthdr = hp->nexthdr; 121 | off += ipv6_optlen(hp); 122 | break; 123 | } 124 | case IPPROTO_FRAGMENT: { 125 | struct frag_hdr *hp; 126 | err = skb_maybe_pull_tail(skb, off + sizeof(struct frag_hdr), MAX_IPV6_HDR_LEN); 127 | if (err < 0) 128 | goto out; 129 | hp = OPT_HDR(struct frag_hdr, skb, off); 130 | if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) 131 | fragment = true; 132 | nexthdr = hp->nexthdr; 133 | off += sizeof(struct frag_hdr); 134 | break; 135 | } 136 | default: 137 | done = true; 138 | break; 139 | } 140 | } 141 | err = -EPROTO; 142 | if (!done || fragment) 143 | goto out; 144 | switch (nexthdr) { 145 | case IPPROTO_TCP: 146 | err = skb_maybe_pull_tail(skb, 147 | off + sizeof(struct tcphdr), 148 | MAX_IPV6_HDR_LEN); 149 | if (err < 0) 150 | goto out; 151 | 152 | if (!skb_partial_csum_set(skb, off, 153 | offsetof(struct tcphdr, check))) { 154 | err = -EPROTO; 155 | goto out; 156 | } 157 | 158 | if (recalculate) 159 | tcp_hdr(skb)->check = 160 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 161 | &ipv6_hdr(skb)->daddr, 162 | skb->len - off, 163 | IPPROTO_TCP, 0); 164 | break; 165 | case IPPROTO_UDP: 166 | err = skb_maybe_pull_tail(skb, 167 | off + sizeof(struct udphdr), 168 | MAX_IPV6_HDR_LEN); 169 | if (err < 0) 170 | goto out; 171 | 172 | if (!skb_partial_csum_set(skb, off, 173 | offsetof(struct udphdr, check))) { 174 | err = -EPROTO; 175 | goto out; 176 | } 177 | 178 | if (recalculate) 179 | udp_hdr(skb)->check = 180 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 181 | &ipv6_hdr(skb)->daddr, 182 | skb->len - off, 183 | IPPROTO_UDP, 0); 184 | break; 185 | default: 186 | goto out; 187 | } 188 | err = 0; 189 | out: 190 | return err; 191 | } 192 | static inline int skb_checksum_setup(struct sk_buff *skb, bool recalculate) 193 | { 194 | int err; 195 | switch (skb->protocol) { 196 | case htons(ETH_P_IP): 197 | err = skb_checksum_setup_ip(skb, recalculate); 198 | break; 199 | 200 | case htons(ETH_P_IPV6): 201 | err = skb_checksum_setup_ipv6(skb, recalculate); 202 | break; 203 | default: 204 | err = -EPROTO; 205 | break; 206 | } 207 | return err; 208 | } 209 | -------------------------------------------------------------------------------- /src/compat/compat-asm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_COMPATASM_H 7 | #define _WG_COMPATASM_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef RHEL_MAJOR 14 | #if RHEL_MAJOR == 7 15 | #define ISRHEL7 16 | #elif RHEL_MAJOR == 8 17 | #define ISRHEL8 18 | #endif 19 | #endif 20 | 21 | /* PaX compatibility */ 22 | #if defined(RAP_PLUGIN) && defined(RAP_ENTRY) 23 | #undef ENTRY 24 | #define ENTRY RAP_ENTRY 25 | #endif 26 | 27 | #if defined(__LINUX_ARM_ARCH__) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) 28 | .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo 29 | .macro ret\c, reg 30 | #if __LINUX_ARM_ARCH__ < 6 31 | mov\c pc, \reg 32 | #else 33 | .ifeqs "\reg", "lr" 34 | bx\c \reg 35 | .else 36 | mov\c pc, \reg 37 | .endif 38 | #endif 39 | .endm 40 | .endr 41 | #endif 42 | 43 | #if defined(__LINUX_ARM_ARCH__) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) 44 | #include 45 | #define lspush push 46 | #define lspull pull 47 | #undef push 48 | #undef pull 49 | #endif 50 | 51 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 76) && !defined(ISRHEL8) && !defined(SYM_FUNC_START) 52 | #define SYM_FUNC_START ENTRY 53 | #define SYM_FUNC_END ENDPROC 54 | #endif 55 | 56 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) 57 | #define blake2s_compress_ssse3 zinc_blake2s_compress_ssse3 58 | #define blake2s_compress_avx512 zinc_blake2s_compress_avx512 59 | #define poly1305_init_arm zinc_poly1305_init_arm 60 | #define poly1305_blocks_arm zinc_poly1305_blocks_arm 61 | #define poly1305_emit_arm zinc_poly1305_emit_arm 62 | #define poly1305_blocks_neon zinc_poly1305_blocks_neon 63 | #define poly1305_emit_neon zinc_poly1305_emit_neon 64 | #define poly1305_init_mips zinc_poly1305_init_mips 65 | #define poly1305_blocks_mips zinc_poly1305_blocks_mips 66 | #define poly1305_emit_mips zinc_poly1305_emit_mips 67 | #define poly1305_init_x86_64 zinc_poly1305_init_x86_64 68 | #define poly1305_blocks_x86_64 zinc_poly1305_blocks_x86_64 69 | #define poly1305_emit_x86_64 zinc_poly1305_emit_x86_64 70 | #define poly1305_emit_avx zinc_poly1305_emit_avx 71 | #define poly1305_blocks_avx zinc_poly1305_blocks_avx 72 | #define poly1305_blocks_avx2 zinc_poly1305_blocks_avx2 73 | #define poly1305_blocks_avx512 zinc_poly1305_blocks_avx512 74 | #define curve25519_neon zinc_curve25519_neon 75 | #define hchacha20_ssse3 zinc_hchacha20_ssse3 76 | #define chacha20_ssse3 zinc_chacha20_ssse3 77 | #define chacha20_avx2 zinc_chacha20_avx2 78 | #define chacha20_avx512 zinc_chacha20_avx512 79 | #define chacha20_avx512vl zinc_chacha20_avx512vl 80 | #define chacha20_mips zinc_chacha20_mips 81 | #define chacha20_arm zinc_chacha20_arm 82 | #define hchacha20_arm zinc_hchacha20_arm 83 | #define chacha20_neon zinc_chacha20_neon 84 | #endif 85 | 86 | #endif /* _WG_COMPATASM_H */ 87 | -------------------------------------------------------------------------------- /src/compat/dst_cache/dst_cache.c: -------------------------------------------------------------------------------- 1 | /* 2 | * net/core/dst_cache.c - dst entry cache 3 | * 4 | * Copyright (c) 2016 Paolo Abeni 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #if IS_ENABLED(CONFIG_IPV6) 17 | #include 18 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 50) 19 | static inline u32 rt6_get_cookie(const struct rt6_info *rt) 20 | { 21 | if ((unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from)) 22 | rt = (struct rt6_info *)(rt->dst.from); 23 | 24 | return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; 25 | } 26 | #endif 27 | #endif 28 | #include 29 | 30 | #ifndef COMPAT_HAS_DEFINED_DST_CACHE_PCPU 31 | struct dst_cache_pcpu { 32 | unsigned long refresh_ts; 33 | struct dst_entry *dst; 34 | u32 cookie; 35 | union { 36 | struct in_addr in_saddr; 37 | struct in6_addr in6_saddr; 38 | }; 39 | }; 40 | #endif 41 | 42 | static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache, 43 | struct dst_entry *dst, u32 cookie) 44 | { 45 | dst_release(dst_cache->dst); 46 | if (dst) 47 | dst_hold(dst); 48 | 49 | dst_cache->cookie = cookie; 50 | dst_cache->dst = dst; 51 | } 52 | 53 | static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache, 54 | struct dst_cache_pcpu *idst) 55 | { 56 | struct dst_entry *dst; 57 | 58 | dst = idst->dst; 59 | if (!dst) 60 | goto fail; 61 | 62 | /* the cache already hold a dst reference; it can't go away */ 63 | dst_hold(dst); 64 | 65 | if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) || 66 | (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) { 67 | dst_cache_per_cpu_dst_set(idst, NULL, 0); 68 | dst_release(dst); 69 | goto fail; 70 | } 71 | return dst; 72 | 73 | fail: 74 | idst->refresh_ts = jiffies; 75 | return NULL; 76 | } 77 | 78 | struct dst_entry *dst_cache_get(struct dst_cache *dst_cache) 79 | { 80 | if (!dst_cache->cache) 81 | return NULL; 82 | 83 | return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache)); 84 | } 85 | 86 | struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr) 87 | { 88 | struct dst_cache_pcpu *idst; 89 | struct dst_entry *dst; 90 | 91 | if (!dst_cache->cache) 92 | return NULL; 93 | 94 | idst = this_cpu_ptr(dst_cache->cache); 95 | dst = dst_cache_per_cpu_get(dst_cache, idst); 96 | if (!dst) 97 | return NULL; 98 | 99 | *saddr = idst->in_saddr.s_addr; 100 | return container_of(dst, struct rtable, dst); 101 | } 102 | 103 | void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, 104 | __be32 saddr) 105 | { 106 | struct dst_cache_pcpu *idst; 107 | 108 | if (!dst_cache->cache) 109 | return; 110 | 111 | idst = this_cpu_ptr(dst_cache->cache); 112 | dst_cache_per_cpu_dst_set(idst, dst, 0); 113 | idst->in_saddr.s_addr = saddr; 114 | } 115 | 116 | #if IS_ENABLED(CONFIG_IPV6) 117 | void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, 118 | const struct in6_addr *addr) 119 | { 120 | struct dst_cache_pcpu *idst; 121 | 122 | if (!dst_cache->cache) 123 | return; 124 | 125 | idst = this_cpu_ptr(dst_cache->cache); 126 | dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst, 127 | rt6_get_cookie((struct rt6_info *)dst)); 128 | idst->in6_saddr = *addr; 129 | } 130 | 131 | struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, 132 | struct in6_addr *saddr) 133 | { 134 | struct dst_cache_pcpu *idst; 135 | struct dst_entry *dst; 136 | 137 | if (!dst_cache->cache) 138 | return NULL; 139 | 140 | idst = this_cpu_ptr(dst_cache->cache); 141 | dst = dst_cache_per_cpu_get(dst_cache, idst); 142 | if (!dst) 143 | return NULL; 144 | 145 | *saddr = idst->in6_saddr; 146 | return dst; 147 | } 148 | #endif 149 | 150 | int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp) 151 | { 152 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) 153 | BUG_ON(gfp & GFP_ATOMIC); 154 | dst_cache->cache = alloc_percpu(struct dst_cache_pcpu); 155 | #else 156 | dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu, 157 | gfp | __GFP_ZERO); 158 | #endif 159 | if (!dst_cache->cache) 160 | return -ENOMEM; 161 | 162 | dst_cache_reset(dst_cache); 163 | return 0; 164 | } 165 | 166 | void dst_cache_destroy(struct dst_cache *dst_cache) 167 | { 168 | int i; 169 | 170 | if (!dst_cache->cache) 171 | return; 172 | 173 | for_each_possible_cpu(i) 174 | dst_release(per_cpu_ptr(dst_cache->cache, i)->dst); 175 | 176 | free_percpu(dst_cache->cache); 177 | } 178 | -------------------------------------------------------------------------------- /src/compat/dst_cache/include/net/dst_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef _WG_NET_DST_CACHE_H 2 | #define _WG_NET_DST_CACHE_H 3 | 4 | #include 5 | #include 6 | #if IS_ENABLED(CONFIG_IPV6) 7 | #include 8 | #endif 9 | 10 | struct dst_cache { 11 | struct dst_cache_pcpu __percpu *cache; 12 | unsigned long reset_ts; 13 | }; 14 | 15 | /** 16 | * dst_cache_get - perform cache lookup 17 | * @dst_cache: the cache 18 | * 19 | * The caller should use dst_cache_get_ip4() if it need to retrieve the 20 | * source address to be used when xmitting to the cached dst. 21 | * local BH must be disabled. 22 | */ 23 | struct dst_entry *dst_cache_get(struct dst_cache *dst_cache); 24 | 25 | /** 26 | * dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address 27 | * @dst_cache: the cache 28 | * @saddr: return value for the retrieved source address 29 | * 30 | * local BH must be disabled. 31 | */ 32 | struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr); 33 | 34 | /** 35 | * dst_cache_set_ip4 - store the ipv4 dst into the cache 36 | * @dst_cache: the cache 37 | * @dst: the entry to be cached 38 | * @saddr: the source address to be stored inside the cache 39 | * 40 | * local BH must be disabled. 41 | */ 42 | void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, 43 | __be32 saddr); 44 | 45 | #if IS_ENABLED(CONFIG_IPV6) 46 | 47 | /** 48 | * dst_cache_set_ip6 - store the ipv6 dst into the cache 49 | * @dst_cache: the cache 50 | * @dst: the entry to be cached 51 | * @saddr: the source address to be stored inside the cache 52 | * 53 | * local BH must be disabled. 54 | */ 55 | void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, 56 | const struct in6_addr *addr); 57 | 58 | /** 59 | * dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address 60 | * @dst_cache: the cache 61 | * @saddr: return value for the retrieved source address 62 | * 63 | * local BH must be disabled. 64 | */ 65 | struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, 66 | struct in6_addr *saddr); 67 | #endif 68 | 69 | /** 70 | * dst_cache_reset - invalidate the cache contents 71 | * @dst_cache: the cache 72 | * 73 | * This do not free the cached dst to avoid races and contentions. 74 | * the dst will be freed on later cache lookup. 75 | */ 76 | static inline void dst_cache_reset(struct dst_cache *dst_cache) 77 | { 78 | dst_cache->reset_ts = jiffies; 79 | } 80 | 81 | /** 82 | * dst_cache_init - initialize the cache, allocating the required storage 83 | * @dst_cache: the cache 84 | * @gfp: allocation flags 85 | */ 86 | int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp); 87 | 88 | /** 89 | * dst_cache_destroy - empty the cache and free the allocated storage 90 | * @dst_cache: the cache 91 | * 92 | * No synchronization is enforced: it must be called only when the cache 93 | * is unused. 94 | */ 95 | void dst_cache_destroy(struct dst_cache *dst_cache); 96 | 97 | #endif /* _WG_NET_DST_CACHE_H */ 98 | -------------------------------------------------------------------------------- /src/compat/dstmetadata/include/net/dst_metadata.h: -------------------------------------------------------------------------------- 1 | #ifndef skb_valid_dst 2 | #define skb_valid_dst(skb) (!!skb_dst(skb)) 3 | #endif 4 | -------------------------------------------------------------------------------- /src/compat/fpu-x86/include/asm/fpu/api.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/compat/intel-family-x86/include/asm/intel-family.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _ASM_X86_INTEL_FAMILY_H 3 | #define _ASM_X86_INTEL_FAMILY_H 4 | 5 | /* 6 | * "Big Core" Processors (Branded as Core, Xeon, etc...) 7 | * 8 | * The "_X" parts are generally the EP and EX Xeons, or the 9 | * "Extreme" ones, like Broadwell-E. 10 | * 11 | * Things ending in "2" are usually because we have no better 12 | * name for them. There's no processor called "SILVERMONT2". 13 | */ 14 | 15 | #define INTEL_FAM6_CORE_YONAH 0x0E 16 | 17 | #define INTEL_FAM6_CORE2_MEROM 0x0F 18 | #define INTEL_FAM6_CORE2_MEROM_L 0x16 19 | #define INTEL_FAM6_CORE2_PENRYN 0x17 20 | #define INTEL_FAM6_CORE2_DUNNINGTON 0x1D 21 | 22 | #define INTEL_FAM6_NEHALEM 0x1E 23 | #define INTEL_FAM6_NEHALEM_G 0x1F /* Auburndale / Havendale */ 24 | #define INTEL_FAM6_NEHALEM_EP 0x1A 25 | #define INTEL_FAM6_NEHALEM_EX 0x2E 26 | 27 | #define INTEL_FAM6_WESTMERE 0x25 28 | #define INTEL_FAM6_WESTMERE_EP 0x2C 29 | #define INTEL_FAM6_WESTMERE_EX 0x2F 30 | 31 | #define INTEL_FAM6_SANDYBRIDGE 0x2A 32 | #define INTEL_FAM6_SANDYBRIDGE_X 0x2D 33 | #define INTEL_FAM6_IVYBRIDGE 0x3A 34 | #define INTEL_FAM6_IVYBRIDGE_X 0x3E 35 | 36 | #define INTEL_FAM6_HASWELL_CORE 0x3C 37 | #define INTEL_FAM6_HASWELL_X 0x3F 38 | #define INTEL_FAM6_HASWELL_ULT 0x45 39 | #define INTEL_FAM6_HASWELL_GT3E 0x46 40 | 41 | #define INTEL_FAM6_BROADWELL_CORE 0x3D 42 | #define INTEL_FAM6_BROADWELL_GT3E 0x47 43 | #define INTEL_FAM6_BROADWELL_X 0x4F 44 | #define INTEL_FAM6_BROADWELL_XEON_D 0x56 45 | 46 | #define INTEL_FAM6_SKYLAKE_MOBILE 0x4E 47 | #define INTEL_FAM6_SKYLAKE_DESKTOP 0x5E 48 | #define INTEL_FAM6_SKYLAKE_X 0x55 49 | #define INTEL_FAM6_KABYLAKE_MOBILE 0x8E 50 | #define INTEL_FAM6_KABYLAKE_DESKTOP 0x9E 51 | 52 | /* "Small Core" Processors (Atom) */ 53 | 54 | #define INTEL_FAM6_ATOM_PINEVIEW 0x1C 55 | #define INTEL_FAM6_ATOM_LINCROFT 0x26 56 | #define INTEL_FAM6_ATOM_PENWELL 0x27 57 | #define INTEL_FAM6_ATOM_CLOVERVIEW 0x35 58 | #define INTEL_FAM6_ATOM_CEDARVIEW 0x36 59 | #define INTEL_FAM6_ATOM_SILVERMONT1 0x37 /* BayTrail/BYT / Valleyview */ 60 | #define INTEL_FAM6_ATOM_SILVERMONT2 0x4D /* Avaton/Rangely */ 61 | #define INTEL_FAM6_ATOM_AIRMONT 0x4C /* CherryTrail / Braswell */ 62 | #define INTEL_FAM6_ATOM_MERRIFIELD 0x4A /* Tangier */ 63 | #define INTEL_FAM6_ATOM_MOOREFIELD 0x5A /* Anniedale */ 64 | #define INTEL_FAM6_ATOM_GOLDMONT 0x5C 65 | #define INTEL_FAM6_ATOM_DENVERTON 0x5F /* Goldmont Microserver */ 66 | #define INTEL_FAM6_ATOM_GEMINI_LAKE 0x7A 67 | 68 | /* Xeon Phi */ 69 | 70 | #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ 71 | #define INTEL_FAM6_XEON_PHI_KNM 0x85 /* Knights Mill */ 72 | 73 | #endif /* _ASM_X86_INTEL_FAMILY_H */ 74 | -------------------------------------------------------------------------------- /src/compat/memneq/include.h: -------------------------------------------------------------------------------- 1 | extern noinline unsigned long __crypto_memneq(const void *a, const void *b, size_t size); 2 | static inline int crypto_memneq(const void *a, const void *b, size_t size) 3 | { 4 | return __crypto_memneq(a, b, size) != 0UL ? 1 : 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/compat/memneq/memneq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Constant-time equality testing of memory regions. 3 | * 4 | * Authors: 5 | * 6 | * James Yonan 7 | * Daniel Borkmann 8 | * 9 | * This file is provided under a dual BSD/GPLv2 license. When using or 10 | * redistributing this file, you may do so under either license. 11 | * 12 | * GPL LICENSE SUMMARY 13 | * 14 | * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved. 15 | * 16 | * This program is free software; you can redistribute it and/or modify 17 | * it under the terms of version 2 of the GNU General Public License as 18 | * published by the Free Software Foundation. 19 | * 20 | * This program is distributed in the hope that it will be useful, but 21 | * WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 | * General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with this program; if not, write to the Free Software 27 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 28 | * The full GNU General Public License is included in this distribution 29 | * in the file called LICENSE.GPL. 30 | * 31 | * BSD LICENSE 32 | * 33 | * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved. 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 39 | * * Redistributions of source code must retain the above copyright 40 | * notice, this list of conditions and the following disclaimer. 41 | * * Redistributions in binary form must reproduce the above copyright 42 | * notice, this list of conditions and the following disclaimer in 43 | * the documentation and/or other materials provided with the 44 | * distribution. 45 | * * Neither the name of OpenVPN Technologies nor the names of its 46 | * contributors may be used to endorse or promote products derived 47 | * from this software without specific prior written permission. 48 | * 49 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 52 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 53 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 54 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 55 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 59 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 | */ 61 | 62 | #include 63 | 64 | /* Make the optimizer believe the variable can be manipulated arbitrarily. */ 65 | #define COMPILER_OPTIMIZER_HIDE_VAR(var) asm("" : "=r" (var) : "0" (var)) 66 | 67 | #ifndef __HAVE_ARCH_CRYPTO_MEMNEQ 68 | 69 | /* Generic path for arbitrary size */ 70 | static inline unsigned long 71 | __crypto_memneq_generic(const void *a, const void *b, size_t size) 72 | { 73 | unsigned long neq = 0; 74 | 75 | #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 76 | while (size >= sizeof(unsigned long)) { 77 | neq |= *(unsigned long *)a ^ *(unsigned long *)b; 78 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 79 | a += sizeof(unsigned long); 80 | b += sizeof(unsigned long); 81 | size -= sizeof(unsigned long); 82 | } 83 | #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ 84 | while (size > 0) { 85 | neq |= *(unsigned char *)a ^ *(unsigned char *)b; 86 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 87 | a += 1; 88 | b += 1; 89 | size -= 1; 90 | } 91 | return neq; 92 | } 93 | 94 | /* Loop-free fast-path for frequently used 16-byte size */ 95 | static inline unsigned long __crypto_memneq_16(const void *a, const void *b) 96 | { 97 | unsigned long neq = 0; 98 | 99 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 100 | if (sizeof(unsigned long) == 8) { 101 | neq |= *(unsigned long *)(a) ^ *(unsigned long *)(b); 102 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 103 | neq |= *(unsigned long *)(a+8) ^ *(unsigned long *)(b+8); 104 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 105 | } else if (sizeof(unsigned int) == 4) { 106 | neq |= *(unsigned int *)(a) ^ *(unsigned int *)(b); 107 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 108 | neq |= *(unsigned int *)(a+4) ^ *(unsigned int *)(b+4); 109 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 110 | neq |= *(unsigned int *)(a+8) ^ *(unsigned int *)(b+8); 111 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 112 | neq |= *(unsigned int *)(a+12) ^ *(unsigned int *)(b+12); 113 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 114 | } else 115 | #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ 116 | { 117 | neq |= *(unsigned char *)(a) ^ *(unsigned char *)(b); 118 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 119 | neq |= *(unsigned char *)(a+1) ^ *(unsigned char *)(b+1); 120 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 121 | neq |= *(unsigned char *)(a+2) ^ *(unsigned char *)(b+2); 122 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 123 | neq |= *(unsigned char *)(a+3) ^ *(unsigned char *)(b+3); 124 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 125 | neq |= *(unsigned char *)(a+4) ^ *(unsigned char *)(b+4); 126 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 127 | neq |= *(unsigned char *)(a+5) ^ *(unsigned char *)(b+5); 128 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 129 | neq |= *(unsigned char *)(a+6) ^ *(unsigned char *)(b+6); 130 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 131 | neq |= *(unsigned char *)(a+7) ^ *(unsigned char *)(b+7); 132 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 133 | neq |= *(unsigned char *)(a+8) ^ *(unsigned char *)(b+8); 134 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 135 | neq |= *(unsigned char *)(a+9) ^ *(unsigned char *)(b+9); 136 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 137 | neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10); 138 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 139 | neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11); 140 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 141 | neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12); 142 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 143 | neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13); 144 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 145 | neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14); 146 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 147 | neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15); 148 | COMPILER_OPTIMIZER_HIDE_VAR(neq); 149 | } 150 | 151 | return neq; 152 | } 153 | 154 | /* Compare two areas of memory without leaking timing information, 155 | * and with special optimizations for common sizes. Users should 156 | * not call this function directly, but should instead use 157 | * crypto_memneq defined in crypto/algapi.h. 158 | */ 159 | noinline unsigned long __crypto_memneq(const void *a, const void *b, 160 | size_t size) 161 | { 162 | switch (size) { 163 | case 16: 164 | return __crypto_memneq_16(a, b); 165 | default: 166 | return __crypto_memneq_generic(a, b, size); 167 | } 168 | } 169 | 170 | #endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */ 171 | -------------------------------------------------------------------------------- /src/compat/neon-arm/include/asm/neon.h: -------------------------------------------------------------------------------- 1 | #ifndef _ARCH_ARM_ASM_NEON 2 | #define _ARCH_ARM_ASM_NEON 3 | #define kernel_neon_begin() \ 4 | BUILD_BUG_ON_MSG(1, "This kernel does not support ARM NEON") 5 | #define kernel_neon_end() \ 6 | BUILD_BUG_ON_MSG(1, "This kernel does not support ARM NEON") 7 | #endif 8 | -------------------------------------------------------------------------------- /src/compat/simd-asm/include/asm/simd.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMPAT_ASM_SIMD_H 2 | #define _COMPAT_ASM_SIMD_H 3 | 4 | #if defined(CONFIG_X86_64) 5 | #include 6 | #endif 7 | 8 | static __must_check inline bool may_use_simd(void) 9 | { 10 | #if defined(CONFIG_X86_64) 11 | return irq_fpu_usable(); 12 | #elif defined(CONFIG_ARM64) && defined(CONFIG_KERNEL_MODE_NEON) 13 | return true; 14 | #elif defined(CONFIG_ARM) && defined(CONFIG_KERNEL_MODE_NEON) 15 | return !in_nmi() && !in_irq() && !in_serving_softirq(); 16 | #else 17 | return false; 18 | #endif 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/compat/simd/include/linux/simd.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_SIMD_H 7 | #define _WG_SIMD_H 8 | 9 | #include 10 | #include 11 | #if defined(CONFIG_X86_64) 12 | #include 13 | #elif defined(CONFIG_KERNEL_MODE_NEON) 14 | #include 15 | #endif 16 | 17 | typedef enum { 18 | HAVE_NO_SIMD = 1 << 0, 19 | HAVE_FULL_SIMD = 1 << 1, 20 | HAVE_SIMD_IN_USE = 1 << 31 21 | } simd_context_t; 22 | 23 | #define DONT_USE_SIMD ((simd_context_t []){ HAVE_NO_SIMD }) 24 | 25 | static inline void simd_get(simd_context_t *ctx) 26 | { 27 | *ctx = !IS_ENABLED(CONFIG_PREEMPT_RT) && !IS_ENABLED(CONFIG_PREEMPT_RT_BASE) && may_use_simd() ? HAVE_FULL_SIMD : HAVE_NO_SIMD; 28 | } 29 | 30 | static inline void simd_put(simd_context_t *ctx) 31 | { 32 | #if defined(CONFIG_X86_64) 33 | if (*ctx & HAVE_SIMD_IN_USE) 34 | kernel_fpu_end(); 35 | #elif defined(CONFIG_KERNEL_MODE_NEON) 36 | if (*ctx & HAVE_SIMD_IN_USE) 37 | kernel_neon_end(); 38 | #endif 39 | *ctx = HAVE_NO_SIMD; 40 | } 41 | 42 | static inline bool simd_relax(simd_context_t *ctx) 43 | { 44 | #ifdef CONFIG_PREEMPT 45 | if ((*ctx & HAVE_SIMD_IN_USE) && need_resched()) { 46 | simd_put(ctx); 47 | simd_get(ctx); 48 | return true; 49 | } 50 | #endif 51 | return false; 52 | } 53 | 54 | static __must_check inline bool simd_use(simd_context_t *ctx) 55 | { 56 | if (!(*ctx & HAVE_FULL_SIMD)) 57 | return false; 58 | if (*ctx & HAVE_SIMD_IN_USE) 59 | return true; 60 | #if defined(CONFIG_X86_64) 61 | kernel_fpu_begin(); 62 | #elif defined(CONFIG_KERNEL_MODE_NEON) 63 | kernel_neon_begin(); 64 | #endif 65 | *ctx |= HAVE_SIMD_IN_USE; 66 | return true; 67 | } 68 | 69 | #endif /* _WG_SIMD_H */ 70 | -------------------------------------------------------------------------------- /src/compat/siphash/include/linux/siphash.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 2 | * 3 | * This file is provided under a dual BSD/GPLv2 license. 4 | * 5 | * SipHash: a fast short-input PRF 6 | * https://131002.net/siphash/ 7 | * 8 | * This implementation is specifically for SipHash2-4 for a secure PRF 9 | * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for 10 | * hashtables. 11 | */ 12 | 13 | #ifndef _WG_LINUX_SIPHASH_H 14 | #define _WG_LINUX_SIPHASH_H 15 | 16 | #include 17 | #include 18 | 19 | #define SIPHASH_ALIGNMENT __alignof__(u64) 20 | typedef struct { 21 | u64 key[2]; 22 | } siphash_key_t; 23 | 24 | u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key); 25 | u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key); 26 | 27 | u64 siphash_1u64(const u64 a, const siphash_key_t *key); 28 | u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key); 29 | u64 siphash_3u64(const u64 a, const u64 b, const u64 c, 30 | const siphash_key_t *key); 31 | u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d, 32 | const siphash_key_t *key); 33 | u64 siphash_1u32(const u32 a, const siphash_key_t *key); 34 | u64 siphash_3u32(const u32 a, const u32 b, const u32 c, 35 | const siphash_key_t *key); 36 | 37 | static inline u64 siphash_2u32(const u32 a, const u32 b, 38 | const siphash_key_t *key) 39 | { 40 | return siphash_1u64((u64)b << 32 | a, key); 41 | } 42 | static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c, 43 | const u32 d, const siphash_key_t *key) 44 | { 45 | return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key); 46 | } 47 | 48 | 49 | static inline u64 ___siphash_aligned(const __le64 *data, size_t len, 50 | const siphash_key_t *key) 51 | { 52 | if (__builtin_constant_p(len) && len == 4) 53 | return siphash_1u32(le32_to_cpup((const __le32 *)data), key); 54 | if (__builtin_constant_p(len) && len == 8) 55 | return siphash_1u64(le64_to_cpu(data[0]), key); 56 | if (__builtin_constant_p(len) && len == 16) 57 | return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), 58 | key); 59 | if (__builtin_constant_p(len) && len == 24) 60 | return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), 61 | le64_to_cpu(data[2]), key); 62 | if (__builtin_constant_p(len) && len == 32) 63 | return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), 64 | le64_to_cpu(data[2]), le64_to_cpu(data[3]), 65 | key); 66 | return __siphash_aligned(data, len, key); 67 | } 68 | 69 | /** 70 | * siphash - compute 64-bit siphash PRF value 71 | * @data: buffer to hash 72 | * @size: size of @data 73 | * @key: the siphash key 74 | */ 75 | static inline u64 siphash(const void *data, size_t len, 76 | const siphash_key_t *key) 77 | { 78 | if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || 79 | !IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT)) 80 | return __siphash_unaligned(data, len, key); 81 | return ___siphash_aligned(data, len, key); 82 | } 83 | 84 | #define HSIPHASH_ALIGNMENT __alignof__(unsigned long) 85 | typedef struct { 86 | unsigned long key[2]; 87 | } hsiphash_key_t; 88 | 89 | u32 __hsiphash_aligned(const void *data, size_t len, 90 | const hsiphash_key_t *key); 91 | u32 __hsiphash_unaligned(const void *data, size_t len, 92 | const hsiphash_key_t *key); 93 | 94 | u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key); 95 | u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key); 96 | u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c, 97 | const hsiphash_key_t *key); 98 | u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d, 99 | const hsiphash_key_t *key); 100 | 101 | static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len, 102 | const hsiphash_key_t *key) 103 | { 104 | if (__builtin_constant_p(len) && len == 4) 105 | return hsiphash_1u32(le32_to_cpu(data[0]), key); 106 | if (__builtin_constant_p(len) && len == 8) 107 | return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), 108 | key); 109 | if (__builtin_constant_p(len) && len == 12) 110 | return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), 111 | le32_to_cpu(data[2]), key); 112 | if (__builtin_constant_p(len) && len == 16) 113 | return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), 114 | le32_to_cpu(data[2]), le32_to_cpu(data[3]), 115 | key); 116 | return __hsiphash_aligned(data, len, key); 117 | } 118 | 119 | /** 120 | * hsiphash - compute 32-bit hsiphash PRF value 121 | * @data: buffer to hash 122 | * @size: size of @data 123 | * @key: the hsiphash key 124 | */ 125 | static inline u32 hsiphash(const void *data, size_t len, 126 | const hsiphash_key_t *key) 127 | { 128 | if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || 129 | !IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT)) 130 | return __hsiphash_unaligned(data, len, key); 131 | return ___hsiphash_aligned(data, len, key); 132 | } 133 | 134 | #endif /* _WG_LINUX_SIPHASH_H */ 135 | -------------------------------------------------------------------------------- /src/compat/skb_array/include/linux/skb_array.h: -------------------------------------------------------------------------------- 1 | #ifndef _WG_SKB_ARRAY_H 2 | #define _WG_SKB_ARRAY_H 3 | 4 | #include 5 | 6 | static void __skb_array_destroy_skb(void *ptr) 7 | { 8 | kfree_skb(ptr); 9 | } 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/compat/udp_tunnel/include/net/udp_tunnel.h: -------------------------------------------------------------------------------- 1 | #ifndef _WG_NET_UDP_TUNNEL_H 2 | #define _WG_NET_UDP_TUNNEL_H 3 | 4 | #include 5 | #include 6 | 7 | #if IS_ENABLED(CONFIG_IPV6) 8 | #include 9 | #include 10 | #endif 11 | 12 | struct udp_port_cfg { 13 | u8 family; 14 | 15 | /* Used only for kernel-created sockets */ 16 | union { 17 | struct in_addr local_ip; 18 | #if IS_ENABLED(CONFIG_IPV6) 19 | struct in6_addr local_ip6; 20 | #endif 21 | }; 22 | 23 | union { 24 | struct in_addr peer_ip; 25 | #if IS_ENABLED(CONFIG_IPV6) 26 | struct in6_addr peer_ip6; 27 | #endif 28 | }; 29 | 30 | __be16 local_udp_port; 31 | __be16 peer_udp_port; 32 | unsigned int use_udp_checksums:1, 33 | use_udp6_tx_checksums:1, 34 | use_udp6_rx_checksums:1, 35 | ipv6_v6only:1; 36 | }; 37 | 38 | int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, 39 | struct socket **sockp); 40 | 41 | #if IS_ENABLED(CONFIG_IPV6) 42 | int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, 43 | struct socket **sockp); 44 | #else 45 | static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, 46 | struct socket **sockp) 47 | { 48 | return 0; 49 | } 50 | #endif 51 | 52 | static inline int udp_sock_create(struct net *net, 53 | struct udp_port_cfg *cfg, 54 | struct socket **sockp) 55 | { 56 | if (cfg->family == AF_INET) 57 | return udp_sock_create4(net, cfg, sockp); 58 | 59 | if (cfg->family == AF_INET6) 60 | return udp_sock_create6(net, cfg, sockp); 61 | 62 | return -EPFNOSUPPORT; 63 | } 64 | 65 | typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb); 66 | 67 | struct udp_tunnel_sock_cfg { 68 | void *sk_user_data; 69 | __u8 encap_type; 70 | udp_tunnel_encap_rcv_t encap_rcv; 71 | }; 72 | 73 | /* Setup the given (UDP) sock to receive UDP encapsulated packets */ 74 | void setup_udp_tunnel_sock(struct net *net, struct socket *sock, 75 | struct udp_tunnel_sock_cfg *sock_cfg); 76 | 77 | /* Transmit the skb using UDP encapsulation. */ 78 | void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, 79 | __be32 src, __be32 dst, __u8 tos, __u8 ttl, 80 | __be16 df, __be16 src_port, __be16 dst_port, 81 | bool xnet, bool nocheck); 82 | 83 | #if IS_ENABLED(CONFIG_IPV6) 84 | int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, 85 | struct sk_buff *skb, 86 | struct net_device *dev, struct in6_addr *saddr, 87 | struct in6_addr *daddr, 88 | __u8 prio, __u8 ttl, __be32 label, 89 | __be16 src_port, __be16 dst_port, bool nocheck); 90 | #endif 91 | 92 | void udp_tunnel_sock_release(struct socket *sock); 93 | 94 | #endif /* _WG_NET_UDP_TUNNEL_H */ 95 | -------------------------------------------------------------------------------- /src/compat/version/linux/version.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2021 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include_next 7 | #undef KERNEL_VERSION 8 | #define KERNEL_VERSION(a, b, c) (((a) << 24) + ((b) << 16) + (c)) 9 | #undef LINUX_VERSION_CODE 10 | #define LINUX_VERSION_CODE KERNEL_VERSION(COMPAT_VERSION, COMPAT_PATCHLEVEL, COMPAT_SUBLEVEL) 11 | -------------------------------------------------------------------------------- /src/cookie.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_COOKIE_H 7 | #define _WG_COOKIE_H 8 | 9 | #include "messages.h" 10 | #include 11 | 12 | struct wg_peer; 13 | 14 | struct cookie_checker { 15 | u8 secret[NOISE_HASH_LEN]; 16 | u8 cookie_encryption_key[NOISE_SYMMETRIC_KEY_LEN]; 17 | u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN]; 18 | u64 secret_birthdate; 19 | struct rw_semaphore secret_lock; 20 | struct wg_device *device; 21 | }; 22 | 23 | struct cookie { 24 | u64 birthdate; 25 | bool is_valid; 26 | u8 cookie[COOKIE_LEN]; 27 | bool have_sent_mac1; 28 | u8 last_mac1_sent[COOKIE_LEN]; 29 | u8 cookie_decryption_key[NOISE_SYMMETRIC_KEY_LEN]; 30 | u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN]; 31 | struct rw_semaphore lock; 32 | }; 33 | 34 | enum cookie_mac_state { 35 | INVALID_MAC, 36 | VALID_MAC_BUT_NO_COOKIE, 37 | VALID_MAC_WITH_COOKIE_BUT_RATELIMITED, 38 | VALID_MAC_WITH_COOKIE 39 | }; 40 | 41 | void wg_cookie_checker_init(struct cookie_checker *checker, 42 | struct wg_device *wg); 43 | void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker); 44 | void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer); 45 | void wg_cookie_init(struct cookie *cookie); 46 | 47 | enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker, 48 | struct sk_buff *skb, 49 | bool check_cookie); 50 | void wg_cookie_add_mac_to_packet(void *message, size_t len, 51 | struct wg_peer *peer); 52 | 53 | void wg_cookie_message_create(struct message_handshake_cookie *src, 54 | struct sk_buff *skb, __le32 index, 55 | struct cookie_checker *checker, u32 message_type); 56 | void wg_cookie_message_consume(struct message_handshake_cookie *src, 57 | struct wg_device *wg); 58 | 59 | #endif /* _WG_COOKIE_H */ 60 | -------------------------------------------------------------------------------- /src/crypto/Kbuild.include: -------------------------------------------------------------------------------- 1 | ifeq ($(CONFIG_X86_64)$(if $(CONFIG_UML),y,n),yn) 2 | CONFIG_ZINC_ARCH_X86_64 := y 3 | endif 4 | ifeq ($(CONFIG_ARM)$(if $(CONFIG_CPU_32v3),y,n),yn) 5 | CONFIG_ZINC_ARCH_ARM := y 6 | endif 7 | ifeq ($(CONFIG_ARM64),y) 8 | CONFIG_ZINC_ARCH_ARM64 := y 9 | endif 10 | ifeq ($(CONFIG_MIPS)$(CONFIG_CPU_MIPS32_R2),yy) 11 | CONFIG_ZINC_ARCH_MIPS := y 12 | endif 13 | ifeq ($(CONFIG_MIPS)$(CONFIG_64BIT),yy) 14 | CONFIG_ZINC_ARCH_MIPS64 := y 15 | endif 16 | 17 | zinc-y += chacha20/chacha20.o 18 | zinc-$(CONFIG_ZINC_ARCH_X86_64) += chacha20/chacha20-x86_64.o 19 | zinc-$(CONFIG_ZINC_ARCH_ARM) += chacha20/chacha20-arm.o chacha20/chacha20-unrolled-arm.o 20 | zinc-$(CONFIG_ZINC_ARCH_ARM64) += chacha20/chacha20-arm64.o 21 | zinc-$(CONFIG_ZINC_ARCH_MIPS) += chacha20/chacha20-mips.o 22 | AFLAGS_chacha20-mips.o += -O2 # This is required to fill the branch delay slots 23 | 24 | zinc-y += poly1305/poly1305.o 25 | zinc-$(CONFIG_ZINC_ARCH_X86_64) += poly1305/poly1305-x86_64.o 26 | zinc-$(CONFIG_ZINC_ARCH_ARM) += poly1305/poly1305-arm.o 27 | zinc-$(CONFIG_ZINC_ARCH_ARM64) += poly1305/poly1305-arm64.o 28 | zinc-$(CONFIG_ZINC_ARCH_MIPS) += poly1305/poly1305-mips.o 29 | AFLAGS_poly1305-mips.o += -O2 # This is required to fill the branch delay slots 30 | zinc-$(CONFIG_ZINC_ARCH_MIPS64) += poly1305/poly1305-mips64.o 31 | 32 | zinc-y += chacha20poly1305.o 33 | 34 | zinc-y += blake2s/blake2s.o 35 | zinc-$(CONFIG_ZINC_ARCH_X86_64) += blake2s/blake2s-x86_64.o 36 | 37 | zinc-y += curve25519/curve25519.o 38 | zinc-$(CONFIG_ZINC_ARCH_ARM) += curve25519/curve25519-arm.o 39 | 40 | quiet_cmd_perlasm = PERLASM $@ 41 | cmd_perlasm = $(PERL) $< > $@ 42 | $(obj)/%.S: $(src)/%.pl FORCE 43 | $(call if_changed,perlasm) 44 | kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) 45 | targets := $(patsubst $(kbuild-dir)/%.pl,%.S,$(wildcard $(patsubst %.o,$(kbuild-dir)/crypto/zinc/%.pl,$(zinc-y) $(zinc-m) $(zinc-)))) 46 | 47 | # Old kernels don't set this, which causes trouble. 48 | .SECONDARY: 49 | 50 | amneziawg-y += $(addprefix crypto/zinc/,$(zinc-y)) 51 | ccflags-y += -I$(kbuild-dir)/crypto/include 52 | ccflags-$(CONFIG_ZINC_ARCH_X86_64) += -DCONFIG_ZINC_ARCH_X86_64 53 | ccflags-$(CONFIG_ZINC_ARCH_ARM) += -DCONFIG_ZINC_ARCH_ARM 54 | ccflags-$(CONFIG_ZINC_ARCH_ARM64) += -DCONFIG_ZINC_ARCH_ARM64 55 | ccflags-$(CONFIG_ZINC_ARCH_MIPS) += -DCONFIG_ZINC_ARCH_MIPS 56 | ccflags-$(CONFIG_ZINC_ARCH_MIPS64) += -DCONFIG_ZINC_ARCH_MIPS64 57 | ccflags-$(CONFIG_WIREGUARD_DEBUG) += -DCONFIG_ZINC_SELFTEST 58 | -------------------------------------------------------------------------------- /src/crypto/include/zinc/blake2s.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _ZINC_BLAKE2S_H 7 | #define _ZINC_BLAKE2S_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | enum blake2s_lengths { 14 | BLAKE2S_BLOCK_SIZE = 64, 15 | BLAKE2S_HASH_SIZE = 32, 16 | BLAKE2S_KEY_SIZE = 32 17 | }; 18 | 19 | struct blake2s_state { 20 | u32 h[8]; 21 | u32 t[2]; 22 | u32 f[2]; 23 | u8 buf[BLAKE2S_BLOCK_SIZE]; 24 | unsigned int buflen; 25 | unsigned int outlen; 26 | }; 27 | 28 | void blake2s_init(struct blake2s_state *state, const size_t outlen); 29 | void blake2s_init_key(struct blake2s_state *state, const size_t outlen, 30 | const void *key, const size_t keylen); 31 | void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen); 32 | void blake2s_final(struct blake2s_state *state, u8 *out); 33 | 34 | static inline void blake2s(u8 *out, const u8 *in, const u8 *key, 35 | const size_t outlen, const size_t inlen, 36 | const size_t keylen) 37 | { 38 | struct blake2s_state state; 39 | 40 | WARN_ON(IS_ENABLED(DEBUG) && ((!in && inlen > 0) || !out || !outlen || 41 | outlen > BLAKE2S_HASH_SIZE || keylen > BLAKE2S_KEY_SIZE || 42 | (!key && keylen))); 43 | 44 | if (keylen) 45 | blake2s_init_key(&state, outlen, key, keylen); 46 | else 47 | blake2s_init(&state, outlen); 48 | 49 | blake2s_update(&state, in, inlen); 50 | blake2s_final(&state, out); 51 | } 52 | 53 | void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const size_t outlen, 54 | const size_t inlen, const size_t keylen); 55 | 56 | #endif /* _ZINC_BLAKE2S_H */ 57 | -------------------------------------------------------------------------------- /src/crypto/include/zinc/chacha20.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _ZINC_CHACHA20_H 7 | #define _ZINC_CHACHA20_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | enum chacha20_lengths { 15 | CHACHA20_NONCE_SIZE = 16, 16 | CHACHA20_KEY_SIZE = 32, 17 | CHACHA20_KEY_WORDS = CHACHA20_KEY_SIZE / sizeof(u32), 18 | CHACHA20_BLOCK_SIZE = 64, 19 | CHACHA20_BLOCK_WORDS = CHACHA20_BLOCK_SIZE / sizeof(u32), 20 | HCHACHA20_NONCE_SIZE = CHACHA20_NONCE_SIZE, 21 | HCHACHA20_KEY_SIZE = CHACHA20_KEY_SIZE 22 | }; 23 | 24 | enum chacha20_constants { /* expand 32-byte k */ 25 | CHACHA20_CONSTANT_EXPA = 0x61707865U, 26 | CHACHA20_CONSTANT_ND_3 = 0x3320646eU, 27 | CHACHA20_CONSTANT_2_BY = 0x79622d32U, 28 | CHACHA20_CONSTANT_TE_K = 0x6b206574U 29 | }; 30 | 31 | struct chacha20_ctx { 32 | union { 33 | u32 state[16]; 34 | struct { 35 | u32 constant[4]; 36 | u32 key[8]; 37 | u32 counter[4]; 38 | }; 39 | }; 40 | }; 41 | 42 | static inline void chacha20_init(struct chacha20_ctx *ctx, 43 | const u8 key[CHACHA20_KEY_SIZE], 44 | const u64 nonce) 45 | { 46 | ctx->constant[0] = CHACHA20_CONSTANT_EXPA; 47 | ctx->constant[1] = CHACHA20_CONSTANT_ND_3; 48 | ctx->constant[2] = CHACHA20_CONSTANT_2_BY; 49 | ctx->constant[3] = CHACHA20_CONSTANT_TE_K; 50 | ctx->key[0] = get_unaligned_le32(key + 0); 51 | ctx->key[1] = get_unaligned_le32(key + 4); 52 | ctx->key[2] = get_unaligned_le32(key + 8); 53 | ctx->key[3] = get_unaligned_le32(key + 12); 54 | ctx->key[4] = get_unaligned_le32(key + 16); 55 | ctx->key[5] = get_unaligned_le32(key + 20); 56 | ctx->key[6] = get_unaligned_le32(key + 24); 57 | ctx->key[7] = get_unaligned_le32(key + 28); 58 | ctx->counter[0] = 0; 59 | ctx->counter[1] = 0; 60 | ctx->counter[2] = nonce & U32_MAX; 61 | ctx->counter[3] = nonce >> 32; 62 | } 63 | void chacha20(struct chacha20_ctx *ctx, u8 *dst, const u8 *src, u32 len, 64 | simd_context_t *simd_context); 65 | 66 | void hchacha20(u32 derived_key[CHACHA20_KEY_WORDS], 67 | const u8 nonce[HCHACHA20_NONCE_SIZE], 68 | const u8 key[HCHACHA20_KEY_SIZE], simd_context_t *simd_context); 69 | 70 | #endif /* _ZINC_CHACHA20_H */ 71 | -------------------------------------------------------------------------------- /src/crypto/include/zinc/chacha20poly1305.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _ZINC_CHACHA20POLY1305_H 7 | #define _ZINC_CHACHA20POLY1305_H 8 | 9 | #include 10 | #include 11 | 12 | struct scatterlist; 13 | 14 | enum chacha20poly1305_lengths { 15 | XCHACHA20POLY1305_NONCE_SIZE = 24, 16 | CHACHA20POLY1305_KEY_SIZE = 32, 17 | CHACHA20POLY1305_AUTHTAG_SIZE = 16 18 | }; 19 | 20 | void chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 21 | const u8 *ad, const size_t ad_len, 22 | const u64 nonce, 23 | const u8 key[CHACHA20POLY1305_KEY_SIZE]); 24 | 25 | bool __must_check chacha20poly1305_encrypt_sg_inplace( 26 | struct scatterlist *src, const size_t src_len, const u8 *ad, 27 | const size_t ad_len, const u64 nonce, 28 | const u8 key[CHACHA20POLY1305_KEY_SIZE], simd_context_t *simd_context); 29 | 30 | bool __must_check 31 | chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, 32 | const u8 *ad, const size_t ad_len, const u64 nonce, 33 | const u8 key[CHACHA20POLY1305_KEY_SIZE]); 34 | 35 | bool __must_check chacha20poly1305_decrypt_sg_inplace( 36 | struct scatterlist *src, size_t src_len, const u8 *ad, 37 | const size_t ad_len, const u64 nonce, 38 | const u8 key[CHACHA20POLY1305_KEY_SIZE], simd_context_t *simd_context); 39 | 40 | void xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, 41 | const u8 *ad, const size_t ad_len, 42 | const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], 43 | const u8 key[CHACHA20POLY1305_KEY_SIZE]); 44 | 45 | bool __must_check xchacha20poly1305_decrypt( 46 | u8 *dst, const u8 *src, const size_t src_len, const u8 *ad, 47 | const size_t ad_len, const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], 48 | const u8 key[CHACHA20POLY1305_KEY_SIZE]); 49 | 50 | #endif /* _ZINC_CHACHA20POLY1305_H */ 51 | -------------------------------------------------------------------------------- /src/crypto/include/zinc/curve25519.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _ZINC_CURVE25519_H 7 | #define _ZINC_CURVE25519_H 8 | 9 | #include 10 | 11 | enum curve25519_lengths { 12 | CURVE25519_KEY_SIZE = 32 13 | }; 14 | 15 | bool __must_check curve25519(u8 mypublic[CURVE25519_KEY_SIZE], 16 | const u8 secret[CURVE25519_KEY_SIZE], 17 | const u8 basepoint[CURVE25519_KEY_SIZE]); 18 | void curve25519_generate_secret(u8 secret[CURVE25519_KEY_SIZE]); 19 | bool __must_check curve25519_generate_public( 20 | u8 pub[CURVE25519_KEY_SIZE], const u8 secret[CURVE25519_KEY_SIZE]); 21 | 22 | static inline void curve25519_clamp_secret(u8 secret[CURVE25519_KEY_SIZE]) 23 | { 24 | secret[0] &= 248; 25 | secret[31] = (secret[31] & 127) | 64; 26 | } 27 | 28 | #endif /* _ZINC_CURVE25519_H */ 29 | -------------------------------------------------------------------------------- /src/crypto/include/zinc/poly1305.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _ZINC_POLY1305_H 7 | #define _ZINC_POLY1305_H 8 | 9 | #include 10 | #include 11 | 12 | enum poly1305_lengths { 13 | POLY1305_BLOCK_SIZE = 16, 14 | POLY1305_KEY_SIZE = 32, 15 | POLY1305_MAC_SIZE = 16 16 | }; 17 | 18 | struct poly1305_ctx { 19 | u8 opaque[24 * sizeof(u64)]; 20 | u32 nonce[4]; 21 | u8 data[POLY1305_BLOCK_SIZE]; 22 | size_t num; 23 | } __aligned(8); 24 | 25 | void poly1305_init(struct poly1305_ctx *ctx, const u8 key[POLY1305_KEY_SIZE]); 26 | void poly1305_update(struct poly1305_ctx *ctx, const u8 *input, size_t len, 27 | simd_context_t *simd_context); 28 | void poly1305_final(struct poly1305_ctx *ctx, u8 mac[POLY1305_MAC_SIZE], 29 | simd_context_t *simd_context); 30 | 31 | #endif /* _ZINC_POLY1305_H */ 32 | -------------------------------------------------------------------------------- /src/crypto/zinc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_ZINC_H 7 | #define _WG_ZINC_H 8 | 9 | int chacha20_mod_init(void); 10 | int poly1305_mod_init(void); 11 | int chacha20poly1305_mod_init(void); 12 | int blake2s_mod_init(void); 13 | int curve25519_mod_init(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/crypto/zinc/blake2s/blake2s-x86_64-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | asmlinkage void blake2s_compress_ssse3(struct blake2s_state *state, 12 | const u8 *block, const size_t nblocks, 13 | const u32 inc); 14 | asmlinkage void blake2s_compress_avx512(struct blake2s_state *state, 15 | const u8 *block, const size_t nblocks, 16 | const u32 inc); 17 | 18 | static bool blake2s_use_ssse3 __ro_after_init; 19 | static bool blake2s_use_avx512 __ro_after_init; 20 | static bool *const blake2s_nobs[] __initconst = { &blake2s_use_ssse3, 21 | &blake2s_use_avx512 }; 22 | 23 | static void __init blake2s_fpu_init(void) 24 | { 25 | blake2s_use_ssse3 = boot_cpu_has(X86_FEATURE_SSSE3); 26 | #ifndef COMPAT_CANNOT_USE_AVX512 27 | blake2s_use_avx512 = 28 | boot_cpu_has(X86_FEATURE_AVX) && 29 | boot_cpu_has(X86_FEATURE_AVX2) && 30 | boot_cpu_has(X86_FEATURE_AVX512F) && 31 | boot_cpu_has(X86_FEATURE_AVX512VL) && 32 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | 33 | XFEATURE_MASK_AVX512, NULL); 34 | #endif 35 | } 36 | 37 | static inline bool blake2s_compress_arch(struct blake2s_state *state, 38 | const u8 *block, size_t nblocks, 39 | const u32 inc) 40 | { 41 | simd_context_t simd_context; 42 | bool used_arch = false; 43 | 44 | /* SIMD disables preemption, so relax after processing each page. */ 45 | BUILD_BUG_ON(PAGE_SIZE / BLAKE2S_BLOCK_SIZE < 8); 46 | 47 | simd_get(&simd_context); 48 | 49 | if (!IS_ENABLED(CONFIG_AS_SSSE3) || !blake2s_use_ssse3 || 50 | !simd_use(&simd_context)) 51 | goto out; 52 | used_arch = true; 53 | 54 | for (;;) { 55 | const size_t blocks = min_t(size_t, nblocks, 56 | PAGE_SIZE / BLAKE2S_BLOCK_SIZE); 57 | 58 | if (IS_ENABLED(CONFIG_AS_AVX512) && blake2s_use_avx512) 59 | blake2s_compress_avx512(state, block, blocks, inc); 60 | else 61 | blake2s_compress_ssse3(state, block, blocks, inc); 62 | 63 | nblocks -= blocks; 64 | if (!nblocks) 65 | break; 66 | block += blocks * BLAKE2S_BLOCK_SIZE; 67 | simd_relax(&simd_context); 68 | } 69 | out: 70 | simd_put(&simd_context); 71 | return used_arch; 72 | } 73 | -------------------------------------------------------------------------------- /src/crypto/zinc/chacha20/chacha20-arm-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #if defined(CONFIG_ZINC_ARCH_ARM) 9 | #include 10 | #include 11 | #endif 12 | 13 | asmlinkage void chacha20_arm(u8 *out, const u8 *in, const size_t len, 14 | const u32 key[8], const u32 counter[4]); 15 | asmlinkage void hchacha20_arm(const u32 state[16], u32 out[8]); 16 | asmlinkage void chacha20_neon(u8 *out, const u8 *in, const size_t len, 17 | const u32 key[8], const u32 counter[4]); 18 | 19 | static bool chacha20_use_neon __ro_after_init; 20 | static bool *const chacha20_nobs[] __initconst = { &chacha20_use_neon }; 21 | static void __init chacha20_fpu_init(void) 22 | { 23 | #if defined(CONFIG_ZINC_ARCH_ARM64) 24 | chacha20_use_neon = cpu_have_named_feature(ASIMD); 25 | #elif defined(CONFIG_ZINC_ARCH_ARM) 26 | switch (read_cpuid_part()) { 27 | case ARM_CPU_PART_CORTEX_A7: 28 | case ARM_CPU_PART_CORTEX_A5: 29 | /* The Cortex-A7 and Cortex-A5 do not perform well with the NEON 30 | * implementation but do incredibly with the scalar one and use 31 | * less power. 32 | */ 33 | break; 34 | default: 35 | chacha20_use_neon = elf_hwcap & HWCAP_NEON; 36 | } 37 | #endif 38 | } 39 | 40 | static inline bool chacha20_arch(struct chacha20_ctx *ctx, u8 *dst, 41 | const u8 *src, size_t len, 42 | simd_context_t *simd_context) 43 | { 44 | /* SIMD disables preemption, so relax after processing each page. */ 45 | BUILD_BUG_ON(PAGE_SIZE < CHACHA20_BLOCK_SIZE || 46 | PAGE_SIZE % CHACHA20_BLOCK_SIZE); 47 | 48 | for (;;) { 49 | if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && chacha20_use_neon && 50 | len >= CHACHA20_BLOCK_SIZE * 3 && simd_use(simd_context)) { 51 | const size_t bytes = min_t(size_t, len, PAGE_SIZE); 52 | 53 | chacha20_neon(dst, src, bytes, ctx->key, ctx->counter); 54 | ctx->counter[0] += (bytes + 63) / 64; 55 | len -= bytes; 56 | if (!len) 57 | break; 58 | dst += bytes; 59 | src += bytes; 60 | simd_relax(simd_context); 61 | } else { 62 | chacha20_arm(dst, src, len, ctx->key, ctx->counter); 63 | ctx->counter[0] += (len + 63) / 64; 64 | break; 65 | } 66 | } 67 | 68 | return true; 69 | } 70 | 71 | static inline bool hchacha20_arch(u32 derived_key[CHACHA20_KEY_WORDS], 72 | const u8 nonce[HCHACHA20_NONCE_SIZE], 73 | const u8 key[HCHACHA20_KEY_SIZE], 74 | simd_context_t *simd_context) 75 | { 76 | if (IS_ENABLED(CONFIG_ZINC_ARCH_ARM)) { 77 | u32 x[] = { CHACHA20_CONSTANT_EXPA, 78 | CHACHA20_CONSTANT_ND_3, 79 | CHACHA20_CONSTANT_2_BY, 80 | CHACHA20_CONSTANT_TE_K, 81 | get_unaligned_le32(key + 0), 82 | get_unaligned_le32(key + 4), 83 | get_unaligned_le32(key + 8), 84 | get_unaligned_le32(key + 12), 85 | get_unaligned_le32(key + 16), 86 | get_unaligned_le32(key + 20), 87 | get_unaligned_le32(key + 24), 88 | get_unaligned_le32(key + 28), 89 | get_unaligned_le32(nonce + 0), 90 | get_unaligned_le32(nonce + 4), 91 | get_unaligned_le32(nonce + 8), 92 | get_unaligned_le32(nonce + 12) 93 | }; 94 | hchacha20_arm(x, derived_key); 95 | return true; 96 | } 97 | return false; 98 | } 99 | -------------------------------------------------------------------------------- /src/crypto/zinc/chacha20/chacha20-mips-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | asmlinkage void chacha20_mips(u32 state[16], u8 *out, const u8 *in, 7 | const size_t len); 8 | static bool *const chacha20_nobs[] __initconst = { }; 9 | static void __init chacha20_fpu_init(void) 10 | { 11 | } 12 | 13 | static inline bool chacha20_arch(struct chacha20_ctx *ctx, u8 *dst, 14 | const u8 *src, size_t len, 15 | simd_context_t *simd_context) 16 | { 17 | chacha20_mips(ctx->state, dst, src, len); 18 | return true; 19 | } 20 | 21 | static inline bool hchacha20_arch(u32 derived_key[CHACHA20_KEY_WORDS], 22 | const u8 nonce[HCHACHA20_NONCE_SIZE], 23 | const u8 key[HCHACHA20_KEY_SIZE], 24 | simd_context_t *simd_context) 25 | { 26 | return false; 27 | } 28 | -------------------------------------------------------------------------------- /src/crypto/zinc/chacha20/chacha20-x86_64-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | asmlinkage void hchacha20_ssse3(u32 *derived_key, const u8 *nonce, 12 | const u8 *key); 13 | asmlinkage void chacha20_ssse3(u8 *out, const u8 *in, const size_t len, 14 | const u32 key[8], const u32 counter[4]); 15 | asmlinkage void chacha20_avx2(u8 *out, const u8 *in, const size_t len, 16 | const u32 key[8], const u32 counter[4]); 17 | asmlinkage void chacha20_avx512(u8 *out, const u8 *in, const size_t len, 18 | const u32 key[8], const u32 counter[4]); 19 | asmlinkage void chacha20_avx512vl(u8 *out, const u8 *in, const size_t len, 20 | const u32 key[8], const u32 counter[4]); 21 | 22 | static bool chacha20_use_ssse3 __ro_after_init; 23 | static bool chacha20_use_avx2 __ro_after_init; 24 | static bool chacha20_use_avx512 __ro_after_init; 25 | static bool chacha20_use_avx512vl __ro_after_init; 26 | static bool *const chacha20_nobs[] __initconst = { 27 | &chacha20_use_ssse3, &chacha20_use_avx2, &chacha20_use_avx512, 28 | &chacha20_use_avx512vl }; 29 | 30 | static void __init chacha20_fpu_init(void) 31 | { 32 | chacha20_use_ssse3 = boot_cpu_has(X86_FEATURE_SSSE3); 33 | chacha20_use_avx2 = 34 | boot_cpu_has(X86_FEATURE_AVX) && 35 | boot_cpu_has(X86_FEATURE_AVX2) && 36 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL); 37 | #ifndef COMPAT_CANNOT_USE_AVX512 38 | chacha20_use_avx512 = 39 | boot_cpu_has(X86_FEATURE_AVX) && 40 | boot_cpu_has(X86_FEATURE_AVX2) && 41 | boot_cpu_has(X86_FEATURE_AVX512F) && 42 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | 43 | XFEATURE_MASK_AVX512, NULL) && 44 | /* Skylake downclocks unacceptably much when using zmm. */ 45 | boot_cpu_data.x86_model != INTEL_FAM6_SKYLAKE_X; 46 | chacha20_use_avx512vl = 47 | boot_cpu_has(X86_FEATURE_AVX) && 48 | boot_cpu_has(X86_FEATURE_AVX2) && 49 | boot_cpu_has(X86_FEATURE_AVX512F) && 50 | boot_cpu_has(X86_FEATURE_AVX512VL) && 51 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | 52 | XFEATURE_MASK_AVX512, NULL); 53 | #endif 54 | } 55 | 56 | static inline bool chacha20_arch(struct chacha20_ctx *ctx, u8 *dst, 57 | const u8 *src, size_t len, 58 | simd_context_t *simd_context) 59 | { 60 | /* SIMD disables preemption, so relax after processing each page. */ 61 | BUILD_BUG_ON(PAGE_SIZE < CHACHA20_BLOCK_SIZE || 62 | PAGE_SIZE % CHACHA20_BLOCK_SIZE); 63 | 64 | if (!IS_ENABLED(CONFIG_AS_SSSE3) || !chacha20_use_ssse3 || 65 | len <= CHACHA20_BLOCK_SIZE || !simd_use(simd_context)) 66 | return false; 67 | 68 | for (;;) { 69 | const size_t bytes = min_t(size_t, len, PAGE_SIZE); 70 | 71 | if (IS_ENABLED(CONFIG_AS_AVX512) && chacha20_use_avx512 && 72 | len >= CHACHA20_BLOCK_SIZE * 8) 73 | chacha20_avx512(dst, src, bytes, ctx->key, ctx->counter); 74 | else if (IS_ENABLED(CONFIG_AS_AVX512) && chacha20_use_avx512vl && 75 | len >= CHACHA20_BLOCK_SIZE * 4) 76 | chacha20_avx512vl(dst, src, bytes, ctx->key, ctx->counter); 77 | else if (IS_ENABLED(CONFIG_AS_AVX2) && chacha20_use_avx2 && 78 | len >= CHACHA20_BLOCK_SIZE * 4) 79 | chacha20_avx2(dst, src, bytes, ctx->key, ctx->counter); 80 | else 81 | chacha20_ssse3(dst, src, bytes, ctx->key, ctx->counter); 82 | ctx->counter[0] += (bytes + 63) / 64; 83 | len -= bytes; 84 | if (!len) 85 | break; 86 | dst += bytes; 87 | src += bytes; 88 | simd_relax(simd_context); 89 | } 90 | 91 | return true; 92 | } 93 | 94 | static inline bool hchacha20_arch(u32 derived_key[CHACHA20_KEY_WORDS], 95 | const u8 nonce[HCHACHA20_NONCE_SIZE], 96 | const u8 key[HCHACHA20_KEY_SIZE], 97 | simd_context_t *simd_context) 98 | { 99 | if (IS_ENABLED(CONFIG_AS_SSSE3) && chacha20_use_ssse3 && 100 | simd_use(simd_context)) { 101 | hchacha20_ssse3(derived_key, nonce, key); 102 | return true; 103 | } 104 | return false; 105 | } 106 | -------------------------------------------------------------------------------- /src/crypto/zinc/chacha20/chacha20.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | * 5 | * Implementation of the ChaCha20 stream cipher. 6 | * 7 | * Information: https://cr.yp.to/chacha.html 8 | */ 9 | 10 | #include 11 | #include "../selftest/run.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include // For crypto_xor_cpy. 18 | 19 | #if defined(CONFIG_ZINC_ARCH_X86_64) 20 | #include "chacha20-x86_64-glue.c" 21 | #elif defined(CONFIG_ZINC_ARCH_ARM) || defined(CONFIG_ZINC_ARCH_ARM64) 22 | #include "chacha20-arm-glue.c" 23 | #elif defined(CONFIG_ZINC_ARCH_MIPS) 24 | #include "chacha20-mips-glue.c" 25 | #else 26 | static bool *const chacha20_nobs[] __initconst = { }; 27 | static void __init chacha20_fpu_init(void) 28 | { 29 | } 30 | static inline bool chacha20_arch(struct chacha20_ctx *ctx, u8 *dst, 31 | const u8 *src, size_t len, 32 | simd_context_t *simd_context) 33 | { 34 | return false; 35 | } 36 | static inline bool hchacha20_arch(u32 derived_key[CHACHA20_KEY_WORDS], 37 | const u8 nonce[HCHACHA20_NONCE_SIZE], 38 | const u8 key[HCHACHA20_KEY_SIZE], 39 | simd_context_t *simd_context) 40 | { 41 | return false; 42 | } 43 | #endif 44 | 45 | #define QUARTER_ROUND(x, a, b, c, d) ( \ 46 | x[a] += x[b], \ 47 | x[d] = rol32((x[d] ^ x[a]), 16), \ 48 | x[c] += x[d], \ 49 | x[b] = rol32((x[b] ^ x[c]), 12), \ 50 | x[a] += x[b], \ 51 | x[d] = rol32((x[d] ^ x[a]), 8), \ 52 | x[c] += x[d], \ 53 | x[b] = rol32((x[b] ^ x[c]), 7) \ 54 | ) 55 | 56 | #define C(i, j) (i * 4 + j) 57 | 58 | #define DOUBLE_ROUND(x) ( \ 59 | /* Column Round */ \ 60 | QUARTER_ROUND(x, C(0, 0), C(1, 0), C(2, 0), C(3, 0)), \ 61 | QUARTER_ROUND(x, C(0, 1), C(1, 1), C(2, 1), C(3, 1)), \ 62 | QUARTER_ROUND(x, C(0, 2), C(1, 2), C(2, 2), C(3, 2)), \ 63 | QUARTER_ROUND(x, C(0, 3), C(1, 3), C(2, 3), C(3, 3)), \ 64 | /* Diagonal Round */ \ 65 | QUARTER_ROUND(x, C(0, 0), C(1, 1), C(2, 2), C(3, 3)), \ 66 | QUARTER_ROUND(x, C(0, 1), C(1, 2), C(2, 3), C(3, 0)), \ 67 | QUARTER_ROUND(x, C(0, 2), C(1, 3), C(2, 0), C(3, 1)), \ 68 | QUARTER_ROUND(x, C(0, 3), C(1, 0), C(2, 1), C(3, 2)) \ 69 | ) 70 | 71 | #define TWENTY_ROUNDS(x) ( \ 72 | DOUBLE_ROUND(x), \ 73 | DOUBLE_ROUND(x), \ 74 | DOUBLE_ROUND(x), \ 75 | DOUBLE_ROUND(x), \ 76 | DOUBLE_ROUND(x), \ 77 | DOUBLE_ROUND(x), \ 78 | DOUBLE_ROUND(x), \ 79 | DOUBLE_ROUND(x), \ 80 | DOUBLE_ROUND(x), \ 81 | DOUBLE_ROUND(x) \ 82 | ) 83 | 84 | static void chacha20_block_generic(struct chacha20_ctx *ctx, __le32 *stream) 85 | { 86 | u32 x[CHACHA20_BLOCK_WORDS]; 87 | int i; 88 | 89 | for (i = 0; i < ARRAY_SIZE(x); ++i) 90 | x[i] = ctx->state[i]; 91 | 92 | TWENTY_ROUNDS(x); 93 | 94 | for (i = 0; i < ARRAY_SIZE(x); ++i) 95 | stream[i] = cpu_to_le32(x[i] + ctx->state[i]); 96 | 97 | ctx->counter[0] += 1; 98 | } 99 | 100 | static void chacha20_generic(struct chacha20_ctx *ctx, u8 *out, const u8 *in, 101 | u32 len) 102 | { 103 | __le32 buf[CHACHA20_BLOCK_WORDS]; 104 | 105 | while (len >= CHACHA20_BLOCK_SIZE) { 106 | chacha20_block_generic(ctx, buf); 107 | crypto_xor_cpy(out, in, (u8 *)buf, CHACHA20_BLOCK_SIZE); 108 | len -= CHACHA20_BLOCK_SIZE; 109 | out += CHACHA20_BLOCK_SIZE; 110 | in += CHACHA20_BLOCK_SIZE; 111 | } 112 | if (len) { 113 | chacha20_block_generic(ctx, buf); 114 | crypto_xor_cpy(out, in, (u8 *)buf, len); 115 | } 116 | } 117 | 118 | void chacha20(struct chacha20_ctx *ctx, u8 *dst, const u8 *src, u32 len, 119 | simd_context_t *simd_context) 120 | { 121 | if (!chacha20_arch(ctx, dst, src, len, simd_context)) 122 | chacha20_generic(ctx, dst, src, len); 123 | } 124 | 125 | static void hchacha20_generic(u32 derived_key[CHACHA20_KEY_WORDS], 126 | const u8 nonce[HCHACHA20_NONCE_SIZE], 127 | const u8 key[HCHACHA20_KEY_SIZE]) 128 | { 129 | u32 x[] = { CHACHA20_CONSTANT_EXPA, 130 | CHACHA20_CONSTANT_ND_3, 131 | CHACHA20_CONSTANT_2_BY, 132 | CHACHA20_CONSTANT_TE_K, 133 | get_unaligned_le32(key + 0), 134 | get_unaligned_le32(key + 4), 135 | get_unaligned_le32(key + 8), 136 | get_unaligned_le32(key + 12), 137 | get_unaligned_le32(key + 16), 138 | get_unaligned_le32(key + 20), 139 | get_unaligned_le32(key + 24), 140 | get_unaligned_le32(key + 28), 141 | get_unaligned_le32(nonce + 0), 142 | get_unaligned_le32(nonce + 4), 143 | get_unaligned_le32(nonce + 8), 144 | get_unaligned_le32(nonce + 12) 145 | }; 146 | 147 | TWENTY_ROUNDS(x); 148 | 149 | memcpy(derived_key + 0, x + 0, sizeof(u32) * 4); 150 | memcpy(derived_key + 4, x + 12, sizeof(u32) * 4); 151 | } 152 | 153 | /* Derived key should be 32-bit aligned */ 154 | void hchacha20(u32 derived_key[CHACHA20_KEY_WORDS], 155 | const u8 nonce[HCHACHA20_NONCE_SIZE], 156 | const u8 key[HCHACHA20_KEY_SIZE], simd_context_t *simd_context) 157 | { 158 | if (!hchacha20_arch(derived_key, nonce, key, simd_context)) 159 | hchacha20_generic(derived_key, nonce, key); 160 | } 161 | 162 | #include "../selftest/chacha20.c" 163 | 164 | static bool nosimd __initdata = false; 165 | 166 | #ifndef COMPAT_ZINC_IS_A_MODULE 167 | int __init chacha20_mod_init(void) 168 | #else 169 | static int __init mod_init(void) 170 | #endif 171 | { 172 | if (!nosimd) 173 | chacha20_fpu_init(); 174 | if (!selftest_run("chacha20", chacha20_selftest, chacha20_nobs, 175 | ARRAY_SIZE(chacha20_nobs))) 176 | return -ENOTRECOVERABLE; 177 | return 0; 178 | } 179 | 180 | #ifdef COMPAT_ZINC_IS_A_MODULE 181 | static void __exit mod_exit(void) 182 | { 183 | } 184 | 185 | module_param(nosimd, bool, 0); 186 | module_init(mod_init); 187 | module_exit(mod_exit); 188 | MODULE_LICENSE("GPL v2"); 189 | MODULE_DESCRIPTION("ChaCha20 stream cipher"); 190 | MODULE_AUTHOR("Jason A. Donenfeld "); 191 | #endif 192 | -------------------------------------------------------------------------------- /src/crypto/zinc/curve25519/curve25519-arm-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE], 11 | const u8 secret[CURVE25519_KEY_SIZE], 12 | const u8 basepoint[CURVE25519_KEY_SIZE]); 13 | 14 | static bool curve25519_use_neon __ro_after_init; 15 | static bool *const curve25519_nobs[] __initconst = { &curve25519_use_neon }; 16 | static void __init curve25519_fpu_init(void) 17 | { 18 | curve25519_use_neon = elf_hwcap & HWCAP_NEON; 19 | } 20 | 21 | static inline bool curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE], 22 | const u8 secret[CURVE25519_KEY_SIZE], 23 | const u8 basepoint[CURVE25519_KEY_SIZE]) 24 | { 25 | simd_context_t simd_context; 26 | bool used_arch = false; 27 | 28 | simd_get(&simd_context); 29 | if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && 30 | !IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && curve25519_use_neon && 31 | simd_use(&simd_context)) { 32 | curve25519_neon(mypublic, secret, basepoint); 33 | used_arch = true; 34 | } 35 | simd_put(&simd_context); 36 | return used_arch; 37 | } 38 | 39 | static inline bool curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], 40 | const u8 secret[CURVE25519_KEY_SIZE]) 41 | { 42 | return false; 43 | } 44 | -------------------------------------------------------------------------------- /src/crypto/zinc/curve25519/curve25519-x86_64-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "curve25519-x86_64.c" 10 | 11 | static bool curve25519_use_bmi2_adx __ro_after_init; 12 | static bool *const curve25519_nobs[] __initconst = { 13 | &curve25519_use_bmi2_adx }; 14 | 15 | static void __init curve25519_fpu_init(void) 16 | { 17 | curve25519_use_bmi2_adx = IS_ENABLED(CONFIG_AS_BMI2) && 18 | IS_ENABLED(CONFIG_AS_ADX) && 19 | boot_cpu_has(X86_FEATURE_BMI2) && 20 | boot_cpu_has(X86_FEATURE_ADX); 21 | } 22 | 23 | static inline bool curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE], 24 | const u8 secret[CURVE25519_KEY_SIZE], 25 | const u8 basepoint[CURVE25519_KEY_SIZE]) 26 | { 27 | if (IS_ENABLED(CONFIG_AS_ADX) && IS_ENABLED(CONFIG_AS_BMI2) && 28 | curve25519_use_bmi2_adx) { 29 | curve25519_ever64(mypublic, secret, basepoint); 30 | return true; 31 | } 32 | return false; 33 | } 34 | 35 | static inline bool curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], 36 | const u8 secret[CURVE25519_KEY_SIZE]) 37 | { 38 | if (IS_ENABLED(CONFIG_AS_ADX) && IS_ENABLED(CONFIG_AS_BMI2) && 39 | curve25519_use_bmi2_adx) { 40 | curve25519_ever64_base(pub, secret); 41 | return true; 42 | } 43 | return false; 44 | } 45 | -------------------------------------------------------------------------------- /src/crypto/zinc/curve25519/curve25519.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | * 5 | * This is an implementation of the Curve25519 ECDH algorithm, using either 6 | * a 32-bit implementation or a 64-bit implementation with 128-bit integers, 7 | * depending on what is supported by the target compiler. 8 | * 9 | * Information: https://cr.yp.to/ecdh.html 10 | */ 11 | 12 | #include 13 | #include "../selftest/run.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include // For crypto_memneq. 21 | 22 | #if defined(CONFIG_ZINC_ARCH_X86_64) 23 | #include "curve25519-x86_64-glue.c" 24 | #elif defined(CONFIG_ZINC_ARCH_ARM) 25 | #include "curve25519-arm-glue.c" 26 | #else 27 | static bool *const curve25519_nobs[] __initconst = { }; 28 | static void __init curve25519_fpu_init(void) 29 | { 30 | } 31 | static inline bool curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE], 32 | const u8 secret[CURVE25519_KEY_SIZE], 33 | const u8 basepoint[CURVE25519_KEY_SIZE]) 34 | { 35 | return false; 36 | } 37 | static inline bool curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], 38 | const u8 secret[CURVE25519_KEY_SIZE]) 39 | { 40 | return false; 41 | } 42 | #endif 43 | 44 | #if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__) 45 | #include "curve25519-hacl64.c" 46 | #else 47 | #include "curve25519-fiat32.c" 48 | #endif 49 | 50 | static const u8 null_point[CURVE25519_KEY_SIZE] = { 0 }; 51 | 52 | bool curve25519(u8 mypublic[CURVE25519_KEY_SIZE], 53 | const u8 secret[CURVE25519_KEY_SIZE], 54 | const u8 basepoint[CURVE25519_KEY_SIZE]) 55 | { 56 | if (!curve25519_arch(mypublic, secret, basepoint)) 57 | curve25519_generic(mypublic, secret, basepoint); 58 | return crypto_memneq(mypublic, null_point, CURVE25519_KEY_SIZE); 59 | } 60 | 61 | bool curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE], 62 | const u8 secret[CURVE25519_KEY_SIZE]) 63 | { 64 | static const u8 basepoint[CURVE25519_KEY_SIZE] __aligned(32) = { 9 }; 65 | 66 | if (unlikely(!crypto_memneq(secret, null_point, CURVE25519_KEY_SIZE))) 67 | return false; 68 | 69 | if (curve25519_base_arch(pub, secret)) 70 | return crypto_memneq(pub, null_point, CURVE25519_KEY_SIZE); 71 | return curve25519(pub, secret, basepoint); 72 | } 73 | 74 | void curve25519_generate_secret(u8 secret[CURVE25519_KEY_SIZE]) 75 | { 76 | get_random_bytes_wait(secret, CURVE25519_KEY_SIZE); 77 | curve25519_clamp_secret(secret); 78 | } 79 | 80 | #include "../selftest/curve25519.c" 81 | 82 | static bool nosimd __initdata = false; 83 | 84 | #ifndef COMPAT_ZINC_IS_A_MODULE 85 | int __init curve25519_mod_init(void) 86 | #else 87 | static int __init mod_init(void) 88 | #endif 89 | { 90 | if (!nosimd) 91 | curve25519_fpu_init(); 92 | if (!selftest_run("curve25519", curve25519_selftest, curve25519_nobs, 93 | ARRAY_SIZE(curve25519_nobs))) 94 | return -ENOTRECOVERABLE; 95 | return 0; 96 | } 97 | 98 | #ifdef COMPAT_ZINC_IS_A_MODULE 99 | static void __exit mod_exit(void) 100 | { 101 | } 102 | 103 | module_param(nosimd, bool, 0); 104 | module_init(mod_init); 105 | module_exit(mod_exit); 106 | MODULE_LICENSE("GPL v2"); 107 | MODULE_DESCRIPTION("Curve25519 scalar multiplication"); 108 | MODULE_AUTHOR("Jason A. Donenfeld "); 109 | #endif 110 | -------------------------------------------------------------------------------- /src/crypto/zinc/poly1305/poly1305-arm-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | asmlinkage void poly1305_init_arm(void *ctx, const u8 key[16]); 10 | asmlinkage void poly1305_blocks_arm(void *ctx, const u8 *inp, const size_t len, 11 | const u32 padbit); 12 | asmlinkage void poly1305_emit_arm(void *ctx, u8 mac[16], const u32 nonce[4]); 13 | asmlinkage void poly1305_blocks_neon(void *ctx, const u8 *inp, const size_t len, 14 | const u32 padbit); 15 | asmlinkage void poly1305_emit_neon(void *ctx, u8 mac[16], const u32 nonce[4]); 16 | 17 | static bool poly1305_use_neon __ro_after_init; 18 | static bool *const poly1305_nobs[] __initconst = { &poly1305_use_neon }; 19 | 20 | static void __init poly1305_fpu_init(void) 21 | { 22 | #if defined(CONFIG_ZINC_ARCH_ARM64) 23 | poly1305_use_neon = cpu_have_named_feature(ASIMD); 24 | #elif defined(CONFIG_ZINC_ARCH_ARM) 25 | poly1305_use_neon = elf_hwcap & HWCAP_NEON; 26 | #endif 27 | } 28 | 29 | #if defined(CONFIG_ZINC_ARCH_ARM64) 30 | struct poly1305_arch_internal { 31 | union { 32 | u32 h[5]; 33 | struct { 34 | u64 h0, h1, h2; 35 | }; 36 | }; 37 | u64 is_base2_26; 38 | u64 r[2]; 39 | }; 40 | #elif defined(CONFIG_ZINC_ARCH_ARM) 41 | struct poly1305_arch_internal { 42 | union { 43 | u32 h[5]; 44 | struct { 45 | u64 h0, h1; 46 | u32 h2; 47 | } __packed; 48 | }; 49 | u32 r[4]; 50 | u32 is_base2_26; 51 | }; 52 | #endif 53 | 54 | /* The NEON code uses base 2^26, while the scalar code uses base 2^64 on 64-bit 55 | * and base 2^32 on 32-bit. If we hit the unfortunate situation of using NEON 56 | * and then having to go back to scalar -- because the user is silly and has 57 | * called the update function from two separate contexts -- then we need to 58 | * convert back to the original base before proceeding. The below function is 59 | * written for 64-bit integers, and so we have to swap words at the end on 60 | * big-endian 32-bit. It is possible to reason that the initial reduction below 61 | * is sufficient given the implementation invariants. However, for an avoidance 62 | * of doubt and because this is not performance critical, we do the full 63 | * reduction anyway. 64 | */ 65 | static void convert_to_base2_64(void *ctx) 66 | { 67 | struct poly1305_arch_internal *state = ctx; 68 | u32 cy; 69 | 70 | if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !state->is_base2_26) 71 | return; 72 | 73 | cy = state->h[0] >> 26; state->h[0] &= 0x3ffffff; state->h[1] += cy; 74 | cy = state->h[1] >> 26; state->h[1] &= 0x3ffffff; state->h[2] += cy; 75 | cy = state->h[2] >> 26; state->h[2] &= 0x3ffffff; state->h[3] += cy; 76 | cy = state->h[3] >> 26; state->h[3] &= 0x3ffffff; state->h[4] += cy; 77 | state->h0 = ((u64)state->h[2] << 52) | ((u64)state->h[1] << 26) | state->h[0]; 78 | state->h1 = ((u64)state->h[4] << 40) | ((u64)state->h[3] << 14) | (state->h[2] >> 12); 79 | state->h2 = state->h[4] >> 24; 80 | if (IS_ENABLED(CONFIG_ZINC_ARCH_ARM) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) { 81 | state->h0 = rol64(state->h0, 32); 82 | state->h1 = rol64(state->h1, 32); 83 | } 84 | #define ULT(a, b) ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)) 85 | cy = (state->h2 >> 2) + (state->h2 & ~3ULL); 86 | state->h2 &= 3; 87 | state->h0 += cy; 88 | state->h1 += (cy = ULT(state->h0, cy)); 89 | state->h2 += ULT(state->h1, cy); 90 | #undef ULT 91 | state->is_base2_26 = 0; 92 | } 93 | 94 | static inline bool poly1305_init_arch(void *ctx, 95 | const u8 key[POLY1305_KEY_SIZE]) 96 | { 97 | poly1305_init_arm(ctx, key); 98 | return true; 99 | } 100 | 101 | static inline bool poly1305_blocks_arch(void *ctx, const u8 *inp, 102 | size_t len, const u32 padbit, 103 | simd_context_t *simd_context) 104 | { 105 | /* SIMD disables preemption, so relax after processing each page. */ 106 | BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE || 107 | PAGE_SIZE % POLY1305_BLOCK_SIZE); 108 | 109 | if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !poly1305_use_neon || 110 | !simd_use(simd_context)) { 111 | convert_to_base2_64(ctx); 112 | poly1305_blocks_arm(ctx, inp, len, padbit); 113 | return true; 114 | } 115 | 116 | for (;;) { 117 | const size_t bytes = min_t(size_t, len, PAGE_SIZE); 118 | 119 | poly1305_blocks_neon(ctx, inp, bytes, padbit); 120 | len -= bytes; 121 | if (!len) 122 | break; 123 | inp += bytes; 124 | simd_relax(simd_context); 125 | } 126 | return true; 127 | } 128 | 129 | static inline bool poly1305_emit_arch(void *ctx, u8 mac[POLY1305_MAC_SIZE], 130 | const u32 nonce[4], 131 | simd_context_t *simd_context) 132 | { 133 | if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !poly1305_use_neon || 134 | !simd_use(simd_context)) { 135 | convert_to_base2_64(ctx); 136 | poly1305_emit_arm(ctx, mac, nonce); 137 | } else 138 | poly1305_emit_neon(ctx, mac, nonce); 139 | return true; 140 | } 141 | -------------------------------------------------------------------------------- /src/crypto/zinc/poly1305/poly1305-donna32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | * 5 | * This is based in part on Andrew Moon's poly1305-donna, which is in the 6 | * public domain. 7 | */ 8 | 9 | struct poly1305_internal { 10 | u32 h[5]; 11 | u32 r[5]; 12 | u32 s[4]; 13 | }; 14 | 15 | static void poly1305_init_generic(void *ctx, const u8 key[16]) 16 | { 17 | struct poly1305_internal *st = (struct poly1305_internal *)ctx; 18 | 19 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ 20 | st->r[0] = (get_unaligned_le32(&key[0])) & 0x3ffffff; 21 | st->r[1] = (get_unaligned_le32(&key[3]) >> 2) & 0x3ffff03; 22 | st->r[2] = (get_unaligned_le32(&key[6]) >> 4) & 0x3ffc0ff; 23 | st->r[3] = (get_unaligned_le32(&key[9]) >> 6) & 0x3f03fff; 24 | st->r[4] = (get_unaligned_le32(&key[12]) >> 8) & 0x00fffff; 25 | 26 | /* s = 5*r */ 27 | st->s[0] = st->r[1] * 5; 28 | st->s[1] = st->r[2] * 5; 29 | st->s[2] = st->r[3] * 5; 30 | st->s[3] = st->r[4] * 5; 31 | 32 | /* h = 0 */ 33 | st->h[0] = 0; 34 | st->h[1] = 0; 35 | st->h[2] = 0; 36 | st->h[3] = 0; 37 | st->h[4] = 0; 38 | } 39 | 40 | static void poly1305_blocks_generic(void *ctx, const u8 *input, size_t len, 41 | const u32 padbit) 42 | { 43 | struct poly1305_internal *st = (struct poly1305_internal *)ctx; 44 | const u32 hibit = padbit << 24; 45 | u32 r0, r1, r2, r3, r4; 46 | u32 s1, s2, s3, s4; 47 | u32 h0, h1, h2, h3, h4; 48 | u64 d0, d1, d2, d3, d4; 49 | u32 c; 50 | 51 | r0 = st->r[0]; 52 | r1 = st->r[1]; 53 | r2 = st->r[2]; 54 | r3 = st->r[3]; 55 | r4 = st->r[4]; 56 | 57 | s1 = st->s[0]; 58 | s2 = st->s[1]; 59 | s3 = st->s[2]; 60 | s4 = st->s[3]; 61 | 62 | h0 = st->h[0]; 63 | h1 = st->h[1]; 64 | h2 = st->h[2]; 65 | h3 = st->h[3]; 66 | h4 = st->h[4]; 67 | 68 | while (len >= POLY1305_BLOCK_SIZE) { 69 | /* h += m[i] */ 70 | h0 += (get_unaligned_le32(&input[0])) & 0x3ffffff; 71 | h1 += (get_unaligned_le32(&input[3]) >> 2) & 0x3ffffff; 72 | h2 += (get_unaligned_le32(&input[6]) >> 4) & 0x3ffffff; 73 | h3 += (get_unaligned_le32(&input[9]) >> 6) & 0x3ffffff; 74 | h4 += (get_unaligned_le32(&input[12]) >> 8) | hibit; 75 | 76 | /* h *= r */ 77 | d0 = ((u64)h0 * r0) + ((u64)h1 * s4) + 78 | ((u64)h2 * s3) + ((u64)h3 * s2) + 79 | ((u64)h4 * s1); 80 | d1 = ((u64)h0 * r1) + ((u64)h1 * r0) + 81 | ((u64)h2 * s4) + ((u64)h3 * s3) + 82 | ((u64)h4 * s2); 83 | d2 = ((u64)h0 * r2) + ((u64)h1 * r1) + 84 | ((u64)h2 * r0) + ((u64)h3 * s4) + 85 | ((u64)h4 * s3); 86 | d3 = ((u64)h0 * r3) + ((u64)h1 * r2) + 87 | ((u64)h2 * r1) + ((u64)h3 * r0) + 88 | ((u64)h4 * s4); 89 | d4 = ((u64)h0 * r4) + ((u64)h1 * r3) + 90 | ((u64)h2 * r2) + ((u64)h3 * r1) + 91 | ((u64)h4 * r0); 92 | 93 | /* (partial) h %= p */ 94 | c = (u32)(d0 >> 26); 95 | h0 = (u32)d0 & 0x3ffffff; 96 | d1 += c; 97 | c = (u32)(d1 >> 26); 98 | h1 = (u32)d1 & 0x3ffffff; 99 | d2 += c; 100 | c = (u32)(d2 >> 26); 101 | h2 = (u32)d2 & 0x3ffffff; 102 | d3 += c; 103 | c = (u32)(d3 >> 26); 104 | h3 = (u32)d3 & 0x3ffffff; 105 | d4 += c; 106 | c = (u32)(d4 >> 26); 107 | h4 = (u32)d4 & 0x3ffffff; 108 | h0 += c * 5; 109 | c = (h0 >> 26); 110 | h0 = h0 & 0x3ffffff; 111 | h1 += c; 112 | 113 | input += POLY1305_BLOCK_SIZE; 114 | len -= POLY1305_BLOCK_SIZE; 115 | } 116 | 117 | st->h[0] = h0; 118 | st->h[1] = h1; 119 | st->h[2] = h2; 120 | st->h[3] = h3; 121 | st->h[4] = h4; 122 | } 123 | 124 | static void poly1305_emit_generic(void *ctx, u8 mac[16], const u32 nonce[4]) 125 | { 126 | struct poly1305_internal *st = (struct poly1305_internal *)ctx; 127 | u32 h0, h1, h2, h3, h4, c; 128 | u32 g0, g1, g2, g3, g4; 129 | u64 f; 130 | u32 mask; 131 | 132 | /* fully carry h */ 133 | h0 = st->h[0]; 134 | h1 = st->h[1]; 135 | h2 = st->h[2]; 136 | h3 = st->h[3]; 137 | h4 = st->h[4]; 138 | 139 | c = h1 >> 26; 140 | h1 = h1 & 0x3ffffff; 141 | h2 += c; 142 | c = h2 >> 26; 143 | h2 = h2 & 0x3ffffff; 144 | h3 += c; 145 | c = h3 >> 26; 146 | h3 = h3 & 0x3ffffff; 147 | h4 += c; 148 | c = h4 >> 26; 149 | h4 = h4 & 0x3ffffff; 150 | h0 += c * 5; 151 | c = h0 >> 26; 152 | h0 = h0 & 0x3ffffff; 153 | h1 += c; 154 | 155 | /* compute h + -p */ 156 | g0 = h0 + 5; 157 | c = g0 >> 26; 158 | g0 &= 0x3ffffff; 159 | g1 = h1 + c; 160 | c = g1 >> 26; 161 | g1 &= 0x3ffffff; 162 | g2 = h2 + c; 163 | c = g2 >> 26; 164 | g2 &= 0x3ffffff; 165 | g3 = h3 + c; 166 | c = g3 >> 26; 167 | g3 &= 0x3ffffff; 168 | g4 = h4 + c - (1UL << 26); 169 | 170 | /* select h if h < p, or h + -p if h >= p */ 171 | mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; 172 | g0 &= mask; 173 | g1 &= mask; 174 | g2 &= mask; 175 | g3 &= mask; 176 | g4 &= mask; 177 | mask = ~mask; 178 | 179 | h0 = (h0 & mask) | g0; 180 | h1 = (h1 & mask) | g1; 181 | h2 = (h2 & mask) | g2; 182 | h3 = (h3 & mask) | g3; 183 | h4 = (h4 & mask) | g4; 184 | 185 | /* h = h % (2^128) */ 186 | h0 = ((h0) | (h1 << 26)) & 0xffffffff; 187 | h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; 188 | h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; 189 | h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; 190 | 191 | /* mac = (h + nonce) % (2^128) */ 192 | f = (u64)h0 + nonce[0]; 193 | h0 = (u32)f; 194 | f = (u64)h1 + nonce[1] + (f >> 32); 195 | h1 = (u32)f; 196 | f = (u64)h2 + nonce[2] + (f >> 32); 197 | h2 = (u32)f; 198 | f = (u64)h3 + nonce[3] + (f >> 32); 199 | h3 = (u32)f; 200 | 201 | put_unaligned_le32(h0, &mac[0]); 202 | put_unaligned_le32(h1, &mac[4]); 203 | put_unaligned_le32(h2, &mac[8]); 204 | put_unaligned_le32(h3, &mac[12]); 205 | } 206 | -------------------------------------------------------------------------------- /src/crypto/zinc/poly1305/poly1305-donna64.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | * 5 | * This is based in part on Andrew Moon's poly1305-donna, which is in the 6 | * public domain. 7 | */ 8 | 9 | typedef __uint128_t u128; 10 | 11 | struct poly1305_internal { 12 | u64 r[3]; 13 | u64 h[3]; 14 | u64 s[2]; 15 | }; 16 | 17 | static void poly1305_init_generic(void *ctx, const u8 key[16]) 18 | { 19 | struct poly1305_internal *st = (struct poly1305_internal *)ctx; 20 | u64 t0, t1; 21 | 22 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ 23 | t0 = get_unaligned_le64(&key[0]); 24 | t1 = get_unaligned_le64(&key[8]); 25 | 26 | st->r[0] = t0 & 0xffc0fffffffULL; 27 | st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffffULL; 28 | st->r[2] = ((t1 >> 24)) & 0x00ffffffc0fULL; 29 | 30 | /* s = 20*r */ 31 | st->s[0] = st->r[1] * 20; 32 | st->s[1] = st->r[2] * 20; 33 | 34 | /* h = 0 */ 35 | st->h[0] = 0; 36 | st->h[1] = 0; 37 | st->h[2] = 0; 38 | } 39 | 40 | static void poly1305_blocks_generic(void *ctx, const u8 *input, size_t len, 41 | const u32 padbit) 42 | { 43 | struct poly1305_internal *st = (struct poly1305_internal *)ctx; 44 | const u64 hibit = ((u64)padbit) << 40; 45 | u64 r0, r1, r2; 46 | u64 s1, s2; 47 | u64 h0, h1, h2; 48 | u64 c; 49 | u128 d0, d1, d2, d; 50 | 51 | r0 = st->r[0]; 52 | r1 = st->r[1]; 53 | r2 = st->r[2]; 54 | 55 | h0 = st->h[0]; 56 | h1 = st->h[1]; 57 | h2 = st->h[2]; 58 | 59 | s1 = st->s[0]; 60 | s2 = st->s[1]; 61 | 62 | while (len >= POLY1305_BLOCK_SIZE) { 63 | u64 t0, t1; 64 | 65 | /* h += m[i] */ 66 | t0 = get_unaligned_le64(&input[0]); 67 | t1 = get_unaligned_le64(&input[8]); 68 | 69 | h0 += t0 & 0xfffffffffffULL; 70 | h1 += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL; 71 | h2 += (((t1 >> 24)) & 0x3ffffffffffULL) | hibit; 72 | 73 | /* h *= r */ 74 | d0 = (u128)h0 * r0; 75 | d = (u128)h1 * s2; 76 | d0 += d; 77 | d = (u128)h2 * s1; 78 | d0 += d; 79 | d1 = (u128)h0 * r1; 80 | d = (u128)h1 * r0; 81 | d1 += d; 82 | d = (u128)h2 * s2; 83 | d1 += d; 84 | d2 = (u128)h0 * r2; 85 | d = (u128)h1 * r1; 86 | d2 += d; 87 | d = (u128)h2 * r0; 88 | d2 += d; 89 | 90 | /* (partial) h %= p */ 91 | c = (u64)(d0 >> 44); 92 | h0 = (u64)d0 & 0xfffffffffffULL; 93 | d1 += c; 94 | c = (u64)(d1 >> 44); 95 | h1 = (u64)d1 & 0xfffffffffffULL; 96 | d2 += c; 97 | c = (u64)(d2 >> 42); 98 | h2 = (u64)d2 & 0x3ffffffffffULL; 99 | h0 += c * 5; 100 | c = h0 >> 44; 101 | h0 = h0 & 0xfffffffffffULL; 102 | h1 += c; 103 | 104 | input += POLY1305_BLOCK_SIZE; 105 | len -= POLY1305_BLOCK_SIZE; 106 | } 107 | 108 | st->h[0] = h0; 109 | st->h[1] = h1; 110 | st->h[2] = h2; 111 | } 112 | 113 | static void poly1305_emit_generic(void *ctx, u8 mac[16], const u32 nonce[4]) 114 | { 115 | struct poly1305_internal *st = (struct poly1305_internal *)ctx; 116 | u64 h0, h1, h2, c; 117 | u64 g0, g1, g2; 118 | u64 t0, t1; 119 | 120 | /* fully carry h */ 121 | h0 = st->h[0]; 122 | h1 = st->h[1]; 123 | h2 = st->h[2]; 124 | 125 | c = h1 >> 44; 126 | h1 &= 0xfffffffffffULL; 127 | h2 += c; 128 | c = h2 >> 42; 129 | h2 &= 0x3ffffffffffULL; 130 | h0 += c * 5; 131 | c = h0 >> 44; 132 | h0 &= 0xfffffffffffULL; 133 | h1 += c; 134 | c = h1 >> 44; 135 | h1 &= 0xfffffffffffULL; 136 | h2 += c; 137 | c = h2 >> 42; 138 | h2 &= 0x3ffffffffffULL; 139 | h0 += c * 5; 140 | c = h0 >> 44; 141 | h0 &= 0xfffffffffffULL; 142 | h1 += c; 143 | 144 | /* compute h + -p */ 145 | g0 = h0 + 5; 146 | c = g0 >> 44; 147 | g0 &= 0xfffffffffffULL; 148 | g1 = h1 + c; 149 | c = g1 >> 44; 150 | g1 &= 0xfffffffffffULL; 151 | g2 = h2 + c - (1ULL << 42); 152 | 153 | /* select h if h < p, or h + -p if h >= p */ 154 | c = (g2 >> ((sizeof(u64) * 8) - 1)) - 1; 155 | g0 &= c; 156 | g1 &= c; 157 | g2 &= c; 158 | c = ~c; 159 | h0 = (h0 & c) | g0; 160 | h1 = (h1 & c) | g1; 161 | h2 = (h2 & c) | g2; 162 | 163 | /* h = (h + nonce) */ 164 | t0 = ((u64)nonce[1] << 32) | nonce[0]; 165 | t1 = ((u64)nonce[3] << 32) | nonce[2]; 166 | 167 | h0 += t0 & 0xfffffffffffULL; 168 | c = h0 >> 44; 169 | h0 &= 0xfffffffffffULL; 170 | h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL) + c; 171 | c = h1 >> 44; 172 | h1 &= 0xfffffffffffULL; 173 | h2 += (((t1 >> 24)) & 0x3ffffffffffULL) + c; 174 | h2 &= 0x3ffffffffffULL; 175 | 176 | /* mac = h % (2^128) */ 177 | h0 = h0 | (h1 << 44); 178 | h1 = (h1 >> 20) | (h2 << 24); 179 | 180 | put_unaligned_le64(h0, &mac[0]); 181 | put_unaligned_le64(h1, &mac[8]); 182 | } 183 | -------------------------------------------------------------------------------- /src/crypto/zinc/poly1305/poly1305-mips-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | asmlinkage void poly1305_init_mips(void *ctx, const u8 key[16]); 7 | asmlinkage void poly1305_blocks_mips(void *ctx, const u8 *inp, const size_t len, 8 | const u32 padbit); 9 | asmlinkage void poly1305_emit_mips(void *ctx, u8 mac[16], const u32 nonce[4]); 10 | 11 | static bool *const poly1305_nobs[] __initconst = { }; 12 | static void __init poly1305_fpu_init(void) 13 | { 14 | } 15 | 16 | static inline bool poly1305_init_arch(void *ctx, 17 | const u8 key[POLY1305_KEY_SIZE]) 18 | { 19 | poly1305_init_mips(ctx, key); 20 | return true; 21 | } 22 | 23 | static inline bool poly1305_blocks_arch(void *ctx, const u8 *inp, 24 | size_t len, const u32 padbit, 25 | simd_context_t *simd_context) 26 | { 27 | poly1305_blocks_mips(ctx, inp, len, padbit); 28 | return true; 29 | } 30 | 31 | static inline bool poly1305_emit_arch(void *ctx, u8 mac[POLY1305_MAC_SIZE], 32 | const u32 nonce[4], 33 | simd_context_t *simd_context) 34 | { 35 | poly1305_emit_mips(ctx, mac, nonce); 36 | return true; 37 | } 38 | -------------------------------------------------------------------------------- /src/crypto/zinc/poly1305/poly1305-x86_64-glue.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | asmlinkage void poly1305_init_x86_64(void *ctx, 11 | const u8 key[POLY1305_KEY_SIZE]); 12 | asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp, 13 | const size_t len, const u32 padbit); 14 | asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_MAC_SIZE], 15 | const u32 nonce[4]); 16 | asmlinkage void poly1305_emit_avx(void *ctx, u8 mac[POLY1305_MAC_SIZE], 17 | const u32 nonce[4]); 18 | asmlinkage void poly1305_blocks_avx(void *ctx, const u8 *inp, const size_t len, 19 | const u32 padbit); 20 | asmlinkage void poly1305_blocks_avx2(void *ctx, const u8 *inp, const size_t len, 21 | const u32 padbit); 22 | asmlinkage void poly1305_blocks_avx512(void *ctx, const u8 *inp, 23 | const size_t len, const u32 padbit); 24 | 25 | static bool poly1305_use_avx __ro_after_init; 26 | static bool poly1305_use_avx2 __ro_after_init; 27 | static bool poly1305_use_avx512 __ro_after_init; 28 | static bool *const poly1305_nobs[] __initconst = { 29 | &poly1305_use_avx, &poly1305_use_avx2, &poly1305_use_avx512 }; 30 | 31 | static void __init poly1305_fpu_init(void) 32 | { 33 | poly1305_use_avx = 34 | boot_cpu_has(X86_FEATURE_AVX) && 35 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL); 36 | poly1305_use_avx2 = 37 | boot_cpu_has(X86_FEATURE_AVX) && 38 | boot_cpu_has(X86_FEATURE_AVX2) && 39 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL); 40 | #ifndef COMPAT_CANNOT_USE_AVX512 41 | poly1305_use_avx512 = 42 | boot_cpu_has(X86_FEATURE_AVX) && 43 | boot_cpu_has(X86_FEATURE_AVX2) && 44 | boot_cpu_has(X86_FEATURE_AVX512F) && 45 | cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | 46 | XFEATURE_MASK_AVX512, NULL) && 47 | /* Skylake downclocks unacceptably much when using zmm. */ 48 | boot_cpu_data.x86_model != INTEL_FAM6_SKYLAKE_X; 49 | #endif 50 | } 51 | 52 | static inline bool poly1305_init_arch(void *ctx, 53 | const u8 key[POLY1305_KEY_SIZE]) 54 | { 55 | poly1305_init_x86_64(ctx, key); 56 | return true; 57 | } 58 | 59 | struct poly1305_arch_internal { 60 | union { 61 | struct { 62 | u32 h[5]; 63 | u32 is_base2_26; 64 | }; 65 | u64 hs[3]; 66 | }; 67 | u64 r[2]; 68 | u64 pad; 69 | struct { u32 r2, r1, r4, r3; } rn[9]; 70 | }; 71 | 72 | /* The AVX code uses base 2^26, while the scalar code uses base 2^64. If we hit 73 | * the unfortunate situation of using AVX and then having to go back to scalar 74 | * -- because the user is silly and has called the update function from two 75 | * separate contexts -- then we need to convert back to the original base before 76 | * proceeding. It is possible to reason that the initial reduction below is 77 | * sufficient given the implementation invariants. However, for an avoidance of 78 | * doubt and because this is not performance critical, we do the full reduction 79 | * anyway. 80 | */ 81 | static void convert_to_base2_64(void *ctx) 82 | { 83 | struct poly1305_arch_internal *state = ctx; 84 | u32 cy; 85 | 86 | if (!state->is_base2_26) 87 | return; 88 | 89 | cy = state->h[0] >> 26; state->h[0] &= 0x3ffffff; state->h[1] += cy; 90 | cy = state->h[1] >> 26; state->h[1] &= 0x3ffffff; state->h[2] += cy; 91 | cy = state->h[2] >> 26; state->h[2] &= 0x3ffffff; state->h[3] += cy; 92 | cy = state->h[3] >> 26; state->h[3] &= 0x3ffffff; state->h[4] += cy; 93 | state->hs[0] = ((u64)state->h[2] << 52) | ((u64)state->h[1] << 26) | state->h[0]; 94 | state->hs[1] = ((u64)state->h[4] << 40) | ((u64)state->h[3] << 14) | (state->h[2] >> 12); 95 | state->hs[2] = state->h[4] >> 24; 96 | #define ULT(a, b) ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)) 97 | cy = (state->hs[2] >> 2) + (state->hs[2] & ~3ULL); 98 | state->hs[2] &= 3; 99 | state->hs[0] += cy; 100 | state->hs[1] += (cy = ULT(state->hs[0], cy)); 101 | state->hs[2] += ULT(state->hs[1], cy); 102 | #undef ULT 103 | state->is_base2_26 = 0; 104 | } 105 | 106 | static inline bool poly1305_blocks_arch(void *ctx, const u8 *inp, 107 | size_t len, const u32 padbit, 108 | simd_context_t *simd_context) 109 | { 110 | struct poly1305_arch_internal *state = ctx; 111 | 112 | /* SIMD disables preemption, so relax after processing each page. */ 113 | BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE || 114 | PAGE_SIZE % POLY1305_BLOCK_SIZE); 115 | 116 | if (!IS_ENABLED(CONFIG_AS_AVX) || !poly1305_use_avx || 117 | (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) || 118 | !simd_use(simd_context)) { 119 | convert_to_base2_64(ctx); 120 | poly1305_blocks_x86_64(ctx, inp, len, padbit); 121 | return true; 122 | } 123 | 124 | for (;;) { 125 | const size_t bytes = min_t(size_t, len, PAGE_SIZE); 126 | 127 | if (IS_ENABLED(CONFIG_AS_AVX512) && poly1305_use_avx512) 128 | poly1305_blocks_avx512(ctx, inp, bytes, padbit); 129 | else if (IS_ENABLED(CONFIG_AS_AVX2) && poly1305_use_avx2) 130 | poly1305_blocks_avx2(ctx, inp, bytes, padbit); 131 | else 132 | poly1305_blocks_avx(ctx, inp, bytes, padbit); 133 | len -= bytes; 134 | if (!len) 135 | break; 136 | inp += bytes; 137 | simd_relax(simd_context); 138 | } 139 | 140 | return true; 141 | } 142 | 143 | static inline bool poly1305_emit_arch(void *ctx, u8 mac[POLY1305_MAC_SIZE], 144 | const u32 nonce[4], 145 | simd_context_t *simd_context) 146 | { 147 | struct poly1305_arch_internal *state = ctx; 148 | 149 | if (!IS_ENABLED(CONFIG_AS_AVX) || !poly1305_use_avx || 150 | !state->is_base2_26 || !simd_use(simd_context)) { 151 | convert_to_base2_64(ctx); 152 | poly1305_emit_x86_64(ctx, mac, nonce); 153 | } else 154 | poly1305_emit_avx(ctx, mac, nonce); 155 | return true; 156 | } 157 | -------------------------------------------------------------------------------- /src/crypto/zinc/poly1305/poly1305.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | * 5 | * Implementation of the Poly1305 message authenticator. 6 | * 7 | * Information: https://cr.yp.to/mac.html 8 | */ 9 | 10 | #include 11 | #include "../selftest/run.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #if defined(CONFIG_ZINC_ARCH_X86_64) 20 | #include "poly1305-x86_64-glue.c" 21 | #elif defined(CONFIG_ZINC_ARCH_ARM) || defined(CONFIG_ZINC_ARCH_ARM64) 22 | #include "poly1305-arm-glue.c" 23 | #elif defined(CONFIG_ZINC_ARCH_MIPS) || defined(CONFIG_ZINC_ARCH_MIPS64) 24 | #include "poly1305-mips-glue.c" 25 | #else 26 | static inline bool poly1305_init_arch(void *ctx, 27 | const u8 key[POLY1305_KEY_SIZE]) 28 | { 29 | return false; 30 | } 31 | static inline bool poly1305_blocks_arch(void *ctx, const u8 *input, 32 | size_t len, const u32 padbit, 33 | simd_context_t *simd_context) 34 | { 35 | return false; 36 | } 37 | static inline bool poly1305_emit_arch(void *ctx, u8 mac[POLY1305_MAC_SIZE], 38 | const u32 nonce[4], 39 | simd_context_t *simd_context) 40 | { 41 | return false; 42 | } 43 | static bool *const poly1305_nobs[] __initconst = { }; 44 | static void __init poly1305_fpu_init(void) 45 | { 46 | } 47 | #endif 48 | 49 | #if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__) 50 | #include "poly1305-donna64.c" 51 | #else 52 | #include "poly1305-donna32.c" 53 | #endif 54 | 55 | void poly1305_init(struct poly1305_ctx *ctx, const u8 key[POLY1305_KEY_SIZE]) 56 | { 57 | ctx->nonce[0] = get_unaligned_le32(&key[16]); 58 | ctx->nonce[1] = get_unaligned_le32(&key[20]); 59 | ctx->nonce[2] = get_unaligned_le32(&key[24]); 60 | ctx->nonce[3] = get_unaligned_le32(&key[28]); 61 | 62 | if (!poly1305_init_arch(ctx->opaque, key)) 63 | poly1305_init_generic(ctx->opaque, key); 64 | 65 | ctx->num = 0; 66 | } 67 | 68 | static inline void poly1305_blocks(void *ctx, const u8 *input, const size_t len, 69 | const u32 padbit, 70 | simd_context_t *simd_context) 71 | { 72 | if (!poly1305_blocks_arch(ctx, input, len, padbit, simd_context)) 73 | poly1305_blocks_generic(ctx, input, len, padbit); 74 | } 75 | 76 | static inline void poly1305_emit(void *ctx, u8 mac[POLY1305_KEY_SIZE], 77 | const u32 nonce[4], 78 | simd_context_t *simd_context) 79 | { 80 | if (!poly1305_emit_arch(ctx, mac, nonce, simd_context)) 81 | poly1305_emit_generic(ctx, mac, nonce); 82 | } 83 | 84 | void poly1305_update(struct poly1305_ctx *ctx, const u8 *input, size_t len, 85 | simd_context_t *simd_context) 86 | { 87 | const size_t num = ctx->num; 88 | size_t rem; 89 | 90 | if (num) { 91 | rem = POLY1305_BLOCK_SIZE - num; 92 | if (len < rem) { 93 | memcpy(ctx->data + num, input, len); 94 | ctx->num = num + len; 95 | return; 96 | } 97 | memcpy(ctx->data + num, input, rem); 98 | poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1, 99 | simd_context); 100 | input += rem; 101 | len -= rem; 102 | } 103 | 104 | rem = len % POLY1305_BLOCK_SIZE; 105 | len -= rem; 106 | 107 | if (len >= POLY1305_BLOCK_SIZE) { 108 | poly1305_blocks(ctx->opaque, input, len, 1, simd_context); 109 | input += len; 110 | } 111 | 112 | if (rem) 113 | memcpy(ctx->data, input, rem); 114 | 115 | ctx->num = rem; 116 | } 117 | 118 | void poly1305_final(struct poly1305_ctx *ctx, u8 mac[POLY1305_MAC_SIZE], 119 | simd_context_t *simd_context) 120 | { 121 | size_t num = ctx->num; 122 | 123 | if (num) { 124 | ctx->data[num++] = 1; 125 | while (num < POLY1305_BLOCK_SIZE) 126 | ctx->data[num++] = 0; 127 | poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0, 128 | simd_context); 129 | } 130 | 131 | poly1305_emit(ctx->opaque, mac, ctx->nonce, simd_context); 132 | 133 | memzero_explicit(ctx, sizeof(*ctx)); 134 | } 135 | 136 | #include "../selftest/poly1305.c" 137 | 138 | static bool nosimd __initdata = false; 139 | 140 | #ifndef COMPAT_ZINC_IS_A_MODULE 141 | int __init poly1305_mod_init(void) 142 | #else 143 | static int __init mod_init(void) 144 | #endif 145 | { 146 | if (!nosimd) 147 | poly1305_fpu_init(); 148 | if (!selftest_run("poly1305", poly1305_selftest, poly1305_nobs, 149 | ARRAY_SIZE(poly1305_nobs))) 150 | return -ENOTRECOVERABLE; 151 | return 0; 152 | } 153 | 154 | #ifdef COMPAT_ZINC_IS_A_MODULE 155 | static void __exit mod_exit(void) 156 | { 157 | } 158 | 159 | module_param(nosimd, bool, 0); 160 | module_init(mod_init); 161 | module_exit(mod_exit); 162 | MODULE_LICENSE("GPL v2"); 163 | MODULE_DESCRIPTION("Poly1305 one-time authenticator"); 164 | MODULE_AUTHOR("Jason A. Donenfeld "); 165 | #endif 166 | -------------------------------------------------------------------------------- /src/crypto/zinc/selftest/run.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _ZINC_SELFTEST_RUN_H 7 | #define _ZINC_SELFTEST_RUN_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | static inline bool selftest_run(const char *name, bool (*selftest)(void), 14 | bool *const nobs[], unsigned int nobs_len) 15 | { 16 | unsigned long set = 0, subset = 0, largest_subset = 0; 17 | unsigned int i; 18 | 19 | BUILD_BUG_ON(!__builtin_constant_p(nobs_len) || 20 | nobs_len >= BITS_PER_LONG); 21 | 22 | if (!IS_ENABLED(CONFIG_ZINC_SELFTEST)) 23 | return true; 24 | 25 | for (i = 0; i < nobs_len; ++i) 26 | set |= ((unsigned long)*nobs[i]) << i; 27 | 28 | do { 29 | for (i = 0; i < nobs_len; ++i) 30 | *nobs[i] = BIT(i) & subset; 31 | if (selftest()) 32 | largest_subset = max(subset, largest_subset); 33 | else 34 | pr_err("%s self-test combination 0x%lx: FAIL\n", name, 35 | subset); 36 | subset = (subset - set) & set; 37 | } while (subset); 38 | 39 | for (i = 0; i < nobs_len; ++i) 40 | *nobs[i] = BIT(i) & largest_subset; 41 | 42 | if (largest_subset == set) 43 | pr_info("%s self-tests: pass\n", name); 44 | 45 | return !WARN_ON(largest_subset != set); 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/device.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_DEVICE_H 7 | #define _WG_DEVICE_H 8 | 9 | #include "noise.h" 10 | #include "allowedips.h" 11 | #include "peerlookup.h" 12 | #include "cookie.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | struct wg_device; 22 | 23 | struct multicore_worker { 24 | void *ptr; 25 | struct work_struct work; 26 | }; 27 | 28 | struct crypt_queue { 29 | struct ptr_ring ring; 30 | struct multicore_worker __percpu *worker; 31 | int last_cpu; 32 | }; 33 | 34 | struct prev_queue { 35 | struct sk_buff *head, *tail, *peeked; 36 | struct { struct sk_buff *next, *prev; } empty; // Match first 2 members of struct sk_buff. 37 | atomic_t count; 38 | }; 39 | 40 | struct amnezia_config { 41 | bool advanced_security; 42 | u16 junk_packet_count; 43 | u16 junk_packet_min_size; 44 | u16 junk_packet_max_size; 45 | u16 init_packet_junk_size; 46 | u16 response_packet_junk_size; 47 | u32 init_packet_magic_header; 48 | u32 response_packet_magic_header; 49 | u32 cookie_packet_magic_header; 50 | u32 transport_packet_magic_header; 51 | }; 52 | 53 | struct wg_device { 54 | struct net_device *dev; 55 | struct crypt_queue encrypt_queue, decrypt_queue, handshake_queue; 56 | struct sock __rcu *sock4, *sock6; 57 | struct net __rcu *creating_net; 58 | struct noise_static_identity static_identity; 59 | struct workqueue_struct *packet_crypt_wq,*handshake_receive_wq, *handshake_send_wq; 60 | struct cookie_checker cookie_checker; 61 | struct pubkey_hashtable *peer_hashtable; 62 | struct index_hashtable *index_hashtable; 63 | struct allowedips peer_allowedips; 64 | struct mutex device_update_lock, socket_update_lock; 65 | struct list_head device_list, peer_list; 66 | struct amnezia_config advanced_security_config; 67 | atomic_t handshake_queue_len; 68 | unsigned int num_peers, device_update_gen; 69 | u32 fwmark; 70 | u16 incoming_port; 71 | }; 72 | 73 | int wg_device_init(void); 74 | void wg_device_uninit(void); 75 | int wg_device_handle_post_config(struct net_device *dev, struct amnezia_config *asc); 76 | 77 | #endif /* _WG_DEVICE_H */ 78 | -------------------------------------------------------------------------------- /src/dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="amneziawg" 2 | PACKAGE_VERSION="1.0.0" 3 | AUTOINSTALL=yes 4 | REMAKE_INITRD=yes 5 | 6 | PRE_BUILD="prepare-sources.sh $kernelver" 7 | POST_BUILD="cleanup-sources.sh" 8 | MAKE[0]="make -C /var/lib/dkms/amneziawg/${PACKAGE_VERSION}/build" 9 | 10 | BUILT_MODULE_NAME="amneziawg" 11 | DEST_MODULE_LOCATION="/kernel/net" 12 | 13 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | * Copyright (C) 2024 AmneziaVPN . All Rights Reserved. 5 | */ 6 | 7 | #include "version.h" 8 | #include "device.h" 9 | #include "noise.h" 10 | #include "queueing.h" 11 | #include "ratelimiter.h" 12 | #include "netlink.h" 13 | #include "uapi/wireguard.h" 14 | #include "crypto/zinc.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | static int __init wg_mod_init(void) 22 | { 23 | int ret; 24 | 25 | if ((ret = chacha20_mod_init()) || (ret = poly1305_mod_init()) || 26 | (ret = chacha20poly1305_mod_init()) || (ret = blake2s_mod_init()) || 27 | (ret = curve25519_mod_init())) 28 | return ret; 29 | 30 | ret = wg_allowedips_slab_init(); 31 | if (ret < 0) 32 | goto err_allowedips; 33 | 34 | #ifdef DEBUG 35 | ret = -ENOTRECOVERABLE; 36 | if (!wg_allowedips_selftest() || !wg_packet_counter_selftest() || 37 | !wg_ratelimiter_selftest()) 38 | goto err_peer; 39 | #endif 40 | wg_noise_init(); 41 | 42 | ret = wg_peer_init(); 43 | if (ret < 0) 44 | goto err_peer; 45 | 46 | ret = wg_device_init(); 47 | if (ret < 0) 48 | goto err_device; 49 | 50 | ret = wg_genetlink_init(); 51 | if (ret < 0) 52 | goto err_netlink; 53 | 54 | pr_info("AmneziaWG " WIREGUARD_VERSION " loaded. See amnezia.org for information.\n"); 55 | pr_info("Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved.\n"); 56 | pr_info("Copyright (C) 2024 AmneziaVPN . All Rights Reserved.\n"); 57 | 58 | return 0; 59 | 60 | err_netlink: 61 | wg_device_uninit(); 62 | err_device: 63 | wg_peer_uninit(); 64 | err_peer: 65 | wg_allowedips_slab_uninit(); 66 | err_allowedips: 67 | return ret; 68 | } 69 | 70 | static void __exit wg_mod_exit(void) 71 | { 72 | wg_genetlink_uninit(); 73 | wg_device_uninit(); 74 | wg_peer_uninit(); 75 | wg_allowedips_slab_uninit(); 76 | } 77 | 78 | module_param(bogus_endpoints, int, 0600); 79 | module_param(bogus_endpoints_prefix, charp, 0600); 80 | module_param(bogus_endpoints_prefix6, charp, 0600); 81 | module_init(wg_mod_init); 82 | module_exit(wg_mod_exit); 83 | MODULE_LICENSE("GPL v2"); 84 | MODULE_DESCRIPTION("AmneziaWG secure network tunnel"); 85 | MODULE_AUTHOR("Jason A. Donenfeld , AmneziaVPN "); 86 | MODULE_VERSION(WIREGUARD_VERSION); 87 | MODULE_ALIAS_RTNL_LINK(KBUILD_MODNAME); 88 | MODULE_ALIAS_GENL_FAMILY(WG_GENL_NAME); 89 | MODULE_INFO(intree, "Y"); 90 | -------------------------------------------------------------------------------- /src/messages.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_MESSAGES_H 7 | #define _WG_MESSAGES_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | enum noise_lengths { 18 | NOISE_PUBLIC_KEY_LEN = CURVE25519_KEY_SIZE, 19 | NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEY_SIZE, 20 | NOISE_TIMESTAMP_LEN = sizeof(u64) + sizeof(u32), 21 | NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAG_SIZE, 22 | NOISE_HASH_LEN = BLAKE2S_HASH_SIZE 23 | }; 24 | 25 | #define noise_encrypted_len(plain_len) ((plain_len) + NOISE_AUTHTAG_LEN) 26 | 27 | enum cookie_values { 28 | COOKIE_SECRET_MAX_AGE = 2 * 60, 29 | COOKIE_SECRET_LATENCY = 5, 30 | COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCE_SIZE, 31 | COOKIE_LEN = 16 32 | }; 33 | 34 | enum counter_values { 35 | COUNTER_BITS_TOTAL = 8192, 36 | COUNTER_REDUNDANT_BITS = BITS_PER_LONG, 37 | COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS 38 | }; 39 | 40 | enum limits { 41 | REKEY_AFTER_MESSAGES = 1ULL << 60, 42 | REJECT_AFTER_MESSAGES = U64_MAX - COUNTER_WINDOW_SIZE - 1, 43 | REKEY_TIMEOUT = 5, 44 | REKEY_TIMEOUT_JITTER_MAX_JIFFIES = HZ / 3, 45 | REKEY_AFTER_TIME = 120, 46 | REJECT_AFTER_TIME = 180, 47 | INITIATIONS_PER_SECOND = 50, 48 | MAX_PEERS_PER_DEVICE = 1U << 20, 49 | KEEPALIVE_TIMEOUT = 10, 50 | MAX_TIMER_HANDSHAKES = 90 / REKEY_TIMEOUT, 51 | MAX_QUEUED_INCOMING_HANDSHAKES = 4096, /* TODO: replace this with DQL */ 52 | MAX_STAGED_PACKETS = 128, 53 | MAX_QUEUED_PACKETS = 1024 /* TODO: replace this with DQL */ 54 | }; 55 | 56 | enum message_type { 57 | MESSAGE_INVALID = 0, 58 | MESSAGE_HANDSHAKE_INITIATION = 1, 59 | MESSAGE_HANDSHAKE_RESPONSE = 2, 60 | MESSAGE_HANDSHAKE_COOKIE = 3, 61 | MESSAGE_DATA = 4 62 | }; 63 | 64 | struct message_header { 65 | /* The actual layout of this that we want is: 66 | * u8 type 67 | * u8 reserved_zero[3] 68 | * 69 | * But it turns out that by encoding this as little endian, 70 | * we achieve the same thing, and it makes checking faster. 71 | */ 72 | __le32 type; 73 | }; 74 | 75 | struct message_macs { 76 | u8 mac1[COOKIE_LEN]; 77 | u8 mac2[COOKIE_LEN]; 78 | }; 79 | 80 | struct message_handshake_initiation { 81 | struct message_header header; 82 | __le32 sender_index; 83 | u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; 84 | u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)]; 85 | u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)]; 86 | struct message_macs macs; 87 | }; 88 | 89 | struct message_handshake_response { 90 | struct message_header header; 91 | __le32 sender_index; 92 | __le32 receiver_index; 93 | u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; 94 | u8 encrypted_nothing[noise_encrypted_len(0)]; 95 | struct message_macs macs; 96 | }; 97 | 98 | struct message_handshake_cookie { 99 | struct message_header header; 100 | __le32 receiver_index; 101 | u8 nonce[COOKIE_NONCE_LEN]; 102 | u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)]; 103 | }; 104 | 105 | struct message_data { 106 | struct message_header header; 107 | __le32 key_idx; 108 | __le64 counter; 109 | u8 encrypted_data[]; 110 | }; 111 | 112 | #define message_data_len(plain_len) \ 113 | (noise_encrypted_len(plain_len) + sizeof(struct message_data)) 114 | 115 | enum message_alignments { 116 | MESSAGE_PADDING_MULTIPLE = 16, 117 | MESSAGE_MINIMUM_LENGTH = message_data_len(0) 118 | }; 119 | 120 | enum message_size { 121 | MESSAGE_INITIATION_SIZE = sizeof(struct message_handshake_initiation), 122 | MESSAGE_RESPONSE_SIZE = sizeof(struct message_handshake_response), 123 | MESSAGE_COOKIE_REPLY_SIZE = sizeof(struct message_handshake_cookie), 124 | MESSAGE_TRANSPORT_SIZE = sizeof(struct message_data), 125 | MESSAGE_MAX_SIZE = 65535 126 | }; 127 | 128 | #define SKB_TYPE_LE32(skb) (((struct message_header *)(skb)->data)->type) 129 | 130 | #define SKB_HEADER_LEN \ 131 | (max(sizeof(struct iphdr), sizeof(struct ipv6hdr)) + \ 132 | sizeof(struct udphdr) + NET_SKB_PAD) 133 | #define DATA_PACKET_HEAD_ROOM \ 134 | ALIGN(sizeof(struct message_data) + SKB_HEADER_LEN, 4) 135 | 136 | enum { HANDSHAKE_DSCP = 0x88 /* AF41, plus 00 ECN */ }; 137 | 138 | #endif /* _WG_MESSAGES_H */ 139 | -------------------------------------------------------------------------------- /src/netlink.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_NETLINK_H 7 | #define _WG_NETLINK_H 8 | 9 | #include "peer.h" 10 | #include "noise.h" 11 | 12 | extern int bogus_endpoints; 13 | extern char *bogus_endpoints_prefix; 14 | extern char *bogus_endpoints_prefix6; 15 | 16 | int wg_genl_mcast_peer_unknown(struct wg_device *wg, const u8 pubkey[NOISE_PUBLIC_KEY_LEN], 17 | struct endpoint *endpoint, bool advanced_security); 18 | int wg_genetlink_init(void); 19 | void wg_genetlink_uninit(void); 20 | 21 | #endif /* _WG_NETLINK_H */ 22 | -------------------------------------------------------------------------------- /src/noise.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | #ifndef _WG_NOISE_H 6 | #define _WG_NOISE_H 7 | 8 | #include "messages.h" 9 | #include "peerlookup.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | struct noise_replay_counter { 19 | u64 counter; 20 | spinlock_t lock; 21 | unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG]; 22 | }; 23 | 24 | struct noise_symmetric_key { 25 | u8 key[NOISE_SYMMETRIC_KEY_LEN]; 26 | u64 birthdate; 27 | bool is_valid; 28 | }; 29 | 30 | struct noise_keypair { 31 | struct index_hashtable_entry entry; 32 | struct noise_symmetric_key sending; 33 | atomic64_t sending_counter; 34 | struct noise_symmetric_key receiving; 35 | struct noise_replay_counter receiving_counter; 36 | __le32 remote_index; 37 | bool i_am_the_initiator; 38 | struct kref refcount; 39 | struct rcu_head rcu; 40 | u64 internal_id; 41 | }; 42 | 43 | struct noise_keypairs { 44 | struct noise_keypair __rcu *current_keypair; 45 | struct noise_keypair __rcu *previous_keypair; 46 | struct noise_keypair __rcu *next_keypair; 47 | spinlock_t keypair_update_lock; 48 | }; 49 | 50 | struct noise_static_identity { 51 | u8 static_public[NOISE_PUBLIC_KEY_LEN]; 52 | u8 static_private[NOISE_PUBLIC_KEY_LEN]; 53 | struct rw_semaphore lock; 54 | bool has_identity; 55 | }; 56 | 57 | enum noise_handshake_state { 58 | HANDSHAKE_ZEROED, 59 | HANDSHAKE_CREATED_INITIATION, 60 | HANDSHAKE_CONSUMED_INITIATION, 61 | HANDSHAKE_CREATED_RESPONSE, 62 | HANDSHAKE_CONSUMED_RESPONSE 63 | }; 64 | 65 | struct noise_handshake { 66 | struct index_hashtable_entry entry; 67 | 68 | enum noise_handshake_state state; 69 | u64 last_initiation_consumption; 70 | 71 | struct noise_static_identity *static_identity; 72 | 73 | u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; 74 | u8 remote_static[NOISE_PUBLIC_KEY_LEN]; 75 | u8 remote_ephemeral[NOISE_PUBLIC_KEY_LEN]; 76 | u8 precomputed_static_static[NOISE_PUBLIC_KEY_LEN]; 77 | 78 | u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]; 79 | 80 | u8 hash[NOISE_HASH_LEN]; 81 | u8 chaining_key[NOISE_HASH_LEN]; 82 | 83 | u8 latest_timestamp[NOISE_TIMESTAMP_LEN]; 84 | __le32 remote_index; 85 | 86 | /* Protects all members except the immutable (after noise_handshake_ 87 | * init): remote_static, precomputed_static_static, static_identity. 88 | */ 89 | struct rw_semaphore lock; 90 | }; 91 | 92 | struct wg_device; 93 | 94 | void wg_noise_init(void); 95 | void wg_noise_handshake_init(struct noise_handshake *handshake, 96 | struct noise_static_identity *static_identity, 97 | const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], 98 | const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], 99 | struct wg_peer *peer); 100 | void wg_noise_handshake_clear(struct noise_handshake *handshake); 101 | static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns) 102 | { 103 | atomic64_set(handshake_ns, ktime_get_coarse_boottime_ns() - 104 | (u64)(REKEY_TIMEOUT + 1) * NSEC_PER_SEC); 105 | } 106 | 107 | void wg_noise_keypair_put(struct noise_keypair *keypair, bool unreference_now); 108 | struct noise_keypair *wg_noise_keypair_get(struct noise_keypair *keypair); 109 | void wg_noise_keypairs_clear(struct noise_keypairs *keypairs); 110 | bool wg_noise_received_with_keypair(struct noise_keypairs *keypairs, 111 | struct noise_keypair *received_keypair); 112 | void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer); 113 | 114 | void wg_noise_set_static_identity_private_key( 115 | struct noise_static_identity *static_identity, 116 | const u8 private_key[NOISE_PUBLIC_KEY_LEN]); 117 | void wg_noise_precompute_static_static(struct wg_peer *peer); 118 | 119 | bool 120 | wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst, 121 | struct noise_handshake *handshake, u32 message_type); 122 | struct wg_peer * 123 | wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src, 124 | struct wg_device *wg, struct sk_buff *skb); 125 | 126 | bool wg_noise_handshake_create_response(struct message_handshake_response *dst, 127 | struct noise_handshake *handshake, u32 message_type); 128 | struct wg_peer * 129 | wg_noise_handshake_consume_response(struct message_handshake_response *src, 130 | struct wg_device *wg); 131 | 132 | bool wg_noise_handshake_begin_session(struct noise_handshake *handshake, 133 | struct noise_keypairs *keypairs); 134 | 135 | #endif /* _WG_NOISE_H */ 136 | -------------------------------------------------------------------------------- /src/patches/003-fix-for-non-linear-skb.patch: -------------------------------------------------------------------------------- 1 | diff --git receive.c receive.c 2 | index b3e0040..e42006d 100644 3 | --- receive.c 4 | +++ receive.c 5 | @@ -54,10 +54,9 @@ static size_t validate_header_len(struct sk_buff *skb, struct wg_device *wg) 6 | return 0; 7 | } 8 | 9 | -void prepare_advanced_secured_message(struct sk_buff *skb, struct wg_device *wg) 10 | +static void prepare_advanced_secured_message(struct sk_buff *skb, struct wg_device *wg) 11 | { 12 | - u32 assumed_type = SKB_TYPE_LE32(skb); 13 | - u32 assumed_offset; 14 | + u32 assumed_type, assumed_offset; 15 | 16 | if (wg->advanced_security_config.advanced_security) { 17 | if (skb->len == MESSAGE_INITIATION_SIZE + wg->advanced_security_config.init_packet_junk_size) { 18 | @@ -72,6 +71,11 @@ void prepare_advanced_secured_message(struct sk_buff *skb, struct wg_device *wg) 19 | if (unlikely(assumed_offset <= 0) || unlikely(!pskb_may_pull(skb, assumed_offset))) 20 | return; 21 | 22 | + if (skb_is_nonlinear(skb) && unlikely(skb_linearize(skb))) { 23 | + net_dbg_skb_ratelimited("%s: non-linear sk_buff from %pISpfsc could not be linearized, dropping packet\n", 24 | + wg->dev->name, skb); 25 | + return; 26 | + } 27 | 28 | skb_pull(skb, assumed_offset); 29 | 30 | diff --git send.c send.c 31 | index d65e58b..d6c27f1 100644 32 | --- send.c 33 | +++ send.c 34 | @@ -20,7 +20,7 @@ 35 | #include 36 | #include 37 | 38 | -u32 wg_get_random_u32_inclusive(u32 floor, u32 ceil) 39 | +static u32 wg_get_random_u32_inclusive(u32 floor, u32 ceil) 40 | { 41 | u32 diff = ceil - floor + 1; 42 | return floor + (get_random_u32() % diff); 43 | @@ -68,7 +60,7 @@ static void wg_packet_send_handshake_initiation(struct wg_peer *peer) 44 | kfree(buffer); 45 | } 46 | 47 | - net_dbg_ratelimited("%s: Initiation magic header: %llu\n", 48 | + net_dbg_ratelimited("%s: Initiation magic header: %u\n", 49 | peer->device->dev->name, 50 | peer->advanced_security ? wg->advanced_security_config.init_packet_magic_header : 51 | MESSAGE_HANDSHAKE_INITIATION); 52 | -------------------------------------------------------------------------------- /src/patches/005-bogus-endpoints-parameter.patch: -------------------------------------------------------------------------------- 1 | diff --git main.c main.c 2 | index 8e5affd..4c321d4 100644 3 | --- main.c 4 | +++ main.c 5 | @@ -75,6 +75,7 @@ static void __exit wg_mod_exit(void) 6 | wg_allowedips_slab_uninit(); 7 | } 8 | 9 | +module_param(bogus_endpoints, int, 0600); 10 | module_init(wg_mod_init); 11 | module_exit(wg_mod_exit); 12 | MODULE_LICENSE("GPL v2"); 13 | diff --git netlink.c netlink.c 14 | index af0ba3a..7d9f3d1 100644 15 | --- netlink.c 16 | +++ netlink.c 17 | @@ -14,6 +14,9 @@ 18 | #include 19 | #include 20 | #include 21 | +#include 22 | + 23 | +int bogus_endpoints = 0; 24 | 25 | static struct genl_family genl_family; 26 | 27 | @@ -164,18 +167,27 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx) 28 | nla_put_u32(skb, WGPEER_A_PROTOCOL_VERSION, 1)) 29 | goto err; 30 | 31 | +#ifndef OMIT_ENDPOINTS 32 | read_lock_bh(&peer->endpoint_lock); 33 | - if (peer->endpoint.addr.sa_family == AF_INET) 34 | - fail = nla_put(skb, WGPEER_A_ENDPOINT, 35 | - sizeof(peer->endpoint.addr4), 36 | - &peer->endpoint.addr4); 37 | - else if (peer->endpoint.addr.sa_family == AF_INET6) 38 | - fail = nla_put(skb, WGPEER_A_ENDPOINT, 39 | - sizeof(peer->endpoint.addr6), 40 | - &peer->endpoint.addr6); 41 | + if (peer->endpoint.addr.sa_family == AF_INET) { 42 | + struct sockaddr_in addr4 = peer->endpoint.addr4; 43 | + 44 | + if (bogus_endpoints) 45 | + addr4.sin_addr.s_addr = get_random_u32(); 46 | + 47 | + fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr4), &addr4); 48 | + } else if (peer->endpoint.addr.sa_family == AF_INET6) { 49 | + struct sockaddr_in6 addr6 = peer->endpoint.addr6; 50 | + 51 | + if (bogus_endpoints) 52 | + get_random_bytes(&addr6.sin6_addr.s6_addr, sizeof(addr6.sin6_addr.s6_addr)); 53 | + 54 | + fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr6), &addr6); 55 | + } 56 | read_unlock_bh(&peer->endpoint_lock); 57 | if (fail) 58 | goto err; 59 | +#endif 60 | allowedips_node = 61 | list_first_entry_or_null(&peer->allowedips_list, 62 | struct allowedips_node, peer_list); 63 | diff --git netlink.h netlink.h 64 | index c1ea75a..0fcc344 100644 65 | --- netlink.h 66 | +++ netlink.h 67 | @@ -9,6 +9,8 @@ 68 | #include "peer.h" 69 | #include "noise.h" 70 | 71 | +extern int bogus_endpoints; 72 | + 73 | int wg_genl_mcast_peer_unknown(struct wg_device *wg, const u8 pubkey[NOISE_PUBLIC_KEY_LEN], 74 | struct endpoint *endpoint, bool advanced_security); 75 | int wg_genetlink_init(void); 76 | -------------------------------------------------------------------------------- /src/patches/006-bogus-endpoints-prefixes.patch: -------------------------------------------------------------------------------- 1 | diff --git main.c main.c 2 | index 4c321d4..c9c7057 100644 3 | --- main.c 4 | +++ main.c 5 | @@ -76,6 +76,8 @@ static void __exit wg_mod_exit(void) 6 | } 7 | 8 | module_param(bogus_endpoints, int, 0600); 9 | +module_param(bogus_endpoints_prefix, charp, 0600); 10 | +module_param(bogus_endpoints_prefix6, charp, 0600); 11 | module_init(wg_mod_init); 12 | module_exit(wg_mod_exit); 13 | MODULE_LICENSE("GPL v2"); 14 | diff --git netlink.c netlink.c 15 | index 7d9f3d1..5043bb3 100644 16 | --- netlink.c 17 | +++ netlink.c 18 | @@ -15,8 +15,20 @@ 19 | #include 20 | #include 21 | #include 22 | +#include 23 | + 24 | +#include 25 | +#include 26 | +#include 27 | +#include 28 | +#include 29 | +#include 30 | +#include 31 | +#include 32 | 33 | int bogus_endpoints = 0; 34 | +char *bogus_endpoints_prefix = "127.0.0.0/8"; 35 | +char *bogus_endpoints_prefix6 = "ff80::/16"; 36 | 37 | static struct genl_family genl_family; 38 | 39 | @@ -114,17 +126,159 @@ struct dump_ctx { 40 | 41 | #define DUMP_CTX(cb) ((struct dump_ctx *)(cb)->args) 42 | 43 | +struct ipv4_prefix { 44 | + __be32 prefix; 45 | + int prefix_len; 46 | +}; 47 | + 48 | +struct ipv6_prefix { 49 | + u8 prefix[16]; 50 | + int prefix_len; 51 | +}; 52 | + 53 | +static inline int parse_ipv4_prefix(const char *prefix_str, struct ipv4_prefix *prefix) 54 | +{ 55 | + char addr_str[INET_ADDRSTRLEN]; 56 | + const char *slash; 57 | + int ret; 58 | + u8 addr[4]; 59 | + 60 | + if (!prefix_str || !prefix) 61 | + return -EINVAL; 62 | + 63 | + slash = strchr(prefix_str, '/'); 64 | + if (!slash) 65 | + return -EINVAL; 66 | + 67 | + if (slash - prefix_str >= INET_ADDRSTRLEN) 68 | + return -EINVAL; 69 | + 70 | + strncpy(addr_str, prefix_str, slash - prefix_str); 71 | + addr_str[slash - prefix_str] = '\0'; 72 | + 73 | + ret = kstrtoint(slash + 1, 10, &prefix->prefix_len); 74 | + if (ret < 0) 75 | + return ret; 76 | + 77 | + if (prefix->prefix_len < 0 || prefix->prefix_len > 32) 78 | + return -EINVAL; 79 | + 80 | + ret = in4_pton(addr_str, -1, addr, '\0', NULL); 81 | + if (ret != 1) 82 | + return -EINVAL; 83 | + 84 | + prefix->prefix = *(__be32 *)addr; 85 | + 86 | + return 0; 87 | +} 88 | + 89 | +static inline int generate_ipv4_address_with_prefix(const struct ipv4_prefix *prefix, __be32 *addr) 90 | +{ 91 | + u32 prefix_host_order, random_suffix, full_addr_host_order; 92 | + u32 suffix_mask; 93 | + 94 | + if (!prefix || !addr) 95 | + return -EINVAL; 96 | + 97 | + prefix_host_order = ntohl(prefix->prefix); 98 | + 99 | + if (prefix->prefix_len == 32) { 100 | + suffix_mask = 0; 101 | + } else { 102 | + suffix_mask = (1U << (32 - prefix->prefix_len)) - 1; 103 | + } 104 | + 105 | + get_random_bytes(&random_suffix, sizeof(random_suffix)); 106 | + random_suffix &= suffix_mask; 107 | + full_addr_host_order = (prefix_host_order & (~suffix_mask)) | random_suffix; 108 | + *addr = htonl(full_addr_host_order); 109 | + 110 | + return 0; 111 | +} 112 | + 113 | +static inline int parse_ipv6_prefix(const char *prefix_str, struct ipv6_prefix *prefix) 114 | +{ 115 | + char addr_str[INET6_ADDRSTRLEN]; 116 | + const char *slash; 117 | + int ret; 118 | + 119 | + if (!prefix_str || !prefix) 120 | + return -EINVAL; 121 | + 122 | + slash = strchr(prefix_str, '/'); 123 | + if (!slash) 124 | + return -EINVAL; 125 | + 126 | + if (slash - prefix_str >= INET6_ADDRSTRLEN) 127 | + return -EINVAL; 128 | + 129 | + strncpy(addr_str, prefix_str, slash - prefix_str); 130 | + addr_str[slash - prefix_str] = '\0'; 131 | + 132 | + ret = kstrtoint(slash + 1, 10, &prefix->prefix_len); 133 | + if (ret < 0) 134 | + return ret; 135 | + 136 | + if (prefix->prefix_len < 0 || prefix->prefix_len > 128) 137 | + return -EINVAL; 138 | + 139 | + ret = in6_pton(addr_str, -1, prefix->prefix, '\0', NULL); 140 | + if (ret != 1) 141 | + return -EINVAL; 142 | + 143 | + return 0; 144 | +} 145 | + 146 | +static inline int generate_ipv6_address_with_prefix(const struct ipv6_prefix *prefix, u8 *addr) 147 | +{ 148 | + int prefix_bytes, prefix_bits; 149 | + u8 mask; 150 | + 151 | + if (!prefix || !addr) 152 | + return -EINVAL; 153 | + 154 | + memcpy(addr, prefix->prefix, 16); 155 | + 156 | + prefix_bytes = prefix->prefix_len / 8; 157 | + prefix_bits = prefix->prefix_len % 8; 158 | + 159 | + if (prefix_bytes < 16) { 160 | + get_random_bytes(addr + prefix_bytes, 16 - prefix_bytes); 161 | + 162 | + if (prefix_bits != 0) { 163 | + mask = (u8)(0xFF << (8 - prefix_bits)); 164 | + addr[prefix_bytes] &= mask; 165 | + addr[prefix_bytes] |= get_random_u8() & ~mask; 166 | + } 167 | + } 168 | + 169 | + return 0; 170 | +} 171 | + 172 | static int 173 | get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx) 174 | { 175 | 176 | struct nlattr *allowedips_nest, *peer_nest = nla_nest_start(skb, 0); 177 | struct allowedips_node *allowedips_node = ctx->next_allowedip; 178 | + struct ipv4_prefix prefix; 179 | + struct ipv6_prefix prefix6; 180 | bool fail; 181 | + int ret; 182 | 183 | if (!peer_nest) 184 | return -EMSGSIZE; 185 | 186 | + if (bogus_endpoints) { 187 | + ret = parse_ipv4_prefix(bogus_endpoints_prefix, &prefix); 188 | + if (ret < 0) 189 | + return ret; 190 | + 191 | + ret = parse_ipv6_prefix(bogus_endpoints_prefix6, &prefix6); 192 | + if (ret < 0) 193 | + return ret; 194 | + } 195 | + 196 | fail = nla_put_u32(skb, WGPEER_A_FLAGS, WGPEER_F_HAS_ADVANCED_SECURITY); 197 | if (fail) 198 | goto err; 199 | @@ -172,15 +326,21 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx) 200 | if (peer->endpoint.addr.sa_family == AF_INET) { 201 | struct sockaddr_in addr4 = peer->endpoint.addr4; 202 | 203 | - if (bogus_endpoints) 204 | - addr4.sin_addr.s_addr = get_random_u32(); 205 | + if (bogus_endpoints) { 206 | + ret = generate_ipv4_address_with_prefix(&prefix, &addr4.sin_addr.s_addr); 207 | + if (ret < 0) 208 | + goto err; 209 | + } 210 | 211 | fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr4), &addr4); 212 | } else if (peer->endpoint.addr.sa_family == AF_INET6) { 213 | struct sockaddr_in6 addr6 = peer->endpoint.addr6; 214 | 215 | - if (bogus_endpoints) 216 | - get_random_bytes(&addr6.sin6_addr.s6_addr, sizeof(addr6.sin6_addr.s6_addr)); 217 | + if (bogus_endpoints) { 218 | + ret = generate_ipv6_address_with_prefix(&prefix6, addr6.sin6_addr.s6_addr); 219 | + if (ret < 0) 220 | + goto err; 221 | + } 222 | 223 | fail = nla_put(skb, WGPEER_A_ENDPOINT, sizeof(addr6), &addr6); 224 | } 225 | diff --git netlink.h netlink.h 226 | index 0fcc344..e7fdab7 100644 227 | --- netlink.h 228 | +++ netlink.h 229 | @@ -10,6 +10,8 @@ 230 | #include "noise.h" 231 | 232 | extern int bogus_endpoints; 233 | +extern char *bogus_endpoints_prefix; 234 | +extern char *bogus_endpoints_prefix6; 235 | 236 | int wg_genl_mcast_peer_unknown(struct wg_device *wg, const u8 pubkey[NOISE_PUBLIC_KEY_LEN], 237 | struct endpoint *endpoint, bool advanced_security); 238 | -------------------------------------------------------------------------------- /src/patches/007-random-bytes-fix.patch: -------------------------------------------------------------------------------- 1 | diff --git netlink.c netlink.c 2 | index 5043bb3..29049ba 100644 3 | --- netlink.c 4 | +++ netlink.c 5 | @@ -232,7 +232,7 @@ static inline int parse_ipv6_prefix(const char *prefix_str, struct ipv6_prefix * 6 | static inline int generate_ipv6_address_with_prefix(const struct ipv6_prefix *prefix, u8 *addr) 7 | { 8 | int prefix_bytes, prefix_bits; 9 | - u8 mask; 10 | + u8 mask, random_byte; 11 | 12 | if (!prefix || !addr) 13 | return -EINVAL; 14 | @@ -246,9 +246,10 @@ static inline int generate_ipv6_address_with_prefix(const struct ipv6_prefix *pr 15 | get_random_bytes(addr + prefix_bytes, 16 - prefix_bytes); 16 | 17 | if (prefix_bits != 0) { 18 | + get_random_bytes(&random_byte, sizeof(random_byte)); 19 | mask = (u8)(0xFF << (8 - prefix_bits)); 20 | addr[prefix_bytes] &= mask; 21 | - addr[prefix_bytes] |= get_random_u8() & ~mask; 22 | + addr[prefix_bytes] |= random_byte & ~mask; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/peer.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_PEER_H 7 | #define _WG_PEER_H 8 | 9 | #include "device.h" 10 | #include "noise.h" 11 | #include "cookie.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | struct wg_device; 20 | 21 | struct endpoint { 22 | union { 23 | struct sockaddr addr; 24 | struct sockaddr_in addr4; 25 | struct sockaddr_in6 addr6; 26 | }; 27 | union { 28 | struct { 29 | struct in_addr src4; 30 | /* Essentially the same as addr6->scope_id */ 31 | int src_if4; 32 | }; 33 | struct in6_addr src6; 34 | }; 35 | }; 36 | 37 | struct wg_peer { 38 | struct wg_device *device; 39 | struct prev_queue tx_queue, rx_queue; 40 | struct sk_buff_head staged_packet_queue; 41 | int serial_work_cpu; 42 | bool is_dead; 43 | struct noise_keypairs keypairs; 44 | struct endpoint endpoint; 45 | struct dst_cache endpoint_cache; 46 | rwlock_t endpoint_lock; 47 | struct noise_handshake handshake; 48 | atomic64_t last_sent_handshake; 49 | struct work_struct transmit_handshake_work, clear_peer_work, transmit_packet_work; 50 | struct cookie latest_cookie; 51 | struct hlist_node pubkey_hash; 52 | u64 rx_bytes, tx_bytes; 53 | struct timer_list timer_retransmit_handshake, timer_send_keepalive; 54 | struct timer_list timer_new_handshake, timer_zero_key_material; 55 | struct timer_list timer_persistent_keepalive; 56 | unsigned int timer_handshake_attempts; 57 | u16 persistent_keepalive_interval; 58 | bool timer_need_another_keepalive; 59 | bool sent_lastminute_handshake; 60 | struct timespec64 walltime_last_handshake; 61 | struct kref refcount; 62 | struct rcu_head rcu; 63 | struct list_head peer_list; 64 | struct list_head allowedips_list; 65 | struct napi_struct napi; 66 | u64 internal_id; 67 | bool advanced_security; 68 | }; 69 | 70 | struct wg_peer *wg_peer_create(struct wg_device *wg, 71 | const u8 public_key[NOISE_PUBLIC_KEY_LEN], 72 | const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]); 73 | 74 | struct wg_peer *__must_check wg_peer_get_maybe_zero(struct wg_peer *peer); 75 | static inline struct wg_peer *wg_peer_get(struct wg_peer *peer) 76 | { 77 | kref_get(&peer->refcount); 78 | return peer; 79 | } 80 | void wg_peer_put(struct wg_peer *peer); 81 | void wg_peer_remove(struct wg_peer *peer); 82 | void wg_peer_remove_all(struct wg_device *wg); 83 | 84 | int wg_peer_init(void); 85 | void wg_peer_uninit(void); 86 | 87 | #endif /* _WG_PEER_H */ 88 | -------------------------------------------------------------------------------- /src/peerlookup.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include "peerlookup.h" 7 | #include "peer.h" 8 | #include "noise.h" 9 | 10 | static struct hlist_head *pubkey_bucket(struct pubkey_hashtable *table, 11 | const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) 12 | { 13 | /* siphash gives us a secure 64bit number based on a random key. Since 14 | * the bits are uniformly distributed, we can then mask off to get the 15 | * bits we need. 16 | */ 17 | const u64 hash = siphash(pubkey, NOISE_PUBLIC_KEY_LEN, &table->key); 18 | 19 | return &table->hashtable[hash & (HASH_SIZE(table->hashtable) - 1)]; 20 | } 21 | 22 | struct pubkey_hashtable *wg_pubkey_hashtable_alloc(void) 23 | { 24 | struct pubkey_hashtable *table = kvmalloc(sizeof(*table), GFP_KERNEL); 25 | 26 | if (!table) 27 | return NULL; 28 | 29 | get_random_bytes(&table->key, sizeof(table->key)); 30 | hash_init(table->hashtable); 31 | mutex_init(&table->lock); 32 | return table; 33 | } 34 | 35 | void wg_pubkey_hashtable_add(struct pubkey_hashtable *table, 36 | struct wg_peer *peer) 37 | { 38 | mutex_lock(&table->lock); 39 | hlist_add_head_rcu(&peer->pubkey_hash, 40 | pubkey_bucket(table, peer->handshake.remote_static)); 41 | mutex_unlock(&table->lock); 42 | } 43 | 44 | void wg_pubkey_hashtable_remove(struct pubkey_hashtable *table, 45 | struct wg_peer *peer) 46 | { 47 | mutex_lock(&table->lock); 48 | hlist_del_init_rcu(&peer->pubkey_hash); 49 | mutex_unlock(&table->lock); 50 | } 51 | 52 | /* Returns a strong reference to a peer */ 53 | struct wg_peer * 54 | wg_pubkey_hashtable_lookup(struct pubkey_hashtable *table, 55 | const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) 56 | { 57 | struct wg_peer *iter_peer, *peer = NULL; 58 | 59 | rcu_read_lock_bh(); 60 | hlist_for_each_entry_rcu_bh(iter_peer, pubkey_bucket(table, pubkey), 61 | pubkey_hash) { 62 | if (!memcmp(pubkey, iter_peer->handshake.remote_static, 63 | NOISE_PUBLIC_KEY_LEN)) { 64 | peer = iter_peer; 65 | break; 66 | } 67 | } 68 | peer = wg_peer_get_maybe_zero(peer); 69 | rcu_read_unlock_bh(); 70 | return peer; 71 | } 72 | 73 | static struct hlist_head *index_bucket(struct index_hashtable *table, 74 | const __le32 index) 75 | { 76 | /* Since the indices are random and thus all bits are uniformly 77 | * distributed, we can find its bucket simply by masking. 78 | */ 79 | return &table->hashtable[(__force u32)index & 80 | (HASH_SIZE(table->hashtable) - 1)]; 81 | } 82 | 83 | struct index_hashtable *wg_index_hashtable_alloc(void) 84 | { 85 | struct index_hashtable *table = kvmalloc(sizeof(*table), GFP_KERNEL); 86 | 87 | if (!table) 88 | return NULL; 89 | 90 | hash_init(table->hashtable); 91 | spin_lock_init(&table->lock); 92 | return table; 93 | } 94 | 95 | /* At the moment, we limit ourselves to 2^20 total peers, which generally might 96 | * amount to 2^20*3 items in this hashtable. The algorithm below works by 97 | * picking a random number and testing it. We can see that these limits mean we 98 | * usually succeed pretty quickly: 99 | * 100 | * >>> def calculation(tries, size): 101 | * ... return (size / 2**32)**(tries - 1) * (1 - (size / 2**32)) 102 | * ... 103 | * >>> calculation(1, 2**20 * 3) 104 | * 0.999267578125 105 | * >>> calculation(2, 2**20 * 3) 106 | * 0.0007318854331970215 107 | * >>> calculation(3, 2**20 * 3) 108 | * 5.360489012673497e-07 109 | * >>> calculation(4, 2**20 * 3) 110 | * 3.9261394135792216e-10 111 | * 112 | * At the moment, we don't do any masking, so this algorithm isn't exactly 113 | * constant time in either the random guessing or in the hash list lookup. We 114 | * could require a minimum of 3 tries, which would successfully mask the 115 | * guessing. this would not, however, help with the growing hash lengths, which 116 | * is another thing to consider moving forward. 117 | */ 118 | 119 | __le32 wg_index_hashtable_insert(struct index_hashtable *table, 120 | struct index_hashtable_entry *entry) 121 | { 122 | struct index_hashtable_entry *existing_entry; 123 | 124 | spin_lock_bh(&table->lock); 125 | hlist_del_init_rcu(&entry->index_hash); 126 | spin_unlock_bh(&table->lock); 127 | 128 | rcu_read_lock_bh(); 129 | 130 | search_unused_slot: 131 | /* First we try to find an unused slot, randomly, while unlocked. */ 132 | entry->index = (__force __le32)get_random_u32(); 133 | hlist_for_each_entry_rcu_bh(existing_entry, 134 | index_bucket(table, entry->index), 135 | index_hash) { 136 | if (existing_entry->index == entry->index) 137 | /* If it's already in use, we continue searching. */ 138 | goto search_unused_slot; 139 | } 140 | 141 | /* Once we've found an unused slot, we lock it, and then double-check 142 | * that nobody else stole it from us. 143 | */ 144 | spin_lock_bh(&table->lock); 145 | hlist_for_each_entry_rcu_bh(existing_entry, 146 | index_bucket(table, entry->index), 147 | index_hash) { 148 | if (existing_entry->index == entry->index) { 149 | spin_unlock_bh(&table->lock); 150 | /* If it was stolen, we start over. */ 151 | goto search_unused_slot; 152 | } 153 | } 154 | /* Otherwise, we know we have it exclusively (since we're locked), 155 | * so we insert. 156 | */ 157 | hlist_add_head_rcu(&entry->index_hash, 158 | index_bucket(table, entry->index)); 159 | spin_unlock_bh(&table->lock); 160 | 161 | rcu_read_unlock_bh(); 162 | 163 | return entry->index; 164 | } 165 | 166 | bool wg_index_hashtable_replace(struct index_hashtable *table, 167 | struct index_hashtable_entry *old, 168 | struct index_hashtable_entry *new) 169 | { 170 | bool ret; 171 | 172 | spin_lock_bh(&table->lock); 173 | ret = !hlist_unhashed(&old->index_hash); 174 | if (unlikely(!ret)) 175 | goto out; 176 | 177 | new->index = old->index; 178 | hlist_replace_rcu(&old->index_hash, &new->index_hash); 179 | 180 | /* Calling init here NULLs out index_hash, and in fact after this 181 | * function returns, it's theoretically possible for this to get 182 | * reinserted elsewhere. That means the RCU lookup below might either 183 | * terminate early or jump between buckets, in which case the packet 184 | * simply gets dropped, which isn't terrible. 185 | */ 186 | INIT_HLIST_NODE(&old->index_hash); 187 | out: 188 | spin_unlock_bh(&table->lock); 189 | return ret; 190 | } 191 | 192 | void wg_index_hashtable_remove(struct index_hashtable *table, 193 | struct index_hashtable_entry *entry) 194 | { 195 | spin_lock_bh(&table->lock); 196 | hlist_del_init_rcu(&entry->index_hash); 197 | spin_unlock_bh(&table->lock); 198 | } 199 | 200 | /* Returns a strong reference to a entry->peer */ 201 | struct index_hashtable_entry * 202 | wg_index_hashtable_lookup(struct index_hashtable *table, 203 | const enum index_hashtable_type type_mask, 204 | const __le32 index, struct wg_peer **peer) 205 | { 206 | struct index_hashtable_entry *iter_entry, *entry = NULL; 207 | 208 | rcu_read_lock_bh(); 209 | hlist_for_each_entry_rcu_bh(iter_entry, index_bucket(table, index), 210 | index_hash) { 211 | if (iter_entry->index == index) { 212 | if (likely(iter_entry->type & type_mask)) 213 | entry = iter_entry; 214 | break; 215 | } 216 | } 217 | if (likely(entry)) { 218 | entry->peer = wg_peer_get_maybe_zero(entry->peer); 219 | if (likely(entry->peer)) 220 | *peer = entry->peer; 221 | else 222 | entry = NULL; 223 | } 224 | rcu_read_unlock_bh(); 225 | return entry; 226 | } 227 | -------------------------------------------------------------------------------- /src/peerlookup.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_PEERLOOKUP_H 7 | #define _WG_PEERLOOKUP_H 8 | 9 | #include "messages.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | struct wg_peer; 16 | 17 | struct pubkey_hashtable { 18 | /* TODO: move to rhashtable */ 19 | DECLARE_HASHTABLE(hashtable, 11); 20 | siphash_key_t key; 21 | struct mutex lock; 22 | }; 23 | 24 | struct pubkey_hashtable *wg_pubkey_hashtable_alloc(void); 25 | void wg_pubkey_hashtable_add(struct pubkey_hashtable *table, 26 | struct wg_peer *peer); 27 | void wg_pubkey_hashtable_remove(struct pubkey_hashtable *table, 28 | struct wg_peer *peer); 29 | struct wg_peer * 30 | wg_pubkey_hashtable_lookup(struct pubkey_hashtable *table, 31 | const u8 pubkey[NOISE_PUBLIC_KEY_LEN]); 32 | 33 | struct index_hashtable { 34 | /* TODO: move to rhashtable */ 35 | DECLARE_HASHTABLE(hashtable, 13); 36 | spinlock_t lock; 37 | }; 38 | 39 | enum index_hashtable_type { 40 | INDEX_HASHTABLE_HANDSHAKE = 1U << 0, 41 | INDEX_HASHTABLE_KEYPAIR = 1U << 1 42 | }; 43 | 44 | struct index_hashtable_entry { 45 | struct wg_peer *peer; 46 | struct hlist_node index_hash; 47 | enum index_hashtable_type type; 48 | __le32 index; 49 | }; 50 | 51 | struct index_hashtable *wg_index_hashtable_alloc(void); 52 | __le32 wg_index_hashtable_insert(struct index_hashtable *table, 53 | struct index_hashtable_entry *entry); 54 | bool wg_index_hashtable_replace(struct index_hashtable *table, 55 | struct index_hashtable_entry *old, 56 | struct index_hashtable_entry *new); 57 | void wg_index_hashtable_remove(struct index_hashtable *table, 58 | struct index_hashtable_entry *entry); 59 | struct index_hashtable_entry * 60 | wg_index_hashtable_lookup(struct index_hashtable *table, 61 | const enum index_hashtable_type type_mask, 62 | const __le32 index, struct wg_peer **peer); 63 | 64 | #endif /* _WG_PEERLOOKUP_H */ 65 | -------------------------------------------------------------------------------- /src/queueing.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #include "queueing.h" 7 | #include 8 | 9 | struct multicore_worker __percpu * 10 | wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) 11 | { 12 | int cpu; 13 | struct multicore_worker __percpu *worker = alloc_percpu(struct multicore_worker); 14 | 15 | if (!worker) 16 | return NULL; 17 | 18 | for_each_possible_cpu(cpu) { 19 | per_cpu_ptr(worker, cpu)->ptr = ptr; 20 | INIT_WORK(&per_cpu_ptr(worker, cpu)->work, function); 21 | } 22 | return worker; 23 | } 24 | 25 | int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, 26 | unsigned int len) 27 | { 28 | int ret; 29 | 30 | memset(queue, 0, sizeof(*queue)); 31 | ret = ptr_ring_init(&queue->ring, len, GFP_KERNEL); 32 | if (ret) 33 | return ret; 34 | queue->worker = wg_packet_percpu_multicore_worker_alloc(function, queue); 35 | if (!queue->worker) { 36 | ptr_ring_cleanup(&queue->ring, NULL); 37 | return -ENOMEM; 38 | } 39 | return 0; 40 | } 41 | 42 | void wg_packet_queue_free(struct crypt_queue *queue, bool purge) 43 | { 44 | free_percpu(queue->worker); 45 | WARN_ON(!purge && !__ptr_ring_empty(&queue->ring)); 46 | ptr_ring_cleanup(&queue->ring, purge ? __skb_array_destroy_skb : NULL); 47 | } 48 | 49 | #define NEXT(skb) ((skb)->prev) 50 | #define STUB(queue) ((struct sk_buff *)&queue->empty) 51 | 52 | void wg_prev_queue_init(struct prev_queue *queue) 53 | { 54 | NEXT(STUB(queue)) = NULL; 55 | queue->head = queue->tail = STUB(queue); 56 | queue->peeked = NULL; 57 | atomic_set(&queue->count, 0); 58 | BUILD_BUG_ON( 59 | offsetof(struct sk_buff, next) != offsetof(struct prev_queue, empty.next) - 60 | offsetof(struct prev_queue, empty) || 61 | offsetof(struct sk_buff, prev) != offsetof(struct prev_queue, empty.prev) - 62 | offsetof(struct prev_queue, empty)); 63 | } 64 | 65 | static void __wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb) 66 | { 67 | WRITE_ONCE(NEXT(skb), NULL); 68 | WRITE_ONCE(NEXT(xchg_release(&queue->head, skb)), skb); 69 | } 70 | 71 | bool wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb) 72 | { 73 | if (!atomic_add_unless(&queue->count, 1, MAX_QUEUED_PACKETS)) 74 | return false; 75 | __wg_prev_queue_enqueue(queue, skb); 76 | return true; 77 | } 78 | 79 | struct sk_buff *wg_prev_queue_dequeue(struct prev_queue *queue) 80 | { 81 | struct sk_buff *tail = queue->tail, *next = smp_load_acquire(&NEXT(tail)); 82 | 83 | if (tail == STUB(queue)) { 84 | if (!next) 85 | return NULL; 86 | queue->tail = next; 87 | tail = next; 88 | next = smp_load_acquire(&NEXT(next)); 89 | } 90 | if (next) { 91 | queue->tail = next; 92 | atomic_dec(&queue->count); 93 | return tail; 94 | } 95 | if (tail != READ_ONCE(queue->head)) 96 | return NULL; 97 | __wg_prev_queue_enqueue(queue, STUB(queue)); 98 | next = smp_load_acquire(&NEXT(tail)); 99 | if (next) { 100 | queue->tail = next; 101 | atomic_dec(&queue->count); 102 | return tail; 103 | } 104 | return NULL; 105 | } 106 | 107 | #undef NEXT 108 | #undef STUB 109 | -------------------------------------------------------------------------------- /src/queueing.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_QUEUEING_H 7 | #define _WG_QUEUEING_H 8 | 9 | #include "peer.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | struct wg_device; 17 | struct wg_peer; 18 | struct multicore_worker; 19 | struct crypt_queue; 20 | struct prev_queue; 21 | struct sk_buff; 22 | 23 | /* queueing.c APIs: */ 24 | int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, 25 | unsigned int len); 26 | void wg_packet_queue_free(struct crypt_queue *queue, bool purge); 27 | struct multicore_worker __percpu * 28 | wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr); 29 | 30 | /* receive.c APIs: */ 31 | void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb); 32 | void wg_packet_handshake_receive_worker(struct work_struct *work); 33 | /* NAPI poll function: */ 34 | int wg_packet_rx_poll(struct napi_struct *napi, int budget); 35 | /* Workqueue worker: */ 36 | void wg_packet_decrypt_worker(struct work_struct *work); 37 | 38 | /* send.c APIs: */ 39 | void wg_packet_send_queued_handshake_initiation(struct wg_peer *peer, 40 | bool is_retry); 41 | void wg_packet_send_handshake_response(struct wg_peer *peer); 42 | void wg_packet_send_handshake_cookie(struct wg_device *wg, 43 | struct sk_buff *initiating_skb, 44 | __le32 sender_index); 45 | void wg_packet_send_keepalive(struct wg_peer *peer); 46 | void wg_packet_purge_staged_packets(struct wg_peer *peer); 47 | void wg_packet_send_staged_packets(struct wg_peer *peer); 48 | /* Workqueue workers: */ 49 | void wg_packet_handshake_send_worker(struct work_struct *work); 50 | void wg_packet_tx_worker(struct work_struct *work); 51 | void wg_packet_encrypt_worker(struct work_struct *work); 52 | 53 | enum packet_state { 54 | PACKET_STATE_UNCRYPTED, 55 | PACKET_STATE_CRYPTED, 56 | PACKET_STATE_DEAD 57 | }; 58 | 59 | struct packet_cb { 60 | u64 nonce; 61 | struct noise_keypair *keypair; 62 | atomic_t state; 63 | u32 mtu; 64 | u8 ds; 65 | }; 66 | 67 | #define PACKET_CB(skb) ((struct packet_cb *)((skb)->cb)) 68 | #define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer) 69 | 70 | static inline bool wg_check_packet_protocol(struct sk_buff *skb) 71 | { 72 | __be16 real_protocol = ip_tunnel_parse_protocol(skb); 73 | return real_protocol && skb->protocol == real_protocol; 74 | } 75 | 76 | static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating) 77 | { 78 | const int pfmemalloc = skb->pfmemalloc; 79 | u32 hash = skb->hash; 80 | u8 l4_hash = skb->l4_hash; 81 | u8 sw_hash = skb->sw_hash; 82 | 83 | skb_scrub_packet(skb, true); 84 | memset(&skb->headers_start, 0, 85 | offsetof(struct sk_buff, headers_end) - 86 | offsetof(struct sk_buff, headers_start)); 87 | skb->pfmemalloc = pfmemalloc; 88 | if (encapsulating) { 89 | skb->hash = hash; 90 | skb->l4_hash = l4_hash; 91 | skb->sw_hash = sw_hash; 92 | } 93 | skb->queue_mapping = 0; 94 | skb->nohdr = 0; 95 | skb->peeked = 0; 96 | skb->mac_len = 0; 97 | skb->dev = NULL; 98 | #ifdef CONFIG_NET_SCHED 99 | skb->tc_index = 0; 100 | #endif 101 | skb_reset_redirect(skb); 102 | skb->hdr_len = skb_headroom(skb); 103 | skb_reset_mac_header(skb); 104 | skb_reset_network_header(skb); 105 | skb_reset_transport_header(skb); 106 | skb_probe_transport_header(skb); 107 | skb_reset_inner_headers(skb); 108 | } 109 | 110 | static inline int wg_cpumask_choose_online(int *stored_cpu, unsigned int id) 111 | { 112 | unsigned int cpu = *stored_cpu, cpu_index, i; 113 | 114 | if (unlikely(cpu == nr_cpumask_bits || 115 | !cpumask_test_cpu(cpu, cpu_online_mask))) { 116 | cpu_index = id % cpumask_weight(cpu_online_mask); 117 | cpu = cpumask_first(cpu_online_mask); 118 | for (i = 0; i < cpu_index; ++i) 119 | cpu = cpumask_next(cpu, cpu_online_mask); 120 | *stored_cpu = cpu; 121 | } 122 | return cpu; 123 | } 124 | 125 | /* This function is racy, in the sense that next is unlocked, so it could return 126 | * the same CPU twice. A race-free version of this would be to instead store an 127 | * atomic sequence number, do an increment-and-return, and then iterate through 128 | * every possible CPU until we get to that index -- choose_cpu. However that's 129 | * a bit slower, and it doesn't seem like this potential race actually 130 | * introduces any performance loss, so we live with it. 131 | */ 132 | static inline int wg_cpumask_next_online(int *next) 133 | { 134 | int cpu = *next; 135 | 136 | while (unlikely(!cpumask_test_cpu(cpu, cpu_online_mask))) 137 | cpu = cpumask_next(cpu, cpu_online_mask) % nr_cpumask_bits; 138 | *next = cpumask_next(cpu, cpu_online_mask) % nr_cpumask_bits; 139 | return cpu; 140 | } 141 | 142 | void wg_prev_queue_init(struct prev_queue *queue); 143 | 144 | /* Multi producer */ 145 | bool wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb); 146 | 147 | /* Single consumer */ 148 | struct sk_buff *wg_prev_queue_dequeue(struct prev_queue *queue); 149 | 150 | /* Single consumer */ 151 | static inline struct sk_buff *wg_prev_queue_peek(struct prev_queue *queue) 152 | { 153 | if (queue->peeked) 154 | return queue->peeked; 155 | queue->peeked = wg_prev_queue_dequeue(queue); 156 | return queue->peeked; 157 | } 158 | 159 | /* Single consumer */ 160 | static inline void wg_prev_queue_drop_peeked(struct prev_queue *queue) 161 | { 162 | queue->peeked = NULL; 163 | } 164 | 165 | static inline int wg_queue_enqueue_per_device_and_peer( 166 | struct crypt_queue *device_queue, struct prev_queue *peer_queue, 167 | struct sk_buff *skb, struct workqueue_struct *wq, int *next_cpu) 168 | { 169 | int cpu; 170 | 171 | atomic_set_release(&PACKET_CB(skb)->state, PACKET_STATE_UNCRYPTED); 172 | /* We first queue this up for the peer ingestion, but the consumer 173 | * will wait for the state to change to CRYPTED or DEAD before. 174 | */ 175 | if (unlikely(!wg_prev_queue_enqueue(peer_queue, skb))) 176 | return -ENOSPC; 177 | 178 | /* Then we queue it up in the device queue, which consumes the 179 | * packet as soon as it can. 180 | */ 181 | cpu = wg_cpumask_next_online(next_cpu); 182 | if (unlikely(ptr_ring_produce_bh(&device_queue->ring, skb))) 183 | return -EPIPE; 184 | queue_work_on(cpu, wq, &per_cpu_ptr(device_queue->worker, cpu)->work); 185 | return 0; 186 | } 187 | 188 | static inline void wg_queue_enqueue_per_peer_tx(struct sk_buff *skb, enum packet_state state) 189 | { 190 | /* We take a reference, because as soon as we call atomic_set, the 191 | * peer can be freed from below us. 192 | */ 193 | struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb)); 194 | 195 | atomic_set_release(&PACKET_CB(skb)->state, state); 196 | queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu, peer->internal_id), 197 | peer->device->packet_crypt_wq, &peer->transmit_packet_work); 198 | wg_peer_put(peer); 199 | } 200 | 201 | static inline void wg_queue_enqueue_per_peer_rx(struct sk_buff *skb, enum packet_state state) 202 | { 203 | /* We take a reference, because as soon as we call atomic_set, the 204 | * peer can be freed from below us. 205 | */ 206 | struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb)); 207 | 208 | atomic_set_release(&PACKET_CB(skb)->state, state); 209 | napi_schedule(&peer->napi); 210 | wg_peer_put(peer); 211 | } 212 | 213 | #ifdef DEBUG 214 | bool wg_packet_counter_selftest(void); 215 | #endif 216 | 217 | #endif /* _WG_QUEUEING_H */ 218 | -------------------------------------------------------------------------------- /src/ratelimiter.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifdef COMPAT_CANNOT_DEPRECIATE_BH_RCU 7 | /* We normally alias all non-_bh functions to the _bh ones in the compat layer, 8 | * but that's not appropriate here, where we actually do want non-_bh ones. 9 | */ 10 | #undef synchronize_rcu 11 | #define synchronize_rcu old_synchronize_rcu 12 | #undef call_rcu 13 | #define call_rcu old_call_rcu 14 | #undef rcu_barrier 15 | #define rcu_barrier old_rcu_barrier 16 | #endif 17 | 18 | #include "ratelimiter.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static struct kmem_cache *entry_cache; 25 | static hsiphash_key_t key; 26 | static spinlock_t table_lock = __SPIN_LOCK_UNLOCKED("ratelimiter_table_lock"); 27 | static DEFINE_MUTEX(init_lock); 28 | static u64 init_refcnt; /* Protected by init_lock, hence not atomic. */ 29 | static atomic_t total_entries = ATOMIC_INIT(0); 30 | static unsigned int max_entries, table_size; 31 | static void wg_ratelimiter_gc_entries(struct work_struct *); 32 | static DECLARE_DEFERRABLE_WORK(gc_work, wg_ratelimiter_gc_entries); 33 | static struct hlist_head *table_v4; 34 | #if IS_ENABLED(CONFIG_IPV6) 35 | static struct hlist_head *table_v6; 36 | #endif 37 | 38 | struct ratelimiter_entry { 39 | u64 last_time_ns, tokens, ip; 40 | void *net; 41 | spinlock_t lock; 42 | struct hlist_node hash; 43 | struct rcu_head rcu; 44 | }; 45 | 46 | enum { 47 | PACKETS_PER_SECOND = 20, 48 | PACKETS_BURSTABLE = 5, 49 | PACKET_COST = NSEC_PER_SEC / PACKETS_PER_SECOND, 50 | TOKEN_MAX = PACKET_COST * PACKETS_BURSTABLE 51 | }; 52 | 53 | static void entry_free(struct rcu_head *rcu) 54 | { 55 | kmem_cache_free(entry_cache, 56 | container_of(rcu, struct ratelimiter_entry, rcu)); 57 | atomic_dec(&total_entries); 58 | } 59 | 60 | static void entry_uninit(struct ratelimiter_entry *entry) 61 | { 62 | hlist_del_rcu(&entry->hash); 63 | call_rcu(&entry->rcu, entry_free); 64 | } 65 | 66 | /* Calling this function with a NULL work uninits all entries. */ 67 | static void wg_ratelimiter_gc_entries(struct work_struct *work) 68 | { 69 | const u64 now = ktime_get_coarse_boottime_ns(); 70 | struct ratelimiter_entry *entry; 71 | struct hlist_node *temp; 72 | unsigned int i; 73 | 74 | for (i = 0; i < table_size; ++i) { 75 | spin_lock(&table_lock); 76 | hlist_for_each_entry_safe(entry, temp, &table_v4[i], hash) { 77 | if (unlikely(!work) || 78 | now - entry->last_time_ns > NSEC_PER_SEC) 79 | entry_uninit(entry); 80 | } 81 | #if IS_ENABLED(CONFIG_IPV6) 82 | hlist_for_each_entry_safe(entry, temp, &table_v6[i], hash) { 83 | if (unlikely(!work) || 84 | now - entry->last_time_ns > NSEC_PER_SEC) 85 | entry_uninit(entry); 86 | } 87 | #endif 88 | spin_unlock(&table_lock); 89 | if (likely(work)) 90 | cond_resched(); 91 | } 92 | if (likely(work)) 93 | queue_delayed_work(system_power_efficient_wq, &gc_work, HZ); 94 | } 95 | 96 | bool wg_ratelimiter_allow(struct sk_buff *skb, struct net *net) 97 | { 98 | /* We only take the bottom half of the net pointer, so that we can hash 99 | * 3 words in the end. This way, siphash's len param fits into the final 100 | * u32, and we don't incur an extra round. 101 | */ 102 | const u32 net_word = (unsigned long)net; 103 | struct ratelimiter_entry *entry; 104 | struct hlist_head *bucket; 105 | u64 ip; 106 | 107 | if (skb->protocol == htons(ETH_P_IP)) { 108 | ip = (u64 __force)ip_hdr(skb)->saddr; 109 | bucket = &table_v4[hsiphash_2u32(net_word, ip, &key) & 110 | (table_size - 1)]; 111 | } 112 | #if IS_ENABLED(CONFIG_IPV6) 113 | else if (skb->protocol == htons(ETH_P_IPV6)) { 114 | /* Only use 64 bits, so as to ratelimit the whole /64. */ 115 | memcpy(&ip, &ipv6_hdr(skb)->saddr, sizeof(ip)); 116 | bucket = &table_v6[hsiphash_3u32(net_word, ip >> 32, ip, &key) & 117 | (table_size - 1)]; 118 | } 119 | #endif 120 | else 121 | return false; 122 | rcu_read_lock(); 123 | hlist_for_each_entry_rcu(entry, bucket, hash) { 124 | if (entry->net == net && entry->ip == ip) { 125 | u64 now, tokens; 126 | bool ret; 127 | /* Quasi-inspired by nft_limit.c, but this is actually a 128 | * slightly different algorithm. Namely, we incorporate 129 | * the burst as part of the maximum tokens, rather than 130 | * as part of the rate. 131 | */ 132 | spin_lock(&entry->lock); 133 | now = ktime_get_coarse_boottime_ns(); 134 | tokens = min_t(u64, TOKEN_MAX, 135 | entry->tokens + now - 136 | entry->last_time_ns); 137 | entry->last_time_ns = now; 138 | ret = tokens >= PACKET_COST; 139 | entry->tokens = ret ? tokens - PACKET_COST : tokens; 140 | spin_unlock(&entry->lock); 141 | rcu_read_unlock(); 142 | return ret; 143 | } 144 | } 145 | rcu_read_unlock(); 146 | 147 | if (atomic_inc_return(&total_entries) > max_entries) 148 | goto err_oom; 149 | 150 | entry = kmem_cache_alloc(entry_cache, GFP_KERNEL); 151 | if (unlikely(!entry)) 152 | goto err_oom; 153 | 154 | entry->net = net; 155 | entry->ip = ip; 156 | INIT_HLIST_NODE(&entry->hash); 157 | spin_lock_init(&entry->lock); 158 | entry->last_time_ns = ktime_get_coarse_boottime_ns(); 159 | entry->tokens = TOKEN_MAX - PACKET_COST; 160 | spin_lock(&table_lock); 161 | hlist_add_head_rcu(&entry->hash, bucket); 162 | spin_unlock(&table_lock); 163 | return true; 164 | 165 | err_oom: 166 | atomic_dec(&total_entries); 167 | return false; 168 | } 169 | 170 | int wg_ratelimiter_init(void) 171 | { 172 | mutex_lock(&init_lock); 173 | if (++init_refcnt != 1) 174 | goto out; 175 | 176 | entry_cache = KMEM_CACHE(ratelimiter_entry, 0); 177 | if (!entry_cache) 178 | goto err; 179 | 180 | /* xt_hashlimit.c uses a slightly different algorithm for ratelimiting, 181 | * but what it shares in common is that it uses a massive hashtable. So, 182 | * we borrow their wisdom about good table sizes on different systems 183 | * dependent on RAM. This calculation here comes from there. 184 | */ 185 | table_size = (totalram_pages() > (1U << 30) / PAGE_SIZE) ? 8192 : 186 | max_t(unsigned long, 16, roundup_pow_of_two( 187 | (totalram_pages() << PAGE_SHIFT) / 188 | (1U << 14) / sizeof(struct hlist_head))); 189 | max_entries = table_size * 8; 190 | 191 | table_v4 = kvcalloc(table_size, sizeof(*table_v4), GFP_KERNEL); 192 | if (unlikely(!table_v4)) 193 | goto err_kmemcache; 194 | 195 | #if IS_ENABLED(CONFIG_IPV6) 196 | table_v6 = kvcalloc(table_size, sizeof(*table_v6), GFP_KERNEL); 197 | if (unlikely(!table_v6)) { 198 | kvfree(table_v4); 199 | goto err_kmemcache; 200 | } 201 | #endif 202 | 203 | queue_delayed_work(system_power_efficient_wq, &gc_work, HZ); 204 | get_random_bytes(&key, sizeof(key)); 205 | out: 206 | mutex_unlock(&init_lock); 207 | return 0; 208 | 209 | err_kmemcache: 210 | kmem_cache_destroy(entry_cache); 211 | err: 212 | --init_refcnt; 213 | mutex_unlock(&init_lock); 214 | return -ENOMEM; 215 | } 216 | 217 | void wg_ratelimiter_uninit(void) 218 | { 219 | mutex_lock(&init_lock); 220 | if (!init_refcnt || --init_refcnt) 221 | goto out; 222 | 223 | cancel_delayed_work_sync(&gc_work); 224 | wg_ratelimiter_gc_entries(NULL); 225 | rcu_barrier(); 226 | kvfree(table_v4); 227 | #if IS_ENABLED(CONFIG_IPV6) 228 | kvfree(table_v6); 229 | #endif 230 | kmem_cache_destroy(entry_cache); 231 | out: 232 | mutex_unlock(&init_lock); 233 | } 234 | 235 | #include "selftest/ratelimiter.c" 236 | -------------------------------------------------------------------------------- /src/ratelimiter.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_RATELIMITER_H 7 | #define _WG_RATELIMITER_H 8 | 9 | #include 10 | 11 | int wg_ratelimiter_init(void); 12 | void wg_ratelimiter_uninit(void); 13 | bool wg_ratelimiter_allow(struct sk_buff *skb, struct net *net); 14 | 15 | #ifdef DEBUG 16 | bool wg_ratelimiter_selftest(void); 17 | #endif 18 | 19 | #endif /* _WG_RATELIMITER_H */ 20 | -------------------------------------------------------------------------------- /src/selftest/counter.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifdef DEBUG 7 | bool __init wg_packet_counter_selftest(void) 8 | { 9 | struct noise_replay_counter *counter; 10 | unsigned int test_num = 0, i; 11 | bool success = true; 12 | 13 | counter = kmalloc(sizeof(*counter), GFP_KERNEL); 14 | if (unlikely(!counter)) { 15 | pr_err("nonce counter self-test malloc: FAIL\n"); 16 | return false; 17 | } 18 | 19 | #define T_INIT do { \ 20 | memset(counter, 0, sizeof(*counter)); \ 21 | spin_lock_init(&counter->lock); \ 22 | } while (0) 23 | #define T_LIM (COUNTER_WINDOW_SIZE + 1) 24 | #define T(n, v) do { \ 25 | ++test_num; \ 26 | if (counter_validate(counter, n) != (v)) { \ 27 | pr_err("nonce counter self-test %u: FAIL\n", \ 28 | test_num); \ 29 | success = false; \ 30 | } \ 31 | } while (0) 32 | 33 | T_INIT; 34 | /* 1 */ T(0, true); 35 | /* 2 */ T(1, true); 36 | /* 3 */ T(1, false); 37 | /* 4 */ T(9, true); 38 | /* 5 */ T(8, true); 39 | /* 6 */ T(7, true); 40 | /* 7 */ T(7, false); 41 | /* 8 */ T(T_LIM, true); 42 | /* 9 */ T(T_LIM - 1, true); 43 | /* 10 */ T(T_LIM - 1, false); 44 | /* 11 */ T(T_LIM - 2, true); 45 | /* 12 */ T(2, true); 46 | /* 13 */ T(2, false); 47 | /* 14 */ T(T_LIM + 16, true); 48 | /* 15 */ T(3, false); 49 | /* 16 */ T(T_LIM + 16, false); 50 | /* 17 */ T(T_LIM * 4, true); 51 | /* 18 */ T(T_LIM * 4 - (T_LIM - 1), true); 52 | /* 19 */ T(10, false); 53 | /* 20 */ T(T_LIM * 4 - T_LIM, false); 54 | /* 21 */ T(T_LIM * 4 - (T_LIM + 1), false); 55 | /* 22 */ T(T_LIM * 4 - (T_LIM - 2), true); 56 | /* 23 */ T(T_LIM * 4 + 1 - T_LIM, false); 57 | /* 24 */ T(0, false); 58 | /* 25 */ T(REJECT_AFTER_MESSAGES, false); 59 | /* 26 */ T(REJECT_AFTER_MESSAGES - 1, true); 60 | /* 27 */ T(REJECT_AFTER_MESSAGES, false); 61 | /* 28 */ T(REJECT_AFTER_MESSAGES - 1, false); 62 | /* 29 */ T(REJECT_AFTER_MESSAGES - 2, true); 63 | /* 30 */ T(REJECT_AFTER_MESSAGES + 1, false); 64 | /* 31 */ T(REJECT_AFTER_MESSAGES + 2, false); 65 | /* 32 */ T(REJECT_AFTER_MESSAGES - 2, false); 66 | /* 33 */ T(REJECT_AFTER_MESSAGES - 3, true); 67 | /* 34 */ T(0, false); 68 | 69 | T_INIT; 70 | for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i) 71 | T(i, true); 72 | T(0, true); 73 | T(0, false); 74 | 75 | T_INIT; 76 | for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i) 77 | T(i, true); 78 | T(1, true); 79 | T(0, false); 80 | 81 | T_INIT; 82 | for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0;) 83 | T(i, true); 84 | 85 | T_INIT; 86 | for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1;) 87 | T(i, true); 88 | T(0, false); 89 | 90 | T_INIT; 91 | for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;) 92 | T(i, true); 93 | T(COUNTER_WINDOW_SIZE + 1, true); 94 | T(0, false); 95 | 96 | T_INIT; 97 | for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;) 98 | T(i, true); 99 | T(0, true); 100 | T(COUNTER_WINDOW_SIZE + 1, true); 101 | 102 | #undef T 103 | #undef T_LIM 104 | #undef T_INIT 105 | 106 | if (success) 107 | pr_info("nonce counter self-tests: pass\n"); 108 | kfree(counter); 109 | return success; 110 | } 111 | #endif 112 | -------------------------------------------------------------------------------- /src/selftest/ratelimiter.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifdef DEBUG 7 | 8 | #include 9 | 10 | static const struct { 11 | bool result; 12 | unsigned int msec_to_sleep_before; 13 | } expected_results[] __initconst = { 14 | [0 ... PACKETS_BURSTABLE - 1] = { true, 0 }, 15 | [PACKETS_BURSTABLE] = { false, 0 }, 16 | [PACKETS_BURSTABLE + 1] = { true, MSEC_PER_SEC / PACKETS_PER_SECOND }, 17 | [PACKETS_BURSTABLE + 2] = { false, 0 }, 18 | [PACKETS_BURSTABLE + 3] = { true, (MSEC_PER_SEC / PACKETS_PER_SECOND) * 2 }, 19 | [PACKETS_BURSTABLE + 4] = { true, 0 }, 20 | [PACKETS_BURSTABLE + 5] = { false, 0 } 21 | }; 22 | 23 | static __init unsigned int maximum_jiffies_at_index(int index) 24 | { 25 | unsigned int total_msecs = 2 * MSEC_PER_SEC / PACKETS_PER_SECOND / 3; 26 | int i; 27 | 28 | for (i = 0; i <= index; ++i) 29 | total_msecs += expected_results[i].msec_to_sleep_before; 30 | return msecs_to_jiffies(total_msecs); 31 | } 32 | 33 | static __init int timings_test(struct sk_buff *skb4, struct iphdr *hdr4, 34 | struct sk_buff *skb6, struct ipv6hdr *hdr6, 35 | int *test) 36 | { 37 | unsigned long loop_start_time; 38 | int i; 39 | 40 | wg_ratelimiter_gc_entries(NULL); 41 | rcu_barrier(); 42 | loop_start_time = jiffies; 43 | 44 | for (i = 0; i < ARRAY_SIZE(expected_results); ++i) { 45 | if (expected_results[i].msec_to_sleep_before) 46 | msleep(expected_results[i].msec_to_sleep_before); 47 | 48 | if (time_is_before_jiffies(loop_start_time + 49 | maximum_jiffies_at_index(i))) 50 | return -ETIMEDOUT; 51 | if (wg_ratelimiter_allow(skb4, &init_net) != 52 | expected_results[i].result) 53 | return -EXFULL; 54 | ++(*test); 55 | 56 | hdr4->saddr = htonl(ntohl(hdr4->saddr) + i + 1); 57 | if (time_is_before_jiffies(loop_start_time + 58 | maximum_jiffies_at_index(i))) 59 | return -ETIMEDOUT; 60 | if (!wg_ratelimiter_allow(skb4, &init_net)) 61 | return -EXFULL; 62 | ++(*test); 63 | 64 | hdr4->saddr = htonl(ntohl(hdr4->saddr) - i - 1); 65 | 66 | #if IS_ENABLED(CONFIG_IPV6) 67 | hdr6->saddr.in6_u.u6_addr32[2] = htonl(i); 68 | hdr6->saddr.in6_u.u6_addr32[3] = htonl(i); 69 | if (time_is_before_jiffies(loop_start_time + 70 | maximum_jiffies_at_index(i))) 71 | return -ETIMEDOUT; 72 | if (wg_ratelimiter_allow(skb6, &init_net) != 73 | expected_results[i].result) 74 | return -EXFULL; 75 | ++(*test); 76 | 77 | hdr6->saddr.in6_u.u6_addr32[0] = 78 | htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) + i + 1); 79 | if (time_is_before_jiffies(loop_start_time + 80 | maximum_jiffies_at_index(i))) 81 | return -ETIMEDOUT; 82 | if (!wg_ratelimiter_allow(skb6, &init_net)) 83 | return -EXFULL; 84 | ++(*test); 85 | 86 | hdr6->saddr.in6_u.u6_addr32[0] = 87 | htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) - i - 1); 88 | 89 | if (time_is_before_jiffies(loop_start_time + 90 | maximum_jiffies_at_index(i))) 91 | return -ETIMEDOUT; 92 | #endif 93 | } 94 | return 0; 95 | } 96 | 97 | static __init int capacity_test(struct sk_buff *skb4, struct iphdr *hdr4, 98 | int *test) 99 | { 100 | int i; 101 | 102 | wg_ratelimiter_gc_entries(NULL); 103 | rcu_barrier(); 104 | 105 | if (atomic_read(&total_entries)) 106 | return -EXFULL; 107 | ++(*test); 108 | 109 | for (i = 0; i <= max_entries; ++i) { 110 | hdr4->saddr = htonl(i); 111 | if (wg_ratelimiter_allow(skb4, &init_net) != (i != max_entries)) 112 | return -EXFULL; 113 | ++(*test); 114 | } 115 | return 0; 116 | } 117 | 118 | bool __init wg_ratelimiter_selftest(void) 119 | { 120 | enum { TRIALS_BEFORE_GIVING_UP = 5000 }; 121 | bool success = false; 122 | int test = 0, trials; 123 | struct sk_buff *skb4, *skb6 = NULL; 124 | struct iphdr *hdr4; 125 | struct ipv6hdr *hdr6 = NULL; 126 | 127 | if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN)) 128 | return true; 129 | 130 | BUILD_BUG_ON(MSEC_PER_SEC % PACKETS_PER_SECOND != 0); 131 | 132 | if (wg_ratelimiter_init()) 133 | goto out; 134 | ++test; 135 | if (wg_ratelimiter_init()) { 136 | wg_ratelimiter_uninit(); 137 | goto out; 138 | } 139 | ++test; 140 | if (wg_ratelimiter_init()) { 141 | wg_ratelimiter_uninit(); 142 | wg_ratelimiter_uninit(); 143 | goto out; 144 | } 145 | ++test; 146 | 147 | skb4 = alloc_skb(sizeof(struct iphdr), GFP_KERNEL); 148 | if (unlikely(!skb4)) 149 | goto err_nofree; 150 | skb4->protocol = htons(ETH_P_IP); 151 | hdr4 = (struct iphdr *)skb_put(skb4, sizeof(*hdr4)); 152 | hdr4->saddr = htonl(8182); 153 | skb_reset_network_header(skb4); 154 | ++test; 155 | 156 | #if IS_ENABLED(CONFIG_IPV6) 157 | skb6 = alloc_skb(sizeof(struct ipv6hdr), GFP_KERNEL); 158 | if (unlikely(!skb6)) { 159 | kfree_skb(skb4); 160 | goto err_nofree; 161 | } 162 | skb6->protocol = htons(ETH_P_IPV6); 163 | hdr6 = (struct ipv6hdr *)skb_put(skb6, sizeof(*hdr6)); 164 | hdr6->saddr.in6_u.u6_addr32[0] = htonl(1212); 165 | hdr6->saddr.in6_u.u6_addr32[1] = htonl(289188); 166 | skb_reset_network_header(skb6); 167 | ++test; 168 | #endif 169 | 170 | for (trials = TRIALS_BEFORE_GIVING_UP;;) { 171 | int test_count = 0, ret; 172 | 173 | ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count); 174 | if (ret == -ETIMEDOUT) { 175 | if (!trials--) { 176 | test += test_count; 177 | goto err; 178 | } 179 | msleep(500); 180 | continue; 181 | } else if (ret < 0) { 182 | test += test_count; 183 | goto err; 184 | } else { 185 | test += test_count; 186 | break; 187 | } 188 | } 189 | 190 | for (trials = TRIALS_BEFORE_GIVING_UP;;) { 191 | int test_count = 0; 192 | 193 | if (capacity_test(skb4, hdr4, &test_count) < 0) { 194 | if (!trials--) { 195 | test += test_count; 196 | goto err; 197 | } 198 | msleep(50); 199 | continue; 200 | } 201 | test += test_count; 202 | break; 203 | } 204 | 205 | success = true; 206 | 207 | err: 208 | kfree_skb(skb4); 209 | #if IS_ENABLED(CONFIG_IPV6) 210 | kfree_skb(skb6); 211 | #endif 212 | err_nofree: 213 | wg_ratelimiter_uninit(); 214 | wg_ratelimiter_uninit(); 215 | wg_ratelimiter_uninit(); 216 | /* Uninit one extra time to check underflow detection. */ 217 | wg_ratelimiter_uninit(); 218 | out: 219 | if (success) 220 | pr_info("ratelimiter self-tests: pass\n"); 221 | else 222 | pr_err("ratelimiter self-test %d: FAIL\n", test); 223 | 224 | return success; 225 | } 226 | #endif 227 | -------------------------------------------------------------------------------- /src/socket.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_SOCKET_H 7 | #define _WG_SOCKET_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int wg_socket_init(struct wg_device *wg, u16 port); 15 | void wg_socket_reinit(struct wg_device *wg, struct sock *new4, 16 | struct sock *new6); 17 | int wg_socket_send_buffer_to_peer(struct wg_peer *peer, void *data, 18 | size_t len, u8 ds); 19 | int wg_socket_send_junked_buffer_to_peer(struct wg_peer *peer, void *data, 20 | size_t len, u8 ds, u16 junk_size); 21 | int wg_socket_send_skb_to_peer(struct wg_peer *peer, struct sk_buff *skb, 22 | u8 ds); 23 | int wg_socket_send_buffer_as_reply_to_skb(struct wg_device *wg, 24 | struct sk_buff *in_skb, 25 | void *out_buffer, size_t len); 26 | 27 | int wg_socket_endpoint_from_skb(struct endpoint *endpoint, 28 | const struct sk_buff *skb); 29 | void wg_socket_set_peer_endpoint(struct wg_peer *peer, 30 | const struct endpoint *endpoint); 31 | void wg_socket_set_peer_endpoint_from_skb(struct wg_peer *peer, 32 | const struct sk_buff *skb); 33 | void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer); 34 | 35 | #if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG) 36 | #define net_dbg_skb_ratelimited(fmt, dev, skb, ...) do { \ 37 | struct endpoint __endpoint; \ 38 | wg_socket_endpoint_from_skb(&__endpoint, skb); \ 39 | net_dbg_ratelimited(fmt, dev, &__endpoint.addr, \ 40 | ##__VA_ARGS__); \ 41 | } while (0) 42 | #else 43 | #define net_dbg_skb_ratelimited(fmt, skb, ...) 44 | #endif 45 | 46 | #endif /* _WG_SOCKET_H */ 47 | -------------------------------------------------------------------------------- /src/tests/debug.mk: -------------------------------------------------------------------------------- 1 | REMOTE_HOST1 ?= root@172.16.48.128 2 | REMOTE_HOST2 ?= root@172.16.48.129 3 | REMOTE_HOST3 ?= root@172.16.48.130 4 | PEER1 := [Peer]\nPublicKey=UQGBaem0U6JjIObMQzunZ2Euv8MMYcUUdWKJV87WDE8=\nAllowedIPs=192.168.2.1/32,abcd::1/128\nEndpoint=$(subst root@,,$(REMOTE_HOST1)):12912\n 5 | PEER2 := [Peer]\nPublicKey=tNXrD6GCvHRNgoZ/D/BmTbTbzoVGZh0R2V6rzY6hwl4=\nAllowedIPs=192.168.2.2/32,abcd::2/128\nEndpoint=$(subst root@,,$(REMOTE_HOST2)):21281\n 6 | PEER3 := [Peer]\nPublicKey=gLvFUb1FTyoACC/yZNqGLKnNkt+w30JEvfFChDVuewo=\nAllowedIPs=192.168.2.3/32,abcd::3/128\nEndpoint=$(subst root@,,$(REMOTE_HOST3)):54812\n 7 | SSH_OPTS := -q -o ControlMaster=auto -o ControlPath=.ssh-deployment.sock 8 | SSH_OPTS1 := $(SSH_OPTS)-1 9 | SSH_OPTS2 := $(SSH_OPTS)-2 10 | SSH_OPTS3 := $(SSH_OPTS)-3 11 | RSYNC_OPTS := --exclude="*.o" --exclude="*.mod.c" --exclude="tests/qemu" --exclude "*.ko" --exclude="*.cmd" -avP 12 | 13 | MAYBE_DEBUG := "debug" 14 | ifeq ($(D),0) 15 | MAYBE_DEBUG := 16 | endif 17 | 18 | insert: debug 19 | -modinfo -F depends wireguard.ko | tr ',' '\n' | sudo xargs -n 1 modprobe 20 | -sudo rmmod wireguard 21 | -sudo insmod wireguard.ko 22 | 23 | test: insert 24 | sudo PATH="$$PATH:/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin" ./tests/netns.sh 25 | 26 | test-qemu: 27 | $(MAKE) -C tests/qemu 28 | 29 | remote-test: 30 | ssh $(SSH_OPTS1) -Nf $(REMOTE_HOST1) 31 | rsync --rsh="ssh $(SSH_OPTS1)" $(RSYNC_OPTS) . $(REMOTE_HOST1):wireguard-build/ 32 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'make -C wireguard-build test -j$$(nproc)' 33 | ssh $(SSH_OPTS1) -O exit $(REMOTE_HOST1) 34 | 35 | remote-run-1: 36 | ssh $(SSH_OPTS1) -Nf $(REMOTE_HOST1) 37 | rsync --rsh="ssh $(SSH_OPTS1)" $(RSYNC_OPTS) . $(REMOTE_HOST1):wireguard-build/ 38 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'ip l d wg0; rmmod wireguard; cd wireguard-build && make -j$$(nproc) $(MAYBE_DEBUG) && make install' 39 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'ip l a wg0 type wireguard' 40 | printf '[Interface]\nListenPort=12912\nPrivateKey=4IoHwlfTyKb9Z9W1YPmBmZvSiU6qcs0oa4xnjAEm/3U=\n$(PEER2)$(PEER3)' | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'cat > config.conf' 41 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'wg setconf wg0 config.conf' 42 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'ip l set up dev wg0' 43 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'ip a a 192.168.2.1/24 dev wg0' 44 | ssh $(SSH_OPTS1) $(REMOTE_HOST1) 'ip a a abcd::1/120 dev wg0' 45 | ssh $(SSH_OPTS1) -O exit $(REMOTE_HOST1) 46 | 47 | 48 | remote-run-2: 49 | ssh $(SSH_OPTS2) -Nf $(REMOTE_HOST2) 50 | rsync --rsh="ssh $(SSH_OPTS2)" $(RSYNC_OPTS) . $(REMOTE_HOST2):wireguard-build/ 51 | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'ip l d wg0; rmmod wireguard; cd wireguard-build && make -j$$(nproc) $(MAYBE_DEBUG) && make install' 52 | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'ip l a wg0 type wireguard' 53 | printf '[Interface]\nListenPort=21281\nPrivateKey=kEKL+m4h5xTn2cYKU6NTEv32kuXHAkuqrjdT9VtsnX8=\n$(PEER1)$(PEER3)' | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'cat > config.conf' 54 | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'wg setconf wg0 config.conf' 55 | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'ip l set up dev wg0' 56 | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'ip a a 192.168.2.2/24 dev wg0' 57 | ssh $(SSH_OPTS2) $(REMOTE_HOST2) 'ip a a abcd::2/120 dev wg0' 58 | ssh $(SSH_OPTS2) -O exit $(REMOTE_HOST2) 59 | 60 | remote-run-3: 61 | ssh $(SSH_OPTS3) -Nf $(REMOTE_HOST3) 62 | rsync --rsh="ssh $(SSH_OPTS3)" $(RSYNC_OPTS) . $(REMOTE_HOST3):wireguard-build/ 63 | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'ip l d wg0; rmmod wireguard; cd wireguard-build && make -j$$(nproc) $(MAYBE_DEBUG) && make install' 64 | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'ip l a wg0 type wireguard' 65 | printf '[Interface]\nListenPort=54812\nPrivateKey=qFunvj5kgENrtWn754hNBLrk5mMA+8+evVtnI2YqWkk=\n$(PEER1)$(PEER2)' | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'cat > config.conf' 66 | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'wg setconf wg0 config.conf' 67 | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'ip l set up dev wg0' 68 | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'ip a a 192.168.2.3/24 dev wg0' 69 | ssh $(SSH_OPTS3) $(REMOTE_HOST3) 'ip a a abcd::3/120 dev wg0' 70 | ssh $(SSH_OPTS3) -O exit $(REMOTE_HOST3) 71 | 72 | remote-run: 73 | $(MAKE) -j3 remote-run-1 remote-run-2 remote-run-3 74 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/aarch64.config: -------------------------------------------------------------------------------- 1 | CONFIG_SERIAL_AMBA_PL011=y 2 | CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 3 | CONFIG_VIRTIO_MENU=y 4 | CONFIG_VIRTIO_MMIO=y 5 | CONFIG_VIRTIO_CONSOLE=y 6 | CONFIG_CMDLINE_BOOL=y 7 | CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1" 8 | CONFIG_FRAME_WARN=1280 9 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/aarch64_be.config: -------------------------------------------------------------------------------- 1 | CONFIG_CPU_BIG_ENDIAN=y 2 | CONFIG_SERIAL_AMBA_PL011=y 3 | CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 4 | CONFIG_VIRTIO_MENU=y 5 | CONFIG_VIRTIO_MMIO=y 6 | CONFIG_VIRTIO_CONSOLE=y 7 | CONFIG_CMDLINE_BOOL=y 8 | CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1" 9 | CONFIG_FRAME_WARN=1280 10 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/arm.config: -------------------------------------------------------------------------------- 1 | CONFIG_MMU=y 2 | CONFIG_ARCH_MULTI_V7=y 3 | CONFIG_ARCH_VIRT=y 4 | CONFIG_THUMB2_KERNEL=n 5 | CONFIG_SERIAL_AMBA_PL011=y 6 | CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 7 | CONFIG_VIRTIO_MENU=y 8 | CONFIG_VIRTIO_MMIO=y 9 | CONFIG_VIRTIO_CONSOLE=y 10 | CONFIG_CMDLINE_BOOL=y 11 | CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1" 12 | CONFIG_FRAME_WARN=1024 13 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/armeb.config: -------------------------------------------------------------------------------- 1 | CONFIG_MMU=y 2 | CONFIG_ARCH_MULTI_V7=y 3 | CONFIG_ARCH_VIRT=y 4 | CONFIG_THUMB2_KERNEL=n 5 | CONFIG_SERIAL_AMBA_PL011=y 6 | CONFIG_SERIAL_AMBA_PL011_CONSOLE=y 7 | CONFIG_VIRTIO_MENU=y 8 | CONFIG_VIRTIO_MMIO=y 9 | CONFIG_VIRTIO_CONSOLE=y 10 | CONFIG_CMDLINE_BOOL=y 11 | CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1" 12 | CONFIG_CPU_BIG_ENDIAN=y 13 | CONFIG_FRAME_WARN=1024 14 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/i686.config: -------------------------------------------------------------------------------- 1 | CONFIG_ACPI=y 2 | CONFIG_SERIAL_8250=y 3 | CONFIG_SERIAL_8250_CONSOLE=y 4 | CONFIG_CMDLINE_BOOL=y 5 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 6 | CONFIG_FRAME_WARN=1024 7 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/m68k.config: -------------------------------------------------------------------------------- 1 | CONFIG_MMU=y 2 | CONFIG_M68KCLASSIC=y 3 | CONFIG_M68040=y 4 | CONFIG_MAC=y 5 | CONFIG_SERIAL_PMACZILOG=y 6 | CONFIG_SERIAL_PMACZILOG_TTYS=y 7 | CONFIG_SERIAL_PMACZILOG_CONSOLE=y 8 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 9 | CONFIG_FRAME_WARN=1024 10 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/mips.config: -------------------------------------------------------------------------------- 1 | CONFIG_CPU_MIPS32_R2=y 2 | CONFIG_MIPS_MALTA=y 3 | CONFIG_MIPS_CPS=y 4 | CONFIG_MIPS_FP_SUPPORT=y 5 | CONFIG_POWER_RESET=y 6 | CONFIG_POWER_RESET_SYSCON=y 7 | CONFIG_SERIAL_8250=y 8 | CONFIG_SERIAL_8250_CONSOLE=y 9 | CONFIG_CMDLINE_BOOL=y 10 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 11 | CONFIG_FRAME_WARN=1024 12 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/mips64.config: -------------------------------------------------------------------------------- 1 | CONFIG_64BIT=y 2 | CONFIG_CPU_MIPS64_R2=y 3 | CONFIG_MIPS32_N32=y 4 | CONFIG_CPU_HAS_MSA=y 5 | CONFIG_MIPS_MALTA=y 6 | CONFIG_MIPS_CPS=y 7 | CONFIG_MIPS_FP_SUPPORT=y 8 | CONFIG_POWER_RESET=y 9 | CONFIG_POWER_RESET_SYSCON=y 10 | CONFIG_SERIAL_8250=y 11 | CONFIG_SERIAL_8250_CONSOLE=y 12 | CONFIG_CMDLINE_BOOL=y 13 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 14 | CONFIG_FRAME_WARN=1280 15 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/mips64el.config: -------------------------------------------------------------------------------- 1 | CONFIG_64BIT=y 2 | CONFIG_CPU_MIPS64_R2=y 3 | CONFIG_MIPS32_N32=y 4 | CONFIG_CPU_HAS_MSA=y 5 | CONFIG_MIPS_MALTA=y 6 | CONFIG_CPU_LITTLE_ENDIAN=y 7 | CONFIG_MIPS_CPS=y 8 | CONFIG_MIPS_FP_SUPPORT=y 9 | CONFIG_POWER_RESET=y 10 | CONFIG_POWER_RESET_SYSCON=y 11 | CONFIG_SERIAL_8250=y 12 | CONFIG_SERIAL_8250_CONSOLE=y 13 | CONFIG_CMDLINE_BOOL=y 14 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 15 | CONFIG_FRAME_WARN=1280 16 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/mipsel.config: -------------------------------------------------------------------------------- 1 | CONFIG_CPU_MIPS32_R2=y 2 | CONFIG_MIPS_MALTA=y 3 | CONFIG_CPU_LITTLE_ENDIAN=y 4 | CONFIG_MIPS_CPS=y 5 | CONFIG_MIPS_FP_SUPPORT=y 6 | CONFIG_POWER_RESET=y 7 | CONFIG_POWER_RESET_SYSCON=y 8 | CONFIG_SERIAL_8250=y 9 | CONFIG_SERIAL_8250_CONSOLE=y 10 | CONFIG_CMDLINE_BOOL=y 11 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 12 | CONFIG_FRAME_WARN=1024 13 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/powerpc.config: -------------------------------------------------------------------------------- 1 | CONFIG_PPC_QEMU_E500=y 2 | CONFIG_FSL_SOC_BOOKE=y 3 | CONFIG_PPC_85xx=y 4 | CONFIG_PHYS_64BIT=y 5 | CONFIG_SERIAL_8250=y 6 | CONFIG_SERIAL_8250_CONSOLE=y 7 | CONFIG_MATH_EMULATION=y 8 | CONFIG_CMDLINE_BOOL=y 9 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 10 | CONFIG_FRAME_WARN=1024 11 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/powerpc64le.config: -------------------------------------------------------------------------------- 1 | CONFIG_PPC64=y 2 | CONFIG_PPC_PSERIES=y 3 | CONFIG_ALTIVEC=y 4 | CONFIG_VSX=y 5 | CONFIG_PPC_OF_BOOT_TRAMPOLINE=y 6 | CONFIG_PPC_RADIX_MMU=y 7 | CONFIG_HVC_CONSOLE=y 8 | CONFIG_CPU_LITTLE_ENDIAN=y 9 | CONFIG_CMDLINE_BOOL=y 10 | CONFIG_CMDLINE="console=hvc0 wg.success=hvc1 panic_on_warn=1" 11 | CONFIG_SECTION_MISMATCH_WARN_ONLY=y 12 | CONFIG_FRAME_WARN=1280 13 | CONFIG_THREAD_SHIFT=14 14 | -------------------------------------------------------------------------------- /src/tests/qemu/arch/x86_64.config: -------------------------------------------------------------------------------- 1 | CONFIG_ACPI=y 2 | CONFIG_SERIAL_8250=y 3 | CONFIG_SERIAL_8250_CONSOLE=y 4 | CONFIG_CMDLINE_BOOL=y 5 | CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1" 6 | CONFIG_FRAME_WARN=1280 7 | -------------------------------------------------------------------------------- /src/tests/qemu/debug.config: -------------------------------------------------------------------------------- 1 | CONFIG_ENABLE_WARN_DEPRECATED=y 2 | CONFIG_ENABLE_MUST_CHECK=y 3 | CONFIG_FRAME_POINTER=y 4 | CONFIG_STACK_VALIDATION=y 5 | CONFIG_DEBUG_KERNEL=y 6 | CONFIG_DEBUG_INFO=y 7 | CONFIG_DEBUG_INFO_DWARF4=y 8 | CONFIG_PAGE_EXTENSION=y 9 | CONFIG_PAGE_POISONING=y 10 | CONFIG_DEBUG_OBJECTS=y 11 | CONFIG_DEBUG_OBJECTS_FREE=y 12 | CONFIG_DEBUG_OBJECTS_TIMERS=y 13 | CONFIG_DEBUG_OBJECTS_WORK=y 14 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y 15 | CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y 16 | CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 17 | CONFIG_SLUB_DEBUG_ON=y 18 | CONFIG_DEBUG_VM=y 19 | CONFIG_DEBUG_MEMORY_INIT=y 20 | CONFIG_HAVE_DEBUG_STACKOVERFLOW=y 21 | CONFIG_DEBUG_STACKOVERFLOW=y 22 | CONFIG_HAVE_ARCH_KMEMCHECK=y 23 | CONFIG_HAVE_ARCH_KASAN=y 24 | CONFIG_KASAN=y 25 | CONFIG_KASAN_INLINE=y 26 | CONFIG_UBSAN=y 27 | CONFIG_UBSAN_SANITIZE_ALL=y 28 | CONFIG_UBSAN_NO_ALIGNMENT=y 29 | CONFIG_UBSAN_NULL=y 30 | CONFIG_DEBUG_KMEMLEAK=y 31 | CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=8192 32 | CONFIG_DEBUG_STACK_USAGE=y 33 | CONFIG_DEBUG_SHIRQ=y 34 | CONFIG_WQ_WATCHDOG=y 35 | CONFIG_SCHED_DEBUG=y 36 | CONFIG_SCHED_INFO=y 37 | CONFIG_SCHEDSTATS=y 38 | CONFIG_SCHED_STACK_END_CHECK=y 39 | CONFIG_DEBUG_TIMEKEEPING=y 40 | CONFIG_TIMER_STATS=y 41 | CONFIG_DEBUG_PREEMPT=y 42 | CONFIG_DEBUG_RT_MUTEXES=y 43 | CONFIG_DEBUG_SPINLOCK=y 44 | CONFIG_DEBUG_MUTEXES=y 45 | CONFIG_DEBUG_LOCK_ALLOC=y 46 | CONFIG_PROVE_LOCKING=y 47 | CONFIG_LOCKDEP=y 48 | CONFIG_DEBUG_ATOMIC_SLEEP=y 49 | CONFIG_TRACE_IRQFLAGS=y 50 | CONFIG_DEBUG_BUGVERBOSE=y 51 | CONFIG_DEBUG_LIST=y 52 | CONFIG_DEBUG_PI_LIST=y 53 | CONFIG_PROVE_RCU=y 54 | CONFIG_SPARSE_RCU_POINTER=y 55 | CONFIG_RCU_CPU_STALL_TIMEOUT=21 56 | CONFIG_RCU_TRACE=y 57 | CONFIG_RCU_EQS_DEBUG=y 58 | CONFIG_USER_STACKTRACE_SUPPORT=y 59 | CONFIG_DEBUG_SG=y 60 | CONFIG_DEBUG_NOTIFIERS=y 61 | CONFIG_DOUBLEFAULT=y 62 | CONFIG_X86_DEBUG_FPU=y 63 | CONFIG_DEBUG_SECTION_MISMATCH=y 64 | CONFIG_DEBUG_PAGEALLOC=y 65 | CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y 66 | CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y 67 | -------------------------------------------------------------------------------- /src/tests/qemu/kernel.config: -------------------------------------------------------------------------------- 1 | CONFIG_NET=y 2 | CONFIG_NETDEVICES=y 3 | CONFIG_NET_CORE=y 4 | CONFIG_NET_IPIP=y 5 | CONFIG_DUMMY=y 6 | CONFIG_VETH=y 7 | CONFIG_MULTIUSER=y 8 | CONFIG_NAMESPACES=y 9 | CONFIG_NET_NS=y 10 | CONFIG_UNIX=y 11 | CONFIG_INET=y 12 | CONFIG_IPV6=y 13 | CONFIG_NETFILTER=y 14 | CONFIG_NETFILTER_ADVANCED=y 15 | CONFIG_NF_CONNTRACK=y 16 | CONFIG_NF_NAT=y 17 | CONFIG_NETFILTER_XTABLES=y 18 | CONFIG_NETFILTER_XT_NAT=y 19 | CONFIG_NETFILTER_XT_MATCH_LENGTH=y 20 | CONFIG_NETFILTER_XT_MARK=y 21 | CONFIG_NF_CONNTRACK_IPV4=y 22 | CONFIG_NF_NAT_IPV4=y 23 | CONFIG_IP_NF_IPTABLES=y 24 | CONFIG_IP_NF_FILTER=y 25 | CONFIG_IP_NF_MANGLE=y 26 | CONFIG_IP_NF_NAT=y 27 | CONFIG_IP_ADVANCED_ROUTER=y 28 | CONFIG_IP_MULTIPLE_TABLES=y 29 | CONFIG_IPV6_MULTIPLE_TABLES=y 30 | CONFIG_TTY=y 31 | CONFIG_BINFMT_ELF=y 32 | CONFIG_BINFMT_SCRIPT=y 33 | CONFIG_VDSO=y 34 | CONFIG_VIRTUALIZATION=y 35 | CONFIG_HYPERVISOR_GUEST=y 36 | CONFIG_PARAVIRT=y 37 | CONFIG_KVM_GUEST=y 38 | CONFIG_PARAVIRT_SPINLOCKS=y 39 | CONFIG_PRINTK=y 40 | CONFIG_KALLSYMS=y 41 | CONFIG_BUG=y 42 | CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y 43 | CONFIG_JUMP_LABEL=y 44 | CONFIG_EMBEDDED=n 45 | CONFIG_BASE_FULL=y 46 | CONFIG_FUTEX=y 47 | CONFIG_SHMEM=y 48 | CONFIG_SLUB=y 49 | CONFIG_SPARSEMEM_VMEMMAP=y 50 | CONFIG_SMP=y 51 | CONFIG_SCHED_SMT=y 52 | CONFIG_SCHED_MC=y 53 | CONFIG_NUMA=y 54 | CONFIG_PREEMPT=y 55 | CONFIG_NO_HZ=y 56 | CONFIG_NO_HZ_IDLE=y 57 | CONFIG_NO_HZ_FULL=n 58 | CONFIG_HZ_PERIODIC=n 59 | CONFIG_HIGH_RES_TIMERS=y 60 | CONFIG_COMPAT_32BIT_TIME=y 61 | CONFIG_ARCH_RANDOM=y 62 | CONFIG_FILE_LOCKING=y 63 | CONFIG_POSIX_TIMERS=y 64 | CONFIG_DEVTMPFS=y 65 | CONFIG_PROC_FS=y 66 | CONFIG_PROC_SYSCTL=y 67 | CONFIG_SYSFS=y 68 | CONFIG_TMPFS=y 69 | CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15 70 | CONFIG_LOG_BUF_SHIFT=18 71 | CONFIG_PRINTK_TIME=y 72 | CONFIG_BLK_DEV_INITRD=y 73 | CONFIG_LEGACY_VSYSCALL_NONE=y 74 | CONFIG_KERNEL_GZIP=y 75 | CONFIG_PANIC_ON_OOPS=y 76 | CONFIG_BUG_ON_DATA_CORRUPTION=y 77 | CONFIG_LOCKUP_DETECTOR=y 78 | CONFIG_SOFTLOCKUP_DETECTOR=y 79 | CONFIG_HARDLOCKUP_DETECTOR=y 80 | CONFIG_WQ_WATCHDOG=y 81 | CONFIG_DETECT_HUNG_TASK=y 82 | CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y 83 | CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y 84 | CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y 85 | CONFIG_PANIC_TIMEOUT=-1 86 | CONFIG_STACKTRACE=y 87 | CONFIG_EARLY_PRINTK=y 88 | CONFIG_GDB_SCRIPTS=y 89 | CONFIG_WIREGUARD=y 90 | CONFIG_WIREGUARD_DEBUG=y 91 | -------------------------------------------------------------------------------- /src/timers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. 4 | */ 5 | 6 | #ifndef _WG_TIMERS_H 7 | #define _WG_TIMERS_H 8 | 9 | #include 10 | 11 | struct wg_peer; 12 | 13 | void wg_timers_init(struct wg_peer *peer); 14 | void wg_timers_stop(struct wg_peer *peer); 15 | void wg_timers_data_sent(struct wg_peer *peer); 16 | void wg_timers_data_received(struct wg_peer *peer); 17 | void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer); 18 | void wg_timers_any_authenticated_packet_received(struct wg_peer *peer); 19 | void wg_timers_handshake_initiated(struct wg_peer *peer); 20 | void wg_timers_handshake_complete(struct wg_peer *peer); 21 | void wg_timers_session_derived(struct wg_peer *peer); 22 | void wg_timers_any_authenticated_packet_traversal(struct wg_peer *peer); 23 | 24 | static inline bool wg_birthdate_has_expired(u64 birthday_nanoseconds, 25 | u64 expiration_seconds) 26 | { 27 | return (s64)(birthday_nanoseconds + expiration_seconds * NSEC_PER_SEC) 28 | <= (s64)ktime_get_coarse_boottime_ns(); 29 | } 30 | 31 | #endif /* _WG_TIMERS_H */ 32 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #ifndef WIREGUARD_VERSION 2 | #define WIREGUARD_VERSION "1.0.20220627" 3 | #endif 4 | --------------------------------------------------------------------------------