Showing preview only (528K chars total). Download the full file or copy to clipboard to get everything.
Repository: WireGuard/wireguard-tools
Branch: master
Commit: 025f00454fec
Files: 125
Total size: 494.1 KB
Directory structure:
gitextract_oz15ttsd/
├── .gitattributes
├── .gitignore
├── COPYING
├── README.md
├── contrib/
│ ├── dns-hatchet/
│ │ ├── README
│ │ ├── apply.sh
│ │ └── hatchet.bash
│ ├── embeddable-wg-library/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README
│ │ ├── test.c
│ │ ├── wireguard.c
│ │ └── wireguard.h
│ ├── external-tests/
│ │ ├── haskell/
│ │ │ ├── Setup.hs
│ │ │ ├── package.yaml
│ │ │ ├── src/
│ │ │ │ ├── Data/
│ │ │ │ │ └── Time/
│ │ │ │ │ └── TAI64.hs
│ │ │ │ └── Main.hs
│ │ │ └── stack.yaml
│ │ ├── python/
│ │ │ └── main.py
│ │ └── rust/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── extract-handshakes/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README
│ │ ├── extract-handshakes.sh
│ │ └── offset-finder.c
│ ├── highlighter/
│ │ ├── Makefile
│ │ ├── README
│ │ ├── fuzz.c
│ │ ├── gui/
│ │ │ ├── highlight.cpp
│ │ │ └── highlight.pro
│ │ ├── highlight.c
│ │ ├── highlighter.c
│ │ └── highlighter.h
│ ├── json/
│ │ ├── README
│ │ └── wg-json
│ ├── keygen-html/
│ │ ├── .gitignore
│ │ ├── README
│ │ ├── keygen.html
│ │ └── wireguard.js
│ ├── launchd/
│ │ ├── README
│ │ └── com.wireguard.wg0.plist
│ ├── nat-hole-punching/
│ │ ├── README
│ │ ├── nat-punch-client.c
│ │ └── nat-punch-server.c
│ ├── ncat-client-server/
│ │ ├── README
│ │ ├── client-quick.sh
│ │ ├── client.sh
│ │ └── server.sh
│ ├── reresolve-dns/
│ │ ├── README
│ │ └── reresolve-dns.sh
│ ├── sticky-sockets/
│ │ ├── README
│ │ └── sticky-sockets.c
│ └── synergy/
│ ├── README
│ ├── synergy-client.sh
│ └── synergy-server.sh
└── src/
├── Makefile
├── completion/
│ ├── wg-quick.bash-completion
│ └── wg.bash-completion
├── config.c
├── config.h
├── containers.h
├── ctype.h
├── curve25519-fiat32.h
├── curve25519-hacl64.h
├── curve25519.c
├── curve25519.h
├── encoding.c
├── encoding.h
├── fuzz/
│ ├── .gitignore
│ ├── Makefile
│ ├── cmd.c
│ ├── config.c
│ ├── set.c
│ ├── setconf.c
│ ├── stringlist.c
│ └── uapi.c
├── genkey.c
├── ipc-freebsd.h
├── ipc-linux.h
├── ipc-openbsd.h
├── ipc-uapi-unix.h
├── ipc-uapi-windows.h
├── ipc-uapi.h
├── ipc-windows.h
├── ipc.c
├── ipc.h
├── man/
│ ├── wg-quick.8
│ └── wg.8
├── netlink.h
├── pubkey.c
├── set.c
├── setconf.c
├── show.c
├── showconf.c
├── subcommands.h
├── systemd/
│ ├── wg-quick.target
│ └── wg-quick@.service
├── terminal.c
├── terminal.h
├── uapi/
│ ├── freebsd/
│ │ └── dev/
│ │ └── wg/
│ │ └── if_wg.h
│ ├── linux/
│ │ └── linux/
│ │ └── wireguard.h
│ ├── openbsd/
│ │ └── net/
│ │ └── if_wg.h
│ └── windows/
│ └── wireguard.h
├── version.h
├── wg-quick/
│ ├── android.c
│ ├── darwin.bash
│ ├── freebsd.bash
│ ├── linux.bash
│ └── openbsd.bash
├── wg.c
└── wincompat/
├── compat.h
├── include/
│ ├── arpa/
│ │ └── inet.h
│ ├── hashtable.h
│ ├── net/
│ │ └── if.h
│ ├── netdb.h
│ ├── netinet/
│ │ └── in.h
│ └── sys/
│ └── socket.h
├── init.c
├── libc.c
├── load_config.c
├── loader.c
├── manifest.xml
└── resources.rc
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
.gitattributes export-ignore
.gitignore export-ignore
================================================
FILE: .gitignore
================================================
cscope.out
*.o
*.d
*.lib
*.dll
*.gch
*.dwo
src/wg
src/wg.exe
*.swp
*.id0
*.id1
*.id2
*.nam
*.til
*.pro.user
maint/
================================================
FILE: COPYING
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
================================================
FILE: README.md
================================================
# [wireguard-tools](https://git.zx2c4.com/wireguard-tools/about/) — tools for configuring [WireGuard](https://www.wireguard.com/)
This supplies the main userspace tooling for using and configuring WireGuard
tunnels, including the
[`wg(8)`](https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8) and
[`wg-quick(8)`](https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8)
utilities. This project supports Linux, OpenBSD, FreeBSD, macOS, Windows, and
Android.
**More information may be found at [WireGuard.com](https://www.wireguard.com/).**
## Building
$ cd src
$ make
There are no dependencies other than a good C compiler and a sane libc.
## Installing
# make install
This command takes into account several environment variables:
* `PREFIX` default: `/usr`
* `DESTDIR` default:
* `BINDIR` default: `$(PREFIX)/bin`
* `LIBDIR` default: `$(PREFIX)/lib`
* `MANDIR` default: `$(PREFIX)/share/man`
* `BASHCOMPDIR` default: `$(PREFIX)/share/bash-completion/completions`
* `RUNSTATEDIR` default: `/var/run`
* `PKG_CONFIG` default: `pkg-config`
* `WITH_BASHCOMPLETION` default: [auto-detect]
* `WITH_WGQUICK` default: [auto-detect]
* `WITH_SYSTEMDUNITS` default: [auto-detect]
* `DEBUG` default:
The first section is rather standard. The second section is not:
* `WITH_BASHCOMPLETION` decides whether or not bash completion files for the
tools are installed. This is just a nice thing for people who have bash.
If you don't have bash, or don't want this, set the environment variable
to `no`. If you'd like to force its use, even if bash-completion isn't
detected in `DESTDIR`, then set it to `yes`.
* `WITH_WGQUICK` decides whether or not the wg-quick(8) script is installed.
This is a very quick and dirty bash script for reading a few extra
variables from wg(8)-style configuration files, and automatically
configures the interface. If you don't have bash, you probably don't want
this at all. Likewise, if you already have a working network management
tool or configuration, you probably want to integrate wg(8) or the direct
WireGuard API into your network manager, rather than using wg-quick(8).
But for folks who like simple quick and dirty scripts, this is nice. If you'd
like to force its use, even if bash isn't detected in DESTDIR, then set it
to `yes`.
* `WITH_SYSTEMDUNITS` decides whether or not systemd units are installed for
wg-quick(8). If you don't use systemd, you certainly don't want this, and
should set it to `no`. If systemd isn't auto-detected, but you still would
like to install it, set this to `yes`.
* `DEBUG` decides whether to build with `-g`, when set to `yes`.
If you're a simple `make && make install` kind of user, you can get away with
not setting these variables and relying on the auto-detection. However, if
you're writing a package for a distro, you'll want to explicitly set these,
depending on what you want.
## `contrib/`
The `contrib/` subdirectory contains various scripts and examples. Most of these
are not immediately useful for production use, but should provide inspiration for
creating fully-featured tools. See the `README` in each directory.
## License
This project is released under the [GPLv2](COPYING).
================================================
FILE: contrib/dns-hatchet/README
================================================
The DNS Hatchet
===============
This is a workaround for distributions without resolvconf or any proper
mechanism of setting the DNS. Running 'apply.sh` in this directory will
insert 'hatchet.bash` into the right place in 'wg-quick.bash`. It is
recommended that distributions without any resolvconf available run this
before calling 'make install` in their packaging scripts.
================================================
FILE: contrib/dns-hatchet/apply.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
ME="$(readlink -f "$(dirname "$(readlink -f "$0")")")"
TOOLS="$ME/../../src"
sed -i "/~~ function override insertion point ~~/r $ME/hatchet.bash" "$TOOLS/wg-quick/linux.bash"
================================================
FILE: contrib/dns-hatchet/hatchet.bash
================================================
set_dns() {
[[ ${#DNS[@]} -gt 0 ]] || return 0
if [[ $(resolvconf --version 2>/dev/null) == openresolv\ * ]]; then
{ printf 'nameserver %s\n' "${DNS[@]}"
[[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
} | cmd resolvconf -a "$INTERFACE" -m 0 -x
else
echo "[#] mount \`${DNS[*]}' /etc/resolv.conf" >&2
[[ -e /etc/resolv.conf ]] || touch /etc/resolv.conf
{ cat <<-_EOF
# This file was generated by wg-quick(8) for use with
# the WireGuard interface $INTERFACE. It cannot be
# removed or altered directly. You may remove this file
# by running \`wg-quick down $INTERFACE', or if that
# poses problems, run \`umount /etc/resolv.conf'.
_EOF
printf 'nameserver %s\n' "${DNS[@]}"
[[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
} | unshare -m --propagation shared bash -c "$(cat <<-_EOF
set -e
context="\$(stat -c %C /etc/resolv.conf 2>/dev/null)" || unset context
mount --make-private /dev/shm
mount -t tmpfs none /dev/shm
cat > /dev/shm/resolv.conf
[[ -z \$context || \$context == "?" ]] || chcon "\$context" /dev/shm/resolv.conf 2>/dev/null || true
mount -o remount,ro /dev/shm
mount -o bind,ro /dev/shm/resolv.conf /etc/resolv.conf
_EOF
)"
fi
HAVE_SET_DNS=1
}
unset_dns() {
[[ ${#DNS[@]} -gt 0 ]] || return 0
if [[ $(resolvconf --version 2>/dev/null) == openresolv\ * ]]; then
cmd resolvconf -d "$INTERFACE"
else
cmd umount /etc/resolv.conf
fi
}
================================================
FILE: contrib/embeddable-wg-library/.gitignore
================================================
test
================================================
FILE: contrib/embeddable-wg-library/Makefile
================================================
CFLAGS += -Wall
test: test.c wireguard.c wireguard.h
clean:
rm -f test
.PHONY: clean
================================================
FILE: contrib/embeddable-wg-library/README
================================================
Embeddable WireGuard C Library
==============================
This is a mini single-file library, meant to be embedded directly into the
source code of your program. It is *not* meant to be built as a shared
library.
Usage
-----
Copy wireguard.c and wireguard.h into your project. They should build with
any C89 compiler. There are no dependencies except libc.
Please see the set of simple functions in wireguard.h for information on
how to use, as well as the example code in test.c.
License
-------
Because this uses code from libmnl, wireguard.c and wireguard.h are licensed
under the LGPL-2.1+.
================================================
FILE: contrib/embeddable-wg-library/test.c
================================================
// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include "wireguard.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void list_devices(void)
{
char *device_names, *device_name;
size_t len;
device_names = wg_list_device_names();
if (!device_names) {
perror("Unable to get device names");
exit(1);
}
wg_for_each_device_name(device_names, device_name, len) {
wg_device *device;
wg_peer *peer;
wg_key_b64_string key;
if (wg_get_device(&device, device_name) < 0) {
perror("Unable to get device");
continue;
}
if (device->flags & WGDEVICE_HAS_PUBLIC_KEY) {
wg_key_to_base64(key, device->public_key);
printf("%s has public key %s\n", device_name, key);
} else
printf("%s has no public key\n", device_name);
wg_for_each_peer(device, peer) {
wg_key_to_base64(key, peer->public_key);
printf(" - peer %s\n", key);
}
wg_free_device(device);
}
free(device_names);
}
int main(int argc, char *argv[])
{
wg_peer new_peer = {
.flags = WGPEER_HAS_PUBLIC_KEY | WGPEER_REPLACE_ALLOWEDIPS
};
wg_device new_device = {
.name = "wgtest0",
.listen_port = 1234,
.flags = WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_LISTEN_PORT,
.first_peer = &new_peer,
.last_peer = &new_peer
};
wg_key temp_private_key;
wg_generate_private_key(temp_private_key);
wg_generate_public_key(new_peer.public_key, temp_private_key);
wg_generate_private_key(new_device.private_key);
if (wg_add_device(new_device.name) < 0) {
perror("Unable to add device");
exit(1);
}
if (wg_set_device(&new_device) < 0) {
perror("Unable to set device");
exit(1);
}
list_devices();
if (wg_del_device(new_device.name) < 0) {
perror("Unable to delete device");
exit(1);
}
return 0;
}
================================================
FILE: contrib/embeddable-wg-library/wireguard.c
================================================
// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright (C) 2008-2012 Pablo Neira Ayuso <pablo@netfilter.org>.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <linux/genetlink.h>
#include <linux/if_link.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include "wireguard.h"
/* wireguard.h netlink uapi: */
#define WG_GENL_NAME "wireguard"
#define WG_GENL_VERSION 1
enum wg_cmd {
WG_CMD_GET_DEVICE,
WG_CMD_SET_DEVICE,
__WG_CMD_MAX
};
enum wgdevice_flag {
WGDEVICE_F_REPLACE_PEERS = 1U << 0
};
enum wgdevice_attribute {
WGDEVICE_A_UNSPEC,
WGDEVICE_A_IFINDEX,
WGDEVICE_A_IFNAME,
WGDEVICE_A_PRIVATE_KEY,
WGDEVICE_A_PUBLIC_KEY,
WGDEVICE_A_FLAGS,
WGDEVICE_A_LISTEN_PORT,
WGDEVICE_A_FWMARK,
WGDEVICE_A_PEERS,
__WGDEVICE_A_LAST
};
enum wgpeer_flag {
WGPEER_F_REMOVE_ME = 1U << 0,
WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1
};
enum wgpeer_attribute {
WGPEER_A_UNSPEC,
WGPEER_A_PUBLIC_KEY,
WGPEER_A_PRESHARED_KEY,
WGPEER_A_FLAGS,
WGPEER_A_ENDPOINT,
WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
WGPEER_A_LAST_HANDSHAKE_TIME,
WGPEER_A_RX_BYTES,
WGPEER_A_TX_BYTES,
WGPEER_A_ALLOWEDIPS,
WGPEER_A_PROTOCOL_VERSION,
__WGPEER_A_LAST
};
enum wgallowedip_attribute {
WGALLOWEDIP_A_UNSPEC,
WGALLOWEDIP_A_FAMILY,
WGALLOWEDIP_A_IPADDR,
WGALLOWEDIP_A_CIDR_MASK,
__WGALLOWEDIP_A_LAST
};
/* libmnl mini library: */
#define MNL_SOCKET_AUTOPID 0
#define MNL_ALIGNTO 4
#define MNL_ALIGN(len) (((len)+MNL_ALIGNTO-1) & ~(MNL_ALIGNTO-1))
#define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr))
#define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr))
enum mnl_attr_data_type {
MNL_TYPE_UNSPEC,
MNL_TYPE_U8,
MNL_TYPE_U16,
MNL_TYPE_U32,
MNL_TYPE_U64,
MNL_TYPE_STRING,
MNL_TYPE_FLAG,
MNL_TYPE_MSECS,
MNL_TYPE_NESTED,
MNL_TYPE_NESTED_COMPAT,
MNL_TYPE_NUL_STRING,
MNL_TYPE_BINARY,
MNL_TYPE_MAX,
};
#define mnl_attr_for_each(attr, nlh, offset) \
for ((attr) = mnl_nlmsg_get_payload_offset((nlh), (offset)); \
mnl_attr_ok((attr), (char *)mnl_nlmsg_get_payload_tail(nlh) - (char *)(attr)); \
(attr) = mnl_attr_next(attr))
#define mnl_attr_for_each_nested(attr, nest) \
for ((attr) = mnl_attr_get_payload(nest); \
mnl_attr_ok((attr), (char *)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - (char *)(attr)); \
(attr) = mnl_attr_next(attr))
#define mnl_attr_for_each_payload(payload, payload_size) \
for ((attr) = (payload); \
mnl_attr_ok((attr), (char *)(payload) + payload_size - (char *)(attr)); \
(attr) = mnl_attr_next(attr))
#define MNL_CB_ERROR -1
#define MNL_CB_STOP 0
#define MNL_CB_OK 1
typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data);
typedef int (*mnl_cb_t)(const struct nlmsghdr *nlh, void *data);
#ifndef MNL_ARRAY_SIZE
#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
#endif
static size_t mnl_ideal_socket_buffer_size(void)
{
static size_t size = 0;
if (size)
return size;
size = (size_t)sysconf(_SC_PAGESIZE);
if (size > 8192)
size = 8192;
return size;
}
static size_t mnl_nlmsg_size(size_t len)
{
return len + MNL_NLMSG_HDRLEN;
}
static struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
{
int len = MNL_ALIGN(sizeof(struct nlmsghdr));
struct nlmsghdr *nlh = buf;
memset(buf, 0, len);
nlh->nlmsg_len = len;
return nlh;
}
static void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
{
char *ptr = (char *)nlh + nlh->nlmsg_len;
size_t len = MNL_ALIGN(size);
nlh->nlmsg_len += len;
memset(ptr, 0, len);
return ptr;
}
static void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
{
return (void *)nlh + MNL_NLMSG_HDRLEN;
}
static void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset)
{
return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
}
static bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
{
return len >= (int)sizeof(struct nlmsghdr) &&
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
(int)nlh->nlmsg_len <= len;
}
static struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
{
*len -= MNL_ALIGN(nlh->nlmsg_len);
return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
}
static void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
{
return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
}
static bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
{
return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
}
static bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
{
return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
}
static uint16_t mnl_attr_get_type(const struct nlattr *attr)
{
return attr->nla_type & NLA_TYPE_MASK;
}
static uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
{
return attr->nla_len - MNL_ATTR_HDRLEN;
}
static void *mnl_attr_get_payload(const struct nlattr *attr)
{
return (void *)attr + MNL_ATTR_HDRLEN;
}
static bool mnl_attr_ok(const struct nlattr *attr, int len)
{
return len >= (int)sizeof(struct nlattr) &&
attr->nla_len >= sizeof(struct nlattr) &&
(int)attr->nla_len <= len;
}
static struct nlattr *mnl_attr_next(const struct nlattr *attr)
{
return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
}
static int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
{
if (mnl_attr_get_type(attr) > max) {
errno = EOPNOTSUPP;
return -1;
}
return 1;
}
static int __mnl_attr_validate(const struct nlattr *attr,
enum mnl_attr_data_type type, size_t exp_len)
{
uint16_t attr_len = mnl_attr_get_payload_len(attr);
const char *attr_data = mnl_attr_get_payload(attr);
if (attr_len < exp_len) {
errno = ERANGE;
return -1;
}
switch(type) {
case MNL_TYPE_FLAG:
if (attr_len > 0) {
errno = ERANGE;
return -1;
}
break;
case MNL_TYPE_NUL_STRING:
if (attr_len == 0) {
errno = ERANGE;
return -1;
}
if (attr_data[attr_len-1] != '\0') {
errno = EINVAL;
return -1;
}
break;
case MNL_TYPE_STRING:
if (attr_len == 0) {
errno = ERANGE;
return -1;
}
break;
case MNL_TYPE_NESTED:
if (attr_len == 0)
break;
if (attr_len < MNL_ATTR_HDRLEN) {
errno = ERANGE;
return -1;
}
break;
default:
break;
}
if (exp_len && attr_len > exp_len) {
errno = ERANGE;
return -1;
}
return 0;
}
static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
[MNL_TYPE_U8] = sizeof(uint8_t),
[MNL_TYPE_U16] = sizeof(uint16_t),
[MNL_TYPE_U32] = sizeof(uint32_t),
[MNL_TYPE_U64] = sizeof(uint64_t),
[MNL_TYPE_MSECS] = sizeof(uint64_t),
};
static int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
{
int exp_len;
if (type >= MNL_TYPE_MAX) {
errno = EINVAL;
return -1;
}
exp_len = mnl_attr_data_type_len[type];
return __mnl_attr_validate(attr, type, exp_len);
}
static int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
mnl_attr_cb_t cb, void *data)
{
int ret = MNL_CB_OK;
const struct nlattr *attr;
mnl_attr_for_each(attr, nlh, offset)
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret;
return ret;
}
static int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb,
void *data)
{
int ret = MNL_CB_OK;
const struct nlattr *attr;
mnl_attr_for_each_nested(attr, nested)
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
return ret;
return ret;
}
static uint8_t mnl_attr_get_u8(const struct nlattr *attr)
{
return *((uint8_t *)mnl_attr_get_payload(attr));
}
static uint16_t mnl_attr_get_u16(const struct nlattr *attr)
{
return *((uint16_t *)mnl_attr_get_payload(attr));
}
static uint32_t mnl_attr_get_u32(const struct nlattr *attr)
{
return *((uint32_t *)mnl_attr_get_payload(attr));
}
static uint64_t mnl_attr_get_u64(const struct nlattr *attr)
{
uint64_t tmp;
memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
return tmp;
}
static const char *mnl_attr_get_str(const struct nlattr *attr)
{
return mnl_attr_get_payload(attr);
}
static void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len,
const void *data)
{
struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
int pad;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy(mnl_attr_get_payload(attr), data, len);
nlh->nlmsg_len += MNL_ALIGN(payload_len);
pad = MNL_ALIGN(len) - len;
if (pad > 0)
memset(mnl_attr_get_payload(attr) + len, 0, pad);
}
static void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data)
{
mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
}
static void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
{
mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
}
static void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data)
{
mnl_attr_put(nlh, type, strlen(data)+1, data);
}
static struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type)
{
struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
start->nla_type = NLA_F_NESTED | type;
nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
return start;
}
static bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, size_t len, const void *data)
{
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
return false;
mnl_attr_put(nlh, type, len, data);
return true;
}
static bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint8_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
}
static bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint16_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
}
static bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type, uint32_t data)
{
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
}
static struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen,
uint16_t type)
{
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
return NULL;
return mnl_attr_nest_start(nlh, type);
}
static void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
{
start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
}
static void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start)
{
nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
}
static int mnl_cb_noop(__attribute__((unused)) const struct nlmsghdr *nlh, __attribute__((unused)) void *data)
{
return MNL_CB_OK;
}
static int mnl_cb_error(const struct nlmsghdr *nlh, __attribute__((unused)) void *data)
{
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
errno = EBADMSG;
return MNL_CB_ERROR;
}
if (err->error < 0)
errno = -err->error;
else
errno = err->error;
return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
}
static int mnl_cb_stop(__attribute__((unused)) const struct nlmsghdr *nlh, __attribute__((unused)) void *data)
{
return MNL_CB_STOP;
}
static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
[NLMSG_NOOP] = mnl_cb_noop,
[NLMSG_ERROR] = mnl_cb_error,
[NLMSG_DONE] = mnl_cb_stop,
[NLMSG_OVERRUN] = mnl_cb_noop,
};
static int __mnl_cb_run(const void *buf, size_t numbytes,
unsigned int seq, unsigned int portid,
mnl_cb_t cb_data, void *data,
const mnl_cb_t *cb_ctl_array,
unsigned int cb_ctl_array_len)
{
int ret = MNL_CB_OK, len = numbytes;
const struct nlmsghdr *nlh = buf;
while (mnl_nlmsg_ok(nlh, len)) {
if (!mnl_nlmsg_portid_ok(nlh, portid)) {
errno = ESRCH;
return -1;
}
if (!mnl_nlmsg_seq_ok(nlh, seq)) {
errno = EPROTO;
return -1;
}
if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
errno = EINTR;
return -1;
}
if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
if (cb_data){
ret = cb_data(nlh, data);
if (ret <= MNL_CB_STOP)
goto out;
}
} else if (nlh->nlmsg_type < cb_ctl_array_len) {
if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
if (ret <= MNL_CB_STOP)
goto out;
}
} else if (default_cb_array[nlh->nlmsg_type]) {
ret = default_cb_array[nlh->nlmsg_type](nlh, data);
if (ret <= MNL_CB_STOP)
goto out;
}
nlh = mnl_nlmsg_next(nlh, &len);
}
out:
return ret;
}
static int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
unsigned int portid, mnl_cb_t cb_data, void *data,
const mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
{
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
cb_ctl_array, cb_ctl_array_len);
}
static int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
unsigned int portid, mnl_cb_t cb_data, void *data)
{
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
}
struct mnl_socket {
int fd;
struct sockaddr_nl addr;
};
static unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
{
return nl->addr.nl_pid;
}
static struct mnl_socket *__mnl_socket_open(int bus, int flags)
{
struct mnl_socket *nl;
nl = calloc(1, sizeof(struct mnl_socket));
if (nl == NULL)
return NULL;
nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus);
if (nl->fd == -1) {
free(nl);
return NULL;
}
return nl;
}
static struct mnl_socket *mnl_socket_open(int bus)
{
return __mnl_socket_open(bus, 0);
}
static int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
{
int ret;
socklen_t addr_len;
nl->addr.nl_family = AF_NETLINK;
nl->addr.nl_groups = groups;
nl->addr.nl_pid = pid;
ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr));
if (ret < 0)
return ret;
addr_len = sizeof(nl->addr);
ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len);
if (ret < 0)
return ret;
if (addr_len != sizeof(nl->addr)) {
errno = EINVAL;
return -1;
}
if (nl->addr.nl_family != AF_NETLINK) {
errno = EINVAL;
return -1;
}
return 0;
}
static ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *buf,
size_t len)
{
static const struct sockaddr_nl snl = {
.nl_family = AF_NETLINK
};
return sendto(nl->fd, buf, len, 0,
(struct sockaddr *) &snl, sizeof(snl));
}
static ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf,
size_t bufsiz)
{
ssize_t ret;
struct sockaddr_nl addr;
struct iovec iov = {
.iov_base = buf,
.iov_len = bufsiz,
};
struct msghdr msg = {
.msg_name = &addr,
.msg_namelen = sizeof(struct sockaddr_nl),
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
ret = recvmsg(nl->fd, &msg, 0);
if (ret == -1)
return ret;
if (msg.msg_flags & MSG_TRUNC) {
errno = ENOSPC;
return -1;
}
if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
errno = EINVAL;
return -1;
}
return ret;
}
static int mnl_socket_close(struct mnl_socket *nl)
{
int ret = close(nl->fd);
free(nl);
return ret;
}
/* mnlg mini library: */
struct mnlg_socket {
struct mnl_socket *nl;
char *buf;
uint16_t id;
uint8_t version;
unsigned int seq;
unsigned int portid;
};
static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
uint16_t flags, uint16_t id,
uint8_t version)
{
struct nlmsghdr *nlh;
struct genlmsghdr *genl;
nlh = mnl_nlmsg_put_header(nlg->buf);
nlh->nlmsg_type = id;
nlh->nlmsg_flags = flags;
nlg->seq = time(NULL);
nlh->nlmsg_seq = nlg->seq;
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
genl->cmd = cmd;
genl->version = version;
return nlh;
}
static struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
uint16_t flags)
{
return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version);
}
static int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh)
{
return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len);
}
static int mnlg_cb_noop(const struct nlmsghdr *nlh, void *data)
{
(void)nlh;
(void)data;
return MNL_CB_OK;
}
static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data)
{
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
(void)data;
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
errno = EBADMSG;
return MNL_CB_ERROR;
}
/* Netlink subsystems returns the errno value with different signess */
if (err->error < 0)
errno = -err->error;
else
errno = err->error;
return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
}
static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data)
{
(void)data;
if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_len == mnl_nlmsg_size(sizeof(int))) {
int error = *(int *)mnl_nlmsg_get_payload(nlh);
/* Netlink subsystems returns the errno value with different signess */
if (error < 0)
errno = -error;
else
errno = error;
return error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
}
return MNL_CB_STOP;
}
static const mnl_cb_t mnlg_cb_array[] = {
[NLMSG_NOOP] = mnlg_cb_noop,
[NLMSG_ERROR] = mnlg_cb_error,
[NLMSG_DONE] = mnlg_cb_stop,
[NLMSG_OVERRUN] = mnlg_cb_noop,
};
static int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data)
{
int err;
do {
err = mnl_socket_recvfrom(nlg->nl, nlg->buf,
mnl_ideal_socket_buffer_size());
if (err <= 0)
break;
err = mnl_cb_run2(nlg->buf, err, nlg->seq, nlg->portid,
data_cb, data, mnlg_cb_array, MNL_ARRAY_SIZE(mnlg_cb_array));
} while (err > 0);
return err;
}
static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
return MNL_CB_ERROR;
if (type == CTRL_ATTR_FAMILY_ID &&
mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
return MNL_CB_ERROR;
tb[type] = attr;
return MNL_CB_OK;
}
static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
{
uint16_t *p_id = data;
struct nlattr *tb[CTRL_ATTR_MAX + 1] = { 0 };
mnl_attr_parse(nlh, sizeof(struct genlmsghdr), get_family_id_attr_cb, tb);
if (!tb[CTRL_ATTR_FAMILY_ID])
return MNL_CB_ERROR;
*p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
return MNL_CB_OK;
}
static struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
{
struct mnlg_socket *nlg;
struct nlmsghdr *nlh;
int err;
nlg = malloc(sizeof(*nlg));
if (!nlg)
return NULL;
nlg->id = 0;
err = -ENOMEM;
nlg->buf = malloc(mnl_ideal_socket_buffer_size());
if (!nlg->buf)
goto err_buf_alloc;
nlg->nl = mnl_socket_open(NETLINK_GENERIC);
if (!nlg->nl) {
err = -errno;
goto err_mnl_socket_open;
}
if (mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID) < 0) {
err = -errno;
goto err_mnl_socket_bind;
}
nlg->portid = mnl_socket_get_portid(nlg->nl);
nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
if (mnlg_socket_send(nlg, nlh) < 0) {
err = -errno;
goto err_mnlg_socket_send;
}
errno = 0;
if (mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id) < 0) {
errno = errno == ENOENT ? EPROTONOSUPPORT : errno;
err = errno ? -errno : -ENOSYS;
goto err_mnlg_socket_recv_run;
}
nlg->version = version;
errno = 0;
return nlg;
err_mnlg_socket_recv_run:
err_mnlg_socket_send:
err_mnl_socket_bind:
mnl_socket_close(nlg->nl);
err_mnl_socket_open:
free(nlg->buf);
err_buf_alloc:
free(nlg);
errno = -err;
return NULL;
}
static void mnlg_socket_close(struct mnlg_socket *nlg)
{
mnl_socket_close(nlg->nl);
free(nlg->buf);
free(nlg);
}
/* wireguard-specific parts: */
struct string_list {
char *buffer;
size_t len;
size_t cap;
};
static int string_list_add(struct string_list *list, const char *str)
{
size_t len = strlen(str) + 1;
if (len == 1)
return 0;
if (len >= list->cap - list->len) {
char *new_buffer;
size_t new_cap = list->cap * 2;
if (new_cap < list->len +len + 1)
new_cap = list->len + len + 1;
new_buffer = realloc(list->buffer, new_cap);
if (!new_buffer)
return -errno;
list->buffer = new_buffer;
list->cap = new_cap;
}
memcpy(list->buffer + list->len, str, len);
list->len += len;
list->buffer[list->len] = '\0';
return 0;
}
struct interface {
const char *name;
bool is_wireguard;
};
static int parse_linkinfo(const struct nlattr *attr, void *data)
{
struct interface *interface = data;
if (mnl_attr_get_type(attr) == IFLA_INFO_KIND && !strcmp(WG_GENL_NAME, mnl_attr_get_str(attr)))
interface->is_wireguard = true;
return MNL_CB_OK;
}
static int parse_infomsg(const struct nlattr *attr, void *data)
{
struct interface *interface = data;
if (mnl_attr_get_type(attr) == IFLA_LINKINFO)
return mnl_attr_parse_nested(attr, parse_linkinfo, data);
else if (mnl_attr_get_type(attr) == IFLA_IFNAME)
interface->name = mnl_attr_get_str(attr);
return MNL_CB_OK;
}
static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
{
struct string_list *list = data;
struct interface interface = { 0 };
int ret;
ret = mnl_attr_parse(nlh, sizeof(struct ifinfomsg), parse_infomsg, &interface);
if (ret != MNL_CB_OK)
return ret;
if (interface.name && interface.is_wireguard)
ret = string_list_add(list, interface.name);
if (ret < 0)
return ret;
if (nlh->nlmsg_type != NLMSG_DONE)
return MNL_CB_OK + 1;
return MNL_CB_OK;
}
static int fetch_device_names(struct string_list *list)
{
struct mnl_socket *nl = NULL;
char *rtnl_buffer = NULL;
size_t message_len;
unsigned int portid, seq;
ssize_t len;
int ret = 0;
struct nlmsghdr *nlh;
struct ifinfomsg *ifm;
ret = -ENOMEM;
rtnl_buffer = calloc(mnl_ideal_socket_buffer_size(), 1);
if (!rtnl_buffer)
goto cleanup;
nl = mnl_socket_open(NETLINK_ROUTE);
if (!nl) {
ret = -errno;
goto cleanup;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
ret = -errno;
goto cleanup;
}
seq = time(NULL);
portid = mnl_socket_get_portid(nl);
nlh = mnl_nlmsg_put_header(rtnl_buffer);
nlh->nlmsg_type = RTM_GETLINK;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
nlh->nlmsg_seq = seq;
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
ifm->ifi_family = AF_UNSPEC;
message_len = nlh->nlmsg_len;
if (mnl_socket_sendto(nl, rtnl_buffer, message_len) < 0) {
ret = -errno;
goto cleanup;
}
another:
if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, mnl_ideal_socket_buffer_size())) < 0) {
ret = -errno;
goto cleanup;
}
if ((len = mnl_cb_run(rtnl_buffer, len, seq, portid, read_devices_cb, list)) < 0) {
/* Netlink returns NLM_F_DUMP_INTR if the set of all tunnels changed
* during the dump. That's unfortunate, but is pretty common on busy
* systems that are adding and removing tunnels all the time. Rather
* than retrying, potentially indefinitely, we just work with the
* partial results. */
if (errno != EINTR) {
ret = -errno;
goto cleanup;
}
}
if (len == MNL_CB_OK + 1)
goto another;
ret = 0;
cleanup:
free(rtnl_buffer);
if (nl)
mnl_socket_close(nl);
return ret;
}
static int add_del_iface(const char *ifname, bool add)
{
struct mnl_socket *nl = NULL;
char *rtnl_buffer;
ssize_t len;
int ret;
struct nlmsghdr *nlh;
struct ifinfomsg *ifm;
struct nlattr *nest;
rtnl_buffer = calloc(mnl_ideal_socket_buffer_size(), 1);
if (!rtnl_buffer) {
ret = -ENOMEM;
goto cleanup;
}
nl = mnl_socket_open(NETLINK_ROUTE);
if (!nl) {
ret = -errno;
goto cleanup;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
ret = -errno;
goto cleanup;
}
nlh = mnl_nlmsg_put_header(rtnl_buffer);
nlh->nlmsg_type = add ? RTM_NEWLINK : RTM_DELLINK;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (add ? NLM_F_CREATE | NLM_F_EXCL : 0);
nlh->nlmsg_seq = time(NULL);
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
ifm->ifi_family = AF_UNSPEC;
mnl_attr_put_strz(nlh, IFLA_IFNAME, ifname);
nest = mnl_attr_nest_start(nlh, IFLA_LINKINFO);
mnl_attr_put_strz(nlh, IFLA_INFO_KIND, WG_GENL_NAME);
mnl_attr_nest_end(nlh, nest);
if (mnl_socket_sendto(nl, rtnl_buffer, nlh->nlmsg_len) < 0) {
ret = -errno;
goto cleanup;
}
if ((len = mnl_socket_recvfrom(nl, rtnl_buffer, mnl_ideal_socket_buffer_size())) < 0) {
ret = -errno;
goto cleanup;
}
if (mnl_cb_run(rtnl_buffer, len, nlh->nlmsg_seq, mnl_socket_get_portid(nl), NULL, NULL) < 0) {
ret = -errno;
goto cleanup;
}
ret = 0;
cleanup:
free(rtnl_buffer);
if (nl)
mnl_socket_close(nl);
return ret;
}
int wg_set_device(wg_device *dev)
{
int ret = 0;
wg_peer *peer = NULL;
wg_allowedip *allowedip = NULL;
struct nlattr *peers_nest, *peer_nest, *allowedips_nest, *allowedip_nest;
struct nlmsghdr *nlh;
struct mnlg_socket *nlg;
nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
if (!nlg)
return -errno;
again:
nlh = mnlg_msg_prepare(nlg, WG_CMD_SET_DEVICE, NLM_F_REQUEST | NLM_F_ACK);
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, dev->name);
if (!peer) {
uint32_t flags = 0;
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY)
mnl_attr_put(nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
if (dev->flags & WGDEVICE_HAS_FWMARK)
mnl_attr_put_u32(nlh, WGDEVICE_A_FWMARK, dev->fwmark);
if (dev->flags & WGDEVICE_REPLACE_PEERS)
flags |= WGDEVICE_F_REPLACE_PEERS;
if (flags)
mnl_attr_put_u32(nlh, WGDEVICE_A_FLAGS, flags);
}
if (!dev->first_peer)
goto send;
peers_nest = peer_nest = allowedips_nest = allowedip_nest = NULL;
peers_nest = mnl_attr_nest_start(nlh, WGDEVICE_A_PEERS);
for (peer = peer ? peer : dev->first_peer; peer; peer = peer->next_peer) {
uint32_t flags = 0;
peer_nest = mnl_attr_nest_start_check(nlh, mnl_ideal_socket_buffer_size(), 0);
if (!peer_nest)
goto toobig_peers;
if (!mnl_attr_put_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_PUBLIC_KEY, sizeof(peer->public_key), peer->public_key))
goto toobig_peers;
if (peer->flags & WGPEER_REMOVE_ME)
flags |= WGPEER_F_REMOVE_ME;
if (!allowedip) {
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
if (!mnl_attr_put_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_PRESHARED_KEY, sizeof(peer->preshared_key), peer->preshared_key))
goto toobig_peers;
}
if (peer->endpoint.addr.sa_family == AF_INET) {
if (!mnl_attr_put_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr4), &peer->endpoint.addr4))
goto toobig_peers;
} else if (peer->endpoint.addr.sa_family == AF_INET6) {
if (!mnl_attr_put_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_ENDPOINT, sizeof(peer->endpoint.addr6), &peer->endpoint.addr6))
goto toobig_peers;
}
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
if (!mnl_attr_put_u16_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, peer->persistent_keepalive_interval))
goto toobig_peers;
}
}
if (flags) {
if (!mnl_attr_put_u32_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_FLAGS, flags))
goto toobig_peers;
}
if (peer->first_allowedip) {
if (!allowedip)
allowedip = peer->first_allowedip;
allowedips_nest = mnl_attr_nest_start_check(nlh, mnl_ideal_socket_buffer_size(), WGPEER_A_ALLOWEDIPS);
if (!allowedips_nest)
goto toobig_allowedips;
for (; allowedip; allowedip = allowedip->next_allowedip) {
allowedip_nest = mnl_attr_nest_start_check(nlh, mnl_ideal_socket_buffer_size(), 0);
if (!allowedip_nest)
goto toobig_allowedips;
if (!mnl_attr_put_u16_check(nlh, mnl_ideal_socket_buffer_size(), WGALLOWEDIP_A_FAMILY, allowedip->family))
goto toobig_allowedips;
if (allowedip->family == AF_INET) {
if (!mnl_attr_put_check(nlh, mnl_ideal_socket_buffer_size(), WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip4), &allowedip->ip4))
goto toobig_allowedips;
} else if (allowedip->family == AF_INET6) {
if (!mnl_attr_put_check(nlh, mnl_ideal_socket_buffer_size(), WGALLOWEDIP_A_IPADDR, sizeof(allowedip->ip6), &allowedip->ip6))
goto toobig_allowedips;
}
if (!mnl_attr_put_u8_check(nlh, mnl_ideal_socket_buffer_size(), WGALLOWEDIP_A_CIDR_MASK, allowedip->cidr))
goto toobig_allowedips;
mnl_attr_nest_end(nlh, allowedip_nest);
allowedip_nest = NULL;
}
mnl_attr_nest_end(nlh, allowedips_nest);
allowedips_nest = NULL;
}
mnl_attr_nest_end(nlh, peer_nest);
peer_nest = NULL;
}
mnl_attr_nest_end(nlh, peers_nest);
peers_nest = NULL;
goto send;
toobig_allowedips:
if (allowedip_nest)
mnl_attr_nest_cancel(nlh, allowedip_nest);
if (allowedips_nest)
mnl_attr_nest_end(nlh, allowedips_nest);
mnl_attr_nest_end(nlh, peer_nest);
mnl_attr_nest_end(nlh, peers_nest);
goto send;
toobig_peers:
if (peer_nest)
mnl_attr_nest_cancel(nlh, peer_nest);
mnl_attr_nest_end(nlh, peers_nest);
goto send;
send:
if (mnlg_socket_send(nlg, nlh) < 0) {
ret = -errno;
goto out;
}
errno = 0;
if (mnlg_socket_recv_run(nlg, NULL, NULL) < 0) {
ret = errno ? -errno : -EINVAL;
goto out;
}
if (peer)
goto again;
out:
mnlg_socket_close(nlg);
errno = -ret;
return ret;
}
static int parse_allowedip(const struct nlattr *attr, void *data)
{
wg_allowedip *allowedip = data;
switch (mnl_attr_get_type(attr)) {
case WGALLOWEDIP_A_UNSPEC:
break;
case WGALLOWEDIP_A_FAMILY:
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
allowedip->family = mnl_attr_get_u16(attr);
break;
case WGALLOWEDIP_A_IPADDR:
if (mnl_attr_get_payload_len(attr) == sizeof(allowedip->ip4))
memcpy(&allowedip->ip4, mnl_attr_get_payload(attr), sizeof(allowedip->ip4));
else if (mnl_attr_get_payload_len(attr) == sizeof(allowedip->ip6))
memcpy(&allowedip->ip6, mnl_attr_get_payload(attr), sizeof(allowedip->ip6));
break;
case WGALLOWEDIP_A_CIDR_MASK:
if (!mnl_attr_validate(attr, MNL_TYPE_U8))
allowedip->cidr = mnl_attr_get_u8(attr);
break;
}
return MNL_CB_OK;
}
static int parse_allowedips(const struct nlattr *attr, void *data)
{
wg_peer *peer = data;
wg_allowedip *new_allowedip = calloc(1, sizeof(wg_allowedip));
int ret;
if (!new_allowedip)
return MNL_CB_ERROR;
if (!peer->first_allowedip)
peer->first_allowedip = peer->last_allowedip = new_allowedip;
else {
peer->last_allowedip->next_allowedip = new_allowedip;
peer->last_allowedip = new_allowedip;
}
ret = mnl_attr_parse_nested(attr, parse_allowedip, new_allowedip);
if (!ret)
return ret;
if (!((new_allowedip->family == AF_INET && new_allowedip->cidr <= 32) || (new_allowedip->family == AF_INET6 && new_allowedip->cidr <= 128))) {
errno = EAFNOSUPPORT;
return MNL_CB_ERROR;
}
return MNL_CB_OK;
}
bool wg_key_is_zero(const wg_key key)
{
volatile uint8_t acc = 0;
unsigned int i;
for (i = 0; i < sizeof(wg_key); ++i) {
acc |= key[i];
__asm__ ("" : "=r" (acc) : "0" (acc));
}
return 1 & ((acc - 1) >> 8);
}
static int parse_peer(const struct nlattr *attr, void *data)
{
wg_peer *peer = data;
switch (mnl_attr_get_type(attr)) {
case WGPEER_A_UNSPEC:
break;
case WGPEER_A_PUBLIC_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->public_key)) {
memcpy(peer->public_key, mnl_attr_get_payload(attr), sizeof(peer->public_key));
peer->flags |= WGPEER_HAS_PUBLIC_KEY;
}
break;
case WGPEER_A_PRESHARED_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->preshared_key)) {
memcpy(peer->preshared_key, mnl_attr_get_payload(attr), sizeof(peer->preshared_key));
if (!wg_key_is_zero(peer->preshared_key))
peer->flags |= WGPEER_HAS_PRESHARED_KEY;
}
break;
case WGPEER_A_ENDPOINT: {
struct sockaddr *addr;
if (mnl_attr_get_payload_len(attr) < sizeof(*addr))
break;
addr = mnl_attr_get_payload(attr);
if (addr->sa_family == AF_INET && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr4))
memcpy(&peer->endpoint.addr4, addr, sizeof(peer->endpoint.addr4));
else if (addr->sa_family == AF_INET6 && mnl_attr_get_payload_len(attr) == sizeof(peer->endpoint.addr6))
memcpy(&peer->endpoint.addr6, addr, sizeof(peer->endpoint.addr6));
break;
}
case WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL:
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
peer->persistent_keepalive_interval = mnl_attr_get_u16(attr);
break;
case WGPEER_A_LAST_HANDSHAKE_TIME:
if (mnl_attr_get_payload_len(attr) == sizeof(peer->last_handshake_time))
memcpy(&peer->last_handshake_time, mnl_attr_get_payload(attr), sizeof(peer->last_handshake_time));
break;
case WGPEER_A_RX_BYTES:
if (!mnl_attr_validate(attr, MNL_TYPE_U64))
peer->rx_bytes = mnl_attr_get_u64(attr);
break;
case WGPEER_A_TX_BYTES:
if (!mnl_attr_validate(attr, MNL_TYPE_U64))
peer->tx_bytes = mnl_attr_get_u64(attr);
break;
case WGPEER_A_ALLOWEDIPS:
return mnl_attr_parse_nested(attr, parse_allowedips, peer);
}
return MNL_CB_OK;
}
static int parse_peers(const struct nlattr *attr, void *data)
{
wg_device *device = data;
wg_peer *new_peer = calloc(1, sizeof(wg_peer));
int ret;
if (!new_peer)
return MNL_CB_ERROR;
if (!device->first_peer)
device->first_peer = device->last_peer = new_peer;
else {
device->last_peer->next_peer = new_peer;
device->last_peer = new_peer;
}
ret = mnl_attr_parse_nested(attr, parse_peer, new_peer);
if (!ret)
return ret;
if (!(new_peer->flags & WGPEER_HAS_PUBLIC_KEY)) {
errno = ENXIO;
return MNL_CB_ERROR;
}
return MNL_CB_OK;
}
static int parse_device(const struct nlattr *attr, void *data)
{
wg_device *device = data;
switch (mnl_attr_get_type(attr)) {
case WGDEVICE_A_UNSPEC:
break;
case WGDEVICE_A_IFINDEX:
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
device->ifindex = mnl_attr_get_u32(attr);
break;
case WGDEVICE_A_IFNAME:
if (!mnl_attr_validate(attr, MNL_TYPE_STRING)) {
strncpy(device->name, mnl_attr_get_str(attr), sizeof(device->name) - 1);
device->name[sizeof(device->name) - 1] = '\0';
}
break;
case WGDEVICE_A_PRIVATE_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(device->private_key)) {
memcpy(device->private_key, mnl_attr_get_payload(attr), sizeof(device->private_key));
device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
}
break;
case WGDEVICE_A_PUBLIC_KEY:
if (mnl_attr_get_payload_len(attr) == sizeof(device->public_key)) {
memcpy(device->public_key, mnl_attr_get_payload(attr), sizeof(device->public_key));
device->flags |= WGDEVICE_HAS_PUBLIC_KEY;
}
break;
case WGDEVICE_A_LISTEN_PORT:
if (!mnl_attr_validate(attr, MNL_TYPE_U16))
device->listen_port = mnl_attr_get_u16(attr);
break;
case WGDEVICE_A_FWMARK:
if (!mnl_attr_validate(attr, MNL_TYPE_U32))
device->fwmark = mnl_attr_get_u32(attr);
break;
case WGDEVICE_A_PEERS:
return mnl_attr_parse_nested(attr, parse_peers, device);
}
return MNL_CB_OK;
}
static int read_device_cb(const struct nlmsghdr *nlh, void *data)
{
return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), parse_device, data);
}
static void coalesce_peers(wg_device *device)
{
wg_peer *old_next_peer, *peer = device->first_peer;
while (peer && peer->next_peer) {
if (memcmp(peer->public_key, peer->next_peer->public_key, sizeof(wg_key))) {
peer = peer->next_peer;
continue;
}
if (!peer->first_allowedip) {
peer->first_allowedip = peer->next_peer->first_allowedip;
peer->last_allowedip = peer->next_peer->last_allowedip;
} else {
peer->last_allowedip->next_allowedip = peer->next_peer->first_allowedip;
peer->last_allowedip = peer->next_peer->last_allowedip;
}
old_next_peer = peer->next_peer;
peer->next_peer = old_next_peer->next_peer;
free(old_next_peer);
}
}
int wg_get_device(wg_device **device, const char *device_name)
{
int ret = 0;
struct nlmsghdr *nlh;
struct mnlg_socket *nlg;
try_again:
*device = calloc(1, sizeof(wg_device));
if (!*device)
return -errno;
nlg = mnlg_socket_open(WG_GENL_NAME, WG_GENL_VERSION);
if (!nlg) {
wg_free_device(*device);
*device = NULL;
return -errno;
}
nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, device_name);
if (mnlg_socket_send(nlg, nlh) < 0) {
ret = -errno;
goto out;
}
errno = 0;
if (mnlg_socket_recv_run(nlg, read_device_cb, *device) < 0) {
ret = errno ? -errno : -EINVAL;
goto out;
}
coalesce_peers(*device);
out:
if (nlg)
mnlg_socket_close(nlg);
if (ret) {
wg_free_device(*device);
if (ret == -EINTR)
goto try_again;
*device = NULL;
}
errno = -ret;
return ret;
}
/* first\0second\0third\0forth\0last\0\0 */
char *wg_list_device_names(void)
{
struct string_list list = { 0 };
int ret = fetch_device_names(&list);
errno = -ret;
if (errno) {
free(list.buffer);
return NULL;
}
return list.buffer ?: strdup("\0");
}
int wg_add_device(const char *device_name)
{
return add_del_iface(device_name, true);
}
int wg_del_device(const char *device_name)
{
return add_del_iface(device_name, false);
}
void wg_free_device(wg_device *dev)
{
wg_peer *peer, *np;
wg_allowedip *allowedip, *na;
if (!dev)
return;
for (peer = dev->first_peer, np = peer ? peer->next_peer : NULL; peer; peer = np, np = peer ? peer->next_peer : NULL) {
for (allowedip = peer->first_allowedip, na = allowedip ? allowedip->next_allowedip : NULL; allowedip; allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
free(allowedip);
free(peer);
}
free(dev);
}
static void encode_base64(char dest[static 4], const uint8_t src[static 3])
{
const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
unsigned int i;
for (i = 0; i < 4; ++i)
dest[i] = input[i] + 'A'
+ (((25 - input[i]) >> 8) & 6)
- (((51 - input[i]) >> 8) & 75)
- (((61 - input[i]) >> 8) & 15)
+ (((62 - input[i]) >> 8) & 3);
}
void wg_key_to_base64(wg_key_b64_string base64, const wg_key key)
{
unsigned int i;
for (i = 0; i < 32 / 3; ++i)
encode_base64(&base64[i * 4], &key[i * 3]);
encode_base64(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
base64[sizeof(wg_key_b64_string) - 2] = '=';
base64[sizeof(wg_key_b64_string) - 1] = '\0';
}
static int decode_base64(const char src[static 4])
{
int val = 0;
unsigned int i;
for (i = 0; i < 4; ++i)
val |= (-1
+ ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64))
+ ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70))
+ ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5))
+ ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63)
+ ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)
) << (18 - 6 * i);
return val;
}
int wg_key_from_base64(wg_key key, const wg_key_b64_string base64)
{
unsigned int i;
int val;
volatile uint8_t ret = 0;
if (strlen(base64) != sizeof(wg_key_b64_string) - 1 || base64[sizeof(wg_key_b64_string) - 2] != '=') {
errno = EINVAL;
goto out;
}
for (i = 0; i < 32 / 3; ++i) {
val = decode_base64(&base64[i * 4]);
ret |= (uint32_t)val >> 31;
key[i * 3 + 0] = (val >> 16) & 0xff;
key[i * 3 + 1] = (val >> 8) & 0xff;
key[i * 3 + 2] = val & 0xff;
}
val = decode_base64((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
ret |= ((uint32_t)val >> 31) | (val & 0xff);
key[i * 3 + 0] = (val >> 16) & 0xff;
key[i * 3 + 1] = (val >> 8) & 0xff;
errno = EINVAL & ~((ret - 1) >> 8);
out:
return -errno;
}
typedef int64_t fe[16];
static __attribute__((noinline)) void memzero_explicit(void *s, size_t count)
{
memset(s, 0, count);
__asm__ __volatile__("": :"r"(s) :"memory");
}
static void carry(fe o)
{
int i;
for (i = 0; i < 16; ++i) {
o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16);
o[i] &= 0xffff;
}
}
static void cswap(fe p, fe q, int b)
{
int i;
int64_t t, c = ~(b - 1);
for (i = 0; i < 16; ++i) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
memzero_explicit(&t, sizeof(t));
memzero_explicit(&c, sizeof(c));
memzero_explicit(&b, sizeof(b));
}
static void pack(uint8_t *o, const fe n)
{
int i, j, b;
fe m, t;
memcpy(t, n, sizeof(t));
carry(t);
carry(t);
carry(t);
for (j = 0; j < 2; ++j) {
m[0] = t[0] - 0xffed;
for (i = 1; i < 15; ++i) {
m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
cswap(t, m, 1 - b);
}
for (i = 0; i < 16; ++i) {
o[2 * i] = t[i] & 0xff;
o[2 * i + 1] = t[i] >> 8;
}
memzero_explicit(m, sizeof(m));
memzero_explicit(t, sizeof(t));
memzero_explicit(&b, sizeof(b));
}
static void add(fe o, const fe a, const fe b)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] + b[i];
}
static void subtract(fe o, const fe a, const fe b)
{
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] - b[i];
}
static void multmod(fe o, const fe a, const fe b)
{
int i, j;
int64_t t[31] = { 0 };
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
t[i + j] += a[i] * b[j];
}
for (i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
memcpy(o, t, sizeof(fe));
carry(o);
carry(o);
memzero_explicit(t, sizeof(t));
}
static void invert(fe o, const fe i)
{
fe c;
int a;
memcpy(c, i, sizeof(c));
for (a = 253; a >= 0; --a) {
multmod(c, c, c);
if (a != 2 && a != 4)
multmod(c, c, i);
}
memcpy(o, c, sizeof(fe));
memzero_explicit(c, sizeof(c));
}
static void clamp_key(uint8_t *z)
{
z[31] = (z[31] & 127) | 64;
z[0] &= 248;
}
void wg_generate_public_key(wg_key public_key, const wg_key private_key)
{
int i, r;
uint8_t z[32];
fe a = { 1 }, b = { 9 }, c = { 0 }, d = { 1 }, e, f;
memcpy(z, private_key, sizeof(z));
clamp_key(z);
for (i = 254; i >= 0; --i) {
r = (z[i >> 3] >> (i & 7)) & 1;
cswap(a, b, r);
cswap(c, d, r);
add(e, a, c);
subtract(a, a, c);
add(c, b, d);
subtract(b, b, d);
multmod(d, e, e);
multmod(f, a, a);
multmod(a, c, a);
multmod(c, b, e);
add(e, a, c);
subtract(a, a, c);
multmod(b, a, a);
subtract(c, d, f);
multmod(a, c, (const fe){ 0xdb41, 1 });
add(a, a, d);
multmod(c, c, a);
multmod(a, d, f);
multmod(d, b, (const fe){ 9 });
multmod(b, e, e);
cswap(a, b, r);
cswap(c, d, r);
}
invert(c, c);
multmod(a, a, c);
pack(public_key, a);
memzero_explicit(&r, sizeof(r));
memzero_explicit(z, sizeof(z));
memzero_explicit(a, sizeof(a));
memzero_explicit(b, sizeof(b));
memzero_explicit(c, sizeof(c));
memzero_explicit(d, sizeof(d));
memzero_explicit(e, sizeof(e));
memzero_explicit(f, sizeof(f));
}
void wg_generate_private_key(wg_key private_key)
{
wg_generate_preshared_key(private_key);
clamp_key(private_key);
}
void wg_generate_preshared_key(wg_key preshared_key)
{
ssize_t ret;
size_t i;
int fd;
#if defined(__OpenBSD__) || (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) || (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))
if (!getentropy(preshared_key, sizeof(wg_key)))
return;
#endif
#if defined(__NR_getrandom) && defined(__linux__)
if (syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0) == sizeof(wg_key))
return;
#endif
fd = open("/dev/urandom", O_RDONLY);
assert(fd >= 0);
for (i = 0; i < sizeof(wg_key); i += ret) {
ret = read(fd, preshared_key + i, sizeof(wg_key) - i);
assert(ret > 0);
}
close(fd);
}
================================================
FILE: contrib/embeddable-wg-library/wireguard.h
================================================
/* SPDX-License-Identifier: LGPL-2.1+ */
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#ifndef WIREGUARD_H
#define WIREGUARD_H
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <time.h>
#include <stdint.h>
#include <stdbool.h>
typedef uint8_t wg_key[32];
typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1];
/* Cross platform __kernel_timespec */
struct timespec64 {
int64_t tv_sec;
int64_t tv_nsec;
};
typedef struct wg_allowedip {
uint16_t family;
union {
struct in_addr ip4;
struct in6_addr ip6;
};
uint8_t cidr;
struct wg_allowedip *next_allowedip;
} wg_allowedip;
enum wg_peer_flags {
WGPEER_REMOVE_ME = 1U << 0,
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
WGPEER_HAS_PRESHARED_KEY = 1U << 3,
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
};
typedef union wg_endpoint {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} wg_endpoint;
typedef struct wg_peer {
enum wg_peer_flags flags;
wg_key public_key;
wg_key preshared_key;
wg_endpoint endpoint;
struct timespec64 last_handshake_time;
uint64_t rx_bytes, tx_bytes;
uint16_t persistent_keepalive_interval;
struct wg_allowedip *first_allowedip, *last_allowedip;
struct wg_peer *next_peer;
} wg_peer;
enum wg_device_flags {
WGDEVICE_REPLACE_PEERS = 1U << 0,
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
WGDEVICE_HAS_FWMARK = 1U << 4
};
typedef struct wg_device {
char name[IFNAMSIZ];
uint32_t ifindex;
enum wg_device_flags flags;
wg_key public_key;
wg_key private_key;
uint32_t fwmark;
uint16_t listen_port;
struct wg_peer *first_peer, *last_peer;
} wg_device;
#define wg_for_each_device_name(__names, __name, __len) for ((__name) = (__names), (__len) = 0; ((__len) = strlen(__name)); (__name) += (__len) + 1)
#define wg_for_each_peer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
#define wg_for_each_allowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
int wg_set_device(wg_device *dev);
int wg_get_device(wg_device **dev, const char *device_name);
int wg_add_device(const char *device_name);
int wg_del_device(const char *device_name);
void wg_free_device(wg_device *dev);
char *wg_list_device_names(void); /* first\0second\0third\0forth\0last\0\0 */
void wg_key_to_base64(wg_key_b64_string base64, const wg_key key);
int wg_key_from_base64(wg_key key, const wg_key_b64_string base64);
bool wg_key_is_zero(const wg_key key);
void wg_generate_public_key(wg_key public_key, const wg_key private_key);
void wg_generate_private_key(wg_key private_key);
void wg_generate_preshared_key(wg_key preshared_key);
#endif
================================================
FILE: contrib/external-tests/haskell/Setup.hs
================================================
import Distribution.Simple
main = defaultMain
================================================
FILE: contrib/external-tests/haskell/package.yaml
================================================
name: cacophony-wg
version: 0.1.0
license: PublicDomain
maintainer: John Galt <jgalt@centromere.net>
category: Cryptography
ghc-options: -Wall
executables:
cacophony-wg:
main: Main.hs
source-dirs: src
dependencies:
- base
- base16-bytestring
- base64-bytestring
- blake2
- bytestring
- cacophony >= 0.10
- cereal
- cryptonite
- memory
- network
- time
ghc-options:
- -O2
- -rtsopts
- -threaded
- -with-rtsopts=-N
other-modules:
- Data.Time.TAI64
default-extensions:
- OverloadedStrings
================================================
FILE: contrib/external-tests/haskell/src/Data/Time/TAI64.hs
================================================
module Data.Time.TAI64 (
TAI64(..)
, TAI64N(..)
, TAI64NA(..)
, posixToTAI64
, posixToTAI64N
, posixToTAI64NA
, getCurrentTAI64
, getCurrentTAI64N
, getCurrentTAI64NA
, tAI64ToPosix
, tAI64NToPosix
, tAI64NAToPosix
) where
import Data.Serialize
import Control.Monad
import Data.Word
import Data.Time.Clock
import Data.Time.Clock.POSIX
import Numeric
data TAI64 = TAI64
{-# UNPACK #-} !Word64
deriving (Eq, Ord)
data TAI64N = TAI64N
{-# UNPACK #-} !TAI64
{-# UNPACK #-} !Word32
deriving (Eq, Ord, Show)
data TAI64NA = TAI64NA
{-# UNPACK #-} !TAI64N
{-# UNPACK #-} !Word32
deriving (Eq, Ord, Show)
instance Show TAI64 where
show (TAI64 t) = "TAI64 0x" ++ showHex t ""
instance Serialize TAI64 where
put (TAI64 t) = putWord64be t
get = liftM TAI64 get
instance Serialize TAI64N where
put (TAI64N t' nt) = put t' >> putWord32be nt
get = liftM2 TAI64N get get
instance Serialize TAI64NA where
put (TAI64NA t' at) = put t' >> putWord32be at
get = liftM2 TAI64NA get get
posixToTAI64 :: POSIXTime -> TAI64
posixToTAI64 = TAI64 . (2^62 +) . truncate . realToFrac
posixToTAI64N :: POSIXTime -> TAI64N
posixToTAI64N pt = TAI64N t' ns where
t' = posixToTAI64 pt
ns = (`mod` 10^9) $ truncate (pts * 10**9)
pts = realToFrac pt
posixToTAI64NA :: POSIXTime -> TAI64NA -- | PICOsecond precision
posixToTAI64NA pt = TAI64NA t' as where
t' = posixToTAI64N pt
as = (`mod` 10^9) $ truncate (pts * 10**18)
pts = realToFrac pt
getCurrentTAI64 :: IO TAI64
getCurrentTAI64N :: IO TAI64N
getCurrentTAI64NA :: IO TAI64NA
getCurrentTAI64 = liftM posixToTAI64 getPOSIXTime
getCurrentTAI64N = liftM posixToTAI64N getPOSIXTime
getCurrentTAI64NA = liftM posixToTAI64NA getPOSIXTime
tAI64ToPosix :: TAI64 -> POSIXTime
tAI64ToPosix (TAI64 s) = fromRational . fromIntegral $ s - 2^62
tAI64NToPosix :: TAI64N -> POSIXTime
tAI64NToPosix (TAI64N t' n) = tAI64ToPosix t' + nanopart where
nanopart = fromRational $ (toRational $ 10**(-9)) * toRational n -- TODO: optimize?
tAI64NAToPosix :: TAI64NA -> POSIXTime
tAI64NAToPosix (TAI64NA t' a) = tAI64NToPosix t' + attopart where
attopart = fromRational $ (toRational $ 10**(-18)) * toRational a
================================================
FILE: contrib/external-tests/haskell/src/Main.hs
================================================
module Main where
import Control.Monad (void)
import Crypto.Hash.BLAKE2.BLAKE2s (hash)
import Data.ByteArray (ScrubbedBytes, convert)
import Data.ByteString (ByteString, replicate, take, drop)
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString.Base64 as B64
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import qualified Data.Serialize as S
import Network.Socket
import qualified Network.Socket.ByteString as NBS
import Prelude hiding (replicate, take, drop)
import Crypto.Noise
import Crypto.Noise.Cipher
import Crypto.Noise.Cipher.ChaChaPoly1305
import Crypto.Noise.DH
import Crypto.Noise.DH.Curve25519
import Crypto.Noise.HandshakePatterns (noiseIKpsk2)
import Crypto.Noise.Hash hiding (hash)
import Crypto.Noise.Hash.BLAKE2s
import Data.Time.TAI64
sampleICMPRequest :: ByteString
sampleICMPRequest = fst . B16.decode $
"450000250000000014018f5b0abd81020abd810108001bfa039901b6576972654775617264"
validateICMPResponse :: ByteString
-> Bool
validateICMPResponse r =
-- Strip off part of IPv4 header because this is only a demo.
drop 12 sample == drop 12 r
where
sample = fst . B16.decode $ "45000025e3030000400180570abd81010abd8102000023fa039901b65769726547756172640000000000000000000000"
unsafeMessage :: (Cipher c, DH d, Hash h)
=> Bool
-> Maybe ScrubbedBytes
-> ScrubbedBytes
-> NoiseState c d h
-> (ScrubbedBytes, NoiseState c d h)
unsafeMessage write mpsk msg ns = case operation msg ns of
NoiseResultMessage ct ns' -> (ct, ns')
NoiseResultNeedPSK ns' -> case mpsk of
Nothing -> error "psk required but not provided"
Just k -> case operation k ns' of
NoiseResultMessage ct ns'' -> (ct, ns'')
_ -> error "something terrible happened"
_ -> error "something terrible happened"
where
operation = if write then writeMessage else readMessage
main :: IO ()
main = do
let ip = "demo.wireguard.com"
port = "12913"
myKeyB64 = "WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=" -- private key
serverKeyB64 = "qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=" -- public key
pskB64 = "FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE="
addrInfo <- head <$> getAddrInfo Nothing (Just ip) (Just port)
sock <- socket (addrFamily addrInfo) Datagram defaultProtocol
let addr = addrAddress addrInfo
myStaticKey = fromMaybe (error "invalid private key")
. dhBytesToPair
. convert
. either (error "error Base64 decoding my private key") id
. B64.decode
$ myKeyB64 :: KeyPair Curve25519
serverKey = fromMaybe (error "invalid public key")
. dhBytesToPub
. convert
. either (error "error Base64 decoding server public key") id
. B64.decode
$ serverKeyB64 :: PublicKey Curve25519
psk = convert
. either (error "error decoding PSK") id
. B64.decode
$ pskB64 :: ScrubbedBytes
myEphemeralKey <- dhGenKey
let dho = defaultHandshakeOpts InitiatorRole "WireGuard v1 zx2c4 Jason@zx2c4.com"
opts = setLocalEphemeral (Just myEphemeralKey)
. setLocalStatic (Just myStaticKey)
. setRemoteStatic (Just serverKey)
$ dho
ns0 = noiseState opts noiseIKpsk2 :: NoiseState ChaChaPoly1305 Curve25519 BLAKE2s
tai64n <- convert . S.encode <$> getCurrentTAI64N
-- Handshake: Initiator to responder -----------------------------------------
let (msg0, ns1) = unsafeMessage True Nothing tai64n ns0
macKey = hash 32 mempty $ "mac1----" `mappend` (convert . dhPubToBytes) serverKey
initiation = "\x01\x00\x00\x00\x1c\x00\x00\x00" <> convert msg0 -- sender index = 28 to match other examples
mac1 = hash 16 macKey initiation
void $ NBS.sendTo sock (initiation <> mac1 <> replicate 16 0) addr
-- Handshake: Responder to initiator -----------------------------------------
(response0, _) <- NBS.recvFrom sock 1024
let theirIndex = take 4 . drop 4 $ response0
(_, ns2) = unsafeMessage False (Just psk) (convert . take 48 . drop 12 $ response0) ns1
-- ICMP: Initiator to responder ----------------------------------------------
let (msg1, ns3) = unsafeMessage True Nothing (convert sampleICMPRequest) ns2
icmp = "\x04\x00\x00\x00" <> theirIndex <> replicate 8 0 <> convert msg1
void $ NBS.sendTo sock icmp addr
-- ICMP: Responder to initiator ----------------------------------------------
(response1, _) <- NBS.recvFrom sock 1024
let (icmpPayload, ns4) = unsafeMessage False Nothing (convert . drop 16 $ response1) ns3
-- KeepAlive: Initiator to responder -----------------------------------------
if validateICMPResponse . convert $ icmpPayload
then do
let (msg2, _) = unsafeMessage True Nothing mempty ns4
keepAlive = "\x04\x00\x00\x00" <> theirIndex <> "\x01" <> replicate 7 0 <> convert msg2
void $ NBS.sendTo sock keepAlive addr
else error "unexpected ICMP response from server!"
================================================
FILE: contrib/external-tests/haskell/stack.yaml
================================================
resolver: lts-8.18
packages:
- '.'
extra-deps: []
flags: {}
extra-package-dbs: []
================================================
FILE: contrib/external-tests/python/main.py
================================================
#!/usr/bin/python3
# SPDX-License-Identifier: MIT
# Author: Piotr Lizonczyk <plizonczyk.public@gmail.com>
import base64
import datetime
from hashlib import blake2s
import socket
import struct
from scapy.layers.inet import IP, ICMP
from noise.connection import NoiseConnection, Keypair
address = ('demo.wireguard.com', 12913)
our_private = base64.b64decode('WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=')
their_public = base64.b64decode('qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=')
preshared = base64.b64decode('FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=')
prologue = b'WireGuard v1 zx2c4 Jason@zx2c4.com'
noise = NoiseConnection.from_name(b'Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s')
noise.set_as_initiator()
noise.set_keypair_from_private_bytes(Keypair.STATIC, our_private)
noise.set_keypair_from_public_bytes(Keypair.REMOTE_STATIC, their_public)
noise.set_psks(psk=preshared)
noise.set_prologue(prologue)
noise.start_handshake()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 1. Prepare and send handshake initiation packet
now = datetime.datetime.now()
tai = struct.pack('!qi', 4611686018427387914 + int(now.timestamp()), int(now.microsecond * 1e3))
initiation_packet = b'\x01' # Type: initiation
initiation_packet += b'\x00' * 3 # Reserved
initiation_packet += struct.pack('<i', 28) # Sender index: 28 (arbitrary)
initiation_packet += noise.write_message(payload=tai)
mac_key = blake2s(b'mac1----' + their_public).digest()
initiation_packet += blake2s(initiation_packet, digest_size=16, key=mac_key).digest()
initiation_packet += b'\x00' * 16
sock.sendto(initiation_packet, address)
# 2. Receive response to finalize handshake
response_packet = sock.recv(92)
assert response_packet[0] == 2 # Type: response
assert response_packet[1:4] == b'\x00' * 3 # Reserved
their_index, our_index = struct.unpack('<ii', response_packet[4:12])
assert our_index == 28
payload = noise.read_message(response_packet[12:60])
assert payload == b''
assert noise.handshake_finished
# 3. Prepare, encrypt and send ping packet
icmp_packet = ICMP(type=8, id=921, seq=438)/b'WireGuard'
ip_packet = IP(proto=1, ttl=20, src="10.189.129.2", dst="10.189.129.1", id=0)/icmp_packet
ping_packet = b'\x04' # Type: data
ping_packet += b'\x00' * 3 # Reserved
ping_packet += struct.pack('<iq', their_index, 0)
ping_packet += noise.encrypt(bytes(ip_packet))
sock.sendto(ping_packet, address)
# 4. Retrieve ping response, decrypt and verify
encrypted_response = sock.recv(80)
assert encrypted_response[0] == 4 # Type: data
assert encrypted_response[1:4] == b'\x00' * 3 # Reserved
our_index, nonce = struct.unpack('<iq', encrypted_response[4:16])
assert our_index == 28
assert nonce == 0
ip = IP(noise.decrypt(encrypted_response[16:]))
icmp = ip[1]
payload = ip[2]
assert icmp.type == 0
assert icmp.code == 0
assert icmp.id == 921
assert icmp.seq == 438
assert payload.load == b'WireGuard'
# 5. Send keepalive
keepalive = b'\x04' # Type: data
keepalive += b'\x00' * 3 # Reserved
keepalive += struct.pack('<iq', their_index, 1)
keepalive += noise.encrypt(b'')
sock.sendto(keepalive, address)
================================================
FILE: contrib/external-tests/rust/.gitignore
================================================
Cargo.lock
target/
================================================
FILE: contrib/external-tests/rust/Cargo.toml
================================================
[package]
name = "wireguard-ping"
version = "0.1.0"
authors = ["jason@zx2c4.com", "me@jake.su"]
publish = false
[dependencies]
snow = "^0.1.0-preview"
base64 = "^0.5"
rust-crypto = "*"
byteorder = "*"
time = "*"
[dependencies.pnet]
version = "*"
features = [ ]
================================================
FILE: contrib/external-tests/rust/src/main.rs
================================================
/* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
extern crate snow;
extern crate base64;
extern crate time;
extern crate byteorder;
extern crate crypto;
extern crate pnet;
use byteorder::{ByteOrder, BigEndian, LittleEndian};
use crypto::blake2s::Blake2s;
use snow::NoiseBuilder;
use pnet::packet::Packet;
use pnet::packet::ip::IpNextHeaderProtocols;
use pnet::packet::ipv4::{MutableIpv4Packet, self};
use pnet::packet::icmp::{MutableIcmpPacket, IcmpTypes, echo_reply, echo_request, self};
use std::net::*;
use std::str::FromStr;
static TEST_SERVER: &'static str = "demo.wireguard.com:12913";
fn memcpy(out: &mut [u8], data: &[u8]) {
out[..data.len()].copy_from_slice(data);
}
fn main() {
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let their_public = base64::decode(&"qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=").unwrap();
let my_private = base64::decode(&"WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=").unwrap();
let my_preshared = base64::decode(&"FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=").unwrap();
let mut noise = NoiseBuilder::new("Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s".parse().unwrap())
.local_private_key(&my_private[..])
.remote_public_key(&their_public[..])
.prologue("WireGuard v1 zx2c4 Jason@zx2c4.com".as_bytes())
.psk(2, &my_preshared[..])
.build_initiator().unwrap();
let now = time::get_time();
let mut tai64n = [0; 12];
BigEndian::write_i64(&mut tai64n[0..], 4611686018427387914 + now.sec);
BigEndian::write_i32(&mut tai64n[8..], now.nsec);
let mut initiation_packet = [0; 148];
initiation_packet[0] = 1; /* Type: Initiation */
initiation_packet[1] = 0; /* Reserved */
initiation_packet[2] = 0; /* Reserved */
initiation_packet[3] = 0; /* Reserved */
LittleEndian::write_u32(&mut initiation_packet[4..], 28); /* Sender index: 28 (arbitrary) */
noise.write_message(&tai64n, &mut initiation_packet[8..]).unwrap();
let mut mac_key_input = [0; 40];
let mut mac_key = [0; 32];
memcpy(&mut mac_key_input, b"mac1----");
memcpy(&mut mac_key_input[8..], &their_public);
Blake2s::blake2s(&mut mac_key, &mac_key_input, &[0; 0]);
let mut mac = [0; 16];
Blake2s::blake2s(&mut mac, &initiation_packet[0..116], &mac_key);
memcpy(&mut initiation_packet[116..], &mac);
socket.send_to(&initiation_packet, TEST_SERVER).unwrap();
let mut response_packet = [0; 92];
socket.recv_from(&mut response_packet).unwrap();
assert!(response_packet[0] == 2 /* Type: Response */);
assert!(response_packet[1] == 0 /* Reserved */);
assert!(response_packet[2] == 0 /* Reserved */);
assert!(response_packet[3] == 0 /* Reserved */);
let their_index = LittleEndian::read_u32(&response_packet[4..]);
let our_index = LittleEndian::read_u32(&response_packet[8..]);
assert!(our_index == 28);
let payload_len = noise.read_message(&response_packet[12..60], &mut []).unwrap();
assert!(payload_len == 0);
noise = noise.into_transport_mode().unwrap();
let mut icmp_packet = [0; 48];
{
let mut ipv4 = MutableIpv4Packet::new(&mut icmp_packet).unwrap();
ipv4.set_version(4);
ipv4.set_header_length(5);
ipv4.set_total_length(37);
ipv4.set_ttl(20);
ipv4.set_next_level_protocol(IpNextHeaderProtocols::Icmp);
ipv4.set_source(Ipv4Addr::from_str("10.189.129.2").unwrap());
ipv4.set_destination(Ipv4Addr::from_str("10.189.129.1").unwrap());
let checksum = ipv4::checksum(&ipv4.to_immutable());
ipv4.set_checksum(checksum);
}
{
let mut icmp = echo_request::MutableEchoRequestPacket::new(&mut icmp_packet[20..]).unwrap();
icmp.set_icmp_type(IcmpTypes::EchoRequest);
icmp.set_icmp_code(echo_request::IcmpCodes::NoCode);
icmp.set_identifier(921);
icmp.set_sequence_number(438);
icmp.set_payload(b"WireGuard");
}
{
let mut icmp = MutableIcmpPacket::new(&mut icmp_packet[20..]).unwrap();
let checksum = icmp::checksum(&icmp.to_immutable());
icmp.set_checksum(checksum);
}
let mut ping_packet = [0; 80];
ping_packet[0] = 4; /* Type: Data */
ping_packet[1] = 0; /* Reserved */
ping_packet[2] = 0; /* Reserved */
ping_packet[3] = 0; /* Reserved */
LittleEndian::write_u32(&mut ping_packet[4..], their_index);
LittleEndian::write_u64(&mut ping_packet[8..], 0);
noise.write_message(&icmp_packet, &mut ping_packet[16..]).unwrap();
socket.send_to(&ping_packet, TEST_SERVER).unwrap();
socket.recv_from(&mut ping_packet).unwrap();
assert!(ping_packet[0] == 4 /* Type: Data */);
assert!(ping_packet[1] == 0 /* Reserved */);
assert!(ping_packet[2] == 0 /* Reserved */);
assert!(ping_packet[3] == 0 /* Reserved */);
let our_index_received = LittleEndian::read_u32(&ping_packet[4..]);
assert!(our_index_received == 28);
let nonce = LittleEndian::read_u64(&ping_packet[8..]);
assert!(nonce == 0);
let payload_len = noise.read_message(&ping_packet[16..], &mut icmp_packet).unwrap();
assert!(payload_len == 48);
let icmp_reply = echo_reply::EchoReplyPacket::new(&icmp_packet[20..37]).unwrap();
assert!(icmp_reply.get_icmp_type() == IcmpTypes::EchoReply && icmp_reply.get_icmp_code() == echo_reply::IcmpCodes::NoCode);
assert!(icmp_reply.get_identifier() == 921 && icmp_reply.get_sequence_number() == 438);
assert!(icmp_reply.payload() == b"WireGuard");
let mut keepalive_packet = [0; 32];
keepalive_packet[0] = 4; /* Type: Data */
keepalive_packet[1] = 0; /* Reserved */
keepalive_packet[2] = 0; /* Reserved */
keepalive_packet[3] = 0; /* Reserved */
LittleEndian::write_u32(&mut keepalive_packet[4..], their_index);
LittleEndian::write_u64(&mut keepalive_packet[8..], 1);
let empty_payload = [0; 0]; /* Empty payload means keepalive */
noise.write_message(&empty_payload, &mut keepalive_packet[16..]).unwrap();
socket.send_to(&keepalive_packet, TEST_SERVER).unwrap();
}
================================================
FILE: contrib/extract-handshakes/.gitignore
================================================
offset-finder.o
offset-finder
offsets.include
================================================
FILE: contrib/extract-handshakes/Makefile
================================================
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
CFLAGS ?= -O3 -march=native
CFLAGS += -Wall -pedantic -std=gnu11
offsets.include: offset-finder
./$^ > $@
offset-finder: offset-finder.c offset-finder.o
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
offset-finder.o: offset-finder.c
$(MAKE) -C $(KERNELDIR) M=$(PWD) $@
objcopy -j '.rodata*' $@ $@
clean:
rm -f offset-finder offsets.include
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
.PHONY: clean
else
obj-m := offset-finder.o
endif
================================================
FILE: contrib/extract-handshakes/README
================================================
Handshake Extractor
===================
This will extract private keys from outgoing handshake sessions, prior
to them being sent, via kprobes. It exports the bare minimum to be
able to then decrypt all packets in the handshake and in the subsequent
transport data session.
Build:
$ make
Run (as root):
# ./extract-handshakes.sh
New handshake session:
LOCAL_STATIC_PRIVATE_KEY = QChaGDXeH3eQsbFAhueUNWFdq9KfpF3yl+eITjZbXEk=
REMOTE_STATIC_PUBLIC_KEY = HzgTY6aWXtuSyW/PUquZtg8LB/DyMwEXGkPiEmdSsUU=
LOCAL_EPHEMERAL_PRIVATE_KEY = UNGdRHuKDeqbFvmiV5FD4wP7a8PqI6v3Xnnz6Jc6NXQ=
PRESHARED_KEY = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
================================================
FILE: contrib/extract-handshakes/extract-handshakes.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
# Copyright (C) 2017-2018 Peter Wu <peter@lekensteyn.nl>. All Rights Reserved.
set -e
ME_DIR="${BASH_SOURCE[0]}"
ME_DIR="${ME_DIR%/*}"
source "$ME_DIR/offsets.include" || { echo "Did you forget to run make?" >&2; exit 1; }
case "$(uname -m)" in
x86_64) ARGUMENT_REGISTER="%si" ;;
i386|i686) ARGUMENT_REGISTER="%dx" ;;
aarch64) ARGUMENT_REGISTER="%x1" ;;
arm) ARGUMENT_REGISTER="%r1" ;;
*) echo "ERROR: Unknown architecture" >&2; exit 1 ;;
esac
ARGS=( )
REGEX=".*: idxadd: .*"
for key in "${!OFFSETS[@]}"; do
values="${OFFSETS[$key]}"
values=( ${values//,/ } )
for i in {0..3}; do
value="$ARGUMENT_REGISTER"
for indirection in "${values[@]:1}"; do
value="+$indirection($value)"
done
value="+$((i * 8 + values[0]))($value)"
ARGS+=( "${key,,}$i=$value:x64" )
REGEX="$REGEX ${key,,}$i=0x([0-9a-f]+)"
done
done
turn_off() {
set +e
[[ -f /sys/kernel/debug/tracing/events/wireguard/idxadd/enable ]] || exit
echo 0 > /sys/kernel/debug/tracing/events/wireguard/idxadd/enable
echo "-:wireguard/idxadd" >> /sys/kernel/debug/tracing/kprobe_events
exit
}
trap turn_off INT TERM EXIT
echo "p:wireguard/idxadd index_hashtable_insert ${ARGS[*]}" >> /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/wireguard/idxadd/enable
unpack_u64() {
local i expanded="$1"
if [[ $ENDIAN == big ]]; then
printf -v expanded "%.*s$expanded" $((16 - ${#expanded})) 0000000000000000
for i in {0..7}; do
echo -n "\\x${expanded:(i * 2):2}"
done
elif [[ $ENDIAN == little ]]; then
(( ${#expanded} % 2 == 1 )) && expanded="0$expanded"
expanded="${expanded}0000000000000000"
for i in {0..7}; do
echo -n "\\x${expanded:((7 - i) * 2):2}"
done
else
echo "ERROR: Unable to determine endian" >&2
exit 1
fi
}
while read -r line; do
[[ $line =~ $REGEX ]] || continue
echo "New handshake session:"
j=1
for key in "${!OFFSETS[@]}"; do
bytes=""
for i in {0..3}; do
bytes="$bytes$(unpack_u64 "${BASH_REMATCH[j]}")"
((++j))
done
echo " $key = $(printf "$bytes" | base64)"
done
done < /sys/kernel/debug/tracing/trace_pipe
================================================
FILE: contrib/extract-handshakes/offset-finder.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
struct def {
const char *name;
unsigned long offset;
unsigned long indirection_offset;
};
extern const struct def defs[];
#ifdef __KERNEL__
#include "../drivers/net/wireguard/noise.h"
const struct def defs[] = {
{ "LOCAL_STATIC_PRIVATE_KEY", offsetof(struct noise_static_identity, static_private), offsetof(struct noise_handshake, static_identity) },
{ "LOCAL_EPHEMERAL_PRIVATE_KEY", offsetof(struct noise_handshake, ephemeral_private), -1 },
{ "REMOTE_STATIC_PUBLIC_KEY", offsetof(struct noise_handshake, remote_static), -1 },
{ "PRESHARED_KEY", offsetof(struct noise_handshake, preshared_key), -1 },
{ NULL, 0 }
};
#else
#include <stdio.h>
int main(int argc, char *argv[])
{
puts("declare -A OFFSETS=(");
for (const struct def *def = defs; def->name; ++def) {
printf("\t[%s]=%ld", def->name, def->offset);
if (def->indirection_offset != -1)
printf(",%ld", def->indirection_offset);
putchar('\n');
}
puts(")");
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
puts("ENDIAN=big");
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
puts("ENDIAN=little");
#else
#error "Unsupported endianness"
#endif
return 0;
}
#endif
================================================
FILE: contrib/highlighter/Makefile
================================================
CFLAGS ?= -O3 -march=native
CFLAGS += -std=gnu99
CFLAGS += -Wall
CFLAGS += -MMD -MP
highlight: highlight.o highlighter.o
fuzz: CC := clang
fuzz: CFLAGS += -fsanitize=fuzzer
fuzz: fuzz.c highlighter.c
gui/Makefile: gui/highlight.pro
cd gui && qmake
gui: gui/Makefile
@$(MAKE) -C gui
clean:
rm -f highlight fuzz *.o *.d
@if [ -f gui/Makefile ]; then $(MAKE) -C gui distclean; fi
.PHONY: clean gui
.DEFAULT_GOAL: highlight
MAKEFLAGS += --no-print-directory
-include *.d
================================================
FILE: contrib/highlighter/README
================================================
wg(8) and wg-quick(8) syntax highlighter library
================================================
highlighter.c contains a simple portable highlighter for the wg(8) and
wg-quick(8) configuration files. Simply copy `highlight.c` and
`highlight.h` into your project wholesale.
As a demo, a simple console highlighter program is included, alongside a
simple Qt5 GUI app to show its usage in realtime.
There is also a basic fuzzer, because why not?
Usage:
$ make
$ ./highlight < path/to/tunnel.conf
$ make gui
$ ./gui/highlight
$ make fuzz
$ ./fuzz -workers=$(nproc) -jobs=$(nproc) ./corpus
================================================
FILE: contrib/highlighter/fuzz.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <stdlib.h>
#include <string.h>
#include "highlighter.h"
int LLVMFuzzerTestOneInput(const char *data, size_t size)
{
char *str = strndup(data, size);
if (!str)
return 0;
struct highlight_span *spans = highlight_config(str);
if (!spans)
return 0;
for (struct highlight_span *span = spans; span->type != HighlightEnd; ++span);
free(spans);
free(str);
return 0;
}
================================================
FILE: contrib/highlighter/gui/highlight.cpp
================================================
#include <QApplication>
#include <QPlainTextEdit>
#include <QPalette>
#include <QFontDatabase>
#include <QVBoxLayout>
#include <QPushButton>
extern "C" {
#include "../highlighter.h"
}
static QColor colormap[] = {
[HighlightSection] = QColor("#ababab"),
[HighlightField] = QColor("#70c0b1"),
[HighlightPrivateKey] = QColor("#7aa6da"),
[HighlightPublicKey] = QColor("#7aa6da"),
[HighlightPresharedKey] = QColor("#7aa6da"),
[HighlightIP] = QColor("#b9ca4a"),
[HighlightCidr] = QColor("#e78c45"),
[HighlightHost] = QColor("#b9ca4a"),
[HighlightPort] = QColor("#e78c45"),
[HighlightMTU] = QColor("#c397d8"),
[HighlightKeepalive] = QColor("#c397d8"),
[HighlightComment] = QColor("#969896"),
[HighlightDelimiter] = QColor("#7aa6da"),
#ifndef MOBILE_WGQUICK_SUBSET
[HighlightTable] = QColor("#c397d8"),
[HighlightFwMark] = QColor("#c397d8"),
[HighlightSaveConfig] = QColor("#c397d8"),
[HighlightCmd] = QColor("#969896"),
#endif
[HighlightError] = QColor("#d54e53")
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setWindowTitle(QObject::tr("WireGuard Configuration Highlighter"));
QVBoxLayout v;
w.setLayout(&v);
QPlainTextEdit e;
v.addWidget(&e);
QPalette p(e.palette());
p.setColor(QPalette::Base, QColor("#010101"));
p.setColor(QPalette::Text, QColor("#eaeaea"));
e.setPalette(p);
QFont f(QFontDatabase::systemFont(QFontDatabase::FixedFont));
f.setPointSize(16);
e.setFont(f);
e.setMinimumSize(400, 500);
bool guard = false;
QObject::connect(&e, &QPlainTextEdit::textChanged, [&]() {
if (guard)
return;
struct highlight_span *spans = highlight_config(e.toPlainText().toLatin1().data());
if (!spans)
return;
QTextCursor cursor(e.document());
QTextCharFormat format;
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
format.setForeground(p.color(QPalette::Text));
format.setUnderlineStyle(QTextCharFormat::NoUnderline);
cursor.mergeCharFormat(format);
for (struct highlight_span *span = spans; span->type != HighlightEnd; ++span) {
cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, span->start);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, span->len);
format.setForeground(colormap[span->type]);
format.setUnderlineStyle(span->type == HighlightError ? QTextCharFormat::SpellCheckUnderline : QTextCharFormat::NoUnderline);
cursor.mergeCharFormat(format);
}
free(spans);
guard = true;
cursor.endEditBlock();
guard = false;
});
QPushButton b;
v.addWidget(&b);
b.setText(QObject::tr("&Randomize colors"));
QObject::connect(&b, &QPushButton::clicked, [&]() {
for (size_t i = 0; i < sizeof(colormap) / sizeof(colormap[0]); ++i)
colormap[i] = QColor::fromHsl(qrand() % 360, qrand() % 192 + 64, qrand() % 128 + 128);
e.setPlainText(e.toPlainText());
});
w.show();
return a.exec();
}
================================================
FILE: contrib/highlighter/gui/highlight.pro
================================================
QT += core gui widgets
TEMPLATE = app
TARGET = highlight
SOURCES += highlight.cpp ../highlighter.c
HEADERS += ../highlighter.h
================================================
FILE: contrib/highlighter/highlight.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "highlighter.h"
#define TERMINAL_FG_BLACK "\x1b[30m"
#define TERMINAL_FG_RED "\x1b[31m"
#define TERMINAL_FG_GREEN "\x1b[32m"
#define TERMINAL_FG_YELLOW "\x1b[33m"
#define TERMINAL_FG_BLUE "\x1b[34m"
#define TERMINAL_FG_MAGENTA "\x1b[35m"
#define TERMINAL_FG_CYAN "\x1b[36m"
#define TERMINAL_FG_WHITE "\x1b[37m"
#define TERMINAL_FG_DEFAULT "\x1b[39m"
#define TERMINAL_BG_BLACK "\x1b[40m"
#define TERMINAL_BG_RED "\x1b[41m"
#define TERMINAL_BG_GREEN "\x1b[42m"
#define TERMINAL_BG_YELLOW "\x1b[43m"
#define TERMINAL_BG_BLUE "\x1b[44m"
#define TERMINAL_BG_MAGENTA "\x1b[45m"
#define TERMINAL_BG_CYAN "\x1b[46m"
#define TERMINAL_BG_WHITE "\x1b[47m"
#define TERMINAL_BG_DEFAULT "\x1b[49m"
#define TERMINAL_BOLD "\x1b[1m"
#define TERMINAL_NO_BOLD "\x1b[22m"
#define TERMINAL_UNDERLINE "\x1b[4m"
#define TERMINAL_NO_UNDERLINE "\x1b[24m"
#define TERMINAL_RESET "\x1b[0m"
static const char *colormap[] = {
[HighlightSection] = TERMINAL_FG_BLACK TERMINAL_BOLD,
[HighlightField] = TERMINAL_FG_BLUE TERMINAL_BOLD,
[HighlightPrivateKey] = TERMINAL_FG_YELLOW TERMINAL_BOLD,
[HighlightPublicKey] = TERMINAL_FG_YELLOW TERMINAL_BOLD,
[HighlightPresharedKey] = TERMINAL_FG_YELLOW TERMINAL_BOLD,
[HighlightIP] = TERMINAL_FG_GREEN,
[HighlightCidr] = TERMINAL_FG_YELLOW,
[HighlightHost] = TERMINAL_FG_GREEN TERMINAL_BOLD,
[HighlightPort] = TERMINAL_FG_MAGENTA,
[HighlightMTU] = TERMINAL_FG_BLUE,
[HighlightKeepalive] = TERMINAL_FG_BLUE,
[HighlightComment] = TERMINAL_FG_CYAN,
[HighlightDelimiter] = TERMINAL_FG_CYAN,
#ifndef MOBILE_WGQUICK_SUBSET
[HighlightTable] = TERMINAL_FG_BLUE,
[HighlightFwMark] = TERMINAL_FG_BLUE,
[HighlightSaveConfig] = TERMINAL_FG_BLUE,
[HighlightCmd] = TERMINAL_FG_WHITE,
#endif
[HighlightError] = TERMINAL_FG_RED TERMINAL_UNDERLINE
};
int main(int argc, char *argv[])
{
char input[1024 * 1024];
struct highlight_span *spans;
size_t last = 0, total_len;
total_len = fread(input, 1, sizeof(input) - 1, stdin);
input[total_len] = '\0';
spans = highlight_config(input);
fputs(TERMINAL_RESET, stdout);
for (struct highlight_span *span = spans; span->type != HighlightEnd; ++span) {
fwrite(input + last, 1, span->start - last, stdout);
fputs(colormap[span->type], stdout);
fwrite(input + span->start, 1, span->len, stdout);
fputs(TERMINAL_RESET, stdout);
last = span->start + span->len;
}
fwrite(input + last, 1, total_len - last, stdout);
free(spans);
return 0;
}
================================================
FILE: contrib/highlighter/highlighter.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "highlighter.h"
typedef struct {
const char *s;
size_t len;
} string_span_t;
static bool is_decimal(char c)
{
return c >= '0' && c <= '9';
}
static bool is_hexadecimal(char c)
{
return is_decimal(c) || ((c | 32) >= 'a' && (c | 32) <= 'f');
}
static bool is_alphabet(char c)
{
return (c | 32) >= 'a' && (c | 32) <= 'z';
}
static bool is_same(string_span_t s, const char *c)
{
size_t len = strlen(c);
if (len != s.len)
return false;
return !memcmp(s.s, c, len);
}
static bool is_caseless_same(string_span_t s, const char *c)
{
size_t len = strlen(c);
if (len != s.len)
return false;
for (size_t i = 0; i < len; ++i) {
char a = c[i], b = s.s[i];
if ((unsigned)a - 'a' < 26)
a &= 95;
if ((unsigned)b - 'a' < 26)
b &= 95;
if (a != b)
return false;
}
return true;
}
static bool is_valid_key(string_span_t s)
{
if (s.len != 44 || s.s[43] != '=')
return false;
for (size_t i = 0; i < 42; ++i) {
if (!is_decimal(s.s[i]) && !is_alphabet(s.s[i]) &&
s.s[i] != '/' && s.s[i] != '+')
return false;
}
switch (s.s[42]) {
case 'A':
case 'E':
case 'I':
case 'M':
case 'Q':
case 'U':
case 'Y':
case 'c':
case 'g':
case 'k':
case 'o':
case 's':
case 'w':
case '4':
case '8':
case '0':
break;
default:
return false;
}
return true;
}
static bool is_valid_hostname(string_span_t s)
{
size_t num_digit = 0, num_entity = s.len;
if (s.len > 63 || !s.len)
return false;
if (s.s[0] == '-' || s.s[s.len - 1] == '-')
return false;
if (s.s[0] == '.' || s.s[s.len - 1] == '.')
return false;
for (size_t i = 0; i < s.len; ++i) {
if (is_decimal(s.s[i])) {
++num_digit;
continue;
}
if (s.s[i] == '.') {
--num_entity;
continue;
}
if (!is_alphabet(s.s[i]) && s.s[i] != '-')
return false;
if (i && s.s[i] == '.' && s.s[i - 1] == '.')
return false;
}
return num_digit != num_entity;
}
static bool is_valid_ipv4(string_span_t s)
{
for (size_t j, i = 0, pos = 0; i < 4 && pos < s.len; ++i) {
uint32_t val = 0;
for (j = 0; j < 3 && pos + j < s.len && is_decimal(s.s[pos + j]); ++j)
val = 10 * val + s.s[pos + j] - '0';
if (j == 0 || (j > 1 && s.s[pos] == '0') || val > 255)
return false;
if (pos + j == s.len && i == 3)
return true;
if (s.s[pos + j] != '.')
return false;
pos += j + 1;
}
return false;
}
static bool is_valid_ipv6(string_span_t s)
{
size_t pos = 0;
bool seen_colon = false;
if (s.len < 2)
return false;
if (s.s[pos] == ':' && s.s[++pos] != ':')
return false;
if (s.s[s.len - 1] == ':' && s.s[s.len - 2] != ':')
return false;
for (size_t j, i = 0; pos < s.len; ++i) {
if (s.s[pos] == ':' && !seen_colon) {
seen_colon = true;
if (++pos == s.len)
break;
if (i == 7)
return false;
continue;
}
for (j = 0; j < 4 && pos + j < s.len && is_hexadecimal(s.s[pos + j]); ++j);
if (j == 0)
return false;
if (pos + j == s.len && (seen_colon || i == 7))
break;
if (i == 7)
return false;
if (s.s[pos + j] != ':') {
if (s.s[pos + j] != '.' || (i < 6 && !seen_colon))
return false;
return is_valid_ipv4((string_span_t){ s.s + pos, s.len - pos });
}
pos += j + 1;
}
return true;
}
static bool is_valid_uint(string_span_t s, bool support_hex, uint64_t min, uint64_t max)
{
uint64_t val = 0;
/* Bound this around 32 bits, so that we don't have to write overflow logic. */
if (s.len > 10 || !s.len)
return false;
if (support_hex && s.len > 2 && s.s[0] == '0' && s.s[1] == 'x') {
for (size_t i = 2; i < s.len; ++i) {
if ((unsigned)s.s[i] - '0' < 10)
val = 16 * val + (s.s[i] - '0');
else if (((unsigned)s.s[i] | 32) - 'a' < 6)
val = 16 * val + (s.s[i] | 32) - 'a' + 10;
else
return false;
}
} else {
for (size_t i = 0; i < s.len; ++i) {
if (!is_decimal(s.s[i]))
return false;
val = 10 * val + s.s[i] - '0';
}
}
return val <= max && val >= min;
}
static bool is_valid_port(string_span_t s)
{
return is_valid_uint(s, false, 0, 65535);
}
static bool is_valid_mtu(string_span_t s)
{
return is_valid_uint(s, false, 576, 65535);
}
static bool is_valid_persistentkeepalive(string_span_t s)
{
if (is_same(s, "off"))
return true;
return is_valid_uint(s, false, 0, 65535);
}
#ifndef MOBILE_WGQUICK_SUBSET
static bool is_valid_fwmark(string_span_t s)
{
if (is_same(s, "off"))
return true;
return is_valid_uint(s, true, 0, 4294967295);
}
static bool is_valid_table(string_span_t s)
{
if (is_same(s, "auto"))
return true;
if (is_same(s, "off"))
return true;
/* This pretty much invalidates the other checks, but rt_names.c's
* fread_id_name does no validation aside from this. */
if (s.len < 512)
return true;
return is_valid_uint(s, false, 0, 4294967295);
}
static bool is_valid_saveconfig(string_span_t s)
{
return is_same(s, "true") || is_same(s, "false");
}
static bool is_valid_prepostupdown(string_span_t s)
{
/* It's probably not worthwhile to try to validate a bash expression.
* So instead we just demand non-zero length. */
return s.len;
}
#endif
static bool is_valid_scope(string_span_t s)
{
if (s.len > 64 || !s.len)
return false;
for (size_t i = 0; i < s.len; ++i) {
if (!is_alphabet(s.s[i]) && !is_decimal(s.s[i]) &&
s.s[i] != '_' && s.s[i] != '=' && s.s[i] != '+' &&
s.s[i] != '.' && s.s[i] != '-')
return false;
}
return true;
}
static bool is_valid_endpoint(string_span_t s)
{
if (!s.len)
return false;
if (s.s[0] == '[') {
bool seen_scope = false;
string_span_t hostspan = { s.s + 1, 0 };
for (size_t i = 1; i < s.len; ++i) {
if (s.s[i] == '%') {
if (seen_scope)
return false;
seen_scope = true;
if (!is_valid_ipv6(hostspan))
return false;
hostspan = (string_span_t){ s.s + i + 1, 0 };
} else if (s.s[i] == ']') {
if (seen_scope) {
if (!is_valid_scope(hostspan))
return false;
} else if (!is_valid_ipv6(hostspan)) {
return false;
}
if (i == s.len - 1 || s.s[i + 1] != ':')
return false;
return is_valid_port((string_span_t){ s.s + i + 2, s.len - i - 2 });
} else {
++hostspan.len;
}
}
return false;
}
for (size_t i = 0; i < s.len; ++i) {
if (s.s[i] == ':') {
string_span_t host = { s.s, i }, port = { s.s + i + 1, s.len - i - 1};
return is_valid_port(port) && (is_valid_ipv4(host) || is_valid_hostname(host));
}
}
return false;
}
static bool is_valid_network(string_span_t s)
{
for (size_t i = 0; i < s.len; ++i) {
if (s.s[i] == '/') {
string_span_t ip = { s.s, i }, cidr = { s.s + i + 1, s.len - i - 1};
uint16_t cidrval = 0;
if (cidr.len > 3 || !cidr.len)
return false;
for (size_t j = 0; j < cidr.len; ++j) {
if (!is_decimal(cidr.s[j]))
return false;
cidrval = 10 * cidrval + cidr.s[j] - '0';
}
if (is_valid_ipv4(ip))
return cidrval <= 32;
else if (is_valid_ipv6(ip))
return cidrval <= 128;
return false;
}
}
return is_valid_ipv4(s) || is_valid_ipv6(s);
}
enum field {
InterfaceSection,
PrivateKey,
ListenPort,
Address,
DNS,
MTU,
#ifndef MOBILE_WGQUICK_SUBSET
FwMark,
Table,
PreUp, PostUp, PreDown, PostDown,
SaveConfig,
#endif
PeerSection,
PublicKey,
PresharedKey,
AllowedIPs,
Endpoint,
PersistentKeepalive,
Invalid
};
static enum field section_for_field(enum field t)
{
if (t > InterfaceSection && t < PeerSection)
return InterfaceSection;
if (t > PeerSection && t < Invalid)
return PeerSection;
return Invalid;
}
static enum field get_field(string_span_t s)
{
#define check_enum(t) do { if (is_caseless_same(s, #t)) return t; } while (0)
check_enum(PrivateKey);
check_enum(ListenPort);
check_enum(Address);
check_enum(DNS);
check_enum(MTU);
check_enum(PublicKey);
check_enum(PresharedKey);
check_enum(AllowedIPs);
check_enum(Endpoint);
check_enum(PersistentKeepalive);
#ifndef MOBILE_WGQUICK_SUBSET
check_enum(FwMark);
check_enum(Table);
check_enum(PreUp);
check_enum(PostUp);
check_enum(PreDown);
check_enum(PostDown);
check_enum(SaveConfig);
#endif
return Invalid;
#undef check_enum
}
static enum field get_sectiontype(string_span_t s)
{
if (is_caseless_same(s, "[Peer]"))
return PeerSection;
if (is_caseless_same(s, "[Interface]"))
return InterfaceSection;
return Invalid;
}
struct highlight_span_array {
size_t len, capacity;
struct highlight_span *spans;
};
/* A useful OpenBSD-ism. */
static void *realloc_array(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= (size_t)1 << (sizeof(size_t) * 4) ||
size >= (size_t)1 << (sizeof(size_t) * 4)) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
errno = ENOMEM;
return NULL;
}
return realloc(optr, size * nmemb);
}
static bool append_highlight_span(struct highlight_span_array *a, const char *o, string_span_t s, enum highlight_type t)
{
if (!s.len)
return true;
if (a->len >= a->capacity) {
struct highlight_span *resized;
a->capacity = a->capacity ? a->capacity * 2 : 64;
resized = realloc_array(a->spans, a->capacity, sizeof(*resized));
if (!resized) {
free(a->spans);
memset(a, 0, sizeof(*a));
return false;
}
a->spans = resized;
}
a->spans[a->len++] = (struct highlight_span){ t, s.s - o, s.len };
return true;
}
static void highlight_multivalue_value(struct highlight_span_array *ret, const string_span_t parent, const string_span_t s, enum field section)
{
switch (section) {
case DNS:
if (is_valid_ipv4(s) || is_valid_ipv6(s))
append_highlight_span(ret, parent.s, s, HighlightIP);
else if (is_valid_hostname(s))
append_highlight_span(ret, parent.s, s, HighlightHost);
else
append_highlight_span(ret, parent.s, s, HighlightError);
break;
case Address:
case AllowedIPs: {
size_t slash;
if (!is_valid_network(s)) {
append_highlight_span(ret, parent.s, s, HighlightError);
break;
}
for (slash = 0; slash < s.len; ++slash) {
if (s.s[slash] == '/')
break;
}
if (slash == s.len) {
append_highlight_span(ret, parent.s, s, HighlightIP);
} else {
append_highlight_span(ret, parent.s, (string_span_t){ s.s, slash }, HighlightIP);
append_highlight_span(ret, parent.s, (string_span_t){ s.s + slash, 1 }, HighlightDelimiter);
append_highlight_span(ret, parent.s, (string_span_t){ s.s + slash + 1, s.len - slash - 1 }, HighlightCidr);
}
break;
}
default:
append_highlight_span(ret, parent.s, s, HighlightError);
}
}
static void highlight_multivalue(struct highlight_span_array *ret, const string_span_t parent, const string_span_t s, enum field section)
{
string_span_t current_span = { s.s, 0 };
size_t len_at_last_space = 0;
for (size_t i = 0; i < s.len; ++i) {
if (s.s[i] == ',') {
current_span.len = len_at_last_space;
highlight_multivalue_value(ret, parent, current_span, section);
append_highlight_span(ret, parent.s, (string_span_t){ s.s + i, 1 }, HighlightDelimiter);
len_at_last_space = 0;
current_span = (string_span_t){ s.s + i + 1, 0 };
} else if (s.s[i] == ' ' || s.s[i] == '\t') {
if (&s.s[i] == current_span.s && !current_span.len)
++current_span.s;
else
++current_span.len;
} else {
len_at_last_space = ++current_span.len;
}
}
current_span.len = len_at_last_space;
if (current_span.len)
highlight_multivalue_value(ret, parent, current_span, section);
else if (ret->spans[ret->len - 1].type == HighlightDelimiter)
ret->spans[ret->len - 1].type = HighlightError;
}
static void highlight_value(struct highlight_span_array *ret, const string_span_t parent, const string_span_t s, enum field section)
{
switch (section) {
case PrivateKey:
append_highlight_span(ret, parent.s, s, is_valid_key(s) ? HighlightPrivateKey : HighlightError);
break;
case PublicKey:
append_highlight_span(ret, parent.s, s, is_valid_key(s) ? HighlightPublicKey : HighlightError);
break;
case PresharedKey:
append_highlight_span(ret, parent.s, s, is_valid_key(s) ? HighlightPresharedKey : HighlightError);
break;
case MTU:
append_highlight_span(ret, parent.s, s, is_valid_mtu(s) ? HighlightMTU : HighlightError);
break;
#ifndef MOBILE_WGQUICK_SUBSET
case SaveConfig:
append_highlight_span(ret, parent.s, s, is_valid_saveconfig(s) ? HighlightSaveConfig : HighlightError);
break;
case FwMark:
append_highlight_span(ret, parent.s, s, is_valid_fwmark(s) ? HighlightFwMark : HighlightError);
break;
case Table:
append_highlight_span(ret, parent.s, s, is_valid_table(s) ? HighlightTable : HighlightError);
break;
case PreUp:
case PostUp:
case PreDown:
case PostDown:
append_highlight_span(ret, parent.s, s, is_valid_prepostupdown(s) ? HighlightCmd : HighlightError);
break;
#endif
case ListenPort:
append_highlight_span(ret, parent.s, s, is_valid_port(s) ? HighlightPort : HighlightError);
break;
case PersistentKeepalive:
append_highlight_span(ret, parent.s, s, is_valid_persistentkeepalive(s) ? HighlightKeepalive : HighlightError);
break;
case Endpoint: {
size_t colon;
if (!is_valid_endpoint(s)) {
append_highlight_span(ret, parent.s, s, HighlightError);
break;
}
for (colon = s.len; colon --> 0;) {
if (s.s[colon] == ':')
break;
}
append_highlight_span(ret, parent.s, (string_span_t){ s.s, colon }, HighlightHost);
append_highlight_span(ret, parent.s, (string_span_t){ s.s + colon, 1 }, HighlightDelimiter);
append_highlight_span(ret, parent.s, (string_span_t){ s.s + colon + 1, s.len - colon - 1 }, HighlightPort);
break;
}
case Address:
case DNS:
case AllowedIPs:
highlight_multivalue(ret, parent, s, section);
break;
default:
append_highlight_span(ret, parent.s, s, HighlightError);
}
}
struct highlight_span *highlight_config(const char *config)
{
struct highlight_span_array ret = { 0 };
const string_span_t s = { config, strlen(config) };
string_span_t current_span = { s.s, 0 };
enum field current_section = Invalid, current_field = Invalid;
enum { OnNone, OnKey, OnValue, OnComment, OnSection } state = OnNone;
size_t len_at_last_space = 0, equals_location = 0;
for (size_t i = 0; i <= s.len; ++i) {
if (i == s.len || s.s[i] == '\n' || (state != OnComment && s.s[i] == '#')) {
if (state == OnKey) {
current_span.len = len_at_last_space;
append_highlight_span(&ret, s.s, current_span, HighlightError);
} else if (state == OnValue) {
if (current_span.len) {
append_highlight_span(&ret, s.s, (string_span_t){ s.s + equals_location, 1 }, HighlightDelimiter);
current_span.len = len_at_last_space;
highlight_value(&ret, s, current_span, current_field);
} else {
append_highlight_span(&ret, s.s, (string_span_t){ s.s + equals_location, 1 }, HighlightError);
}
} else if (state == OnSection) {
current_span.len = len_at_last_space;
current_section = get_sectiontype(current_span);
append_highlight_span(&ret, s.s, current_span, current_section == Invalid ? HighlightError : HighlightSection);
} else if (state == OnComment) {
append_highlight_span(&ret, s.s, current_span, HighlightComment);
}
if (i == s.len)
break;
len_at_last_space = 0;
current_field = Invalid;
if (s.s[i] == '#') {
current_span = (string_span_t){ s.s + i, 1 };
state = OnComment;
} else {
current_span = (string_span_t){ s.s + i + 1, 0 };
state = OnNone;
}
} else if (state == OnComment) {
++current_span.len;
} else if (s.s[i] == ' ' || s.s[i] == '\t') {
if (&s.s[i] == current_span.s && !current_span.len)
++current_span.s;
else
++current_span.len;
} else if (s.s[i] == '=' && state == OnKey) {
current_span.len = len_at_last_space;
current_field = get_field(current_span);
enum field section = section_for_field(current_field);
if (section == Invalid || current_field == Invalid || section != current_section)
append_highlight_span(&ret, s.s, current_span, HighlightError);
else
append_highlight_span(&ret, s.s, current_span, HighlightField);
equals_location = i;
current_span = (string_span_t){ s.s + i + 1, 0 };
state = OnValue;
} else {
if (state == OnNone)
state = s.s[i] == '[' ? OnSection : OnKey;
len_at_last_space = ++current_span.len;
}
}
append_highlight_span(&ret, s.s, (string_span_t){ s.s, -1 }, HighlightEnd);
return ret.spans;
}
================================================
FILE: contrib/highlighter/highlighter.h
================================================
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <sys/types.h>
enum highlight_type {
HighlightSection,
HighlightField,
HighlightPrivateKey,
HighlightPublicKey,
HighlightPresharedKey,
HighlightIP,
HighlightCidr,
HighlightHost,
HighlightPort,
HighlightMTU,
HighlightKeepalive,
HighlightComment,
HighlightDelimiter,
#ifndef MOBILE_WGQUICK_SUBSET
HighlightTable,
HighlightFwMark,
HighlightSaveConfig,
HighlightCmd,
#endif
HighlightError,
HighlightEnd
};
struct highlight_span {
enum highlight_type type;
size_t start, len;
};
struct highlight_span *highlight_config(const char *config);
================================================
FILE: contrib/json/README
================================================
wg-json
=======
This will dump all current WireGuard status as JSON output.
Usage:
# wg-json
================================================
FILE: contrib/json/wg-json
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
exec < <(exec wg show all dump)
printf '{'
while read -r -d $'\t' device; do
if [[ $device != "$last_device" ]]; then
[[ -z $last_device ]] && printf '\n' || printf '%s,\n' "$end"
last_device="$device"
read -r private_key public_key listen_port fwmark
printf '\t"%s": {' "$device"
delim=$'\n'
[[ $private_key == "(none)" ]] || { printf '%s\t\t"privateKey": "%s"' "$delim" "$private_key"; delim=$',\n'; }
[[ $public_key == "(none)" ]] || { printf '%s\t\t"publicKey": "%s"' "$delim" "$public_key"; delim=$',\n'; }
[[ $listen_port == "0" ]] || { printf '%s\t\t"listenPort": %u' "$delim" $(( $listen_port )); delim=$',\n'; }
[[ $fwmark == "off" ]] || { printf '%s\t\t"fwmark": %u' "$delim" $(( $fwmark )); delim=$',\n'; }
printf '%s\t\t"peers": {' "$delim"; end=$'\n\t\t}\n\t}'
delim=$'\n'
else
read -r public_key preshared_key endpoint allowed_ips latest_handshake transfer_rx transfer_tx persistent_keepalive
printf '%s\t\t\t"%s": {' "$delim" "$public_key"
delim=$'\n'
[[ $preshared_key == "(none)" ]] || { printf '%s\t\t\t\t"presharedKey": "%s"' "$delim" "$preshared_key"; delim=$',\n'; }
[[ $endpoint == "(none)" ]] || { printf '%s\t\t\t\t"endpoint": "%s"' "$delim" "$endpoint"; delim=$',\n'; }
[[ $latest_handshake == "0" ]] || { printf '%s\t\t\t\t"latestHandshake": %u' "$delim" $(( $latest_handshake )); delim=$',\n'; }
[[ $transfer_rx == "0" ]] || { printf '%s\t\t\t\t"transferRx": %u' "$delim" $(( $transfer_rx )); delim=$',\n'; }
[[ $transfer_tx == "0" ]] || { printf '%s\t\t\t\t"transferTx": %u' "$delim" $(( $transfer_tx )); delim=$',\n'; }
[[ $persistent_keepalive == "off" ]] || { printf '%s\t\t\t\t"persistentKeepalive": %u' "$delim" $(( $persistent_keepalive )); delim=$',\n'; }
printf '%s\t\t\t\t"allowedIps": [' "$delim"
delim=$'\n'
if [[ $allowed_ips != "(none)" ]]; then
old_ifs="$IFS"
IFS=,
for ip in $allowed_ips; do
printf '%s\t\t\t\t\t"%s"' "$delim" "$ip"
delim=$',\n'
done
IFS="$old_ifs"
delim=$'\n'
fi
printf '%s\t\t\t\t]' "$delim"
printf '\n\t\t\t}'
delim=$',\n'
fi
done
printf '%s\n' "$end"
printf '}\n'
================================================
FILE: contrib/keygen-html/.gitignore
================================================
curve25519_generate.js
================================================
FILE: contrib/keygen-html/README
================================================
WireGuard Key Generation in JavaScript
======================================
Various people believe in JavaScript crypto, unfortunately. This small
example helps them fuel their poor taste.
It's possible to generate WireGuard keys (and thus configurations) in the
browser. The webpage here simulates talking to a server to exchange keys
and then generates a configuration file for the user to download.
Bugs
----
Who knows how emscripten actually compiles this and whether or not it
introduces interesting side-channel attacks.
Secrets aren't zerored after use. Maybe you can get around this with
some tricks taking advantage of browser allocator behavior and different
processes, but it seems pretty hard.
================================================
FILE: contrib/keygen-html/keygen.html
================================================
<script src="wireguard.js"></script>
<script>
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
function sendPubkeyToServer(pubkey, username, password)
{
var node = document.createElement("li");
node.innerText = "Sending " + username + ":" + password + " to server for new pubkey " + pubkey + "...";
document.body.appendChild(node);
// send info to server
var serverResponse = {
publicKey: "6spHEFoJrp9pijbxjJoS6fHjZaAWQqtdFFO/OtpVe3w=",
allowedIPs: [ "0.0.0.0/0", "::/0" ],
endpoint: "demo.wireguard.com:63321",
address: [ "192.168.18.42/32", "fd08:1234:1111::77/128" ],
dns: [ "8.8.8.8", "8.8.4.4" ]
}
return serverResponse;
}
function downloadNewConfiguration()
{
var keypair = wireguard.generateKeypair();
var serverResponse = sendPubkeyToServer(keypair.publicKey, "zx2c4", "supersecretpassword");
var config = [];
config.push("[Interface]");
config.push("PrivateKey = " + keypair.privateKey);
config.push("Address = " + serverResponse.address.join(", "));
config.push("DNS = " + serverResponse.dns.join(", "));
config.push("");
config.push("[Peer]");
config.push("PublicKey = " + serverResponse.publicKey);
config.push("AllowedIPs = " + serverResponse.allowedIPs.join(", "));
config.push("Endpoint = " + serverResponse.endpoint);
config.push("");
return config.join("\n");
}
function giveOneConfigurationToUser()
{
var config = downloadNewConfiguration();
var blob = new Blob([config], { type: "text/plain" });
var a = document.createElement("a");
a.download = "demo0.conf";
a.href = URL.createObjectURL(blob);
a.style.display = "none";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
function putU32(b, n)
{
b.push(n & 0xff, (n >>> 8) & 0xff, (n >>> 16) & 0xff, (n >>> 24) & 0xff);
}
function putU16(b, n)
{
b.push(n & 0xff, (n >>> 8) & 0xff);
}
function putBytes(b, a)
{
for (var i = 0; i < a.length; ++i)
b.push(a[i] & 0xff);
}
function encodeString(s)
{
var utf8 = unescape(encodeURIComponent(s));
var b = new Uint8Array(utf8.length);
for (var i = 0; i < utf8.length; ++i)
b[i] = utf8.charCodeAt(i);
return b;
}
function crc32(b)
{
if (!crc32.table) {
crc32.table = [];
for (var c = 0, n = 0; n < 256; c = ++n) {
for (var k = 0; k < 8; ++k)
c = ((c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1));
crc32.table[n] = c;
}
}
var crc = -1;
for (var i = 0; i < b.length; ++i)
crc = (crc >>> 8) ^ crc32.table[(crc ^ b[i]) & 0xff];
return (crc ^ (-1)) >>> 0;
}
function createZipFile(files)
{
var b = [];
var cd = [];
var offset = 0;
for (var i = 0; i < files.length; ++i) {
var name = encodeString(files[i].name);
var contents = encodeString(files[i].contents);
var crc = crc32(contents);
putU32(b, 0x04034b50); /* signature */
putU16(b, 20); /* version needed */
putU16(b, 0); /* flags */
putU16(b, 0); /* compression method */
putU16(b, 0); /* mtime */
putU16(b, 0); /* mdate */
putU32(b, crc); /* crc32 */
putU32(b, contents.length); /* compressed size */
putU32(b, contents.length); /* uncompressed size */
putU16(b, name.length); /* file name length */
putU16(b, 0); /* extra field length */
putBytes(b, name);
putBytes(b, contents);
putU32(cd, 0x02014b50); /* signature */
putU16(cd, 0); /* version made */
putU16(cd, 20); /* version needed */
putU16(cd, 0); /* flags */
putU16(cd, 0); /* compression method */
putU16(cd, 0); /* mtime */
putU16(cd, 0); /* mdate */
putU32(cd, crc); /* crc32 */
putU32(cd, contents.length); /* compressed size */
putU32(cd, contents.length); /* uncompressed size */
putU16(cd, name.length); /* file name length */
putU16(cd, 0); /* extra field length */
putU16(cd, 0); /* file comment length */
putU16(cd, 0); /* disk number start */
putU16(cd, 0); /* internal file attributes */
putU32(cd, 32); /* external file attributes - 'archive' bit set (32) */
putU32(cd, offset); /* relative offset of local header */
putBytes(cd, name); /* file name */
offset += 30 + contents.length + name.length
}
putBytes(b, cd); /* central directory */
putU32(b, 0x06054b50); /* end of central directory signature */
putU16(b, 0); /* number of this disk */
putU16(b, 0); /* number of disk with central directory start */
putU16(b, files.length); /* number of entries on disk */
putU16(b, files.length); /* number of entries */
putU32(b, cd.length); /* length of central directory */
putU32(b, offset); /* offset to start of central directory */
putU16(b, 0); /* zip comment size */
return Uint8Array.from(b);
}
function giveMultipleConfigurationsToUser()
{
var zipFile = createZipFile([
{ name: "demo0.conf", contents: downloadNewConfiguration() },
{ name: "demo1.conf", contents: downloadNewConfiguration() },
{ name: "demo2.conf", contents: downloadNewConfiguration() }
]);
var blob = new Blob([zipFile], { type: "application/zip" });
var a = document.createElement("a");
a.download = "demo-configs.zip";
a.href = URL.createObjectURL(blob);
a.style.display = "none";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
</script>
<p><a href="javascript:giveOneConfigurationToUser()">Download a WireGuard configuration file</a></p>
<p><a href="javascript:giveMultipleConfigurationsToUser()">Download several WireGuard configuration files</a></p>
================================================
FILE: contrib/keygen-html/wireguard.js
================================================
/*! SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
(function() {
function gf(init) {
var r = new Float64Array(16);
if (init) {
for (var i = 0; i < init.length; ++i)
r[i] = init[i];
}
return r;
}
function pack(o, n) {
var b, m = gf(), t = gf();
for (var i = 0; i < 16; ++i)
t[i] = n[i];
carry(t);
carry(t);
carry(t);
for (var j = 0; j < 2; ++j) {
m[0] = t[0] - 0xffed;
for (var i = 1; i < 15; ++i) {
m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
cswap(t, m, 1 - b);
}
for (var i = 0; i < 16; ++i) {
o[2 * i] = t[i] & 0xff;
o[2 * i + 1] = t[i] >> 8;
}
}
function carry(o) {
var c;
for (var i = 0; i < 16; ++i) {
o[(i + 1) % 16] += (i < 15 ? 1 : 38) * Math.floor(o[i] / 65536);
o[i] &= 0xffff;
}
}
function cswap(p, q, b) {
var t, c = ~(b - 1);
for (var i = 0; i < 16; ++i) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
}
function add(o, a, b) {
for (var i = 0; i < 16; ++i)
o[i] = (a[i] + b[i]) | 0;
}
function subtract(o, a, b) {
for (var i = 0; i < 16; ++i)
o[i] = (a[i] - b[i]) | 0;
}
function multmod(o, a, b) {
var t = new Float64Array(31);
for (var i = 0; i < 16; ++i) {
for (var j = 0; j < 16; ++j)
t[i + j] += a[i] * b[j];
}
for (var i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
for (var i = 0; i < 16; ++i)
o[i] = t[i];
carry(o);
carry(o);
}
function invert(o, i) {
var c = gf();
for (var a = 0; a < 16; ++a)
c[a] = i[a];
for (var a = 253; a >= 0; --a) {
multmod(c, c, c);
if (a !== 2 && a !== 4)
multmod(c, c, i);
}
for (var a = 0; a < 16; ++a)
o[a] = c[a];
}
function clamp(z) {
z[31] = (z[31] & 127) | 64;
z[0] &= 248;
}
function generatePublicKey(privateKey) {
var r, z = new Uint8Array(32);
var a = gf([1]),
b = gf([9]),
c = gf(),
d = gf([1]),
e = gf(),
f = gf(),
_121665 = gf([0xdb41, 1]),
_9 = gf([9]);
for (var i = 0; i < 32; ++i)
z[i] = privateKey[i];
clamp(z);
for (var i = 254; i >= 0; --i) {
r = (z[i >>> 3] >>> (i & 7)) & 1;
cswap(a, b, r);
cswap(c, d, r);
add(e, a, c);
subtract(a, a, c);
add(c, b, d);
subtract(b, b, d);
multmod(d, e, e);
multmod(f, a, a);
multmod(a, c, a);
multmod(c, b, e);
add(e, a, c);
subtract(a, a, c);
multmod(b, a, a);
subtract(c, d, f);
multmod(a, c, _121665);
add(a, a, d);
multmod(c, c, a);
multmod(a, d, f);
multmod(d, b, _9);
multmod(b, e, e);
cswap(a, b, r);
cswap(c, d, r);
}
invert(c, c);
multmod(a, a, c);
pack(z, a);
return z;
}
function generatePresharedKey() {
var privateKey = new Uint8Array(32);
window.crypto.getRandomValues(privateKey);
return privateKey;
}
function generatePrivateKey() {
var privateKey = generatePresharedKey();
clamp(privateKey);
return privateKey;
}
function encodeBase64(dest, src) {
var input = Uint8Array.from([(src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63]);
for (var i = 0; i < 4; ++i)
dest[i] = input[i] + 65 +
(((25 - input[i]) >> 8) & 6) -
(((51 - input[i]) >> 8) & 75) -
(((61 - input[i]) >> 8) & 15) +
(((62 - input[i]) >> 8) & 3);
}
function keyToBase64(key) {
var i, base64 = new Uint8Array(44);
for (i = 0; i < 32 / 3; ++i)
encodeBase64(base64.subarray(i * 4), key.subarray(i * 3));
encodeBase64(base64.subarray(i * 4), Uint8Array.from([key[i * 3 + 0], key[i * 3 + 1], 0]));
base64[43] = 61;
return String.fromCharCode.apply(null, base64);
}
window.wireguard = {
generateKeypair: function() {
var privateKey = generatePrivateKey();
var publicKey = generatePublicKey(privateKey);
return {
publicKey: keyToBase64(publicKey),
privateKey: keyToBase64(privateKey)
};
}
};
})();
================================================
FILE: contrib/launchd/README
================================================
WireGuard for Launchd
=====================
The example `com.wireguard.wg0.plist` file may be used for running wg-quick(8)
as a launchd service. Note that the `PATH` variable is modified to point to
the PATH used by Homebrew or Macports, so that it uses the non-system bash(1).
Usage
-----
$ sudo cp com.wireguard.wg0.plist /Library/LaunchDaemons
$ sudo launchctl load /Library/LaunchDaemons/com.wireguard.wg0.plist
================================================
FILE: contrib/launchd/com.wireguard.wg0.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.wireguard.wg0</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/wg-quick</string>
<string>up</string>
<string>/usr/local/etc/wireguard/wg0.conf</string>
</array>
<key>OnDemand</key>
<false/>
<key>RunAtLoad</key>
<true/>
<key>TimeOut</key>
<integer>90</integer>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
</dict>
</plist>
================================================
FILE: contrib/nat-hole-punching/README
================================================
== NAT Hole Punching Example ==
This code should never be used, ever. But, it's a nice demonstration of how
to punch holes and have two NAT'd peers talk to each other.
Compile with:
$ gcc nat-punch-client.c -o client -lresolv
$ gcc nat-punch-server.c -o server
Server is 1.2.3.4 and is on the public internet accepting UDP:49918.
Client A is NAT'd and doesn't know its IP address.
Client B is NAT'd and doesn't know its IP address.
Server runs:
$ ./server
Client A runs:
# ip link add wg0 type wireguard
# ip addr add 10.200.200.1 peer 10.200.200.2 dev wg0
# wg set wg0 private-key ... peer ... allowed-ips 10.200.200.2/32
# ./client 1.2.3.4 wg0
# ping 10.200.200.2
Client B runs:
# ip link add wg0 type wireguard
# ip addr add 10.200.200.2 peer 10.200.200.1 dev wg0
# wg set wg0 private-key ... peer ... allowed-ips 10.200.200.1/32
# ./client 1.2.3.4 wg0
# ping 10.200.200.1
And voila! Client A and Client B can speak from behind NAT.
-----
Keep in mind that this is proof-of-concept example code. It is not code that
should be used in production, ever. It is woefully insecure, and is unsuitable
for any real usage. With that said, this is useful as a learning example of
how NAT hole punching might work within a more developed solution.
================================================
FILE: contrib/nat-hole-punching/nat-punch-client.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* Example only. Do not run in production.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <linux/filter.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <resolv.h>
#include <stdint.h>
#include <stdbool.h>
enum { MAX_PEERS = 65536, PORT = 49918 };
static struct {
uint8_t base64_key[45];
bool have_seen;
} peers[MAX_PEERS];
static unsigned int total_peers;
static const char *cmd(const char *line, ...)
{
static char buf[2048];
char full_cmd[2048] = { 0 };
size_t len;
FILE *f;
va_list args;
va_start(args, line);
vsnprintf(full_cmd, 2047, line, args);
va_end(args);
f = popen(full_cmd, "r");
if (!f) {
perror("popen");
exit(errno);
}
if (!fgets(buf, 2048, f)) {
pclose(f);
return NULL;
}
pclose(f);
len = strlen(buf);
if (!len)
return NULL;
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
return buf;
}
static void read_peers(const char *interface)
{
char full_cmd[2048] = { 0 };
size_t len;
FILE *f;
snprintf(full_cmd, 2047, "wg show %s peers", interface);
f = popen(full_cmd, "r");
if (!f) {
perror("popen");
exit(errno);
}
for (;;) {
if (!fgets(peers[total_peers].base64_key, 45, f))
break;
len = strlen(peers[total_peers].base64_key);
if (len != 44 && len != 45)
continue;
if (peers[total_peers].base64_key[len - 1] == '\n')
peers[total_peers].base64_key[len - 1] = '\0';
++total_peers;
}
pclose(f);
}
static void unbase64(uint8_t dstkey[32], const char *srckey)
{
uint8_t buf[33];
if (b64_pton(srckey, buf, 33) != 32) {
fprintf(stderr, "Could not parse base64 key: %s\n", srckey);
exit(EINVAL);
}
memcpy(dstkey, buf, 32);
}
static void apply_bpf(int sock, uint16_t port, uint32_t ip)
{
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 12 /* src ip */),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ip, 0, 5),
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 /* src port */),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, PORT, 0, 3),
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 22 /* dst port */),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 0, 1),
BPF_STMT(BPF_RET + BPF_K, -1),
BPF_STMT(BPF_RET + BPF_K, 0)
};
struct sock_fprog filter_prog = {
.len = sizeof(filter) / sizeof(filter[0]),
.filter = filter
};
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) < 0) {
perror("setsockopt(bpf)");
exit(errno);
}
}
int main(int argc, char *argv[])
{
struct sockaddr_in addr = {
.sin_family = AF_INET
};
struct {
struct udphdr udp;
uint8_t my_pubkey[32];
uint8_t their_pubkey[32];
} __attribute__((packed)) packet = {
.udp = {
.len = htons(sizeof(packet)),
.dest = htons(PORT)
}
};
struct {
struct iphdr iphdr;
struct udphdr udp;
uint32_t ip;
uint16_t port;
} __attribute__((packed)) reply;
ssize_t len;
int sock, i;
bool repeat;
struct hostent *ent;
const char *server = argv[1], *interface = argv[2];
if (argc < 3) {
fprintf(stderr, "Usage: %s SERVER WIREGUARD_INTERFACE\nExample:\n %s demo.wireguard.com wg0\n", argv[0], argv[0]);
return EINVAL;
}
if (getuid() != 0) {
fprintf(stderr, "Must be root!\n");
return EPERM;
}
ent = gethostbyname2(server, AF_INET);
if (!ent) {
herror("gethostbyname2");
return h_errno;
}
addr.sin_addr = *(struct in_addr *)ent->h_addr;
read_peers(interface);
cmd("ip link set %s up", interface);
unbase64(packet.my_pubkey, cmd("wg show %s public-key", interface));
packet.udp.source = htons(atoi(cmd("wg show %s listen-port", interface)));
/* We use raw sockets so that the WireGuard interface can actually own the real socket. */
sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (sock < 0) {
perror("socket");
return errno;
}
apply_bpf(sock, ntohs(packet.udp.source), ntohl(addr.sin_addr.s_addr));
check_again:
repeat = false;
for (i = 0; i < total_peers; ++i) {
if (peers[i].have_seen)
continue;
printf("[+] Requesting IP and port of %s: ", peers[i].base64_key);
unbase64(packet.their_pubkey, peers[i].base64_key);
if (sendto(sock, &packet, sizeof(packet), 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
putchar('\n');
perror("sendto");
return errno;
}
len = recv(sock, &reply, sizeof(reply), 0);
if (len < 0) {
putchar('\n');
perror("recv");
return errno;
}
if (len != sizeof(reply)) {
printf("server does not yet have it\n");
repeat = true;
} else {
printf("%s:%d\n", inet_ntoa(*(struct in_addr *)&reply.ip), ntohs(reply.port));
peers[i].have_seen = true;
cmd("wg set %s peer %s persistent-keepalive 25 endpoint %s:%d", interface, peers[i].base64_key, inet_ntoa(*(struct in_addr *)&reply.ip), ntohs(reply.port));
}
}
if (repeat) {
sleep(2);
goto check_again;
}
close(sock);
return 0;
}
================================================
FILE: contrib/nat-hole-punching/nat-punch-server.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* Example only. Do not run in production.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
struct entry {
uint8_t pubkey[32];
uint32_t ip;
uint16_t port;
};
enum { MAX_ENTRIES = 65536, PORT = 49918 };
static struct entry entries[MAX_ENTRIES];
static unsigned int next_entry;
/* XX: this should use a hash table */
static struct entry *find_entry(uint8_t key[32])
{
int i;
for (i = 0; i < MAX_ENTRIES; ++i) {
if (!memcmp(entries[i].pubkey, key, 32))
return &entries[i];
}
return NULL;
}
/* XX: this is obviously vulnerable to DoS */
static struct entry *find_or_insert_entry(uint8_t key[32])
{
struct entry *entry = find_entry(key);
if (!entry) {
entry = &entries[next_entry++ % MAX_ENTRIES];
memcpy(entry->pubkey, key, 32);
}
return entry;
}
int main(int argc, char *argv[])
{
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr = { .s_addr = htonl(INADDR_ANY) },
.sin_port = htons(PORT)
};
struct {
uint8_t my_pubkey[32];
uint8_t their_pubkey[32];
} __attribute__((packed)) packet;
struct {
uint32_t ip;
uint16_t port;
} __attribute__((packed)) reply;
struct entry *entry;
socklen_t len;
ssize_t retlen;
int optval;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return errno;
}
optval = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
perror("setsockopt");
return errno;
}
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return errno;
}
for (;;) {
len = sizeof(addr);
if (recvfrom(sock, &packet, sizeof(packet), 0, (struct sockaddr *)&addr, &len) != sizeof(packet)) {
perror("recvfrom");
continue;
}
entry = find_or_insert_entry(packet.my_pubkey);
entry->ip = addr.sin_addr.s_addr;
entry->port = addr.sin_port;
entry = find_entry(packet.their_pubkey);
if (entry) {
reply.ip = entry->ip;
reply.port = entry->port;
if (sendto(sock, &reply, sizeof(reply), 0, (struct sockaddr *)&addr, len) < 0) {
perror("sendto");
continue;
}
} else {
if (sendto(sock, NULL, 0, 0, (struct sockaddr *)&addr, len) < 0) {
perror("sendto");
continue;
}
}
}
close(sock);
return 0;
}
================================================
FILE: contrib/ncat-client-server/README
================================================
=== IMPORTANT NOTE ===
Do not use these scripts in production. They are simply a
demonstration of how easy the `wg(8)` tool is at the command
line, but by no means should you actually attempt to use
these. They are horribly insecure and defeat the purpose
of WireGuard.
STAY AWAY!
That all said, this is a pretty cool example of just how
darn easy WireGuard can be.
Disclaimer:
The `demo.wireguard.com` server in client.sh is for testing
purposes only. You may not use this server for abusive or
illegal purposes.
================================================
FILE: contrib/ncat-client-server/client-quick.sh
================================================
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
set -e
echo "[!] Warning: This server is for testing purposes only. You may not use this server for abusive or illegal purposes."
echo "[+] Generating private key."
privatekey="$(wg genkey)"
echo "[+] Sending public key to server."
exec 7<>/dev/tcp/demo.wireguard.com/42912
wg pubkey <<<"$privatekey" >&7
echo "[+] Parsing server response."
IFS=: read -r status server_pubkey server_port internal_ip <&7
[[ $status == OK ]] || exit 1
echo "[+] Writing config file."
[[ $UID -eq 0 ]] || sudo=sudo
$sudo sh -c 'umask 077; mkdir -p /etc/wireguard; cat > /etc/wireguard/demo.conf' <<_EOF
[Interface]
PrivateKey = $privatekey
Address = $internal_ip/24
DNS = 8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1
[Peer]
PublicKey = $server_pubkey
Endpoint = demo.wireguard.com:$server_port
AllowedIPs = 0.0.0.0/0
_EOF
echo "[+] Success. Run \`wg-quick up demo\` to turn on the tunnel to the demo server and \`wg-quick down demo\` to turn it off."
================================================
FILE: contrib/ncat-client-server/client.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
set -e
[[ $UID == 0 ]] || { echo "You must be root to run this."; exit 1; }
exec 3<>/dev/tcp/demo.wireguard.com/42912
privatekey="$(wg genkey)"
wg pubkey <<<"$privatekey" >&3
IFS=: read -r status server_pubkey server_port internal_ip <&3
[[ $status == OK ]]
ip link del dev wg0 2>/dev/null || true
ip link add dev wg0 type wireguard
wg set wg0 private-key <(echo "$privatekey") peer "$server_pubkey" allowed-ips 0.0.0.0/0 endpoint "demo.wireguard.com:$server_port" persistent-keepalive 25
ip address add "$internal_ip"/24 dev wg0
ip link set up dev wg0
if [ "$1" == "default-route" ]; then
host="$(wg show wg0 endpoints | sed -n 's/.*\t\(.*\):.*/\1/p')"
ip route add $(ip route get $host | sed '/ via [0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/{s/^\(.* via [0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/}' | head -n 1) 2>/dev/null || true
ip route add 0/1 dev wg0
ip route add 128/1 dev wg0
fi
================================================
FILE: contrib/ncat-client-server/server.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
if [[ -z $NCAT_REMOTE_ADDR ]]; then
ip link del dev wg0 2>/dev/null
set -e
ip link add dev wg0 type wireguard
ip address add 192.168.4.1/24 dev wg0
wg set wg0 private-key <(wg genkey) listen-port 12912
ip link set up dev wg0
exec ncat -e "$(readlink -f "$0")" -k -l -p 42912 -v
fi
read -r public_key
[[ $(wg show wg0 peers | wc -l) -ge 253 ]] && wg set wg0 peer $(wg show wg0 latest-handshakes | sort -k 2 -b -n | head -n 1 | cut -f 1) remove
next_ip=$(all="$(wg show wg0 allowed-ips)"; for ((i=2; i<=254; i++)); do ip="192.168.4.$i"; [[ $all != *$ip/32* ]] && echo $ip && break; done)
wg set wg0 peer "$public_key" allowed-ips $next_ip/32 2>/dev/null && echo "OK:$(wg show wg0 private-key | wg pubkey):$(wg show wg0 listen-port):$next_ip" || echo ERROR
================================================
FILE: contrib/reresolve-dns/README
================================================
reresolve-dns
=============
Run this script from cron every thirty seconds or so, and it will ensure
that if, when using a dynamic DNS service, the DNS entry for a hosts
changes, the kernel will get the update to the DNS entry.
This works by parsing configuration files, and simply running:
$ wg set wg0 peer ... endpoint ...
================================================
FILE: contrib/reresolve-dns/reresolve-dns.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
set -e
shopt -s nocasematch
shopt -s extglob
export LC_ALL=C
CONFIG_FILE="$1"
[[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf"
[[ $CONFIG_FILE =~ /?([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]]
INTERFACE="${BASH_REMATCH[1]}"
process_peer() {
[[ $PEER_SECTION -ne 1 || -z $PUBLIC_KEY || -z $ENDPOINT ]] && return 0
[[ $(wg show "$INTERFACE" latest-handshakes) =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 0
(( ($EPOCHSECONDS - ${BASH_REMATCH[1]}) > 135 )) || return 0
wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT"
reset_peer_section
}
reset_peer_section() {
PEER_SECTION=0
PUBLIC_KEY=""
ENDPOINT=""
}
reset_peer_section
while read -r line || [[ -n $line ]]; do
stripped="${line%%\#*}"
key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}"
value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}"
[[ $key == "["* ]] && { process_peer; reset_peer_section; }
[[ $key == "[Peer]" ]] && PEER_SECTION=1
if [[ $PEER_SECTION -eq 1 ]]; then
case "$key" in
PublicKey) PUBLIC_KEY="$value"; continue ;;
Endpoint) ENDPOINT="$value"; continue ;;
esac
fi
done < "$CONFIG_FILE"
process_peer
================================================
FILE: contrib/sticky-sockets/README
================================================
Sticky Sockets
==============
This is a small userspace mini-library that implements as close to
possible how the kernel does its sticky src address sending.
================================================
FILE: contrib/sticky-sockets/sticky-sockets.c
================================================
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* This implements userspace semantics of "sticky sockets", modeled after
* WireGuard's kernelspace implementation.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <linux/ipv6.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
struct magic_endpoint {
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
};
union {
struct {
struct in_addr src4;
int src_if4; /* Essentially the same as addr6->scope_id */
};
struct in6_addr src6;
};
};
ssize_t magic_send4(int sock, struct magic_endpoint *endpoint, void *buffer, size_t len)
{
ssize_t ret;
struct iovec iovec = {
.iov_base = buffer,
.iov_len = len
};
struct {
struct cmsghdr cmsghdr;
struct in_pktinfo pktinfo;
} cmsg = {
.cmsghdr.cmsg_level = IPPROTO_IP,
.cmsghdr.cmsg_type = IP_PKTINFO,
.cmsghdr.cmsg_len = CMSG_LEN(sizeof(cmsg.pktinfo)),
.pktinfo.ipi_spec_dst = endpoint->src4,
.pktinfo.ipi_ifindex = endpoint->src_if4
};
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_name = &endpoint->addr4,
.msg_namelen = sizeof(endpoint->addr4),
.msg_control = &cmsg,
.msg_controllen = sizeof(cmsg)
};
ret = sendmsg(sock, &msghdr, 0);
if (ret < 0 && errno == EINVAL) {
memset(&cmsg.pktinfo, 0, sizeof(cmsg.pktinfo));
endpoint->src4.s_addr = endpoint->src_if4 = 0;
return sendmsg(sock, &msghdr, 0);
}
return ret;
}
ssize_t magic_send6(int sock, struct magic_endpoint *endpoint, void *buffer, size_t len)
{
ssize_t ret;
struct iovec iovec = {
.iov_base = buffer,
.iov_len = len
};
struct {
struct cmsghdr cmsghdr;
struct in6_pktinfo pktinfo;
} cmsg = {
.cmsghdr.cmsg_level = IPPROTO_IPV6,
.cmsghdr.cmsg_type = IPV6_PKTINFO,
.cmsghdr.cmsg_len = CMSG_LEN(sizeof(cmsg.pktinfo)),
.pktinfo.ipi6_addr = endpoint->src6,
.pktinfo.ipi6_ifindex = memcmp(&in6addr_any, &endpoint->src6, sizeof(endpoint->src6)) ? endpoint->addr6.sin6_scope_id : 0
};
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_name = &endpoint->addr6,
.msg_namelen = sizeof(endpoint->addr6),
.msg_control = &cmsg,
.msg_controllen = sizeof(cmsg)
};
ret = sendmsg(sock, &msghdr, 0);
if (ret < 0 && errno == EINVAL) {
memset(&cmsg.pktinfo, 0, sizeof(cmsg.pktinfo));
memset(&endpoint->src6, 0, sizeof(endpoint->src6));
return sendmsg(sock, &msghdr, 0);
}
return ret;
}
ssize_t magic_receive4(int sock, struct magic_endpoint *endpoint, void *buffer, size_t len)
{
ssize_t ret;
struct iovec iovec = {
.iov_base = buffer,
.iov_len = len
};
struct {
struct cmsghdr cmsghdr;
struct in_pktinfo pktinfo;
} cmsg;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_name = &endpoint->addr4,
.msg_namelen = sizeof(endpoint->addr4),
.msg_control = &cmsg,
.msg_controllen = sizeof(cmsg)
};
ret = recvmsg(sock, &msghdr, 0);
if (ret < 0)
return ret;
if (cmsg.cmsghdr.cmsg_level == IPPROTO_IP && cmsg.cmsghdr.cmsg_type == IP_PKTINFO && cmsg.cmsghdr.cmsg_len >= CMSG_LEN(sizeof(cmsg.pktinfo))) {
endpoint->src4 = cmsg.pktinfo.ipi_spec_dst;
endpoint->src_if4 = cmsg.pktinfo.ipi_ifindex;
}
return ret;
}
ssize_t magic_receive6(int sock, struct magic_endpoint *endpoint, void *buffer, size_t len)
{
ssize_t ret;
struct iovec iovec = {
.iov_base = buffer,
.iov_len = len
};
struct {
struct cmsghdr cmsghdr;
struct in6_pktinfo pktinfo;
} cmsg;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_name = &endpoint->addr6,
.msg_namelen = sizeof(endpoint->addr6),
.msg_control = &cmsg,
.msg_controllen = sizeof(cmsg)
};
ret = recvmsg(sock, &msghdr, 0);
if (ret < 0)
return ret;
if (cmsg.cmsghdr.cmsg_level == IPPROTO_IPV6 && cmsg.cmsghdr.cmsg_type == IPV6_PKTINFO && cmsg.cmsghdr.cmsg_len >= CMSG_LEN(sizeof(cmsg.pktinfo))) {
endpoint->src6 = cmsg.pktinfo.ipi6_addr;
endpoint->addr6.sin6_scope_id = cmsg.pktinfo.ipi6_ifindex;
}
return ret;
}
void magic_endpoint_clearsrc(struct magic_endpoint *endpoint)
{
if (endpoint->addr.sa_family == AF_INET)
endpoint->src4.s_addr = endpoint->src_if4 = 0;
else if (endpoint->addr.sa_family == AF_INET6)
memset(&endpoint->src6, 0, sizeof(endpoint->src6));
else
memset(endpoint, 0, sizeof(*endpoint));
}
void magic_endpoint_set(struct magic_endpoint *endpoint, const struct sockaddr *addr)
{
if (addr->sa_family == AF_INET)
endpoint->addr4 = *(struct sockaddr_in *)addr;
else if (addr->sa_family == AF_INET6)
endpoint->addr6 = *(struct sockaddr_in6 *)addr;
magic_endpoint_clearsrc(endpoint);
}
int magic_create_sock4(uint16_t listen_port)
{
static const int on = 1;
struct sockaddr_in listen_addr = {
.sin_family = AF_INET,
.sin_port = htons(listen_port),
.sin_addr = INADDR_ANY
};
int fd, ret;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
return fd;
ret = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
if (ret < 0)
goto err;
ret = bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr));
if (ret < 0)
goto err;
return fd;
err:
close(fd);
return ret;
}
int magic_create_sock6(uint16_t listen_port)
{
static const int on = 1;
struct sockaddr_in6 listen_addr = {
.sin6_family = AF_INET6,
.sin6_port = htons(listen_port),
.sin6_addr = IN6ADDR_ANY_INIT
};
int fd, ret;
fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd < 0)
return fd;
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
if (ret < 0)
goto err;
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (ret < 0)
goto err;
ret = bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr));
if (ret < 0)
goto err;
return fd;
err:
close(fd);
return ret;
}
int main(int argc, char *argv[])
{
struct magic_endpoint endpoint = { 0 };
int sock;
ssize_t ret;
uint8_t buffer[1024] = { 0 };
char srcaddr[40], dstaddr[40];
if (argc == 2 && !strcmp(argv[1], "-4"))
goto v4;
if (argc == 2 && !strcmp(argv[1], "-6"))
goto v6;
return 1;
v6:
sock = magic_create_sock6(51820);
if (sock < 0) {
perror("magic_create_sock6");
return 1;
}
ret = magic_receive6(sock, &endpoint, buffer, sizeof(buffer));
if (ret < 0) {
perror("magic_receive6");
return 1;
}
if (!inet_ntop(AF_INET6, &endpoint.src6, srcaddr, sizeof(srcaddr))) {
perror("inet_ntop");
return 1;
}
if (!inet_ntop(AF_INET6, &endpoint.addr6.sin6_addr, dstaddr, sizeof(dstaddr))) {
perror("inet_ntop");
return 1;
}
printf("if:%d src:%s dst:%s\n", endpoint.addr6.sin6_scope_id, srcaddr, dstaddr);
printf("Received a packet. Sleeping for 10 seconds before replying, so you have time to mess with your networking setup.\n");
sleep(10);
ret = magic_send6(sock, &endpoint, buffer, sizeof(buffer));
if (ret < 0) {
perror("magic_send6");
return 1;
}
close(sock);
return 0;
v4:
sock = magic_create_sock4(51820);
if (sock < 0) {
perror("magic_create_sock4");
return 1;
}
ret = magic_receive4(sock, &endpoint, buffer, sizeof(buffer));
if (ret < 0) {
perror("magic_receive4");
return 1;
}
if (!inet_ntop(AF_INET, &endpoint.src4, srcaddr, sizeof(srcaddr))) {
perror("inet_ntop");
return 1;
}
if (!inet_ntop(AF_INET, &endpoint.addr4.sin_addr, dstaddr, sizeof(dstaddr))) {
perror("inet_ntop");
return 1;
}
printf("if:%d src:%s dst:%s\n", endpoint.src_if4, srcaddr, dstaddr);
printf("Received a packet. Sleeping for 10 seconds before replying, so you have time to mess with your networking setup.\n");
sleep(10);
ret = magic_send4(sock, &endpoint, buffer, sizeof(buffer));
if (ret < 0) {
perror("magic_send4");
return 1;
}
close(sock);
return 0;
}
================================================
FILE: contrib/synergy/README
================================================
These scripts should be modified according to your precise setup.
They provide a very simple way of tunneling synergy inside of a
WireGuard tunnel, to protect your data in transit.
================================================
FILE: contrib/synergy/synergy-client.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
set -ex
if [[ $UID == 0 ]]; then
ip link del dev synergy || true
ip link add dev synergy type wireguard
ip address add 10.193.125.39/32 peer 10.193.125.38/32 dev synergy
wg set synergy \
listen-port 29184 \
private-key <(echo oNcsXA5Ma56q9xHmvvKuzLfwXYy7Uqy+bTmmXg/XtVs=) \
peer m321UMZXoJ6qw8Jli2spbAVBc2MdOzV/EHDKfZQy0g0= \
allowed-ips 10.193.125.38/32 \
endpoint 10.10.10.100:29184
ip link set up dev synergy
else
sudo "$(readlink -f "$0")"
killall synergyc || true
synergyc 10.193.125.38:38382
fi
================================================
FILE: contrib/synergy/synergy-server.sh
================================================
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
set -ex
if [[ $UID == 0 ]]; then
ip link del dev synergy || true
ip link add dev synergy type wireguard
ip address add 10.193.125.38/32 peer 10.193.125.39/32 dev synergy
wg set synergy \
listen-port 29184 \
private-key <(echo 2InSrlZA5eQfI/MvnvPieqNTBo9cd+udc3SOO9yFpXo=) \
peer CBnoidQLjlbRsrqrI56WQbANWwkll41w/rVUIW9zISI= \
allowed-ips 10.193.125.39/32
ip link set up dev synergy
else
sudo "$(readlink -f "$0")"
killall synergys || true
synergys -a 10.193.125.38:38382
fi
================================================
FILE: src/Makefile
================================================
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
PKG_CONFIG ?= pkg-config
PREFIX ?= /usr
DESTDIR ?=
SYSCONFDIR ?= /etc
BINDIR ?= $(PREFIX)/bin
LIBDIR ?= $(PREFIX)/lib
MANDIR ?= $(PREFIX)/share/man
BASHCOMPDIR ?= $(PREFIX)/share/bash-completion/completions
SYSTEMDUNITDIR ?= $(shell $(PKG_CONFIG) --variable=systemdsystemunitdir systemd 2>/dev/null || echo "$(PREFIX)/lib/systemd/system")
RUNSTATEDIR ?= /var/run
WITH_BASHCOMPLETION ?=
WITH_WGQUICK ?=
WITH_SYSTEMDUNITS ?=
ifeq ($(WITH_BASHCOMPLETION),)
ifneq ($(strip $(wildcard $(BASHCOMPDIR))),)
WITH_BASHCOMPLETION := yes
endif
endif
ifeq ($(WITH_WGQUICK),)
ifneq ($(strip $(wildcard $(BINDIR)/bash)),)
WITH_WGQUICK := yes
endif
ifneq ($(strip $(wildcard $(DESTDIR)/bin/bash)),)
WITH_WGQUICK := yes
endif
endif
ifeq ($(WITH_SYSTEMDUNITS),)
ifneq ($(strip $(wildcard $(SYSTEMDUNITDIR))),)
WITH_SYSTEMDUNITS := yes
endif
endif
PLATFORM ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
CFLAGS ?= -O3
ifneq ($(wildcard uapi/$(PLATFORM)/.),)
CFLAGS += -isystem uapi/$(PLATFORM)
endif
CFLAGS += -std=gnu99 -D_GNU_SOURCE
CFLAGS += -Wall -Wextra
CFLAGS += -MMD -MP
CFLAGS += -DRUNSTATEDIR="\"$(RUNSTATEDIR)\""
ifeq ($(DEBUG),yes)
CFLAGS += -g
endif
WIREGUARD_TOOLS_VERSION = $(patsubst v%,%,$(shell GIT_DIR="$(PWD)/../.git" git describe --dirty 2>/dev/null))
ifneq ($(WIREGUARD_TOOLS_VERSION),)
CFLAGS += -D'WIREGUARD_TOOLS_VERSION="$(WIREGUARD_TOOLS_VERSION)"'
endif
ifeq ($(PLATFORM),freebsd)
LDLIBS += -lnv
endif
ifeq ($(PLATFORM),haiku)
LDLIBS += -lnetwork -lbsd
endif
ifeq ($(PLATFORM),windows)
CC := x86_64-w64-mingw32-clang
WINDRES := $(shell $(CC) $(CFLAGS) -print-prog-name=windres 2>/dev/null)
CFLAGS += -Iwincompat/include -include wincompat/compat.h -DWINVER=0x0A00 -D_WIN32_WINNT=0x0A00 -flto
LDLIBS += -lws2_32 -lsetupapi -lole32 -ladvapi32 -lntdll -Lwincompat
LDFLAGS += -flto -Wl,--dynamicbase -Wl,--nxcompat -Wl,--tsaware -mconsole
LDFLAGS += -Wl,--major-os-version=10 -Wl,--minor-os-version=0 -Wl,--major-subsystem-version=10 -Wl,--minor-subsystem-version=0
# The use of -Wl,/delayload: here implies we're using llvm-mingw
LDFLAGS += -Wl,/delayload:ws2_32.dll -Wl,/delayload:setupapi.dll -Wl,/delayload:ole32.dll -Wl,/delayload:advapi32.dll
VERSION := $(patsubst "%",%,$(filter "%",$(file < version.h)))
wg: wincompat/libc.o wincompat/init.o wincompat/load_config.o wincompat/loader.o wincompat/resources.o
wincompat/resources.o: wincompat/resources.rc wincompat/manifest.xml
$(WINDRES) -DVERSION_STR=$(VERSION) -O coff -c 65001 -i $< -o $@
endif
ifneq ($(V),1)
BUILT_IN_LINK.o := $(LINK.o)
LINK.o = @echo " LD $@";
LINK.o += $(BUILT_IN_LINK.o)
BUILT_IN_COMPILE.c := $(COMPILE.c)
COMPILE.c = @echo " CC $@";
COMPILE.c += $(BUILT_IN_COMPILE.c)
BUILT_IN_RM := $(RM)
RM := @a() { echo " CLEAN $$@"; $(BUILT_IN_RM) "$$@"; }; a
WINDRES := @a() { echo " WINDRES $${@: -1}"; $(WINDRES) "$$@"; }; a
endif
wg: $(sort $(patsubst %.c,%.o,$(wildcard *.c)))
clean:
$(RM) wg *.o *.d $(wildcard wincompat/*.o wincompat/*.lib wincompat/*.dll)
install: wg
@install -v -d "$(DESTDIR)$(BINDIR)" && install -v -m 0755 wg "$(DESTDIR)$(BINDIR)/wg"
@install -v -d "$(DESTDIR)$(MANDIR)/man8" && install -v -m 0644 man/wg.8 "$(DESTDIR)$(MANDIR)/man8/wg.8"
@[ "$(WITH_BASHCOMPLETION)" = "yes" ] || exit 0; \
install -v -d "$(DESTDIR)$(BASHCOMPDIR)" && install -v -m 0644 completion/wg.bash-completion "$(DESTDIR)$(BASHCOMPDIR)/wg"
@[ "$(WITH_WGQUICK)" = "yes" ] || exit 0; \
install -v -m 0755 wg-quick/$(PLATFORM).bash "$(DESTDIR)$(BINDIR)/wg-quick" && install -v -m 0700 -d "$(DESTDIR)$(SYSCONFDIR)/wireguard"
@[ "$(WITH_WGQUICK)" = "yes" ] || exit 0; \
install -v -m 0644 man/wg-quick.8 "$(DESTDIR)$(MANDIR)/man8/wg-quick.8"
@[ "$(WITH_WGQUICK)" = "yes" -a "$(WITH_BASHCOMPLETION)" = "yes" ] || exit 0; \
install -v -m 0644 completion/wg-quick.bash-completion "$(DESTDIR)$(BASHCOMPDIR)/wg-quick"
@[ "$(WITH_WGQUICK)" = "yes" -a "$(WITH_SYSTEMDUNITS)" = "yes" ] || exit 0; \
install -v -d "$(DESTDIR)$(SYSTEMDUNITDIR)" && install -v -m 0644 systemd/* "$(DESTDIR)$(SYSTEMDUNITDIR)/"
check: clean
scan-build --html-title=wireguard-tools -maxloop 100 --view --keep-going $(MAKE) wg
all: wg
.DEFAULT_GOAL: all
.PHONY: clean install check
-include *.d
================================================
FILE: src/completion/wg-quick.bash-completion
================================================
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
_wg_quick_completion() {
local p i a search_paths old_glob
search_paths=( /etc/wireguard )
old_glob="$(shopt -p nullglob)"
shopt -s nullglob
[[ $OSTYPE == *freebsd* || $OSTYPE == *darwin* ]] && search_paths+=( /usr/local/etc/wireguard )
if [[ $COMP_CWORD -eq 1 ]]; then
COMPREPLY+=( $(compgen -W "up down" -- "${COMP_WORDS[1]}") )
elif [[ $COMP_CWORD -eq 2 ]]; then
if [[ ${COMP_WORDS[1]} == up ]]; then
for p in "${search_paths[@]}"; do
for i in "$p"/*.conf; do
i="${i##*/}"; i="${i%.conf}"
mapfile -t a < <(compgen -W "$i" -- "${COMP_WORDS[2]}")
COMPREPLY+=( "${a[@]}" )
done
done
mapfile -t a < <(compgen -f -X '!*.conf' -- "${COMP_WORDS[2]}")
COMPREPLY+=( "${a[@]}" )
mapfile -t a < <(compgen -d -- "${COMP_WORDS[2]}")
COMPREPLY+=( "${a[@]}" )
elif [[ ${COMP_WORDS[1]} == down ]]; then
if [[ $OSTYPE == *openbsd* || $OSTYPE == *darwin* ]]; then
for i in /var/run/wireguard/*.name; do
i="${i##*/}"; i="${i%.name}"
mapfile -t a < <(compgen -W "$i" -- "${COMP_WORDS[2]}")
COMPREPLY+=( "${a[@]}" )
done
else
COMPREPLY+=( $(compgen -W "$(wg show interfaces)" -- "${COMP_WORDS[2]}") )
fi
fi
fi
eval "$old_glob"
}
complete -o filenames -o nosort -F _wg_quick_completion wg-quick
================================================
FILE: src/completion/wg.bash-completion
================================================
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
_wg_completion() {
local a
if [[ $COMP_CWORD -eq 1 ]]; then
COMPREPLY+=( $(compgen -W "help show showconf set setconf addconf syncconf genkey genpsk pubkey" -- "${COMP_WORDS[1]}") )
return
fi
case "${COMP_WORDS[1]}" in
genkey|genpsk|pubkey|help) return; ;;
show|showconf|set|setconf|addconf|syncconf) ;;
*) return;
esac
if [[ $COMP_CWORD -eq 2 ]]; then
local extra
[[ ${COMP_WORDS[1]} == show ]] && extra=" all interfaces"
COMPREPLY+=( $(compgen -W "$(wg show interfaces 2>/dev/null)$extra" -- "${COMP_WORDS[2]}") )
return
fi
if [[ $COMP_CWORD -eq 3 && ${COMP_WORDS[1]} == show && ${COMP_WORDS[2]} != interfaces ]]; then
COMPREPLY+=( $(compgen -W "public-key private-key listen-port peers preshared-keys endpoints allowed-ips fwmark latest-handshakes persistent-keepalive transfer dump" -- "${COMP_WORDS[3]}") )
return
fi
if [[ $COMP_CWORD -eq 3 && ( ${COMP_WORDS[1]} == setconf || ${COMP_WORDS[1]} == addconf || ${COMP_WORDS[1]} == syncconf) ]]; then
compopt -o filenames
mapfile -t a < <(compgen -f -- "${COMP_WORDS[3]}")
COMPREPLY+=( "${a[@]}" )
return
fi
[[ ${COMP_WORDS[1]} == set ]] || return
local has_listen_port=0 has_fwmark=0 has_private_key=0 has_preshared_key=0 has_peer=0 has_remove=0 has_endpoint=0 has_persistent_keepalive=0 has_allowed_ips=0 words=() i j
for ((i=3;i<COMP_CWORD;i+=2)); do
[[ ${COMP_WORDS[i]} == listen-port ]] && has_listen_port=1
[[ ${COMP_WORDS[i]} == fwmark ]] && has_fwmark=1
[[ ${COMP_WORDS[i]} == private-key ]] && has_private_key=1
[[ ${COMP_WORDS[i]} == peer ]] && { has_peer=$i; break; }
done
if [[ $has_peer -eq 0 ]]; then
if ((COMP_CWORD % 2 != 0)); then
[[ $has_listen_port -eq 1 ]] || words+=( listen-port )
[[ $has_fwmark -eq 1 ]] || words+=( fwmark )
[[ $has_private_key -eq 1 ]] || words+=( private-key )
words+=( peer )
COMPREPLY+=( $(compgen -W "${words[*]}" -- "${COMP_WORDS[COMP_CWORD]}") )
elif [[ ${COMP_WORDS[COMP_CWORD-1]} == *-key ]]; then
compopt -o filenames
mapfile -t a < <(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")
COMPREPLY+=( "${a[@]}" )
fi
return
fi
if [[ ${COMP_WORDS[COMP_CWORD-1]} == peer ]]; then
COMPREPLY+=( $(compgen -W "$(wg show "${COMP_WORDS[2]}" peers 2>/dev/null)" -- "${COMP_WORDS[COMP_CWORD]}") )
return
fi
for ((i=has_peer;i<COMP_CWORD;i++)); do
j=i
if [[ ${COMP_WORDS[i]} == peer ]]; then
has_remove=0
has_endpoint=0
has_persistent_keepalive=0
has_allowed_ips=0
has_preshared_key=0
[[ ${COMP_WORDS[i+2]} == = ]] && ((i+=2)) || ((i++))
continue
fi
[[ ${COMP_WORDS[i]} == remove ]] && has_remove=1
[[ ${COMP_WORDS[i]} == endpoint ]] && has_endpoint=1
[[ ${COMP_WORDS[i]} == persistent-keepalive ]] && has_persistent_keepalive=1
[[ ${COMP_WORDS[i]} == allowed-ips ]] && has_allowed_ips=1
[[ ${COMP_WORDS[i]} == preshared-key ]] && has_preshared_key=1
[[ ${COMP_WORDS[i]} == remove ]] || ((i++))
done
((COMP_CWORD == j)) || return
if [[ $has_remove -ne 1 ]]; then
[[ $has_preshared_key -eq 1 ]] || words+=( preshared-key )
[[ $has_endpoint -eq 1 ]] || words+=( endpoint )
[[ $has_allowed_ips -eq 1 ]] || words+=( allowed-ips )
[[ $has_persistent_keepalive -eq 1 ]] || words+=( persistent-keepalive )
words+=( remove )
fi
words+=( peer )
COMPREPLY+=( $(compgen -W "${words[*]}" -- "${COMP_WORDS[COMP_CWORD]}") )
}
complete -o nosort -F _wg_completion wg
================================================
FILE: src/config.c
================================================
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <arpa/inet.h>
#include <limits.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <errno.h>
#include "config.h"
#include "containers.h"
#include "ipc.h"
#include "encoding.h"
#include "ctype.h"
#define COMMENT_CHAR '#'
static const char *get_value(const char *line, const char *key)
{
size_t linelen = strlen(line);
size_t keylen = strlen(key);
if (keylen >= linelen)
return NULL;
if (strncasecmp(line, key, keylen))
return NULL;
return line + keylen;
}
static inline bool parse_port(uint16_t *port, uint32_t *flags, const char *value)
{
int ret;
struct addrinfo *resolved;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP,
.ai_flags = AI_PASSIVE
};
if (!strlen(value)) {
fprintf(stderr, "Unable to parse empty port\n");
return false;
}
ret = getaddrinfo(NULL, value, &hints, &resolved);
if (ret) {
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value);
return false;
}
ret = -1;
if (resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) {
*port = ntohs(((struct sockaddr_in *)resolved->ai_addr)->sin_port);
ret = 0;
} else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)) {
*port = ntohs(((struct sockaddr_in6 *)resolved->ai_addr)->sin6_port);
ret = 0;
} else
fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s'\n", value);
freeaddrinfo(resolved);
if (!ret)
*flags |= WGDEVICE_HAS_LISTEN_PORT;
return ret == 0;
}
static inline bool parse_fwmark(uint32_t *fwmark, uint32_t *flags, const char *value)
{
unsigned long ret;
char *end;
int base = 10;
if (!strcasecmp(value, "off")) {
*fwmark = 0;
*flags |= WGDEVICE_HAS_FWMARK;
return true;
}
if (!char_is_digit(value[0]))
goto err;
if (strlen(value) > 2 && value[0] == '0' && value[1] == 'x')
base = 16;
ret = strtoul(value, &end, base);
if (*end || ret > UINT32_MAX)
goto err;
*fwmark = ret;
*flags |= WGDEVICE_HAS_FWMARK;
return true;
err:
fprintf(stderr, "Fwmark is neither 0/off nor 0-0xffffffff: `%s'\n", value);
return false;
}
static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
{
if (!key_from_base64(key, value)) {
fprintf(stderr, "Key is not the correct length or format: `%s'\n", value);
memset(key, 0, WG_KEY_LEN);
return false;
}
return true;
}
static bool parse_keyfile(uint8_t key[static WG_KEY_LEN], const char *path)
{
FILE *f;
int c;
char dst[WG_KEY_LEN_BASE64];
bool ret = false;
f = fopen(path, "r");
if (!f) {
perror("fopen");
return false;
}
if (fread(dst, WG_KEY_LEN_BASE64 - 1, 1, f) != 1) {
/* If we're at the end and we didn't read anything, we're /dev/null or an empty file. */
if (!ferror(f) && feof(f) && !ftell(f)) {
memset(key, 0, WG_KEY_LEN);
ret = true;
goto out;
}
fprintf(stderr, "Invalid length key in key file\n");
goto out;
}
dst[WG_KEY_LEN_BASE64 - 1] = '\0';
while ((c = getc(f)) != EOF) {
if (!char_is_space(c)) {
fprintf(stderr, "Found trailing character in key file: `%c'\n", c);
goto out;
}
}
if (ferror(f) && errno) {
perror("getc");
goto out;
}
ret = parse_key(key, dst);
out:
fclose(f);
return ret;
}
static inline bool parse_ip(struct wgallowedip *allowedip, const char *value)
{
allowedip->family = AF_UNSPEC;
if (strchr(value, ':')) {
if (inet_pton(AF_INET6, value, &allowedip->ip6) == 1)
allowedip->family = AF_INET6;
} else {
if (inet_pton(AF_INET, value, &allowedip->ip4) == 1)
allowedip->family = AF_INET;
}
if (allowedip->family == AF_UNSPEC) {
fprintf(stderr, "Unable to parse IP address: `%s'\n", value);
return false;
}
return true;
}
static inline int parse_dns_retries(void)
{
unsigned long ret;
char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end;
if (!retries)
return 15;
if (!strcmp(retries, "infinity"))
return -1;
ret = strtoul(retries, &end, 10);
if (*end || ret > INT_MAX) {
fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries);
exit(1);
}
return (int)ret;
}
static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value)
{
char *mutable = strdup(value);
char *begin, *end;
int ret, retries = parse_dns_retries();
struct addrinfo *resolved;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_protocol = IPPROTO_UDP
};
if (!mutable) {
perror("strdup");
return false;
}
if (!strlen(value)) {
free(mutable);
fprintf(stderr, "Unable to parse empty endpoint\n");
return false;
}
if (mutable[0] == '[') {
begin = &mutable[1];
end = strchr(mutable, ']');
if (!end) {
free(mutable);
fprintf(stderr, "Unable to find matching brace of endpoint: `%s'\n", value);
return false;
}
*end++ = '\0';
if (*end++ != ':' || !*end) {
free(mutable);
fprintf(stderr, "Unable to find port of endpoint: `%s'\n", value);
return false;
}
} else {
begin = mutable;
end = strrchr(mutable, ':');
if (!end || !*(end + 1)) {
free(mutable);
fprintf(stderr, "Unable to find port of endpoint: `%s'\n", value);
return false;
}
*end++ = '\0';
}
#define min(a, b) ((a) < (b) ? (a) : (b))
for (unsigned int timeout = 1000000;; timeout = min(20000000, timeout * 6 / 5)) {
ret = getaddrinfo(begin, end, &hints, &resolved);
if (!ret)
break;
/* The set of return codes that are "permanent failures". All other possibilities are potentially transient.
*
* This is according to https://sourceware.org/glibc/wiki/NameResolver which states:
* "From the perspective of the application that calls getaddrinfo() it perhaps
* doesn't matter that much since EAI_FAIL, EAI_NONAME and EAI_NODATA are all
* permanent failure codes and the causes are all permanent failures in the
* sense that there is no point in retrying later."
*
* So this is what we do, except FreeBSD removed EAI_NODATA some time ago, so that's conditional.
*/
if (ret == EAI_NONAME || ret == EAI_FAIL ||
#ifdef EAI_NODATA
ret == EAI_NODATA ||
#endif
(retries >= 0 && !retries--)) {
free(mutable);
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value);
return false;
}
fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value, timeout / 1000000.0);
usleep(timeout);
}
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
(resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
memcpy(endpoint, resolved->ai_addr, resolved->ai_addrlen);
else {
freeaddrinfo(resolved);
free(mutable);
fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s'\n", value);
return false;
}
freeaddrinfo(resolved);
free(mutable);
return true;
}
static inline bool parse_persistent_keepalive(uint16_t *interval, uint32_t *flags, const char *value)
{
unsigned long ret;
char *end;
if (!strcasecmp(value, "off")) {
*interval = 0;
*flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
return true;
}
if (!char_is_digit(value[0]))
goto err;
ret = strtoul(value, &end, 10);
if (*end || ret > 65535)
goto err;
*interval = (uint16_t)ret;
*flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
return true;
err:
fprintf(stderr, "Persistent keepalive interval is neither 0/off nor 1-65535: `%s'\n", value);
return false;
}
static bool validate_netmask(struct wgallowedip *allowedip)
{
uint32_t *ip;
int last;
switch (allowedip->family) {
case AF_INET:
last = 0;
ip = (uint32_t *)&allowedip->ip4;
break;
case AF_INET6:
last = 3;
ip = (uint32_t *)&allowedip->ip6;
break;
default:
return true; /* We don't know how to validate it, so say 'okay'. */
}
for (int i = last; i >= 0; --i) {
uint32_t mask = ~0;
if (allowedip->cidr >= 32 * (i + 1))
break;
if (allowedip->cidr > 32 * i)
mask >>= (allowedip->cidr - 32 * i);
if (ntohl(ip[i]) & mask)
return false;
}
return true;
}
static inline void parse_ip_prefix(struct wgpeer *peer, uint32_t *flags, char **mask)
{
/* If the IP is prefixed with either '+' or '-' consider this an
* incremental change. Disable WGPEER_REPLACE_ALLOWEDIPS. */
switch ((*mask)[0]) {
case '-':
*flags |= WGALLOWEDIP_REMOVE_ME;
/* fall through */
case '+':
peer->flags &= ~WGPEER_REPLACE_ALLOWEDIPS;
++(*mask);
}
}
static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **last_allowedip, const char *value)
{
struct wgallowedip *allowedip = *last_allowedip, *new_allowedip;
char *mask, *mutable = strdup(value), *sep, *saved_entry;
if (!mutable) {
perror("strdup");
return false;
}
peer->flags |= WGPEER_REPLACE_ALLOWEDIPS;
if (!strlen(value)) {
free(mutable);
return true;
}
sep = mutable;
while ((mask = strsep(&sep, ","))) {
uint32_t flags = 0;
unsigned long cidr;
char *end, *ip;
parse_ip_prefix(peer, &flags, &mask);
saved_entry = strdup(mask);
if (!saved_entry) {
perror("strdup");
free(mutable);
return false;
}
ip = strsep(&mask, "/");
new_allowedip = calloc(1, sizeof(*new_allowedip));
if (!new_allowedip) {
perror("calloc");
free(saved_entry);
free(mutable);
return false;
}
if (!parse_ip(new_allowedip, ip)) {
free(new_allowedip);
free(saved_entry);
free(mutable);
return false;
}
if (mask) {
if (!char_is_digit(mask[0]))
goto err;
cidr = strtoul(mask, &end, 10);
if (*end || (cidr > 32 && new_allowedip->family == AF_INET) || (cidr > 128 && new_allowedip->family == AF_INET6))
goto err;
} else if (new_allowedip->family == AF_INET)
cidr = 32;
else if (new_allowedip->family == AF_INET6)
cidr = 128;
else
goto err;
new_allowedip->cidr = cidr;
new_allowedip->flags = flags;
if (!validate_netmask(new_allowedip))
fprintf(stderr, "Warning: AllowedIP has nonzero host part: %s/%s\n", ip, mask);
if (allowedip)
allowedip->next_allowedip = new_allowedip;
else
peer->first_allowedip = new_allowedip;
allowedip = new_allowedip;
free(saved_entry);
}
free(mutable);
*last_allowedip = allowedip;
return true;
err:
free(new_allowedip);
free(mutable);
fprintf(stderr, "AllowedIP is not in the correct format: `%s'\n", saved_entry);
free(saved_entry);
return false;
}
static bool process_line(struct config_ctx *ctx, const char *line)
{
const char *value;
bool ret = true;
if (!strcasecmp(line, "[Interface]")) {
ctx->is_peer_section = false;
ctx->is_device_section = true;
return true;
}
if (!strcasecmp(line, "[Peer]")) {
struct wgpeer *new_peer = calloc(1, sizeof(struct wgpeer));
if (!new_peer) {
perror("calloc");
return false;
}
ctx->last_allowedip = NULL;
if (ctx->last_peer)
ctx->last_peer->next_peer = new_peer;
else
ctx->device->first_peer = new_peer;
ctx->last_peer = new_peer;
ctx->is_peer_section = true;
ctx->is_device_section = false;
ctx->last_peer->flags |= WGPEER_REPLACE_ALLOWEDIPS;
return true;
}
#define key_match(key) (value = get_value(line, key "="))
if (ctx->is_device_section) {
if (key_match("ListenPort"))
ret = parse_port(&ctx->device->listen_port, &ctx->device->flags, value);
else if (key_match("FwMark"))
ret = parse_fwmark(&ctx->device->fwmark, &ctx->device->flags, value);
else if (key_match("PrivateKey")) {
ret = parse_key(ctx->device->private_key, value);
if (ret)
ctx->device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
} else
goto error;
} else if (ctx->is_peer_section) {
if (key_match("Endpoint"))
ret = parse_endpoint(&ctx->last_peer->endpoint.addr, value);
else if (key_match("PublicKey")) {
ret = parse_key(ctx->last_peer->public_key, value);
if (ret)
ctx->last_peer->flags |= WGPEER_HAS_PUBLIC_KEY;
} else if (key_match("AllowedIPs"))
ret = parse_allowedips(ctx->last_peer, &ctx->last_allowedip, value);
else if (key_match("PersistentKeepalive"))
ret = parse_persistent_keepalive(&ctx->last_peer->persistent_keepalive_interval, &ctx->last_peer->flags, value);
else if (key_match("PresharedKey")) {
ret = parse_key(ctx->last_peer->preshared_key, value);
if (ret)
ctx->last_peer->flags |= WGPEER_HAS_PRESHARED_KEY;
} else
goto error;
} else
goto error;
return ret;
#undef key_match
error:
fprintf(stderr, "Line unrecognized: `%s'\n", line);
return false;
}
bool config_read_line(struct config_ctx *ctx, const char *input)
{
size_t len, cleaned_len = 0;
const char *comment;
bool ret = true;
char *line;
/* This is what strchrnul is for, but that isn't portable. */
comment = strchr(input, COMMENT_CHAR);
if (comment)
len = comment - input;
else
len = strlen(input);
line = calloc(len + 1, sizeof(char));
if (!line) {
perror("calloc");
ret = false;
goto out;
}
for (size_t i = 0; i < len; ++i) {
if (!char_is_space(input[i]))
line[cleaned_len++] = input[i];
}
if (!cleaned_len)
goto out;
ret = process_line(ctx, line);
out:
free(line);
if (!ret)
free_wgdevice(ctx->device);
return ret;
}
bool config_read_init(struct config_ctx *ctx, bool append)
{
memset(ctx, 0, sizeof(*ctx));
ctx->device = calloc(1, sizeof(*ctx->device));
if (!ctx->device) {
perror("calloc");
return false;
}
if (!append)
ctx->device->flags |= WGDEVICE_REPLACE_PEERS | WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_FWMARK | WGDEVICE_HAS_LISTEN_PORT;
return true;
}
struct wgdevice *config_read_finish(struct config_ctx *ctx)
{
struct wgpeer *peer;
for_each_wgpeer(ctx->device, peer) {
if (!(peer->flags & WGPEER_HAS_PUBLIC_KEY)) {
fprintf(stderr, "A peer is missing a public key\n");
goto err;
}
}
return ctx->device;
err:
free_wgdevice(ctx->device);
return NULL;
}
static char *strip_spaces(const char *in)
{
char *out;
size_t t, l, i;
t = strlen(in);
out = calloc(t + 1, sizeof(char));
if (!out) {
perror("calloc");
return NULL;
}
for (i = 0, l = 0; i < t; ++i) {
if (!char_is_space(in[i]))
out[l++] = in[i];
}
return out;
}
struct wgdevice *config_read_cmd(const char *argv[], int argc)
{
struct wgdevice *device = calloc(1, sizeof(*device));
struct wgpeer *peer = NULL;
struct wgallowedip *allowedip = NULL;
if (!device) {
perror("calloc");
return false;
}
while (argc > 0) {
if (!strcmp(argv[0], "listen-port") && argc >= 2 && !peer) {
if (!parse_port(&device->listen_port, &device->flags, argv[1]))
goto error;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "fwmark") && argc >= 2 && !peer) {
if (!parse_fwmark(&device->fwmark, &device->flags, argv[1]))
goto error;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "private-key") && argc >= 2 && !peer) {
if (!parse_keyfile(device->private_key, argv[1]))
goto error;
device->flags |= WGDEVICE_HAS_PRIVATE_KEY;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "peer") && argc >= 2) {
struct wgpeer *new_peer = calloc(1, sizeof(*new_peer));
allowedip = NULL;
if (!new_peer) {
perror("calloc");
goto error;
}
if (peer)
peer->next_peer = new_peer;
else
device->first_peer = new_peer;
peer = new_peer;
if (!parse_key(peer->public_key, argv[1]))
goto error;
peer->flags |= WGPEER_HAS_PUBLIC_KEY;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "remove") && argc >= 1 && peer) {
peer->flags |= WGPEER_REMOVE_ME;
argv += 1;
argc -= 1;
} else if (!strcmp(argv[0], "endpoint") && argc >= 2 && peer) {
if (!parse_endpoint(&peer->endpoint.addr, argv[1]))
goto error;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "allowed-ips") && argc >= 2 && peer) {
char *line = strip_spaces(argv[1]);
if (!line)
goto error;
if (!parse_allowedips(peer, &allowedip, line)) {
free(line);
goto error;
}
free(line);
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "persistent-keepalive") && argc >= 2 && peer) {
if (!parse_persistent_keepalive(&peer->persistent_keepalive_interval, &peer->flags, argv[1]))
goto error;
argv += 2;
argc -= 2;
} else if (!strcmp(argv[0], "preshared-key") && argc >= 2 && peer) {
if (!parse_keyfile(peer->preshared_key, argv[1]))
goto error;
peer->flags |= WGPEER_HAS_PRESHARED_KEY;
argv += 2;
argc -= 2;
} else {
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
goto error;
}
}
return device;
error:
free_wgdevice(device);
return false;
}
================================================
FILE: src/config.h
================================================
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <stdbool.h>
struct wgdevice;
struct wgpeer;
struct wgallowedip;
struct config_ctx {
struct wgdevice *device;
struct wgpeer *last_peer;
struct wgallowedip *last_allowedip;
bool is_peer_section, is_device_section;
};
struct wgdevice *config_read_cmd(const char *argv[], int argc);
bool config_read_init(struct config_ctx *ctx, bool append);
bool config_read_line(struct config_ctx *ctx, const char *line);
struct wgdevice *config_read_finish(struct config_ctx *ctx);
#endif
================================================
FILE: src/containers.h
================================================
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#ifndef CONTAINERS_H
#define CONTAINERS_H
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#if defined(__linux__)
#include <linux/wireguard.h>
#elif defined(__OpenBSD__)
#include <net/if_wg.h>
#endif
#ifndef WG_KEY_LEN
#define WG_KEY_LEN 32
#endif
/* Cross platform __kernel_timespec */
struct timespec64 {
int64_t tv_sec;
int64_t tv_nsec;
};
enum {
WGALLOWEDIP_REMOVE_ME = 1U << 0,
};
struct wgallowedip {
uint16_t family;
union {
struct in_addr ip4;
struct in6_addr ip6;
};
uint8_t cidr;
uint32_t flags;
struct wgallowedip *next_allowedip;
};
enum {
WGPEER_REMOVE_ME = 1U << 0,
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
WGPEER_HAS_PRESHARED_KEY = 1U << 3,
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
};
struct wgpeer {
uint32_t flags;
uint8_t public_key[WG_KEY_LEN];
uint8_t preshared_key[WG_KEY_LEN];
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} endpoint;
struct timespec64 last_handshake_time;
uint64_t rx_bytes, tx_bytes;
uint16_t persistent_keepalive_interval;
struct wgallowedip *first_allowedip, *last_allowedip;
struct wgpeer *next_peer;
};
enum {
WGDEVICE_REPLACE_PEERS = 1U << 0,
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
WGDEVICE_HAS_FWMARK = 1U << 4
};
struct wgdevice {
char name[IFNAMSIZ];
uint32_t ifindex;
uint32_t flags;
uint8_t public_key[WG_KEY_LEN];
uint8_t private_key[WG_KEY_LEN];
uint32_t fwmark;
uint16_t listen_port;
struct wgpeer *first_peer, *last_peer;
};
#define for_each_wgpeer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
#define for_each_wgallowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
static inline void free_wgdevice(struct wgdevice *dev)
{
if (!dev)
return;
for (struct wgpeer *peer = dev->first_peer, *np = peer ? peer->next_peer : NULL; peer; peer = np, np = peer ? peer->next_peer : NULL) {
for (struct wgallowedip *allowedip = peer->first_allowedip, *na = allowedip ? allowedip->next_allowedip : NULL; allowedip; allowedip = na, na = allowedip ? allowedip->next_allowedip : NULL)
free(allowedip);
free(peer);
}
free(dev);
}
#endif
================================================
FILE: src/ctype.h
================================================
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* Specialized constant-time ctype.h reimplementations that aren't locale-specific.
*/
#ifndef CTYPE_H
#define CTYPE_H
#include <stdbool.h>
static inline bool char_is_space(int c)
{
unsigned char d = c - 9;
return (0x80001FU >> (d & 31)) & (1U >> (d >> 5));
}
static inline bool char_is_digit(int c)
{
return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1);
}
static inline bool char_is_alpha(int c)
{
return (unsigned int)(('a' - 1 - (c | 32)) & ((c | 32) - ('z' + 1))) >> (sizeof(c) * 8 - 1);
}
#endif
================================================
FILE: src/curve25519-fiat32.h
================================================
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Copyright (C) 2015-2016 The fiat-crypto Authors.
* Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
* This is a machine-generated formally verified implementation of Curve25519
* ECDH from: <https://github.com/mit-plv/fiat-crypto>. Though originally
* machine generated, it has been tweaked to be suitable for use in the kernel.
* It is optimized for 32-bit machines and machines that cannot work efficiently
* with 128-bit integer types.
*/
/* fe means field element. Here the field is \Z/(2^255-19). An element t,
* entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
* t[3]+2^102 t[4]+...+2^230 t[9].
* fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc.
* Multiplication and carrying produce fe from fe_loose.
*/
typedef struct fe { u32 v[10]; } fe;
/* fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc
* Addition and subtraction produce fe_loose from (fe, fe).
*/
typedef struct fe_loose { u32 v[10]; } fe_loose;
static __always_inline void fe_frombytes_impl(u32 h[10], const u8 *s)
{
/* Ignores top bit of s. */
u32 a0 = get_unaligned_le32(s);
u32 a1 = get_unaligned_le32(s+4);
u32 a2 = get_unaligned_le32(s+8);
u32 a3 = get_unaligned_le32(s+12);
u32 a4 = get_unaligned_le32(s+16);
u32 a5 = get_unaligned_le32(s+20);
u32 a6 = get_unaligned_le32(s+24);
u32 a7 = get_unaligned_le32(s+28);
h[0] = a0&((1<<26)-1); /* 26 used, 32-26 left. 26 */
h[1] = (a0>>26) | ((a1&((1<<19)-1))<< 6); /* (32-26) + 19 = 6+19 = 25 */
h[2] = (a1>>19) | ((a2&((1<<13)-1))<<13); /* (32-19) + 13 = 13+13 = 26 */
h[3] = (a2>>13) | ((a3&((1<< 6)-1))<<19); /* (32-13) + 6 = 19+ 6 = 25 */
h[4] = (a3>> 6); /* (32- 6) = 26 */
h[5] = a4&((1<<25)-1); /* 25 */
h[6] = (a4>>25) | ((a5&((1<<19)-1))<< 7); /* (32-25) + 19 = 7+19 = 26 */
h[7] = (a5>>19) | ((a6&((1<<12)-1))<<13); /* (32-19) + 12 = 13+12 = 25 */
h[8] = (a6>>12) | ((a7&((1<< 6)-1))<<20); /* (32-12) + 6 = 20+ 6 = 26 */
h[9] = (a7>> 6)&((1<<25)-1); /* 25 */
}
static __always_inline void fe_frombytes(fe *h, const u8 *s)
{
fe_frombytes_impl(h->v, s);
}
static __always_inline u8 /*bool*/
addcarryx_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
{
/* This function extracts 25 bits of result and 1 bit of carry
* (26 total), so a 32-bit intermediate is sufficient.
*/
u32 x = a + b + c;
*low = x & ((1 << 25) - 1);
return (x >> 25) & 1;
}
static __always_inline u8 /*bool*/
addcarryx_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
{
/* This function extracts 26 bits of result and 1 bit of carry
* (27 total), so a 32-bit intermediate is sufficient.
*/
u32 x = a + b + c;
*low = x & ((1 << 26) - 1);
return (x >> 26) & 1;
}
static __always_inline u8 /*bool*/
subborrow_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
{
/* This function extracts 25 bits of result and 1 bit of borrow
* (26 total), so a 32-bit intermediate is sufficient.
*/
u32 x = a - b - c;
*low = x & ((1 << 25) - 1);
return x >> 31;
}
static __always_inline u8 /*bool*/
subborrow_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
{
/* This function extracts 26 bits of result and 1 bit of borrow
*(27 total), so a 32-bit intermediate is sufficient.
*/
u32 x = a - b - c;
*low = x & ((1 << 26) - 1);
return x >> 31;
}
static __always_inline u32 cmovznz32(u32 t, u32 z, u32 nz)
{
t = -!!t; /* all set if nonzero, 0 if 0 */
return (t&nz) | ((~t)&z);
}
static __always_inline void fe_freeze(u32 out[10], const u32 in1[10])
{
{ const u32 x17 = in1[9];
{ const u32 x18 = in1[8];
{ const u32 x16 = in1[7];
{ const u32 x14 = in1[6];
{ const u32 x12 = in1[5];
{ const u32 x10 = in1[4];
{ const u32 x8 = in1[3];
{ const u32 x6 = in1[2];
{ const u32 x4 = in1[1];
{ const u32 x2 = in1[0];
{ u32 x20; u8/*bool*/ x21 = subborrow_u26(0x0, x2, 0x3ffffed, &x20);
{ u32 x23; u8/*bool*/ x24 = subborrow_u25(x21, x4, 0x1ffffff, &x23);
{ u32 x26; u8/*bool*/ x27 = subborrow_u26(x24, x6, 0x3ffffff, &x26);
{ u32 x29; u8/*bool*/ x30 = subborrow_u25(x27, x8, 0x1ffffff, &x29);
{ u32 x32; u8/*bool*/ x33 = subborrow_u26(x30, x10, 0x3ffffff, &x32);
{ u32 x35; u8/*bool*/ x36 = subborrow_u25(x33, x12, 0x1ffffff, &x35);
{ u3
gitextract_oz15ttsd/
├── .gitattributes
├── .gitignore
├── COPYING
├── README.md
├── contrib/
│ ├── dns-hatchet/
│ │ ├── README
│ │ ├── apply.sh
│ │ └── hatchet.bash
│ ├── embeddable-wg-library/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README
│ │ ├── test.c
│ │ ├── wireguard.c
│ │ └── wireguard.h
│ ├── external-tests/
│ │ ├── haskell/
│ │ │ ├── Setup.hs
│ │ │ ├── package.yaml
│ │ │ ├── src/
│ │ │ │ ├── Data/
│ │ │ │ │ └── Time/
│ │ │ │ │ └── TAI64.hs
│ │ │ │ └── Main.hs
│ │ │ └── stack.yaml
│ │ ├── python/
│ │ │ └── main.py
│ │ └── rust/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── extract-handshakes/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README
│ │ ├── extract-handshakes.sh
│ │ └── offset-finder.c
│ ├── highlighter/
│ │ ├── Makefile
│ │ ├── README
│ │ ├── fuzz.c
│ │ ├── gui/
│ │ │ ├── highlight.cpp
│ │ │ └── highlight.pro
│ │ ├── highlight.c
│ │ ├── highlighter.c
│ │ └── highlighter.h
│ ├── json/
│ │ ├── README
│ │ └── wg-json
│ ├── keygen-html/
│ │ ├── .gitignore
│ │ ├── README
│ │ ├── keygen.html
│ │ └── wireguard.js
│ ├── launchd/
│ │ ├── README
│ │ └── com.wireguard.wg0.plist
│ ├── nat-hole-punching/
│ │ ├── README
│ │ ├── nat-punch-client.c
│ │ └── nat-punch-server.c
│ ├── ncat-client-server/
│ │ ├── README
│ │ ├── client-quick.sh
│ │ ├── client.sh
│ │ └── server.sh
│ ├── reresolve-dns/
│ │ ├── README
│ │ └── reresolve-dns.sh
│ ├── sticky-sockets/
│ │ ├── README
│ │ └── sticky-sockets.c
│ └── synergy/
│ ├── README
│ ├── synergy-client.sh
│ └── synergy-server.sh
└── src/
├── Makefile
├── completion/
│ ├── wg-quick.bash-completion
│ └── wg.bash-completion
├── config.c
├── config.h
├── containers.h
├── ctype.h
├── curve25519-fiat32.h
├── curve25519-hacl64.h
├── curve25519.c
├── curve25519.h
├── encoding.c
├── encoding.h
├── fuzz/
│ ├── .gitignore
│ ├── Makefile
│ ├── cmd.c
│ ├── config.c
│ ├── set.c
│ ├── setconf.c
│ ├── stringlist.c
│ └── uapi.c
├── genkey.c
├── ipc-freebsd.h
├── ipc-linux.h
├── ipc-openbsd.h
├── ipc-uapi-unix.h
├── ipc-uapi-windows.h
├── ipc-uapi.h
├── ipc-windows.h
├── ipc.c
├── ipc.h
├── man/
│ ├── wg-quick.8
│ └── wg.8
├── netlink.h
├── pubkey.c
├── set.c
├── setconf.c
├── show.c
├── showconf.c
├── subcommands.h
├── systemd/
│ ├── wg-quick.target
│ └── wg-quick@.service
├── terminal.c
├── terminal.h
├── uapi/
│ ├── freebsd/
│ │ └── dev/
│ │ └── wg/
│ │ └── if_wg.h
│ ├── linux/
│ │ └── linux/
│ │ └── wireguard.h
│ ├── openbsd/
│ │ └── net/
│ │ └── if_wg.h
│ └── windows/
│ └── wireguard.h
├── version.h
├── wg-quick/
│ ├── android.c
│ ├── darwin.bash
│ ├── freebsd.bash
│ ├── linux.bash
│ └── openbsd.bash
├── wg.c
└── wincompat/
├── compat.h
├── include/
│ ├── arpa/
│ │ └── inet.h
│ ├── hashtable.h
│ ├── net/
│ │ └── if.h
│ ├── netdb.h
│ ├── netinet/
│ │ └── in.h
│ └── sys/
│ └── socket.h
├── init.c
├── libc.c
├── load_config.c
├── loader.c
├── manifest.xml
└── resources.rc
SYMBOL INDEX (619 symbols across 56 files)
FILE: contrib/embeddable-wg-library/test.c
function list_devices (line 11) | void list_devices(void)
function main (line 44) | int main(int argc, char *argv[])
FILE: contrib/embeddable-wg-library/wireguard.c
type wg_cmd (line 32) | enum wg_cmd {
type wgdevice_flag (line 38) | enum wgdevice_flag {
type wgdevice_attribute (line 41) | enum wgdevice_attribute {
type wgpeer_flag (line 54) | enum wgpeer_flag {
type wgpeer_attribute (line 58) | enum wgpeer_attribute {
type wgallowedip_attribute (line 73) | enum wgallowedip_attribute {
type mnl_attr_data_type (line 89) | enum mnl_attr_data_type {
type nlattr (line 124) | struct nlattr
type nlmsghdr (line 125) | struct nlmsghdr
function mnl_ideal_socket_buffer_size (line 131) | static size_t mnl_ideal_socket_buffer_size(void)
function mnl_nlmsg_size (line 143) | static size_t mnl_nlmsg_size(size_t len)
type nlmsghdr (line 148) | struct nlmsghdr
type nlmsghdr (line 150) | struct nlmsghdr
type nlmsghdr (line 151) | struct nlmsghdr
type nlmsghdr (line 158) | struct nlmsghdr
type nlmsghdr (line 167) | struct nlmsghdr
type nlmsghdr (line 172) | struct nlmsghdr
function mnl_nlmsg_ok (line 177) | static bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
type nlmsghdr (line 184) | struct nlmsghdr
type nlmsghdr (line 184) | struct nlmsghdr
type nlmsghdr (line 187) | struct nlmsghdr
type nlmsghdr (line 190) | struct nlmsghdr
function mnl_nlmsg_seq_ok (line 195) | static bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
function mnl_nlmsg_portid_ok (line 200) | static bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int...
function mnl_attr_get_type (line 205) | static uint16_t mnl_attr_get_type(const struct nlattr *attr)
function mnl_attr_get_payload_len (line 210) | static uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
type nlattr (line 215) | struct nlattr
function mnl_attr_ok (line 220) | static bool mnl_attr_ok(const struct nlattr *attr, int len)
type nlattr (line 227) | struct nlattr
type nlattr (line 227) | struct nlattr
type nlattr (line 229) | struct nlattr
function mnl_attr_type_valid (line 232) | static int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
function __mnl_attr_validate (line 241) | static int __mnl_attr_validate(const struct nlattr *attr,
function mnl_attr_validate (line 303) | static int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_da...
function mnl_attr_parse (line 315) | static int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
function mnl_attr_parse_nested (line 327) | static int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_c...
function mnl_attr_get_u8 (line 339) | static uint8_t mnl_attr_get_u8(const struct nlattr *attr)
function mnl_attr_get_u16 (line 344) | static uint16_t mnl_attr_get_u16(const struct nlattr *attr)
function mnl_attr_get_u32 (line 349) | static uint32_t mnl_attr_get_u32(const struct nlattr *attr)
function mnl_attr_get_u64 (line 354) | static uint64_t mnl_attr_get_u64(const struct nlattr *attr)
type nlattr (line 361) | struct nlattr
function mnl_attr_put (line 366) | static void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len,
function mnl_attr_put_u16 (line 382) | static void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16...
function mnl_attr_put_u32 (line 387) | static void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32...
function mnl_attr_put_strz (line 392) | static void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const...
type nlattr (line 397) | struct nlattr
type nlmsghdr (line 397) | struct nlmsghdr
type nlattr (line 399) | struct nlattr
type nlattr (line 402) | struct nlattr
function mnl_attr_put_check (line 406) | static bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
function mnl_attr_put_u8_check (line 415) | static bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
function mnl_attr_put_u16_check (line 421) | static bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
function mnl_attr_put_u32_check (line 427) | static bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
type nlattr (line 433) | struct nlattr
type nlmsghdr (line 433) | struct nlmsghdr
function mnl_attr_nest_end (line 441) | static void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
function mnl_attr_nest_cancel (line 446) | static void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *st...
function mnl_cb_noop (line 451) | static int mnl_cb_noop(__attribute__((unused)) const struct nlmsghdr *nl...
function mnl_cb_error (line 456) | static int mnl_cb_error(const struct nlmsghdr *nlh, __attribute__((unuse...
function mnl_cb_stop (line 473) | static int mnl_cb_stop(__attribute__((unused)) const struct nlmsghdr *nl...
function __mnl_cb_run (line 485) | static int __mnl_cb_run(const void *buf, size_t numbytes,
function mnl_cb_run2 (line 534) | static int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
function mnl_cb_run (line 542) | static int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
type mnl_socket (line 548) | struct mnl_socket {
function mnl_socket_get_portid (line 553) | static unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
type mnl_socket (line 558) | struct mnl_socket
type mnl_socket (line 560) | struct mnl_socket
type mnl_socket (line 562) | struct mnl_socket
type mnl_socket (line 575) | struct mnl_socket
function mnl_socket_bind (line 580) | static int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, p...
function mnl_socket_sendto (line 609) | static ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void...
function mnl_socket_recvfrom (line 619) | static ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf,
function mnl_socket_close (line 652) | static int mnl_socket_close(struct mnl_socket *nl)
type mnlg_socket (line 661) | struct mnlg_socket {
type nlmsghdr (line 670) | struct nlmsghdr
type mnlg_socket (line 670) | struct mnlg_socket
type nlmsghdr (line 674) | struct nlmsghdr
type genlmsghdr (line 675) | struct genlmsghdr
type genlmsghdr (line 683) | struct genlmsghdr
type nlmsghdr (line 690) | struct nlmsghdr
type mnlg_socket (line 690) | struct mnlg_socket
function mnlg_socket_send (line 696) | static int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsgh...
function mnlg_cb_noop (line 701) | static int mnlg_cb_noop(const struct nlmsghdr *nlh, void *data)
function mnlg_cb_error (line 708) | static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data)
function mnlg_cb_stop (line 726) | static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data)
function mnlg_socket_recv_run (line 749) | static int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_c...
function get_family_id_attr_cb (line 765) | static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
function get_family_id_cb (line 780) | static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
type mnlg_socket (line 792) | struct mnlg_socket
type mnlg_socket (line 794) | struct mnlg_socket
type nlmsghdr (line 795) | struct nlmsghdr
function mnlg_socket_close (line 853) | static void mnlg_socket_close(struct mnlg_socket *nlg)
type string_list (line 862) | struct string_list {
function string_list_add (line 868) | static int string_list_add(struct string_list *list, const char *str)
type interface (line 893) | struct interface {
function parse_linkinfo (line 898) | static int parse_linkinfo(const struct nlattr *attr, void *data)
function parse_infomsg (line 907) | static int parse_infomsg(const struct nlattr *attr, void *data)
function read_devices_cb (line 918) | static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
function fetch_device_names (line 936) | static int fetch_device_names(struct string_list *list)
function add_del_iface (line 1005) | static int add_del_iface(const char *ifname, bool add)
function wg_set_device (line 1064) | int wg_set_device(wg_device *dev)
function parse_allowedip (line 1198) | static int parse_allowedip(const struct nlattr *attr, void *data)
function parse_allowedips (line 1224) | static int parse_allowedips(const struct nlattr *attr, void *data)
function wg_key_is_zero (line 1248) | bool wg_key_is_zero(const wg_key key)
function parse_peer (line 1260) | static int parse_peer(const struct nlattr *attr, void *data)
function parse_peers (line 1315) | static int parse_peers(const struct nlattr *attr, void *data)
function parse_device (line 1339) | static int parse_device(const struct nlattr *attr, void *data)
function read_device_cb (line 1383) | static int read_device_cb(const struct nlmsghdr *nlh, void *data)
function coalesce_peers (line 1388) | static void coalesce_peers(wg_device *device)
function wg_get_device (line 1410) | int wg_get_device(wg_device **device, const char *device_name)
type string_list (line 1457) | struct string_list
function wg_add_device (line 1468) | int wg_add_device(const char *device_name)
function wg_del_device (line 1473) | int wg_del_device(const char *device_name)
function wg_free_device (line 1478) | void wg_free_device(wg_device *dev)
function encode_base64 (line 1493) | static void encode_base64(char dest[static 4], const uint8_t src[static 3])
function wg_key_to_base64 (line 1507) | void wg_key_to_base64(wg_key_b64_string base64, const wg_key key)
function decode_base64 (line 1518) | static int decode_base64(const char src[static 4])
function wg_key_from_base64 (line 1534) | int wg_key_from_base64(wg_key key, const wg_key_b64_string base64)
function memzero_explicit (line 1563) | static __attribute__((noinline)) void memzero_explicit(void *s, size_t c...
function carry (line 1569) | static void carry(fe o)
function cswap (line 1579) | static void cswap(fe p, fe q, int b)
function pack (line 1595) | static void pack(uint8_t *o, const fe n)
function add (line 1625) | static void add(fe o, const fe a, const fe b)
function subtract (line 1633) | static void subtract(fe o, const fe a, const fe b)
function multmod (line 1641) | static void multmod(fe o, const fe a, const fe b)
function invert (line 1659) | static void invert(fe o, const fe i)
function clamp_key (line 1675) | static void clamp_key(uint8_t *z)
function wg_generate_public_key (line 1681) | void wg_generate_public_key(wg_key public_key, const wg_key private_key)
function wg_generate_private_key (line 1729) | void wg_generate_private_key(wg_key private_key)
function wg_generate_preshared_key (line 1735) | void wg_generate_preshared_key(wg_key preshared_key)
FILE: contrib/embeddable-wg-library/wireguard.h
type timespec64 (line 20) | struct timespec64 {
type wg_allowedip (line 25) | typedef struct wg_allowedip {
type wg_peer_flags (line 35) | enum wg_peer_flags {
type wg_endpoint (line 43) | typedef union wg_endpoint {
type wg_peer (line 49) | typedef struct wg_peer {
type wg_device_flags (line 65) | enum wg_device_flags {
type wg_device (line 73) | typedef struct wg_device {
FILE: contrib/external-tests/rust/src/main.rs
function memcpy (line 22) | fn memcpy(out: &mut [u8], data: &[u8]) {
function main (line 26) | fn main() {
FILE: contrib/extract-handshakes/offset-finder.c
type def (line 6) | struct def {
type def (line 11) | struct def
type def (line 16) | struct def
type noise_static_identity (line 17) | struct noise_static_identity
type noise_handshake (line 17) | struct noise_handshake
type noise_handshake (line 18) | struct noise_handshake
type noise_handshake (line 19) | struct noise_handshake
type noise_handshake (line 20) | struct noise_handshake
function main (line 25) | int main(int argc, char *argv[])
FILE: contrib/highlighter/fuzz.c
function LLVMFuzzerTestOneInput (line 10) | int LLVMFuzzerTestOneInput(const char *data, size_t size)
FILE: contrib/highlighter/gui/highlight.cpp
function main (line 35) | int main(int argc, char *argv[])
FILE: contrib/highlighter/highlight.c
function main (line 61) | int main(int argc, char *argv[])
FILE: contrib/highlighter/highlighter.c
type string_span_t (line 13) | typedef struct {
function is_decimal (line 18) | static bool is_decimal(char c)
function is_hexadecimal (line 23) | static bool is_hexadecimal(char c)
function is_alphabet (line 28) | static bool is_alphabet(char c)
function is_same (line 33) | static bool is_same(string_span_t s, const char *c)
function is_caseless_same (line 42) | static bool is_caseless_same(string_span_t s, const char *c)
function is_valid_key (line 60) | static bool is_valid_key(string_span_t s)
function is_valid_hostname (line 94) | static bool is_valid_hostname(string_span_t s)
function is_valid_ipv4 (line 124) | static bool is_valid_ipv4(string_span_t s)
function is_valid_ipv6 (line 142) | static bool is_valid_ipv6(string_span_t s)
function is_valid_uint (line 180) | static bool is_valid_uint(string_span_t s, bool support_hex, uint64_t mi...
function is_valid_port (line 207) | static bool is_valid_port(string_span_t s)
function is_valid_mtu (line 212) | static bool is_valid_mtu(string_span_t s)
function is_valid_persistentkeepalive (line 217) | static bool is_valid_persistentkeepalive(string_span_t s)
function is_valid_fwmark (line 226) | static bool is_valid_fwmark(string_span_t s)
function is_valid_table (line 233) | static bool is_valid_table(string_span_t s)
function is_valid_saveconfig (line 246) | static bool is_valid_saveconfig(string_span_t s)
function is_valid_prepostupdown (line 251) | static bool is_valid_prepostupdown(string_span_t s)
function is_valid_scope (line 259) | static bool is_valid_scope(string_span_t s)
function is_valid_endpoint (line 272) | static bool is_valid_endpoint(string_span_t s)
function is_valid_network (line 315) | static bool is_valid_network(string_span_t s)
type field (line 340) | enum field {
function section_for_field (line 364) | static enum field section_for_field(enum field t)
function get_field (line 373) | static enum field get_field(string_span_t s)
function get_sectiontype (line 399) | static enum field get_sectiontype(string_span_t s)
type highlight_span_array (line 408) | struct highlight_span_array {
function append_highlight_span (line 425) | static bool append_highlight_span(struct highlight_span_array *a, const ...
function highlight_multivalue_value (line 445) | static void highlight_multivalue_value(struct highlight_span_array *ret,...
function highlight_multivalue (line 482) | static void highlight_multivalue(struct highlight_span_array *ret, const...
function highlight_value (line 510) | static void highlight_value(struct highlight_span_array *ret, const stri...
type highlight_span (line 574) | struct highlight_span
type highlight_span_array (line 576) | struct highlight_span_array
type field (line 579) | enum field
type field (line 624) | enum field
FILE: contrib/highlighter/highlighter.h
type highlight_type (line 8) | enum highlight_type {
type highlight_span (line 32) | struct highlight_span {
type highlight_span (line 37) | struct highlight_span
FILE: contrib/keygen-html/wireguard.js
function gf (line 7) | function gf(init) {
function pack (line 16) | function pack(o, n) {
function carry (line 40) | function carry(o) {
function cswap (line 48) | function cswap(p, q, b) {
function add (line 57) | function add(o, a, b) {
function subtract (line 62) | function subtract(o, a, b) {
function multmod (line 67) | function multmod(o, a, b) {
function invert (line 81) | function invert(o, i) {
function clamp (line 94) | function clamp(z) {
function generatePublicKey (line 99) | function generatePublicKey(privateKey) {
function generatePresharedKey (line 143) | function generatePresharedKey() {
function generatePrivateKey (line 149) | function generatePrivateKey() {
function encodeBase64 (line 155) | function encodeBase64(dest, src) {
function keyToBase64 (line 165) | function keyToBase64(key) {
FILE: contrib/nat-hole-punching/nat-punch-client.c
function read_peers (line 62) | static void read_peers(const char *interface)
function unbase64 (line 86) | static void unbase64(uint8_t dstkey[32], const char *srckey)
function apply_bpf (line 96) | static void apply_bpf(int sock, uint16_t port, uint32_t ip)
function main (line 118) | int main(int argc, char *argv[])
FILE: contrib/nat-hole-punching/nat-punch-server.c
type entry (line 19) | struct entry {
type entry (line 27) | struct entry
type entry (line 31) | struct entry
type entry (line 42) | struct entry
type entry (line 44) | struct entry
function main (line 52) | int main(int argc, char *argv[])
FILE: contrib/sticky-sockets/sticky-sockets.c
type magic_endpoint (line 21) | struct magic_endpoint {
function magic_send4 (line 36) | ssize_t magic_send4(int sock, struct magic_endpoint *endpoint, void *buf...
function magic_send6 (line 70) | ssize_t magic_send6(int sock, struct magic_endpoint *endpoint, void *buf...
function magic_receive4 (line 105) | ssize_t magic_receive4(int sock, struct magic_endpoint *endpoint, void *...
function magic_receive6 (line 135) | ssize_t magic_receive6(int sock, struct magic_endpoint *endpoint, void *...
function magic_endpoint_clearsrc (line 165) | void magic_endpoint_clearsrc(struct magic_endpoint *endpoint)
function magic_endpoint_set (line 175) | void magic_endpoint_set(struct magic_endpoint *endpoint, const struct so...
function magic_create_sock4 (line 184) | int magic_create_sock4(uint16_t listen_port)
function magic_create_sock6 (line 213) | int magic_create_sock6(uint16_t listen_port)
function main (line 246) | int main(int argc, char *argv[])
FILE: src/config.c
function parse_port (line 39) | static inline bool parse_port(uint16_t *port, uint32_t *flags, const cha...
function parse_fwmark (line 77) | static inline bool parse_fwmark(uint32_t *fwmark, uint32_t *flags, const...
function parse_key (line 107) | static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char ...
function parse_keyfile (line 117) | static bool parse_keyfile(uint8_t key[static WG_KEY_LEN], const char *path)
function parse_ip (line 160) | static inline bool parse_ip(struct wgallowedip *allowedip, const char *v...
function parse_dns_retries (line 177) | static inline int parse_dns_retries(void)
function parse_endpoint (line 195) | static inline bool parse_endpoint(struct sockaddr *endpoint, const char ...
function parse_persistent_keepalive (line 282) | static inline bool parse_persistent_keepalive(uint16_t *interval, uint32...
function validate_netmask (line 308) | static bool validate_netmask(struct wgallowedip *allowedip)
function parse_ip_prefix (line 340) | static inline void parse_ip_prefix(struct wgpeer *peer, uint32_t *flags,...
function parse_allowedips (line 354) | static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowe...
function process_line (line 436) | static bool process_line(struct config_ctx *ctx, const char *line)
function config_read_line (line 506) | bool config_read_line(struct config_ctx *ctx, const char *input)
function config_read_init (line 541) | bool config_read_init(struct config_ctx *ctx, bool append)
type wgdevice (line 554) | struct wgdevice
type config_ctx (line 554) | struct config_ctx
type wgpeer (line 556) | struct wgpeer
type wgdevice (line 588) | struct wgdevice
type wgdevice (line 590) | struct wgdevice
type wgpeer (line 591) | struct wgpeer
type wgallowedip (line 592) | struct wgallowedip
type wgpeer (line 616) | struct wgpeer
FILE: src/config.h
type wgdevice (line 11) | struct wgdevice
type wgpeer (line 12) | struct wgpeer
type wgallowedip (line 13) | struct wgallowedip
type config_ctx (line 15) | struct config_ctx {
type wgdevice (line 22) | struct wgdevice
type config_ctx (line 23) | struct config_ctx
type config_ctx (line 24) | struct config_ctx
type wgdevice (line 25) | struct wgdevice
type config_ctx (line 25) | struct config_ctx
FILE: src/containers.h
type timespec64 (line 26) | struct timespec64 {
type wgallowedip (line 35) | struct wgallowedip {
type wgpeer (line 54) | struct wgpeer {
type wgdevice (line 82) | struct wgdevice {
function free_wgdevice (line 100) | static inline void free_wgdevice(struct wgdevice *dev)
FILE: src/ctype.h
function char_is_space (line 13) | static inline bool char_is_space(int c)
function char_is_digit (line 19) | static inline bool char_is_digit(int c)
function char_is_alpha (line 24) | static inline bool char_is_alpha(int c)
FILE: src/curve25519-fiat32.h
type fe (line 19) | typedef struct fe { u32 v[10]; } fe;
type fe_loose (line 24) | typedef struct fe_loose { u32 v[10]; } fe_loose;
function __always_inline (line 26) | static __always_inline void fe_frombytes_impl(u32 h[10], const u8 *s)
function __always_inline (line 49) | static __always_inline void fe_frombytes(fe *h, const u8 *s)
function __always_inline (line 54) | static __always_inline u8 /*bool*/
function __always_inline (line 65) | static __always_inline u8 /*bool*/
function __always_inline (line 76) | static __always_inline u8 /*bool*/
function __always_inline (line 87) | static __always_inline u8 /*bool*/
function __always_inline (line 98) | static __always_inline u32 cmovznz32(u32 t, u32 z, u32 nz)
function __always_inline (line 104) | static __always_inline void fe_freeze(u32 out[10], const u32 in1[10])
function __always_inline (line 160) | static __always_inline void fe_tobytes(u8 s[32], const fe *f)
function __always_inline (line 199) | static __always_inline void fe_copy(fe *h, const fe *f)
function __always_inline (line 204) | static __always_inline void fe_copy_lt(fe_loose *h, const fe *f)
function __always_inline (line 210) | static __always_inline void fe_0(fe *h)
function __always_inline (line 216) | static __always_inline void fe_1(fe *h)
function fe_add_impl (line 222) | static void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
function __always_inline (line 260) | static __always_inline void fe_add(fe_loose *h, const fe *f, const fe *g)
function fe_sub_impl (line 265) | static void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
function __always_inline (line 303) | static __always_inline void fe_sub(fe_loose *h, const fe *f, const fe *g)
function fe_mul_impl (line 308) | static void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
function __always_inline (line 424) | static __always_inline void fe_mul_ttt(fe *h, const fe *f, const fe *g)
function __always_inline (line 429) | static __always_inline void fe_mul_tlt(fe *h, const fe_loose *f, const f...
function __always_inline (line 434) | static __always_inline void
function fe_sqr_impl (line 440) | static void fe_sqr_impl(u32 out[10], const u32 in1[10])
function __always_inline (line 546) | static __always_inline void fe_sq_tl(fe *h, const fe_loose *f)
function __always_inline (line 551) | static __always_inline void fe_sq_tt(fe *h, const fe *f)
function __always_inline (line 556) | static __always_inline void fe_loose_invert(fe *out, const fe_loose *z)
function __always_inline (line 606) | static __always_inline void fe_invert(fe *out, const fe *z)
function __always_inline (line 618) | static __always_inline void fe_cswap(fe *f, fe *g, unsigned int b)
function __always_inline (line 631) | static __always_inline void fe_mul_121666_impl(u32 out[10], const u32 in...
function __always_inline (line 747) | static __always_inline void fe_mul121666(fe *h, const fe_loose *f)
function curve25519_generic (line 752) | static void curve25519_generic(u8 out[CURVE25519_KEY_SIZE],
FILE: src/curve25519-hacl64.h
type __uint128_t (line 13) | typedef __uint128_t u128;
function __always_inline (line 15) | static __always_inline u64 u64_eq_mask(u64 a, u64 b)
function __always_inline (line 25) | static __always_inline u64 u64_gte_mask(u64 a, u64 b)
function __always_inline (line 39) | static __always_inline void modulo_carry_top(u64 *b)
function __always_inline (line 49) | static __always_inline void fproduct_copy_from_wide_(u64 *output, u128 *...
function __always_inline (line 73) | static __always_inline void
function __always_inline (line 83) | static __always_inline void fproduct_carry_wide_(u128 *tmp)
function __always_inline (line 124) | static __always_inline void fmul_shift_reduce(u64 *output)
function __always_inline (line 153) | static __always_inline void fmul_mul_shift_reduce_(u128 *output, u64 *in...
function __always_inline (line 183) | static __always_inline void fmul_fmul(u64 *output, u64 *input, u64 *inpu...
function __always_inline (line 214) | static __always_inline void fsquare_fsquare__(u128 *tmp, u64 *output)
function __always_inline (line 243) | static __always_inline void fsquare_fsquare_(u128 *tmp, u64 *output)
function __always_inline (line 270) | static __always_inline void fsquare_fsquare_times_(u64 *output, u128 *tmp,
function __always_inline (line 279) | static __always_inline void fsquare_fsquare_times(u64 *output, u64 *input,
function __always_inline (line 287) | static __always_inline void fsquare_fsquare_times_inplace(u64 *output,
function __always_inline (line 294) | static __always_inline void crecip_crecip(u64 *out, u64 *z)
function __always_inline (line 338) | static __always_inline void fsum(u64 *a, u64 *b)
function __always_inline (line 347) | static __always_inline void fdifference(u64 *a, u64 *b)
function __always_inline (line 393) | static __always_inline void fscalar(u64 *output, u64 *b, u64 s)
function __always_inline (line 430) | static __always_inline void fmul(u64 *output, u64 *a, u64 *b)
function __always_inline (line 435) | static __always_inline void crecip(u64 *output, u64 *input)
function __always_inline (line 440) | static __always_inline void point_swap_conditional_step(u64 *a, u64 *b,
function __always_inline (line 453) | static __always_inline void point_swap_conditional5(u64 *a, u64 *b, u64 ...
function __always_inline (line 462) | static __always_inline void point_swap_conditional(u64 *a, u64 *b, u64 i...
function __always_inline (line 469) | static __always_inline void point_copy(u64 *output, u64 *input)
function __always_inline (line 475) | static __always_inline void addanddouble_fmonty(u64 *pp, u64 *ppq, u64 *p,
function __always_inline (line 541) | static __always_inline void
function __always_inline (line 553) | static __always_inline void
function __always_inline (line 563) | static __always_inline void
function __always_inline (line 574) | static __always_inline void ladder_bigloop_cmult_big_loop(u8 *n1, u64 *nq,
function ladder_cmult (line 586) | static void ladder_cmult(u64 *result, u8 *n1, u64 *q)
function __always_inline (line 599) | static __always_inline void format_fexpand(u64 *output, const u8 *input)
function __always_inline (line 623) | static __always_inline void format_fcontract_first_carry_pass(u64 *input)
function __always_inline (line 645) | static __always_inline void format_fcontract_first_carry_full(u64 *input)
function __always_inline (line 651) | static __always_inline void format_fcontract_second_carry_pass(u64 *input)
function __always_inline (line 673) | static __always_inline void format_fcontract_second_carry_full(u64 *input)
function __always_inline (line 689) | static __always_inline void format_fcontract_trim(u64 *input)
function __always_inline (line 714) | static __always_inline void format_fcontract_store(u8 *output, u64 *input)
function __always_inline (line 735) | static __always_inline void format_fcontract(u8 *output, u64 *input)
function __always_inline (line 743) | static __always_inline void format_scalar_of_point(u8 *scalar, u64 *point)
function curve25519_generic (line 755) | static void curve25519_generic(u8 mypublic[CURVE25519_KEY_SIZE],
FILE: src/curve25519.c
type __u64 (line 23) | typedef __u64 u64;
type __u32 (line 24) | typedef __u32 u32;
type __u8 (line 25) | typedef __u8 u8;
type __s64 (line 26) | typedef __s64 s64;
type u64 (line 28) | typedef uint64_t u64, __le64;
type u32 (line 29) | typedef uint32_t u32, __le32;
type u8 (line 30) | typedef uint8_t u8;
type s64 (line 31) | typedef int64_t s64;
function __le32 (line 58) | __le32 get_unaligned_le32(const u8 *a)
function __le64 (line 64) | __le64 get_unaligned_le64(const u8 *a)
function put_unaligned_le64 (line 70) | void put_unaligned_le64(u64 s, u8 *d)
function noinline (line 76) | static noinline void memzero_explicit(void *s, size_t count)
function curve25519_generate_public (line 88) | void curve25519_generate_public(uint8_t pub[static CURVE25519_KEY_SIZE],...
function curve25519 (line 95) | void curve25519(uint8_t mypublic[static CURVE25519_KEY_SIZE], const uint...
FILE: src/curve25519.h
type curve25519_lengths (line 12) | enum curve25519_lengths {
function curve25519_clamp_secret (line 18) | static inline void curve25519_clamp_secret(uint8_t secret[static CURVE25...
FILE: src/encoding.c
function encode_base64 (line 11) | static inline void encode_base64(char dest[static 4], const uint8_t src[...
function key_to_base64 (line 24) | void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t ...
function decode_base64 (line 35) | static inline int decode_base64(const char src[static 4])
function key_from_base64 (line 50) | bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
function key_to_hex (line 74) | void key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[stati...
function key_from_hex (line 85) | bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex)
function key_is_zero (line 116) | bool key_is_zero(const uint8_t key[static WG_KEY_LEN])
FILE: src/fuzz/cmd.c
function LLVMFuzzerTestOneInput (line 20) | int LLVMFuzzerTestOneInput(const char *data, size_t data_len)
FILE: src/fuzz/config.c
function LLVMFuzzerTestOneInput (line 24) | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t len)
FILE: src/fuzz/set.c
function FILE (line 32) | static FILE *hacked_fopen(const char *pathname, const char *mode)
function LLVMFuzzerTestOneInput (line 37) | int LLVMFuzzerTestOneInput(const char *data, size_t data_len)
FILE: src/fuzz/setconf.c
type hacked_pointers (line 33) | struct hacked_pointers {
function FILE (line 38) | static FILE *hacked_fopen(const char *pathname, const char *mode)
function LLVMFuzzerTestOneInput (line 44) | int LLVMFuzzerTestOneInput(const char *data, size_t data_len)
FILE: src/fuzz/stringlist.c
function LLVMFuzzerTestOneInput (line 23) | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t data_len)
FILE: src/fuzz/uapi.c
function FILE (line 34) | static FILE *hacked_userspace_interface_file(const char *iface)
function LLVMFuzzerTestOneInput (line 45) | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t len)
FILE: src/genkey.c
function get_random_bytes (line 32) | static inline bool __attribute__((__warn_unused_result__)) get_random_by...
function get_random_bytes (line 69) | static inline bool __attribute__((__warn_unused_result__)) get_random_by...
function genkey_main (line 75) | int genkey_main(int argc, const char *argv[])
FILE: src/ipc-freebsd.h
function get_dgram_socket (line 14) | static int get_dgram_socket(void)
function kernel_get_wireguard_interfaces (line 22) | static int kernel_get_wireguard_interfaces(struct string_list *list)
function kernel_get_device (line 53) | static int kernel_get_device(struct wgdevice **device, const char *ifname)
function kernel_set_device (line 250) | static int kernel_set_device(struct wgdevice *dev)
FILE: src/ipc-linux.h
type interface (line 30) | struct interface {
function parse_linkinfo (line 35) | static int parse_linkinfo(const struct nlattr *attr, void *data)
function parse_infomsg (line 44) | static int parse_infomsg(const struct nlattr *attr, void *data)
function read_devices_cb (line 55) | static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
function kernel_get_wireguard_interfaces (line 73) | static int kernel_get_wireguard_interfaces(struct string_list *list)
function kernel_set_device (line 142) | static int kernel_set_device(struct wgdevice *dev)
function parse_allowedip (line 278) | static int parse_allowedip(const struct nlattr *attr, void *data)
function parse_allowedips (line 304) | static int parse_allowedips(const struct nlattr *attr, void *data)
function parse_peer (line 328) | static int parse_peer(const struct nlattr *attr, void *data)
function parse_peers (line 383) | static int parse_peers(const struct nlattr *attr, void *data)
function parse_device (line 407) | static int parse_device(const struct nlattr *attr, void *data)
function read_device_cb (line 451) | static int read_device_cb(const struct nlmsghdr *nlh, void *data)
function coalesce_peers (line 456) | static void coalesce_peers(struct wgdevice *device)
function kernel_get_device (line 478) | static int kernel_get_device(struct wgdevice **device, const char *iface)
FILE: src/ipc-openbsd.h
function get_dgram_socket (line 22) | static int get_dgram_socket(void)
function kernel_get_wireguard_interfaces (line 30) | static int kernel_get_wireguard_interfaces(struct string_list *list)
function kernel_get_device (line 61) | static int kernel_get_device(struct wgdevice **device, const char *iface)
function kernel_set_device (line 182) | static int kernel_set_device(struct wgdevice *dev)
FILE: src/ipc-uapi-unix.h
function FILE (line 20) | static FILE *userspace_interface_file(const char *iface)
function userspace_has_wireguard_interface (line 64) | static bool userspace_has_wireguard_interface(const char *iface)
function userspace_get_wireguard_interfaces (line 91) | static int userspace_get_wireguard_interfaces(struct string_list *list)
FILE: src/ipc-uapi-windows.h
function FILE (line 15) | static FILE *userspace_interface_file(const char *iface)
type hashtable (line 53) | struct hashtable
function userspace_has_wireguard_interface (line 55) | static bool userspace_has_wireguard_interface(const char *iface)
function userspace_get_wireguard_interfaces (line 79) | static int userspace_get_wireguard_interfaces(struct string_list *list)
FILE: src/ipc-uapi.h
function userspace_set_device (line 28) | static int userspace_set_device(struct wgdevice *dev)
function userspace_get_device (line 138) | static int userspace_get_device(struct wgdevice **out, const char *iface)
FILE: src/ipc-windows.h
type hashtable (line 20) | struct hashtable
function kernel_get_wireguard_interfaces (line 23) | static int kernel_get_wireguard_interfaces(struct string_list *list)
function HANDLE (line 95) | static HANDLE kernel_interface_handle(const char *iface)
function kernel_get_device (line 214) | static int kernel_get_device(struct wgdevice **device, const char *iface)
function kernel_set_device (line 341) | static int kernel_set_device(struct wgdevice *dev)
FILE: src/ipc.c
type string_list (line 12) | struct string_list {
function string_list_add (line 18) | static int string_list_add(struct string_list *list, const char *str)
type string_list (line 57) | struct string_list
function ipc_get_device (line 78) | int ipc_get_device(struct wgdevice **dev, const char *iface)
function ipc_set_device (line 89) | int ipc_set_device(struct wgdevice *dev)
FILE: src/ipc.h
type wgdevice (line 11) | struct wgdevice
type wgdevice (line 13) | struct wgdevice
type wgdevice (line 14) | struct wgdevice
FILE: src/netlink.h
type mnl_attr_data_type (line 28) | enum mnl_attr_data_type {
type nlattr (line 63) | struct nlattr
type nlmsghdr (line 64) | struct nlmsghdr
function mnl_ideal_socket_buffer_size (line 70) | static size_t mnl_ideal_socket_buffer_size(void)
function mnl_nlmsg_size (line 82) | static size_t mnl_nlmsg_size(size_t len)
type nlmsghdr (line 87) | struct nlmsghdr
type nlmsghdr (line 89) | struct nlmsghdr
type nlmsghdr (line 90) | struct nlmsghdr
type nlmsghdr (line 97) | struct nlmsghdr
type nlmsghdr (line 106) | struct nlmsghdr
type nlmsghdr (line 111) | struct nlmsghdr
function mnl_nlmsg_ok (line 116) | static bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
type nlmsghdr (line 123) | struct nlmsghdr
type nlmsghdr (line 123) | struct nlmsghdr
type nlmsghdr (line 126) | struct nlmsghdr
type nlmsghdr (line 129) | struct nlmsghdr
function mnl_nlmsg_seq_ok (line 134) | static bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
function mnl_nlmsg_portid_ok (line 139) | static bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int...
function mnl_attr_get_type (line 144) | static uint16_t mnl_attr_get_type(const struct nlattr *attr)
function mnl_attr_get_payload_len (line 149) | static uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
type nlattr (line 154) | struct nlattr
function mnl_attr_ok (line 159) | static bool mnl_attr_ok(const struct nlattr *attr, int len)
type nlattr (line 166) | struct nlattr
type nlattr (line 166) | struct nlattr
type nlattr (line 168) | struct nlattr
function mnl_attr_type_valid (line 171) | static int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
function __mnl_attr_validate (line 180) | static int __mnl_attr_validate(const struct nlattr *attr,
function mnl_attr_validate (line 242) | static int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_da...
function mnl_attr_parse (line 254) | static int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
function mnl_attr_parse_nested (line 266) | static int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_c...
function mnl_attr_get_u8 (line 278) | static uint8_t mnl_attr_get_u8(const struct nlattr *attr)
function mnl_attr_get_u16 (line 283) | static uint16_t mnl_attr_get_u16(const struct nlattr *attr)
function mnl_attr_get_u32 (line 288) | static uint32_t mnl_attr_get_u32(const struct nlattr *attr)
function mnl_attr_get_u64 (line 293) | static uint64_t mnl_attr_get_u64(const struct nlattr *attr)
type nlattr (line 300) | struct nlattr
function mnl_attr_put (line 305) | static void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len,
function mnl_attr_put_u16 (line 321) | static void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16...
function mnl_attr_put_u32 (line 326) | static void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32...
function mnl_attr_put_strz (line 331) | static void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const...
type nlattr (line 336) | struct nlattr
type nlmsghdr (line 336) | struct nlmsghdr
type nlattr (line 338) | struct nlattr
type nlattr (line 341) | struct nlattr
function mnl_attr_put_check (line 345) | static bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
function mnl_attr_put_u8_check (line 354) | static bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
function mnl_attr_put_u16_check (line 360) | static bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
function mnl_attr_put_u32_check (line 366) | static bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
type nlattr (line 372) | struct nlattr
type nlmsghdr (line 372) | struct nlmsghdr
function mnl_attr_nest_end (line 380) | static void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
function mnl_attr_nest_cancel (line 385) | static void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *st...
function mnl_cb_noop (line 390) | static int mnl_cb_noop(__attribute__((unused)) const struct nlmsghdr *nl...
function mnl_cb_error (line 395) | static int mnl_cb_error(const struct nlmsghdr *nlh, __attribute__((unuse...
function mnl_cb_stop (line 412) | static int mnl_cb_stop(__attribute__((unused)) const struct nlmsghdr *nl...
function __mnl_cb_run (line 424) | static int __mnl_cb_run(const void *buf, size_t numbytes,
function mnl_cb_run2 (line 473) | static int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
function mnl_cb_run (line 481) | static int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
type mnl_socket (line 487) | struct mnl_socket {
function mnl_socket_get_portid (line 492) | static unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
type mnl_socket (line 497) | struct mnl_socket
type mnl_socket (line 499) | struct mnl_socket
type mnl_socket (line 501) | struct mnl_socket
type mnl_socket (line 514) | struct mnl_socket
function mnl_socket_bind (line 519) | static int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, p...
function mnl_socket_sendto (line 548) | static ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void...
function mnl_socket_recvfrom (line 558) | static ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf,
function mnl_socket_close (line 591) | static int mnl_socket_close(struct mnl_socket *nl)
type mnlg_socket (line 600) | struct mnlg_socket {
type nlmsghdr (line 609) | struct nlmsghdr
type mnlg_socket (line 609) | struct mnlg_socket
type nlmsghdr (line 613) | struct nlmsghdr
type genlmsghdr (line 614) | struct genlmsghdr
type genlmsghdr (line 622) | struct genlmsghdr
type nlmsghdr (line 629) | struct nlmsghdr
type mnlg_socket (line 629) | struct mnlg_socket
function mnlg_socket_send (line 635) | static int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsgh...
function mnlg_cb_noop (line 640) | static int mnlg_cb_noop(const struct nlmsghdr *nlh, void *data)
function mnlg_cb_error (line 647) | static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data)
function mnlg_cb_stop (line 665) | static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data)
function mnlg_socket_recv_run (line 688) | static int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_c...
function get_family_id_attr_cb (line 704) | static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
function get_family_id_cb (line 719) | static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
type mnlg_socket (line 731) | struct mnlg_socket
type mnlg_socket (line 733) | struct mnlg_socket
type nlmsghdr (line 734) | struct nlmsghdr
function mnlg_socket_close (line 792) | static void mnlg_socket_close(struct mnlg_socket *nlg)
FILE: src/pubkey.c
function pubkey_main (line 14) | int pubkey_main(int argc, const char *argv[])
FILE: src/set.c
function set_main (line 15) | int set_main(int argc, const char *argv[])
FILE: src/setconf.c
type peer_origin (line 16) | struct peer_origin {
function peer_cmp (line 21) | static int peer_cmp(const void *first, const void *second)
function sync_conf (line 30) | static bool sync_conf(struct wgdevice *file)
function setconf_main (line 116) | int setconf_main(int argc, const char *argv[])
FILE: src/show.c
function peer_cmp (line 27) | static int peer_cmp(const void *first, const void *second)
function sort_peers (line 47) | static void sort_peers(struct wgdevice *device)
type wgallowedip (line 94) | struct wgallowedip
type sockaddr (line 106) | struct sockaddr
type sockaddr_in (line 116) | struct sockaddr_in
type sockaddr_in6 (line 118) | struct sockaddr_in6
function pretty_time (line 129) | static size_t pretty_time(char *buf, const size_t len, unsigned long lon...
type timespec64 (line 157) | struct timespec64
function show_usage (line 203) | static void show_usage(void)
function pretty_print (line 208) | static void pretty_print(struct wgdevice *device)
function dump_print (line 253) | static void dump_print(struct wgdevice *device, bool with_interface)
function ugly_print (line 290) | static bool ugly_print(struct wgdevice *device, const char *param, bool ...
function show_main (line 379) | int show_main(int argc, const char *argv[])
FILE: src/showconf.c
function showconf_main (line 21) | int showconf_main(int argc, const char *argv[])
FILE: src/terminal.c
function color_mode (line 16) | static bool color_mode(void)
function filter_ansi (line 33) | static void filter_ansi(const char *fmt, va_list args)
function terminal_printf (line 69) | void terminal_printf(const char *fmt, ...)
FILE: src/uapi/freebsd/dev/wg/if_wg.h
type wg_data_io (line 7) | struct wg_data_io {
FILE: src/uapi/linux/linux/wireguard.h
type wg_cmd (line 143) | enum wg_cmd {
type wgdevice_flag (line 150) | enum wgdevice_flag {
type wgdevice_attribute (line 154) | enum wgdevice_attribute {
type wgpeer_flag (line 168) | enum wgpeer_flag {
type wgpeer_attribute (line 175) | enum wgpeer_attribute {
type wgallowedip_flag (line 191) | enum wgallowedip_flag {
type wgallowedip_attribute (line 195) | enum wgallowedip_attribute {
FILE: src/uapi/openbsd/net/if_wg.h
type wg_aip_io (line 31) | struct wg_aip_io {
type wg_peer_io (line 52) | struct wg_peer_io {
type wg_interface_io (line 76) | struct wg_interface_io {
type wg_data_io (line 86) | struct wg_data_io {
FILE: src/uapi/windows/wireguard.h
type WG_IOCTL_ALLOWED_IP_FLAG (line 17) | typedef enum
type WG_IOCTL_ALLOWED_IP (line 22) | typedef struct _WG_IOCTL_ALLOWED_IP
type WG_IOCTL_PEER_FLAG (line 34) | typedef enum
type WG_IOCTL_PEER (line 46) | typedef struct _WG_IOCTL_PEER
type WG_IOCTL_INTERFACE_FLAG (line 60) | typedef enum
type WG_IOCTL_INTERFACE (line 68) | typedef struct _WG_IOCTL_INTERFACE
FILE: src/wg-quick/android.c
function xregcomp (line 72) | static void xregcomp(regex_t *preg, const char *regex, int cflags)
type command_buffer (line 114) | struct command_buffer {
function free_command_buffer (line 120) | static void free_command_buffer(struct command_buffer *c)
function freep (line 129) | static void freep(void *p)
function fclosep (line 133) | static void fclosep(FILE **f)
type command_buffer (line 144) | struct command_buffer
function cmd (line 176) | static void cmd(const char *cmd_fmt, ...)
type command_buffer (line 201) | struct command_buffer
function cndc (line 212) | static void cndc(const char *cmd_fmt, ...)
type AIBinder (line 284) | struct AIBinder
type AParcel (line 285) | struct AParcel
type AStatus (line 286) | struct AStatus
type AIBinder_Class (line 287) | struct AIBinder_Class
type AIBinder (line 288) | typedef struct AIBinder AIBinder;
type AParcel (line 289) | typedef struct AParcel AParcel;
type AStatus (line 290) | typedef struct AStatus AStatus;
type AIBinder_Class (line 291) | typedef struct AIBinder_Class AIBinder_Class;
type binder_status_t (line 292) | typedef int32_t binder_status_t;
type binder_exception_t (line 293) | typedef int32_t binder_exception_t;
type transaction_code_t (line 294) | typedef uint32_t transaction_code_t;
type binder_flags_t (line 295) | typedef uint32_t binder_flags_t;
type binder_status_t (line 298) | typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder *binder, t...
function load_symbols (line 323) | static __attribute__((__constructor__(65535))) void load_symbols(void)
function cleanup_binder (line 361) | static void cleanup_binder(AIBinder **binder)
function cleanup_status (line 366) | static void cleanup_status(AStatus **status)
function cleanup_parcel (line 371) | static void cleanup_parcel(AParcel **parcel)
function string_size (line 381) | static int32_t string_size(const char *str)
function string_array_size (line 386) | static int32_t string_array_size(char *const *array)
function binder_status_t (line 402) | static binder_status_t meaningful_binder_status(const AStatus *status_out)
type dnsresolver_params (line 442) | struct dnsresolver_params {
function on_destroy (line 464) | static void on_destroy()
function binder_status_t (line 470) | static binder_status_t on_transact()
function AIBinder (line 477) | static AIBinder *dnsresolver_get_handle(void)
function dnsresolver_create_network_cache (line 501) | static int32_t dnsresolver_create_network_cache(void *handle, int32_t ne...
function dnsresolver_set_resolver_configuration (line 531) | static int32_t dnsresolver_set_resolver_configuration(void *handle, cons...
function auto_su (line 612) | static void auto_su(int argc, char *argv[])
function add_if (line 633) | static void add_if(const char *iface)
function del_if (line 638) | static void del_if(const char *iface)
function should_block_ipv6 (line 678) | static bool should_block_ipv6(const char *iface)
function determine_listen_port (line 697) | static uint16_t determine_listen_port(const char *iface)
function up_if (line 717) | static void up_if(unsigned int *netid, const char *iface, uint16_t liste...
function compare_uid (line 736) | static int compare_uid(const void *a, const void *b)
function uid_t (line 741) | static uid_t *get_uid_list(const char *selected_applications)
function set_users (line 787) | static void set_users(unsigned int netid, const char *excluded_applicati...
function set_dnses (line 837) | static void set_dnses(unsigned int netid, const char *dnses)
function add_addr (line 927) | static void add_addr(const char *iface, const char *addr)
function set_addr (line 945) | static void set_addr(const char *iface, const char *addrs)
function get_route_mtu (line 956) | static int get_route_mtu(const char *endpoint)
function set_mtu (line 992) | static void set_mtu(const char *iface, unsigned int mtu)
function add_route (line 1024) | static void add_route(const char *iface, unsigned int netid, const char ...
function set_routes (line 1029) | static void set_routes(const char *iface, unsigned int netid)
function set_config (line 1047) | static void set_config(const char *iface, const char *config)
function broadcast_change (line 1069) | static void broadcast_change(void)
function print_search_paths (line 1077) | static void print_search_paths(FILE *file, const char *prefix)
function cmd_usage (line 1085) | static void cmd_usage(const char *program)
function cmd_up_cleanup (line 1107) | static void cmd_up_cleanup(void)
function cmd_up (line 1115) | static void cmd_up(const char *iface, const char *config, unsigned int m...
function cmd_down (line 1145) | static void cmd_down(const char *iface)
function parse_options (line 1169) | static void parse_options(char **iface, char **config, unsigned int *mtu...
function main (line 1274) | int main(int argc, char *argv[])
FILE: src/wg.c
function show_usage (line 31) | static void show_usage(FILE *file)
function main (line 40) | int main(int argc, const char *argv[])
FILE: src/wincompat/include/hashtable.h
type hashtable_entry (line 13) | struct hashtable_entry {
type hashtable (line 19) | struct hashtable {
function hashtable_bucket (line 23) | static unsigned int hashtable_bucket(const char *str)
type hashtable_entry (line 32) | struct hashtable_entry
type hashtable (line 32) | struct hashtable
type hashtable_entry (line 34) | struct hashtable_entry
type hashtable_entry (line 42) | struct hashtable_entry
type hashtable (line 42) | struct hashtable
type hashtable_entry (line 44) | struct hashtable_entry
FILE: src/wincompat/init.c
function init (line 13) | __attribute__((constructor)) static void init(void)
function deinit (line 40) | __attribute__((destructor)) static void deinit(void)
FILE: src/wincompat/libc.c
function getdelim (line 25) | ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
function getline (line 66) | ssize_t getline(char **buf, size_t *bufsiz, FILE *fp)
FILE: src/wincompat/loader.c
function FARPROC (line 9) | static FARPROC WINAPI delayed_load_library_hook(unsigned dliNotify, PDel...
Condensed preview — 125 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (554K chars).
[
{
"path": ".gitattributes",
"chars": 54,
"preview": ".gitattributes export-ignore\n.gitignore export-ignore\n"
},
{
"path": ".gitignore",
"chars": 115,
"preview": "cscope.out\n*.o\n*.d\n*.lib\n*.dll\n*.gch\n*.dwo\nsrc/wg\nsrc/wg.exe\n*.swp\n*.id0\n*.id1\n*.id2\n*.nam\n*.til\n*.pro.user\nmaint/\n"
},
{
"path": "COPYING",
"chars": 18092,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
},
{
"path": "README.md",
"chars": 3422,
"preview": "# [wireguard-tools](https://git.zx2c4.com/wireguard-tools/about/) — tools for configuring [WireGuard](https://www."
},
{
"path": "contrib/dns-hatchet/README",
"chars": 377,
"preview": "The DNS Hatchet\n===============\n\nThis is a workaround for distributions without resolvconf or any proper\nmechanism of se"
},
{
"path": "contrib/dns-hatchet/apply.sh",
"chars": 311,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/dns-hatchet/hatchet.bash",
"chars": 1475,
"preview": "set_dns() {\n\t[[ ${#DNS[@]} -gt 0 ]] || return 0\n\n\tif [[ $(resolvconf --version 2>/dev/null) == openresolv\\ * ]]; then\n\t\t"
},
{
"path": "contrib/embeddable-wg-library/.gitignore",
"chars": 5,
"preview": "test\n"
},
{
"path": "contrib/embeddable-wg-library/Makefile",
"chars": 88,
"preview": "CFLAGS += -Wall\n\ntest: test.c wireguard.c wireguard.h\n\nclean:\n\trm -f test\n.PHONY: clean\n"
},
{
"path": "contrib/embeddable-wg-library/README",
"chars": 607,
"preview": "Embeddable WireGuard C Library\n==============================\n\nThis is a mini single-file library, meant to be embedded "
},
{
"path": "contrib/embeddable-wg-library/test.c",
"chars": 1811,
"preview": "// SPDX-License-Identifier: LGPL-2.1+\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Res"
},
{
"path": "contrib/embeddable-wg-library/wireguard.c",
"chars": 43694,
"preview": "// SPDX-License-Identifier: LGPL-2.1+\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Res"
},
{
"path": "contrib/embeddable-wg-library/wireguard.h",
"chars": 2871,
"preview": "/* SPDX-License-Identifier: LGPL-2.1+ */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights "
},
{
"path": "contrib/external-tests/haskell/Setup.hs",
"chars": 46,
"preview": "import Distribution.Simple\nmain = defaultMain\n"
},
{
"path": "contrib/external-tests/haskell/package.yaml",
"chars": 619,
"preview": "name: cacophony-wg\nversion: 0.1.0\nlicense: PublicDomain\nmaintainer: John Galt <jgalt@centromere.net>\ncategory: Cryptogra"
},
{
"path": "contrib/external-tests/haskell/src/Data/Time/TAI64.hs",
"chars": 2208,
"preview": "module Data.Time.TAI64 (\n TAI64(..)\n , TAI64N(..)\n , TAI64NA(..)\n , posixToTAI64\n , posixToTAI64N\n , posixToTAI6"
},
{
"path": "contrib/external-tests/haskell/src/Main.hs",
"chars": 5444,
"preview": "module Main where\n\nimport Control.Monad (void)\nimport Crypto.Hash.BLAKE2.BLAKE2s (hash)"
},
{
"path": "contrib/external-tests/haskell/stack.yaml",
"chars": 84,
"preview": "resolver: lts-8.18\npackages:\n - '.'\nextra-deps: []\nflags: {}\nextra-package-dbs: []\n"
},
{
"path": "contrib/external-tests/python/main.py",
"chars": 3101,
"preview": "#!/usr/bin/python3\n\n# SPDX-License-Identifier: MIT\n# Author: Piotr Lizonczyk <plizonczyk.public@gmail.com>\n\nimport base6"
},
{
"path": "contrib/external-tests/rust/.gitignore",
"chars": 19,
"preview": "Cargo.lock\ntarget/\n"
},
{
"path": "contrib/external-tests/rust/Cargo.toml",
"chars": 263,
"preview": "[package]\nname = \"wireguard-ping\"\nversion = \"0.1.0\"\nauthors = [\"jason@zx2c4.com\", \"me@jake.su\"]\npublish = false\n\n[depend"
},
{
"path": "contrib/external-tests/rust/src/main.rs",
"chars": 5705,
"preview": "/* Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */\n\nextern crate snow;\nextern crat"
},
{
"path": "contrib/extract-handshakes/.gitignore",
"chars": 46,
"preview": "offset-finder.o\noffset-finder\noffsets.include\n"
},
{
"path": "contrib/extract-handshakes/Makefile",
"chars": 525,
"preview": "ifeq ($(KERNELRELEASE),)\nKERNELDIR ?= /lib/modules/$(shell uname -r)/build\nPWD := $(shell pwd)\nCFLAGS ?= -O3 -march=nati"
},
{
"path": "contrib/extract-handshakes/README",
"chars": 673,
"preview": "Handshake Extractor\n===================\n\nThis will extract private keys from outgoing handshake sessions, prior\nto them "
},
{
"path": "contrib/extract-handshakes/extract-handshakes.sh",
"chars": 2222,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/extract-handshakes/offset-finder.c",
"chars": 1266,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/highlighter/Makefile",
"chars": 477,
"preview": "CFLAGS ?= -O3 -march=native\nCFLAGS += -std=gnu99\nCFLAGS += -Wall\nCFLAGS += -MMD -MP\n\nhighlight: highlight.o highlighter."
},
{
"path": "contrib/highlighter/README",
"chars": 618,
"preview": "wg(8) and wg-quick(8) syntax highlighter library\n================================================\n\nhighlighter.c contain"
},
{
"path": "contrib/highlighter/fuzz.c",
"chars": 512,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/highlighter/gui/highlight.cpp",
"chars": 3033,
"preview": "#include <QApplication>\n#include <QPlainTextEdit>\n#include <QPalette>\n#include <QFontDatabase>\n#include <QVBoxLayout>\n#i"
},
{
"path": "contrib/highlighter/gui/highlight.pro",
"chars": 127,
"preview": "QT += core gui widgets\nTEMPLATE = app\nTARGET = highlight\nSOURCES += highlight.cpp ../highlighter.c\nHEADERS += ../highlig"
},
{
"path": "contrib/highlighter/highlight.c",
"chars": 2618,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/highlighter/highlighter.c",
"chars": 16391,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/highlighter/highlighter.h",
"chars": 700,
"preview": "/* SPDX-License-Identifier: GPL-2.0 */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Re"
},
{
"path": "contrib/json/README",
"chars": 100,
"preview": "wg-json\n=======\n\nThis will dump all current WireGuard status as JSON output.\n\nUsage:\n\n # wg-json\n"
},
{
"path": "contrib/json/wg-json",
"chars": 2249,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/keygen-html/.gitignore",
"chars": 23,
"preview": "curve25519_generate.js\n"
},
{
"path": "contrib/keygen-html/README",
"chars": 713,
"preview": "WireGuard Key Generation in JavaScript\n======================================\n\nVarious people believe in JavaScript cryp"
},
{
"path": "contrib/keygen-html/keygen.html",
"chars": 5385,
"preview": "<script src=\"wireguard.js\"></script>\n<script>\n/* SPDX-License-Identifier: GPL-2.0\n *\n * Copyright (C) 2015-2026 Jason A."
},
{
"path": "contrib/keygen-html/wireguard.js",
"chars": 4013,
"preview": "/*! SPDX-License-Identifier: GPL-2.0\n *\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Rese"
},
{
"path": "contrib/launchd/README",
"chars": 419,
"preview": "WireGuard for Launchd\n=====================\n\nThe example `com.wireguard.wg0.plist` file may be used for running wg-quick"
},
{
"path": "contrib/launchd/com.wireguard.wg0.plist",
"chars": 694,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.c"
},
{
"path": "contrib/nat-hole-punching/README",
"chars": 1294,
"preview": "== NAT Hole Punching Example ==\n\nThis code should never be used, ever. But, it's a nice demonstration of how\nto punch ho"
},
{
"path": "contrib/nat-hole-punching/nat-punch-client.c",
"chars": 5033,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/nat-hole-punching/nat-punch-server.c",
"chars": 2499,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/ncat-client-server/README",
"chars": 560,
"preview": " === IMPORTANT NOTE ===\n\nDo not use these scripts in production. They are simply a\ndemonstration of how e"
},
{
"path": "contrib/ncat-client-server/client-quick.sh",
"chars": 1072,
"preview": "#!/usr/bin/env bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>."
},
{
"path": "contrib/ncat-client-server/client.sh",
"chars": 1061,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/ncat-client-server/server.sh",
"chars": 896,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/reresolve-dns/README",
"chars": 332,
"preview": "reresolve-dns\n=============\n\nRun this script from cron every thirty seconds or so, and it will ensure\nthat if, when usin"
},
{
"path": "contrib/reresolve-dns/reresolve-dns.sh",
"chars": 1351,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/sticky-sockets/README",
"chars": 159,
"preview": "Sticky Sockets\n==============\n\nThis is a small userspace mini-library that implements as close to\npossible how the kerne"
},
{
"path": "contrib/sticky-sockets/sticky-sockets.c",
"chars": 7842,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "contrib/synergy/README",
"chars": 181,
"preview": "These scripts should be modified according to your precise setup.\nThey provide a very simple way of tunneling synergy in"
},
{
"path": "contrib/synergy/synergy-client.sh",
"chars": 656,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "contrib/synergy/synergy-server.sh",
"chars": 626,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "src/Makefile",
"chars": 4302,
"preview": "# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved"
},
{
"path": "src/completion/wg-quick.bash-completion",
"chars": 1395,
"preview": "# SPDX-License-Identifier: GPL-2.0\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n"
},
{
"path": "src/completion/wg.bash-completion",
"chars": 3515,
"preview": "# SPDX-License-Identifier: GPL-2.0\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n"
},
{
"path": "src/config.c",
"chars": 16753,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/config.h",
"chars": 664,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/containers.h",
"chars": 2552,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/ctype.h",
"chars": 676,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/curve25519-fiat32.h",
"chars": 30164,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2016 The fiat-crypto Authors.\n * Copyright (C) 2018-"
},
{
"path": "src/curve25519-hacl64.h",
"chars": 17772,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2016-2017 INRIA and Microsoft Corporation.\n * Copyright ("
},
{
"path": "src/curve25519.c",
"chars": 2504,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/curve25519.h",
"chars": 730,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/encoding.c",
"chars": 3767,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/encoding.h",
"chars": 744,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/fuzz/.gitignore",
"chars": 39,
"preview": "config\nuapi\nstringlist\ncmd\nset\nsetconf\n"
},
{
"path": "src/fuzz/Makefile",
"chars": 931,
"preview": "# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved"
},
{
"path": "src/fuzz/cmd.c",
"chars": 1715,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/fuzz/config.c",
"chars": 1409,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/fuzz/set.c",
"chars": 1236,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/fuzz/setconf.c",
"chars": 1235,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/fuzz/stringlist.c",
"chars": 1304,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/fuzz/uapi.c",
"chars": 1211,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/genkey.c",
"chars": 2320,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/ipc-freebsd.h",
"chars": 10634,
"preview": "// SPDX-License-Identifier: MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved."
},
{
"path": "src/ipc-linux.h",
"chars": 15563,
"preview": "// SPDX-License-Identifier: MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved."
},
{
"path": "src/ipc-openbsd.h",
"chars": 7718,
"preview": "// SPDX-License-Identifier: MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved."
},
{
"path": "src/ipc-uapi-unix.h",
"chars": 2663,
"preview": "// SPDX-License-Identifier: MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved."
},
{
"path": "src/ipc-uapi-windows.h",
"chars": 2822,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/ipc-uapi.h",
"chars": 8507,
"preview": "// SPDX-License-Identifier: MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved."
},
{
"path": "src/ipc-windows.h",
"chars": 13223,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/ipc.c",
"chars": 2051,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/ipc.h",
"chars": 355,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/man/wg-quick.8",
"chars": 9248,
"preview": ".TH WG-QUICK 8 \"2016 January 1\" ZX2C4 \"WireGuard\"\n\n.SH NAME\nwg-quick - set up a WireGuard interface simply\n\n.SH SYNOPSIS"
},
{
"path": "src/man/wg.8",
"chars": 11340,
"preview": ".TH WG 8 \"2015 August 13\" ZX2C4 \"WireGuard\"\n\n.SH NAME\nwg - set and retrieve configuration of WireGuard interfaces\n\n.SH S"
},
{
"path": "src/netlink.h",
"chars": 18849,
"preview": "// SPDX-License-Identifier: LGPL-2.1+\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Res"
},
{
"path": "src/pubkey.c",
"chars": 1223,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/set.c",
"chars": 1049,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/setconf.c",
"chars": 4253,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/show.c",
"chars": 14984,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/showconf.c",
"chars": 2864,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/subcommands.h",
"chars": 503,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/systemd/wg-quick.target",
"chars": 53,
"preview": "[Unit]\nDescription=WireGuard Tunnels via wg-quick(8)\n"
},
{
"path": "src/systemd/wg-quick@.service",
"chars": 794,
"preview": "[Unit]\nDescription=WireGuard via wg-quick(8) for %I\nBefore=wg-quick.target\nAfter=network-online.target nss-lookup.target"
},
{
"path": "src/terminal.c",
"chars": 1373,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/terminal.h",
"chars": 1617,
"preview": "/* SPDX-License-Identifier: GPL-2.0 OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Ri"
},
{
"path": "src/uapi/freebsd/dev/wg/if_wg.h",
"chars": 281,
"preview": "#ifndef __IF_WG_H__\n#define __IF_WG_H__\n\n#include <net/if.h>\n#include <netinet/in.h>\n\nstruct wg_data_io {\n\tchar wgd_name"
},
{
"path": "src/uapi/linux/linux/wireguard.h",
"chars": 8187,
"preview": "/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld"
},
{
"path": "src/uapi/openbsd/net/if_wg.h",
"chars": 2202,
"preview": "/* SPDX-License-Identifier: ISC */\n/*\n * Copyright (C) 2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n "
},
{
"path": "src/uapi/windows/wireguard.h",
"chars": 2125,
"preview": "/* SPDX-License-Identifier: GPL-2.0\n *\n * Copyright (C) 2021 WireGuard LLC. All Rights Reserved.\n */\n\n#ifndef _WIREGUARD"
},
{
"path": "src/version.h",
"chars": 86,
"preview": "#ifndef WIREGUARD_TOOLS_VERSION\n#define WIREGUARD_TOOLS_VERSION \"1.0.20260223\"\n#endif\n"
},
{
"path": "src/wg-quick/android.c",
"chars": 38424,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/wg-quick/darwin.bash",
"chars": 16344,
"preview": "#!/usr/bin/env bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>."
},
{
"path": "src/wg-quick/freebsd.bash",
"chars": 14693,
"preview": "#!/usr/local/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com"
},
{
"path": "src/wg-quick/linux.bash",
"chars": 13784,
"preview": "#!/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rig"
},
{
"path": "src/wg-quick/openbsd.bash",
"chars": 14530,
"preview": "#!/usr/local/bin/bash\n# SPDX-License-Identifier: GPL-2.0\n#\n# Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com"
},
{
"path": "src/wg.c",
"chars": 2443,
"preview": "// SPDX-License-Identifier: GPL-2.0 OR MIT\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Right"
},
{
"path": "src/wincompat/compat.h",
"chars": 599,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/wincompat/include/arpa/inet.h",
"chars": 0,
"preview": ""
},
{
"path": "src/wincompat/include/hashtable.h",
"chars": 1416,
"preview": "/* SPDX-License-Identifier: GPL-2.0\n *\n * Copyright (C) 2018-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/wincompat/include/net/if.h",
"chars": 0,
"preview": ""
},
{
"path": "src/wincompat/include/netdb.h",
"chars": 0,
"preview": ""
},
{
"path": "src/wincompat/include/netinet/in.h",
"chars": 0,
"preview": ""
},
{
"path": "src/wincompat/include/sys/socket.h",
"chars": 0,
"preview": ""
},
{
"path": "src/wincompat/init.c",
"chars": 1038,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/wincompat/libc.c",
"chars": 1254,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/wincompat/load_config.c",
"chars": 800,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld. All Rights Reserved.\n *\n * This he"
},
{
"path": "src/wincompat/loader.c",
"chars": 530,
"preview": "// SPDX-License-Identifier: GPL-2.0\n/*\n * Copyright (C) 2015-2026 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reser"
},
{
"path": "src/wincompat/manifest.xml",
"chars": 767,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersi"
},
{
"path": "src/wincompat/resources.rc",
"chars": 1103,
"preview": "/* SPDX-License-Identifier: GPL-2.0\n *\n * Copyright (C) 2020-2026 Jason A. Donenfeld. All Rights Reserved.\n */\n\n#include"
}
]
About this extraction
This page contains the full source code of the WireGuard/wireguard-tools GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 125 files (494.1 KB), approximately 167.2k tokens, and a symbol index with 619 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.