[GH-ISSUE #162] AWG 2.0 ranged headers (e939553) removed per-peer advanced_security checks, breaking legacy WireGuard client support #99

Open
opened 2026-10-13 21:06:30 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @otternetwork on GitHub (Apr 5, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amneziawg-linux-kernel-module/issues/162

Commit e939553f72 ("feat: implement H1-H4 ranged headers", part of PR #88 / AWG 2.0) removed the per-peer advanced_security conditional logic that was introduced in commit 8eb278b208 ("Support for legacy clients", PR #16). As a result, an AmneziaWG server with custom obfuscation parameters (H1-H4, S1-S2) can no longer communicate with standard WireGuard clients on the same interface.

PR #16 (Sep 2024) added the ability for AmneziaWG to operate in a mixed mode: standard WireGuard peers received standard message headers (MESSAGE_HANDSHAKE_INITIATION=1, MESSAGE_HANDSHAKE_RESPONSE=2, etc.), while AmneziaWG peers received obfuscated headers. This was implemented via:

  1. A peer->advanced_security boolean on each peer
  2. Conditional send paths in send.c: peer->advanced_security ? custom_header : standard_header
  3. Auto-detection in noise.c: setting peer->advanced_security based on whether the incoming handshake used a custom magic header
  4. Cookie response logic that matched the header type of the incoming packet

What broke

The ranged headers refactoring replaced all conditional per-peer logic with unconditional mh_genheader() calls:

src/send.c — handshake initiation (before):

if (wg_noise_handshake_create_initiation(&packet, &peer->handshake,
  peer->advanced_security ?
	  wg->advanced_security_config.init_packet_magic_header :
	  MESSAGE_HANDSHAKE_INITIATION))

After:

if (wg_noise_handshake_create_initiation(&packet, &peer->handshake,
  mh_genheader(&wg->headers[MSGIDX_HANDSHAKE_INIT])))

The same removal happened for:

  • Response headers (wg_packet_send_handshake_response)
  • Cookie headers (wg_packet_send_handshake_cookie) — removed the logic that sent standard cookies in response to standard handshake packets
  • Transport data headers (wg_packet_encrypt_worker)
  • Junk packet gating — was wg->...advanced_security && peer->advanced_security, now only checks device-level flag

Additionally, wg_packet_encrypt_worker appears to have a merge artifact/syntax error with a leftover ternary fragment:

encrypt_packet(
  mh_genheader(&wg->headers[MSGIDX_TRANSPORT]),
  wg->advanced_security_config.transport_packet_magic_header : MESSAGE_DATA,  // ← broken

Dead code

peer->advanced_security still exists in peer.h, is still set in noise.c (via mh_validate), and is still read/written via netlink WGPEER_A_ADVANCED_SECURITY / WGPEER_F_HAS_ADVANCED_SECURITY). However, no code in send.c or receive.c consults it anymore. The entire per-peer flag infrastructure is dead code.

Impact

When custom AmneziaWG parameters are configured (H1-H4 ≠ default, S1/S2 > 0):

  • Send path: All peers receive obfuscated headers regardless of their capabilities. Standard WireGuard clients cannot parse these packets.
  • Receive path: The new prepare_awg_message() function couples size matching with junk sizes. Standard WireGuard packets (no junk prefix) fail size checks and are dropped as "Unknown message."
  • Mixed-mode operation is impossible: An AmneziaWG server cannot simultaneously serve both AmneziaWG and standard WireGuard peers.

Suggested fix

Restore per-peer advanced_security checks in the send and receive paths, adapted for the new mh_genheader/mh_validate API. When peer->advanced_security is false, send standard WireGuard message types and skip junk packet prepending.
The receive path should continue accepting both standard and custom headers (as 8eb278b intended).

Originally created by @otternetwork on GitHub (Apr 5, 2026). Original GitHub issue: https://github.com/amnezia-vpn/amneziawg-linux-kernel-module/issues/162 Commit e939553f7225e131849c2a1e8c73c6844cbda4ce ("feat: implement H1-H4 ranged headers", part of PR #88 / AWG 2.0) removed the per-peer advanced_security conditional logic that was introduced in commit 8eb278b2088033c4724b42b722e5ae49637a6f9f ("Support for legacy clients", PR #16). As a result, an AmneziaWG server with custom obfuscation parameters (H1-H4, S1-S2) can no longer communicate with standard WireGuard clients on the same interface. PR #16 (Sep 2024) added the ability for AmneziaWG to operate in a mixed mode: standard WireGuard peers received standard message headers (MESSAGE_HANDSHAKE_INITIATION=1, MESSAGE_HANDSHAKE_RESPONSE=2, etc.), while AmneziaWG peers received obfuscated headers. This was implemented via: 1. A `peer->advanced_security boolean` on each peer 2. Conditional send paths in `send.c`: `peer->advanced_security ? custom_header : standard_header` 3. Auto-detection in `noise.c`: setting `peer->advanced_security` based on whether the incoming handshake used a custom magic header 4. Cookie response logic that matched the header type of the incoming packet ## What broke The ranged headers refactoring replaced all conditional per-peer logic with unconditional `mh_genheader()` calls: `src/send.c` — handshake initiation (before): ```c if (wg_noise_handshake_create_initiation(&packet, &peer->handshake, peer->advanced_security ? wg->advanced_security_config.init_packet_magic_header : MESSAGE_HANDSHAKE_INITIATION)) ``` After: ```c if (wg_noise_handshake_create_initiation(&packet, &peer->handshake, mh_genheader(&wg->headers[MSGIDX_HANDSHAKE_INIT]))) ``` The same removal happened for: - Response headers (`wg_packet_send_handshake_response`) - Cookie headers (`wg_packet_send_handshake_cookie`) — removed the logic that sent standard cookies in response to standard handshake packets - Transport data headers (`wg_packet_encrypt_worker`) - Junk packet gating — was `wg->...advanced_security && peer->advanced_security`, now only checks device-level flag Additionally, `wg_packet_encrypt_worker` appears to have a merge artifact/syntax error with a leftover ternary fragment: ```c encrypt_packet( mh_genheader(&wg->headers[MSGIDX_TRANSPORT]), wg->advanced_security_config.transport_packet_magic_header : MESSAGE_DATA, // ← broken ``` ## Dead code `peer->advanced_security` still exists in `peer.h`, is still set in `noise.c` (via `mh_validate`), and is still read/written via netlink WGPEER_A_ADVANCED_SECURITY / WGPEER_F_HAS_ADVANCED_SECURITY). However, no code in `send.c` or `receive.c` consults it anymore. The entire per-peer flag infrastructure is dead code. ## Impact When custom AmneziaWG parameters are configured (H1-H4 ≠ default, S1/S2 > 0): - Send path: All peers receive obfuscated headers regardless of their capabilities. Standard WireGuard clients cannot parse these packets. - Receive path: The new `prepare_awg_message()` function couples size matching with junk sizes. Standard WireGuard packets (no junk prefix) fail size checks and are dropped as "Unknown message." - Mixed-mode operation is impossible: An AmneziaWG server cannot simultaneously serve both AmneziaWG and standard WireGuard peers. ## Suggested fix Restore per-peer `advanced_security` checks in the send and receive paths, adapted for the new `mh_genheader`/`mh_validate` API. When `peer->advanced_security` is false, send standard WireGuard message types and skip junk packet prepending. The receive path should continue accepting both standard and custom headers (as 8eb278b intended).
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amnezia-vpn/amneziawg-linux-kernel-module#99
No description provided.