kmod-amneziawg: add AmneziaWG kernel module package - #30492
Conversation
3d46569 to
cd182d0
Compare
cd182d0 to
76e0c31
Compare
|
Thanks for this endeavour, I'm sure it would be appreciated by many OpenWrt users. FWIW regarding the luci app -- as far as I remember the previous discussions, there was a strong preference from the core team to adjust the luci-app-wireguard to support additional amneziawg options, rather than duplicating the code of the existing app into luci-app-amneziawg. |
|
Thanks, that makes sense, and I agree that avoiding a duplicated LuCI implementation would be preferable. There is one part I am not yet sure how you would prefer to handle: the existing AmneziaWG uses So I think sharing the existing WireGuard LuCI code is possible, and I would actually prefer that if it is acceptable upstream, but it would require making the existing LuCI/rpcd implementation protocol-aware rather than simply adding the AWG options to the WireGuard form. For example, the common code could select Is this roughly the approach the core team had in mind? Also, what do you think about the overall approach of this integration and the way I am trying to keep the AmneziaWG-specific delta small and reviewable? |
|
What is different than in the last PR #26971 and others https://github.com/openwrt/packages/pulls?q=is%3Apr+state%3Aclosed+kmod-amneziawg ? 🤔 |
|
@BKPepe The main difference is that this time I am submitting the complete integration as a coordinated set of three parts:
They are maintained together in one repository, and the OpenWrt package sources are generated from the corresponding WireGuard packages in a staged way. This makes the AmneziaWG-specific delta explicit and easier to review. I also track upstream changes in both WireGuard/OpenWrt and AmneziaWG, so the generated packages can be kept in sync instead of drifting as independent copies. In addition, I use these packages myself, and around 30 other users are currently using them as well. So far we have not encountered any known issues with the integration. So compared to the previous PRs, this is intended as a complete, actively used, and maintainable integration rather than separate one-off package submissions. |
|
Sorry, but from your response I am kinda confused. For LuCI:
For packages repository:
Well, I am not sure how they are maintained in one repository as looking into the PKG_SOURCE_URL, but fine, maybe the AI prompt was not right. Even thought, all previous attempts were complete and actively used as well. |
|
@BKPepe You're right, my previous wording was unclear. By "maintained together in one repository" I did not mean that the upstream source code of the kernel module and tools lives in the same repository. What I meant is that I maintain the OpenWrt integration for all three parts in one repository:
I also did not mean to imply that the previous attempts were incomplete or unused. I understand that there were several complete attempts before. The main difference in my approach is the maintenance model. The OpenWrt packages are generated from the corresponding WireGuard packages in stages, so I can regularly track changes in the OpenWrt WireGuard implementation and keep the AmneziaWG-specific delta small and explicit. For example, the generation process separates:
This makes it easier for me to see what really differs from WireGuard and to update the packages when either OpenWrt WireGuard or AmneziaWG changes. So the difference I was trying to describe is not that this is the first complete or actively used attempt, but rather that I am trying to provide a reproducible maintenance process for keeping all three parts synchronized over time. https://github.com/karen07/amneziawg-openwrt-package https://github.com/karen07/amneziawg-openwrt-package/blob/main/generate.py |
|
@BKPepe Thanks for the clarification. Then I think the most useful question from my side is: what exactly would need to be changed or improved for AmneziaWG support to be acceptable for inclusion in OpenWrt? There have already been several attempts over the years, so I would really like to understand whether there are still concrete technical or maintenance blockers, and what you would prefer to see addressed. I am happy to rework the integration if needed. For example, if the preferred approach for LuCI is to share more code with My goal is not just to submit another version of the same PR, but to understand the upstream expectations and maintain the packages accordingly. This support is also quite important in practice. AmneziaWG is widely used by people in Russia and other places where ordinary WireGuard traffic may be blocked or filtered, so having the packages available directly from the official OpenWrt repositories would make a significant difference for users. If there are specific requirements that would make these packages mergeable, please let me know and I will try to address them. |
| FILES:=$(PKG_BUILD_DIR)/$(MAKE_PATH)/amneziawg.ko | ||
| DEPENDS:= \ | ||
| +kmod-udptunnel4 \ | ||
| +kmod-udptunnel6 \ |
There was a problem hiding this comment.
kmod-udptunnel6 is declared DEPENDS:=@IPV6, so an unconditional dependency makes kmod-amneziawg unselectable on IPv6-disabled builds. Use the conditional form, like kmod-wireguard and kernel/ovpn-dco.
| +kmod-udptunnel6 \ | |
| +IPV6:kmod-udptunnel6 \ |
Generated by Claude Code
There was a problem hiding this comment.
|
|
||
| PKG_BUILD_PARALLEL:=1 | ||
|
|
||
| MAKE_PATH:=src |
There was a problem hiding this comment.
The module is built in $(PKG_BUILD_DIR)/src, but PKG_EXTMOD_SUBDIRS is left at its default ., so collect_module_symvers looks for Module.symvers/modules.order in the build-dir root and stores an empty symvers file for this package. Set it too, the way kernel/ovpn-dco and net/batman-adv do.
| MAKE_PATH:=src | |
| MAKE_PATH:=src | |
| PKG_EXTMOD_SUBDIRS:=src |
Generated by Claude Code
There was a problem hiding this comment.
| +kmod-udptunnel4 \ | ||
| +kmod-udptunnel6 \ | ||
| +kmod-crypto-lib-chacha20poly1305 \ | ||
| +kmod-crypto-lib-curve25519 |
There was a problem hiding this comment.
No AUTOLOAD here, while kmod-wireguard and the other out-of-tree kmods in this feed (kernel/ovpn-dco, net/siit, net/jool) all set one. The v3.1.20260906 sources do carry MODULE_ALIAS_RTNL_LINK / MODULE_ALIAS_GENL_FAMILY, so on-demand probing should work — is omitting AUTOLOAD:=$(call AutoProbe,amneziawg) intentional?
Generated by Claude Code
There was a problem hiding this comment.
| SECTION:=kernel | ||
| CATEGORY:=Kernel modules | ||
| SUBMENU:=Network Support | ||
| TITLE:=AmneziaWG VPN Kernel Module |
There was a problem hiding this comment.
nit: two things on this block:
SECTIONandCATEGORYare already set for everyKernelPackageby kernel.mk.- A
define KernelPackage/<name>metadata block is indented with two spaces rather than tabs; same for theFILES/DEPENDSlines below.
| SECTION:=kernel | |
| CATEGORY:=Kernel modules | |
| SUBMENU:=Network Support | |
| TITLE:=AmneziaWG VPN Kernel Module | |
| SUBMENU:=Network Support | |
| TITLE:=AmneziaWG VPN Kernel Module |
Generated by Claude Code
There was a problem hiding this comment.
| PKG_VERSION:=3.1.20260906 | ||
| PKG_RELEASE:=1 | ||
|
|
||
| PKG_SOURCE_PROTO:=git |
There was a problem hiding this comment.
Optional: PKG_SOURCE_PROTO:=git is meant as a last resort when upstream ships no archives, and upstream tags releases here. The usual form in this feed is a tarball plus PKG_HASH, e.g. PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz with PKG_SOURCE_URL:=https://codeload.github.com/amnezia-vpn/amneziawg-linux-kernel-module/tar.gz/v$(PKG_VERSION)?, which also drops PKG_MIRROR_HASH.
Generated by Claude Code
There was a problem hiding this comment.
fixed, thanks — solved with the archive/refs/tags/ + PKG_SOURCE_URL_FILE form rather than codeload, which works equally well.
Generated by Claude Code
| include $(TOPDIR)/rules.mk | ||
| include $(INCLUDE_DIR)/kernel.mk | ||
|
|
||
| PKG_NAME:=kmod-amneziawg |
There was a problem hiding this comment.
nit: no other package in this feed carries a kmod- prefix in PKG_NAME or in its directory name — kernel-module packages are named after the source (kernel/ovpn-dco → ovpn-backports, net/batman-adv, kernel/mdio-netlink). PKG_NAME:=amneziawg still produces the kmod-amneziawg package through $(eval $(call KernelPackage,amneziawg)).
Generated by Claude Code
There was a problem hiding this comment.
fixed, thanks — solved by renaming both PKG_NAME and the directory to amneziawg.
Generated by Claude Code
76e0c31 to
fd6bca0
Compare
fd6bca0 to
dae00d4
Compare
| PKG_SOURCE_URL:=https://github.com/amnezia-vpn/amneziawg-linux-kernel-module/archive/refs/tags/ | ||
| PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz | ||
| PKG_HASH:=e32fa46f1b6f9e319c5261f0b0765c3a9261e40cb7c4616fd73500da961a2932 | ||
| PKG_BUILD_DIR:=$(BUILD_DIR)/amneziawg-linux-kernel-module-$(PKG_VERSION) |
There was a problem hiding this comment.
$(BUILD_DIR) is shared by every subtarget of the same arch (ath79/generic and ath79/nand are both mips_24kc), so an out-of-tree module built here is reused against a different kernel and is not removed by make target/linux/clean — which is why kernel.mk defaults kmod build dirs to $(KERNEL_BUILD_DIR). Keep the override under it, as net/jool/Makefile:23 does.
| PKG_BUILD_DIR:=$(BUILD_DIR)/amneziawg-linux-kernel-module-$(PKG_VERSION) | |
| PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/amneziawg-linux-kernel-module-$(PKG_VERSION) |
Generated by Claude Code
There was a problem hiding this comment.
dae00d4 to
1d67cff
Compare
|
@BKPepe @stangri, I fixed all the issues raised by the @openwrt-ai reviewer. |
|
@neheb @1715173329 @hnyman Could you please take a look at this PR? |
|
|
||
| PKG_SOURCE:=amneziawg-linux-kernel-module-$(PKG_VERSION).tar.gz | ||
| PKG_SOURCE_URL:=https://github.com/amnezia-vpn/amneziawg-linux-kernel-module/archive/refs/tags/ | ||
| PKG_SOURCE_URL_FILE:=v$(PKG_VERSION).tar.gz |
| endef | ||
|
|
||
| define KernelPackage/amneziawg/description | ||
| AmneziaWG VPN kernel module. |
There was a problem hiding this comment.
This is quite short description, it looks like as TITLE.
|
Look, you've just dropped two massive essays here within a few minutes, and it's honestly really hard to parse through because, first of all, it was clearly written by AI, and second, you aren't actually answering what I asked. 🤷 Maybe, you'll need to tweak your AI prompts a lot.
Also, it’s definitely not appropriate to mass-ping people for a review just 2 days after opening a pull request. According to Repology, barely any distributions package AmneziaWG anyway. |
|
Hi, just adding a user perspective here. I use OpenWrt in networks where plain WireGuard gets filtered and becomes unreliable, while AmneziaWG works fine for the same use case. For me this has nothing to do with the commercial Amnezia VPN service. I use AWG in a fully self-hosted setup. Right now this means relying on third-party packages. Having the kernel module and tools in the official OpenWrt packages would make the setup much simpler and more accessible for users who don’t want to maintain their own builds or feeds |
|
I think the main missing context here is what AWG actually changes compared to WG, and why those changes exist in the first place. Why AWG exists when WG already existsPlain WireGuard is very easy to fingerprint on the wire. A standard WG handshake initiation packet has a fixed size of 148 bytes and starts with:
The handshake response has a fixed size of 92 bytes and starts with:
So even a very simple first-pass detector can look for a characteristic pattern such as:
There is no need to break the encryption, know the keys, or perform particularly sophisticated DPI. These are observable properties of the WireGuard wire protocol itself. In Russia, this stopped being a theoretical problem a long time ago. Protocol-level filtering of WireGuard has been observed for years, and in 2023 there were widespread reports of plain WG being blocked across multiple Russian networks. This is exactly the problem AWG is intended to solve. AWG keeps the cryptographic foundation and much of the architecture of WireGuard, but deliberately changes the protocol properties that DPI can observe on the wire. And the differences are no longer limited to just a couple of additional parameters. What AWG actually adds on top of WGLet me start with the simpler mechanisms.
So instead of the first characteristic packet in a flow immediately being a standard 148-byte WG handshake, there may be a variable number of packets of varying sizes before it. Then there are
This directly removes one of the simplest fingerprints of standard WireGuard: fixed message sizes. WG initiation is 148 bytes, and the response is 92 bytes. With AWG, those message sizes no longer have to match the standard values. The next group is In standard WireGuard, every packet starts with a 32-bit message type:
That is why you see the characteristic:
and:
on the wire. AWG allows those values to be changed:
Modern AWG versions can also use ranges rather than just one fixed value. So another very simple WireGuard fingerprint — fixed message types Then there are These are not just padding applied to existing WireGuard packets. AWG can send up to five additional custom packets before the handshake. Each
So the beginning of a connection no longer necessarily looks like the beginning of a WireGuard flow at all. AWG 3 also introduced This is a separate 32-byte key used for header protection. Its purpose is to protect low-entropy packet-header fields that would otherwise remain convenient classification signals. When header protection is enabled, Another parameter is It adds additional variable padding to packet contents. This can be specified as a range, for example something conceptually like:
rather than as a single constant value. That makes packet-size fingerprints even less stable: the same logical traffic does not necessarily produce packets of the same size every time. AWG also allows the timing behavior of WireGuard to be changed. For that, it adds parameters such as:
and the normal WG The idea is the same: avoid stable and easily recognizable timing patterns. AWG 3.1 added further mechanisms.
There is also a per-peer So if we reduce this to observable properties, plain WG gives DPI a fairly stable picture:
AWG allows nearly all of those characteristics to be changed:
So the question "why not just use WireGuard?" has a very concrete technical answer: if a network filters standard WireGuard by its wire fingerprint, continuing to use the same wire protocol does not solve the problem. This is not a paid Amnezia serviceI also think two very different things are being conflated here: the commercial Amnezia VPN service and AmneziaWG as an open-source protocol implementation. The packages in these PRs are for the open-source Using AWG does not require:
AWG can be fully self-hosted. That is exactly how I use it myself. I maintain my own OpenWrt AWG packages here: https://github.com/karen07/amneziawg-openwrt-package and my own deployment here: https://github.com/karen07/openwrt-mesh-builder I deploy and control both ends myself: the OpenWrt nodes and the servers. There is no paid Amnezia service involved anywhere in that setup. There are other self-hosted deployment options as well, including Docker-based deployments. More importantly, AWG does not even have to be used in a traditional:
model. For example, I use AWG simply as a secure infrastructure link between my own routers and servers. So it is more accurate to think of AWG primarily as an independent WireGuard-derived protocol implementation, not as a client for some paid VPN service. For my own infrastructure, inclusion of these packages in the official OpenWrt feed is not even necessary: I already have my own packages, builder and working deployment. I am upstreaming this because there are many OpenWrt users in Russia who need AWG directly on their routers because plain WG is filtered, and most of those users are not going to maintain their own kernel module, userspace tools, LuCI integration and OpenWrt package feed. Why AWG needs separate packagesHere I actually agree with part of the concern: the OpenWrt integration for WG and AWG is indeed very similar. That is intentional. AWG is derived from WireGuard. They have essentially the same model for:
There is no reason to rewrite all of that from scratch just to make it look different. In fact, my It starts from the WireGuard-based OpenWrt integration, performs the mechanical WG -> AWG transformation separately, and only then adds the AWG-specific functionality. This compare shows exactly that substantive delta: This is important: the starting commit in that compare is already the state after the normal WireGuard -> AmneziaWG renaming has been done. So the diff is not thousands of lines of:
or file and namespace renames. It specifically shows what actually needs to be added on top of the WireGuard integration in order to support AWG. You can see the new AWG configuration fields, range types, handling of the additional parameters, their propagation through netifd/LuCI/userspace interfaces, and the other pieces required for AWG-specific protocol functionality. So the statement that "essentially they will be two nearly identical packages" is true in one sense: at the OpenWrt integration level, they should remain as similar as possible. I consider that an advantage. The smaller the independent delta from the existing WireGuard integration, the easier it is to read, review and maintain. But that does not mean the backend is the same. It is not: WG:
AWG:
The Stock
AWG-specific timing ranges
or the other AWG protocol extensions. So simply adding these fields to LuCI or UCI while continuing to use ordinary The UI could store That is why a separate kernel module and the matching userspace control tool are required. Can WG and AWG be used side by side?Yes. And this is not theoretical either. WG uses:
AWG uses:
They are separate kernel modules, separate interface types and separate userspace tools. Installing AWG does not replace They can be installed and used at the same time on the same system. My own deployment is a practical example of exactly that setup. I use AWG for infrastructure links between nodes, while ordinary WG is used for access VPN. So on the same OpenWrt router you can have, for example:
and:
with each serving a different purpose. There is no requirement to choose "either WG or AWG". WG and AWG compatibilityThere is another relevant detail here. AWG is derived from WG and, with the appropriate configuration, can operate in a WG-compatible mode. In other words, if the AWG-specific protocol modifications are effectively disabled and the standard WG values are used, the AWG implementation can behave like ordinary WireGuard. The reverse is not true. Stock WireGuard cannot suddenly understand a connection using AWG-specific:
Stock WireGuard simply does not implement those extensions. So, very roughly, the relationship is:
but:
That is another reason why having a separate implementation is natural here. To answer the two questions directly
Because AWG is not a paid VPN service and not just another frontend for WireGuard. It is a self-hostable WireGuard-derived protocol implementation specifically designed to change the wire-level characteristics that make plain WG very easy to fingerprint and block. Where plain WG works, you can continue using WG. Where the standard WG fingerprint is filtered, you need different wire behavior — and that is what AWG exists for.
The OpenWrt integration is intentionally kept as close as possible to WireGuard, and the compare above shows the relatively small AWG-specific delta without the noise of mechanical renaming. But the backend is different because the changes are part of the wire protocol itself. WG uses AWG uses They do not replace each other, they do not require choosing one over the other, and they can run side by side on the same OpenWrt router. That is exactly how I already use them in my own deployment. |
1d67cff to
7b0157d
Compare
|
Great initiative! |
|
Honestly, that AI-written comment of yours is too long, and I’m going to spend way more time reading it than I would the actual source code you’re adding. I think you might want to tame that AI in a little bit. I’d genuinely love to know who actually read the whole thing. 😄 |
|
I personally reread and rewrote that reply about ten times, trying to choose every word carefully. I didn’t want to just formally respond to the comments — I wanted to properly explain what exactly differs between WireGuard and AmneziaWG, what additional features AWG introduces, why they are needed, and why some parts of the package are implemented the way they are. I mainly use AI to translate from Russian into English. The content, technical arguments, and the points I want to get across are my own) |
AmneziaWG is a WireGuard-based VPN protocol with additional traffic obfuscation features designed to make VPN traffic harder to identify and block. This package provides the AmneziaWG Linux kernel module for OpenWrt. Signed-off-by: Karen Khachatryan <karen0734@gmail.com>
7b0157d to
a5360f1
Compare
Lots of people in Russia use AWG as a replacement for WG - just as a VPN protocol, that cannot be filtered by government. WG tunnel don't live even several hours here. |
|
Is there anything else I should explain or fix? |
|
Hi! I would really appreciate having AmneziaWG support in OpenWrt. I run my own AWG server, so being able to connect to it directly from my router would be very useful and convenient. Thanks for your work on this! |
AmneziaWG OpenWrt integration — 1/3
This PR adds the
kmod-amneziawgpackage.It is the first part of a complete AmneziaWG integration for OpenWrt:
The related PRs will be linked here once submitted.
Maintenance approach
I maintain the complete integration here:
https://github.com/karen07/amneziawg-openwrt-package
The repository is built around a generator:
https://github.com/karen07/amneziawg-openwrt-package/blob/main/generate.py
The goal is to avoid maintaining a large, manually diverging copy of the
OpenWrt WireGuard integration.
generate.pyis the source of truth for the generated packages.For
amneziawg-toolsandluci-proto-amneziawg, the generator starts fromthe corresponding upstream OpenWrt / LuCI WireGuard packages, performs the
mechanical WireGuard-to-AmneziaWG transformations, and then applies only the
AmneziaWG-specific changes.
For review, the generation process can be stopped at separate stages:
This makes it possible to inspect separately:
This is intended to make both review and future maintenance easier: when the
OpenWrt or LuCI WireGuard integration changes, the AmneziaWG packages can be
regenerated from the new upstream baseline instead of manually rebasing a
large copied implementation.
kmod-amneziawg/Makefileis also generated by the same script from the pinnedAmneziaWG kernel-module version.
The generator is maintenance and review tooling only. The generated package
files are committed to Git, so OpenWrt does not need the generator at build
time.
Upstream tracking
The generator provides:
to check whether a newer AmneziaWG kernel-module or tools release is available.
I currently run this check manually on a regular basis (normally daily).
When a new upstream version appears, the script stops and requires the version
change to be reviewed explicitly before regeneration, rather than silently
updating to an unreviewed upstream revision.
AmneziaWG sources are pinned to official upstream release tags.
Build and testing workflow
The repository contains an OpenWrt SDK build workflow and a GitHub Actions
target/subtarget matrix for building the generated packages across OpenWrt
targets.
The same repository can also build and install the packages directly on an
OpenWrt device for local testing.
I use this AmneziaWG OpenWrt integration myself, so it is maintained as a
working deployment rather than only as a packaging experiment.
Previous submissions
This is a renewed attempt to bring AmneziaWG support to OpenWrt, with a focus
on addressing the long-term maintenance and reviewability concerns raised
around previous submissions.
Related previous work:
kmod-amneziawgamneziawg-toolsThe reproducible generation approach is specifically intended to keep the
WireGuard-derived parts synchronized with OpenWrt/LuCI upstream while keeping
the AmneziaWG-specific changes small and auditable.
PR series
Once all parts are submitted, this section will link the complete series:
kmod-amneziawg— this PRamneziawg-toolsluci-proto-amneziawg— TODO