[GH-ISSUE #3271] [Linux] Dual-stack Address (IPv4 + IPv6) in imported WireGuard/AWG config → garbage IPv4 on amn0, no internet #1517

Open
opened 2026-10-13 20:44:08 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @wansiedler on GitHub (Oct 10, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3271

Describe the bug

On Linux, importing a WireGuard/AmneziaWG .conf whose [Interface] Address contains both an IPv4 and an IPv6 address (dual-stack) results in a tunnel interface with a garbage IPv4 address. The tunnel comes up, the kill switch blocks everything outside it, and the server drops all packets because their source IP is wrong. The result: as soon as you connect, the whole machine loses internet access.

Same root cause as #1630 (macOS), but on Linux the symptom is worse: a random IPv4 ends up on amn0.

To Reproduce

  1. Import a third-party AmneziaWG config (here: a commercial provider) with:
    [Interface]
    Address = 10.142.213.12,fd64:e20:68a3::e:d50c
    DNS = 10.0.0.21
    Jc = 4
    Jmin = 40
    Jmax = 67
    S1 = 0
    S2 = 0
    H1 = 1
    H2 = 2
    H3 = 3
    H4 = 4
    
    After import, the stored last_config contains
    "client_ip": "10.142.213.12/32, fd64:e20:68a3::e:d50c/128".
  2. Connect.
  3. Check the interface:
    $ ip -br a show amn0
    amn0  UNKNOWN  62.86.0.0/32 fd58:baa6:dead::1/64 ...
    $ ping -c3 1.1.1.1
    3 packets transmitted, 0 received, 100% packet loss
    
    62.86.0.0 appears nowhere in the config. It is uninitialised memory (see below). The value differs between runs/machines.

Expected behavior

amn0 gets 10.142.213.12/32 (and ideally the configured IPv6 address), and traffic flows.

Root cause (current dev, 4c2e950)

  1. client/core/controllers/selfhosted/importController.cpp:572 stores the entire Address value (both addresses, comma-separated) in configKey::clientIp:
    lastConfig[configKey::clientIp] = configMap.value(protocols::wireguard::Address);
    
  2. client/mozilla/localsocketcontroller.cpp:141 passes that string unchanged as deviceIpv4Address, and line 151 always hardcodes deviceIpv6Address = "fd58:baa6:dead::1". The configured IPv6 address is thrown away.
  3. client/platforms/linux/daemon/iputilslinux.cpp:84 runs QHostAddress::parseSubnet("10.142.213.12/32, fd64:..."). That fails and returns a null address, toString() gives "", and inet_pton() fails. Its return value is never checked, so ifr (with its uninitialised sin_addr) is still passed to ioctl(SIOCSIFADDR), which assigns a garbage address.

Suggested fix:

  • Split Address on , during import (or when building the activate message), and send the IPv4 entry as deviceIpv4Address and the IPv6 entry as deviceIpv6Address. Fall back to the ULA only when no IPv6 address is configured.
  • In IPUtilsLinux::addIP4AddressToDevice (and the macOS equivalent), check that parseSubnet succeeded and that inet_pton() == 1, and fail the activation with a clear error instead of assigning garbage.

Workaround

Remove the IPv6 address from Address (Address = 10.142.213.12/32) and re-import. With that change the connection works.

Related

  • #1630: same dual-stack Address problem on macOS
  • #2539: configured IPv6 address dropped, fd58:baa6:dead::1 used as fallback
  • The daemon log also shows Adding exclusion route for /999999 → Invalid destination prefix on every connect (an empty exclusion entry). This looks harmless but is noise.

Desktop

  • OS: SteamOS 3 (holo, Arch-based), kernel 6.18 (valve), NetworkManager + systemd-resolved, Tailscale also running
  • AmneziaVPN version: 5.0.3.0 (Linux installer)
  • Protocol: AmneziaWG (amnezia-awg), imported from a .conf file

Log (daemon, excerpt)

WireguardUtilsLinux : Created wireguard interface amn0
LinuxFirewall : 100.blockAll(IPv4): OFF -> ON
LinuxRouteMonitor : Adding exclusion route for <endpoint>/32
WireguardUtilsLinux : Configuring peer <pubkey> via <endpoint>
LinuxRouteMonitor : Adding exclusion route for /999999
[WARNING] LinuxRouteMonitor : Invalid destination prefix
DnsUtilsLinux : Adding DNS resolver 10.0.0.21 via amn0
LinuxRouteMonitor : Adding route to 0.0.0.0/1
LinuxRouteMonitor : Adding route to 128.0.0.0/1
Daemon : Checking for handshake...
Originally created by @wansiedler on GitHub (Oct 10, 2026). Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3271 **Describe the bug** On Linux, importing a WireGuard/AmneziaWG `.conf` whose `[Interface] Address` contains both an IPv4 and an IPv6 address (dual-stack) results in a tunnel interface with a **garbage IPv4 address**. The tunnel comes up, the kill switch blocks everything outside it, and the server drops all packets because their source IP is wrong. The result: as soon as you connect, the whole machine loses internet access. Same root cause as #1630 (macOS), but on Linux the symptom is worse: a random IPv4 ends up on `amn0`. **To Reproduce** 1. Import a third-party AmneziaWG config (here: a commercial provider) with: ```ini [Interface] Address = 10.142.213.12,fd64:e20:68a3::e:d50c DNS = 10.0.0.21 Jc = 4 Jmin = 40 Jmax = 67 S1 = 0 S2 = 0 H1 = 1 H2 = 2 H3 = 3 H4 = 4 ``` After import, the stored `last_config` contains `"client_ip": "10.142.213.12/32, fd64:e20:68a3::e:d50c/128"`. 2. Connect. 3. Check the interface: ``` $ ip -br a show amn0 amn0 UNKNOWN 62.86.0.0/32 fd58:baa6:dead::1/64 ... $ ping -c3 1.1.1.1 3 packets transmitted, 0 received, 100% packet loss ``` `62.86.0.0` appears nowhere in the config. It is uninitialised memory (see below). The value differs between runs/machines. **Expected behavior** `amn0` gets `10.142.213.12/32` (and ideally the configured IPv6 address), and traffic flows. **Root cause (current `dev`, 4c2e950)** 1. `client/core/controllers/selfhosted/importController.cpp:572` stores the entire `Address` value (both addresses, comma-separated) in `configKey::clientIp`: ```cpp lastConfig[configKey::clientIp] = configMap.value(protocols::wireguard::Address); ``` 2. `client/mozilla/localsocketcontroller.cpp:141` passes that string unchanged as `deviceIpv4Address`, and line 151 always hardcodes `deviceIpv6Address = "fd58:baa6:dead::1"`. The configured IPv6 address is thrown away. 3. `client/platforms/linux/daemon/iputilslinux.cpp:84` runs `QHostAddress::parseSubnet("10.142.213.12/32, fd64:...")`. That fails and returns a null address, `toString()` gives `""`, and `inet_pton()` fails. Its return value is never checked, so `ifr` (with its uninitialised `sin_addr`) is still passed to `ioctl(SIOCSIFADDR)`, which assigns a garbage address. Suggested fix: - Split `Address` on `,` during import (or when building the activate message), and send the IPv4 entry as `deviceIpv4Address` and the IPv6 entry as `deviceIpv6Address`. Fall back to the ULA only when no IPv6 address is configured. - In `IPUtilsLinux::addIP4AddressToDevice` (and the macOS equivalent), check that `parseSubnet` succeeded and that `inet_pton() == 1`, and fail the activation with a clear error instead of assigning garbage. **Workaround** Remove the IPv6 address from `Address` (`Address = 10.142.213.12/32`) and re-import. With that change the connection works. **Related** - #1630: same dual-stack `Address` problem on macOS - #2539: configured IPv6 address dropped, `fd58:baa6:dead::1` used as fallback - The daemon log also shows `Adding exclusion route for /999999` → `Invalid destination prefix` on every connect (an empty exclusion entry). This looks harmless but is noise. **Desktop** - OS: SteamOS 3 (holo, Arch-based), kernel 6.18 (valve), NetworkManager + systemd-resolved, Tailscale also running - AmneziaVPN version: 5.0.3.0 (Linux installer) - Protocol: AmneziaWG (`amnezia-awg`), imported from a `.conf` file **Log (daemon, excerpt)** ``` WireguardUtilsLinux : Created wireguard interface amn0 LinuxFirewall : 100.blockAll(IPv4): OFF -> ON LinuxRouteMonitor : Adding exclusion route for <endpoint>/32 WireguardUtilsLinux : Configuring peer <pubkey> via <endpoint> LinuxRouteMonitor : Adding exclusion route for /999999 [WARNING] LinuxRouteMonitor : Invalid destination prefix DnsUtilsLinux : Adding DNS resolver 10.0.0.21 via amn0 LinuxRouteMonitor : Adding route to 0.0.0.0/1 LinuxRouteMonitor : Adding route to 128.0.0.0/1 Daemon : Checking for handshake... ```
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/amnezia-client#1517
No description provided.