[GH-ISSUE #3083] AmneziaVPN 5.0.1.5 (macOS, arm64): клиенту не присваивается собственный Address из конфига AmneziaWG — интерфейс получает IP шлюза вместо адреса из [Interf… #1427

Open
opened 2026-10-13 20:42:16 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @specialprojectskir-alt on GitHub (Aug 28, 2026).
Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3083

Environment

  • App version: 5.0.1.5 (7d4f3e0)
  • Previously working version: 4.8.21.0 (72ee32a) — same server, same network, same protocol
  • OS: macOS Tahoe 26.6 (arm64)
  • Server: self-hosted
  • Protocol/container: amnezia-awg2 (AmneziaWG)
  • Route mode: VpnAllExceptSites

Describe the bug

After upgrading from 4.8.21.0 to 5.0.1.5, the VPN connects successfully (handshake completes and status becomes "Connected"), but no traffic passes through the tunnel.

No websites load, and even a raw ping by IP (bypassing DNS) times out.

To Reproduce

  1. Connect to a self-hosted AmneziaWG server using 5.0.1.5.
  2. Wait for the "Connected" status (handshake completes successfully).
  3. Run ping 1.1.1.1 — 100% packet loss / timeout.
  4. Run ping ya.ru — DNS resolution fails because no traffic reaches the configured DNS servers.

The issue occurs both with and without site split tunneling enabled.

Root cause found

Comparing the client's exported AmneziaWG configuration against the actual state of the interface after connecting reveals a mismatch.

Config

The [Interface] section of the exported configuration contains:

Address = 10.8.1.3/32

Actual interface state

While connected on 5.0.1.5, ifconfig shows:

utun4: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1376
    inet 10.8.1.1 --> 10.8.1.1 netmask 0xffffffff

The interface is assigned 10.8.1.1 as both the local and point-to-point address, instead of the client's assigned 10.8.1.3 pointing to the gateway 10.8.1.1.

The expected state is:

inet 10.8.1.3 --> 10.8.1.1

This appears to cause outgoing packets to use the gateway's address as their source address, preventing traffic from being routed correctly despite the WireGuard handshake completing successfully.

Routing

Routing itself appears correct and does not seem to be the cause of the issue:

0/1       utun4       USc
default   utun4       UGScg
10.8.1.1  10.8.1.1    UH       utun4
128.0/1   utun4       USc      utun4

This is consistent with the standard WireGuard full-tunnel route split.

DNS

DNS is configured correctly at the system level (scutil --dns shows 1.1.1.1 / 1.0.0.1).

DNS resolution fails because no traffic appears to leave the machine through the tunnel, rather than because of a DNS configuration issue.

Expected behavior

ifconfig should show:

inet 10.8.1.3 --> 10.8.1.1

matching the Address field in the AmneziaWG configuration.

This is the behavior observed with the previously working version 4.8.21.0.

Additional notes

  • Tested with site split tunneling both enabled and disabled.
  • The underlying failure is identical in both configurations: the VPN reports "Connected", but no traffic passes through the tunnel.
  • With split tunneling disabled, the connection is established faster.
  • With split tunneling enabled, there is no meaningful difference in the final broken state.
Originally created by @specialprojectskir-alt on GitHub (Aug 28, 2026). Original GitHub issue: https://github.com/amnezia-vpn/amnezia-client/issues/3083 ## Environment * App version: 5.0.1.5 (7d4f3e0) * Previously working version: 4.8.21.0 (72ee32a) — same server, same network, same protocol * OS: macOS Tahoe 26.6 (arm64) * Server: self-hosted * Protocol/container: amnezia-awg2 (AmneziaWG) * Route mode: VpnAllExceptSites ## Describe the bug After upgrading from 4.8.21.0 to 5.0.1.5, the VPN connects successfully (handshake completes and status becomes "Connected"), but no traffic passes through the tunnel. No websites load, and even a raw ping by IP (bypassing DNS) times out. ## To Reproduce 1. Connect to a self-hosted AmneziaWG server using 5.0.1.5. 2. Wait for the "Connected" status (handshake completes successfully). 3. Run `ping 1.1.1.1` — 100% packet loss / timeout. 4. Run `ping ya.ru` — DNS resolution fails because no traffic reaches the configured DNS servers. The issue occurs both with and without site split tunneling enabled. ## Root cause found Comparing the client's exported AmneziaWG configuration against the actual state of the interface after connecting reveals a mismatch. ### Config The `[Interface]` section of the exported configuration contains: ```ini Address = 10.8.1.3/32 ``` ### Actual interface state While connected on 5.0.1.5, `ifconfig` shows: ```text utun4: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1376 inet 10.8.1.1 --> 10.8.1.1 netmask 0xffffffff ``` The interface is assigned `10.8.1.1` as both the local and point-to-point address, instead of the client's assigned `10.8.1.3` pointing to the gateway `10.8.1.1`. The expected state is: ```text inet 10.8.1.3 --> 10.8.1.1 ``` This appears to cause outgoing packets to use the gateway's address as their source address, preventing traffic from being routed correctly despite the WireGuard handshake completing successfully. ## Routing Routing itself appears correct and does not seem to be the cause of the issue: ```text 0/1 utun4 USc default utun4 UGScg 10.8.1.1 10.8.1.1 UH utun4 128.0/1 utun4 USc utun4 ``` This is consistent with the standard WireGuard full-tunnel route split. ## DNS DNS is configured correctly at the system level (`scutil --dns` shows `1.1.1.1` / `1.0.0.1`). DNS resolution fails because no traffic appears to leave the machine through the tunnel, rather than because of a DNS configuration issue. ## Expected behavior `ifconfig` should show: ```text inet 10.8.1.3 --> 10.8.1.1 ``` matching the `Address` field in the AmneziaWG configuration. This is the behavior observed with the previously working version 4.8.21.0. ## Additional notes * Tested with site split tunneling both enabled and disabled. * The underlying failure is identical in both configurations: the VPN reports "Connected", but no traffic passes through the tunnel. * With split tunneling disabled, the connection is established faster. * With split tunneling enabled, there is no meaningful difference in the final broken state.
Author
Owner

@HeisLuka commented on GitHub (Sep 9, 2026):

I checked this against current dev.

There are real source-level address handling problems here, but I think one distinction is important before attributing the observed .1 directly to the exported config.

First: the exported .conf is not necessarily the active peer

For a self-hosted server, exporting a native AWG configuration currently does not simply serialize the peer that the desktop client is using.

ExportController::generateNativeConfig() calls:

configurator->createConfig(...)

and then registers the returned client ID:

emit appendClientRequested(
    serverId,
    clientId,
    clientName,
    container);

For AWG/WireGuard, createConfig() allocates another peer/client address on the server.

Therefore this sequence is possible:

currently stored desktop peer:
    clientIp = 10.8.1.1

user exports a native config:
    a new peer is allocated
    Address = 10.8.1.3/32

So:

exported Address = 10.8.1.3
runtime utun     = 10.8.1.1

does not by itself prove that the runtime ignored the Address = 10.8.1.3 line.

They may be two different peers.

That is worth separating from the actual runtime bug.

Runtime does not use [Interface] Address as its authoritative value

For desktop AWG/WireGuard, LocalSocketController::activate() obtains the local address from the structured configuration:

QJsonObject wgConfig =
    rawConfig.value(protocolName + "_config_data").toObject();

json.insert(
    "deviceIpv4Address",
    wgConfig.value(amnezia::configKey::clientIp));

So the authoritative runtime path is:

AwgClientConfig.clientIp
        ↓
rawConfig["clientIp"]
        ↓
deviceIpv4Address
        ↓
InterfaceConfig.m_deviceIpv4Address
        ↓
macOS interface

It is not:

nativeConfig
        ↓
parse [Interface] Address at activation time

This matters because the current AWG model stores both representations independently:

AwgClientConfig.nativeConfig

and

AwgClientConfig.clientIp

toJson() serializes clientIp separately, and fromJson() restores it separately from the native configuration.

I don't see an invariant equivalent to:

parse(nativeConfig.[Interface].Address)
    ==
clientIp

being enforced when an existing stored profile is activated.

So a state such as:

nativeConfig Address = 10.8.1.3/32
structured clientIp  = 10.8.1.1

is representable by the model.

And if it occurs, the daemon will use:

10.8.1.1

because clientIp wins.

This creates a dual-source-of-truth problem

At profile creation/import time the two fields are normally generated together.

But after:

migration
edit
regeneration
partial update
legacy-profile conversion

there are now two independently persisted copies of the same semantic value.

The useful invariant should be:

CLIENT_TUNNEL_ADDRESS has exactly one canonical owner

rather than:

native config contains one copy
structured model contains another copy
and whichever path is being executed decides which copy wins

This is especially relevant to a reported:

4.8.21 -> 5.0.1.5

upgrade because the configuration model changed substantially between those generations.

I cannot prove from the source alone yet that this exact user's stored clientIp became .1 during migration, but current architecture makes that mismatch possible and provides the exact path by which a stale/wrong structured value would reach utun.

There is also a separate macOS point-to-point address bug

IPUtilsMacos::addIP4AddressToDevice() receives:

config.m_deviceIpv4Address

and correctly uses that as the local interface address.

So if this function receives:

10.8.1.3

it does not independently replace it with:

10.8.1.1

However, the point-to-point destination setup itself is problematic.

The code explicitly creates a /32 mask:

memset(
    &ifrMask->sin_addr,
    0xff,
    sizeof(ifrMask->sin_addr));

and then calculates ifra_broadaddr from the local address:

ifrBcast->sin_addr.s_addr =
    ifrAddr->sin_addr.s_addr |
    ~ifrMask->sin_addr.s_addr;

With a /32:

~mask = 0

therefore:

destination/broadaddr = local address

So if the correct client address were .3, this code naturally describes:

10.8.1.3 -> 10.8.1.3

rather than:

10.8.1.3 -> 10.8.1.1

The tunnel peer/gateway is not involved in this calculation.

I also do not see a separate SIOCSIFDSTADDR operation establishing the intended point-to-point peer address.

serverIpv4Gateway cannot currently fix that directly either

There is another semantic problem in the daemon input.

LocalSocketController currently does:

json.insert(
    "serverIpv4Gateway",
    wgConfig.value(amnezia::configKey::hostName));

But hostName in this configuration represents the public VPN endpoint, e.g.:

203.0.113.50

not the inner tunnel peer/gateway:

10.8.1.1

So the model currently conflates concepts that should be distinct:

public VPN endpoint
client tunnel address
server/peer tunnel address

Before wiring serverIpv4Gateway into the macOS point-to-point configuration, its semantics need to be corrected.

Why the WireGuard handshake can still succeed

A successful handshake does not validate the inner tunnel address.

The control plane needs approximately:

server endpoint
server public key
client private key
PSK
AWG parameters

It can therefore produce:

handshake = OK

while the inner interface is configured with an invalid/conflicting source address.

For example:

server awg0 = 10.8.1.1
client utun = 10.8.1.1

can still permit encrypted WireGuard transport to the public server endpoint while making the inner routed data plane unusable.

So:

HANDSHAKE_OK

must not be treated as proof that:

CLIENT_TUNNEL_ADDRESS_VALID

One diagnostic would identify the exact .1 origin

Before changing anything, I would log these values immediately before sending the activation request to the daemon:

structured clientIp
native [Interface] Address
deviceIpv4Address sent to daemon

For this report the interesting outcomes are:

Case A

native Address     = 10.8.1.3
structured clientIp = 10.8.1.1
deviceIpv4Address   = 10.8.1.1

=> structured/native configuration drift
Case B

native Address      = 10.8.1.1
structured clientIp = 10.8.1.1

fresh export        = 10.8.1.3

=> export created a separate peer;
   active stored profile itself is .1
Case C

native Address      = 10.8.1.3
structured clientIp = 10.8.1.3
deviceIpv4Address   = 10.8.1.3

but ifconfig local  = 10.8.1.1

=> corruption occurs after the controller boundary

Current source makes Case C look much less likely because IPUtilsMacos directly consumes m_deviceIpv4Address.

I would also compare the active peer against the server:

awg show awg0 allowed-ips

and the server [Interface] Address.

If both server interface and the active client claim:

10.8.1.1

that should be detected as an invalid configuration immediately.

Suggested fix boundary

I would address this as an address-identity contract rather than patching one macOS ioctl.

Conceptually separate:

endpointAddress
    = public server IP/domain

clientTunnelAddress
    = e.g. 10.8.1.3

serverTunnelAddress
    = e.g. 10.8.1.1

and give each exactly one owner.

Then:

native AWG config

should be generated from the canonical structured state, or the structured state should be parsed once from the native config.

They should not remain two independently mutable authoritative representations.

Before activation:

parse(native Address)
        ==
structured clientTunnelAddress

should either be guaranteed by construction or validated explicitly.

A mismatch should not silently choose one representation.

macOS should explicitly establish point-to-point semantics

For a desired configuration:

client = 10.8.1.3
peer   = 10.8.1.1

the resulting interface state should deterministically be:

inet 10.8.1.3 --> 10.8.1.1

The peer destination should come from an explicit tunnel-peer value.

It should not be derived as the /32 broadcast address of the client IP.

Activation should reject address conflicts

At minimum these states should be forbidden:

clientTunnelAddress == serverTunnelAddress

and:

clientTunnelAddress already assigned
to another peer on this server

A connection should fail before Connected rather than successfully handshaking with an invalid inner address.

Export semantics are also worth making clearer

Because exporting a native config currently creates/registers another client peer, an exported native config should not be used diagnostically as:

"this is the config of my currently active desktop connection"

unless the UI explicitly offers such an operation.

There are two different actions:

export current connection

and

create/export new client

They should ideally have different semantics/naming.

Regression cases

  1. macOS self-hosted AWG:
server tunnel IP = 10.8.1.1
client tunnel IP = 10.8.1.3

Expected:

ifconfig:
10.8.1.3 --> 10.8.1.1
  1. Force:
native Address      = 10.8.1.3
structured clientIp = 10.8.1.2

Expected:

configuration rejected/reconciled deterministically

not silent selection of one copy.

  1. Upgrade an existing AWG profile from the 4.8.x storage format to the current model.

Verify after migration:

stored clientIp
native Address
server peer AllowedIPs
runtime interface address

all identify the same client.

  1. Server interface:
10.8.1.1

and stored client:

10.8.1.1

Expected:

activation rejected as address conflict

even if the AWG handshake itself would succeed.

  1. Export a new guest/native config while another connection is active.

Expected:

new peer allocation does not modify
the active connection's clientTunnelAddress

and diagnostics clearly distinguish the two peers.

  1. Reconnect repeatedly.

The local address and point-to-point peer must remain stable.

  1. Split tunnel and full tunnel should produce the same inner interface identity:
local client address
peer tunnel address

must not depend on route mode.

So my current classification would be:

partially confirmed, with two source-confirmed address-state bugs.

What is not yet proven is the exact operation that changed this reporter's active structured clientIp to 10.8.1.1.

What is confirmed in current dev is:

  1. the runtime client address comes from a structured clientIp, while the native AWG config stores another copy of the same address with no enforced equality invariant;

  2. the macOS /32 interface setup derives the point-to-point destination from the local address itself and does not explicitly use the inner server tunnel address.

The three-value diagnostic above should identify the exact .1 origin in one reproduction.

<!-- gh-comment-id:5609667166 --> @HeisLuka commented on GitHub (Sep 9, 2026): I checked this against current `dev`. There are real source-level address handling problems here, but I think one distinction is important before attributing the observed `.1` directly to the exported config. ### First: the exported `.conf` is not necessarily the active peer For a self-hosted server, exporting a native AWG configuration currently does not simply serialize the peer that the desktop client is using. `ExportController::generateNativeConfig()` calls: ```cpp configurator->createConfig(...) ``` and then registers the returned client ID: ```cpp emit appendClientRequested( serverId, clientId, clientName, container); ``` For AWG/WireGuard, `createConfig()` allocates another peer/client address on the server. Therefore this sequence is possible: ```text currently stored desktop peer: clientIp = 10.8.1.1 user exports a native config: a new peer is allocated Address = 10.8.1.3/32 ``` So: ```text exported Address = 10.8.1.3 runtime utun = 10.8.1.1 ``` does not by itself prove that the runtime ignored the `Address = 10.8.1.3` line. They may be two different peers. That is worth separating from the actual runtime bug. ### Runtime does not use `[Interface] Address` as its authoritative value For desktop AWG/WireGuard, `LocalSocketController::activate()` obtains the local address from the structured configuration: ```cpp QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject(); json.insert( "deviceIpv4Address", wgConfig.value(amnezia::configKey::clientIp)); ``` So the authoritative runtime path is: ```text AwgClientConfig.clientIp ↓ rawConfig["clientIp"] ↓ deviceIpv4Address ↓ InterfaceConfig.m_deviceIpv4Address ↓ macOS interface ``` It is not: ```text nativeConfig ↓ parse [Interface] Address at activation time ``` This matters because the current AWG model stores both representations independently: ```text AwgClientConfig.nativeConfig and AwgClientConfig.clientIp ``` `toJson()` serializes `clientIp` separately, and `fromJson()` restores it separately from the native configuration. I don't see an invariant equivalent to: ```text parse(nativeConfig.[Interface].Address) == clientIp ``` being enforced when an existing stored profile is activated. So a state such as: ```text nativeConfig Address = 10.8.1.3/32 structured clientIp = 10.8.1.1 ``` is representable by the model. And if it occurs, the daemon will use: ```text 10.8.1.1 ``` because `clientIp` wins. ### This creates a dual-source-of-truth problem At profile creation/import time the two fields are normally generated together. But after: ```text migration edit regeneration partial update legacy-profile conversion ``` there are now two independently persisted copies of the same semantic value. The useful invariant should be: ```text CLIENT_TUNNEL_ADDRESS has exactly one canonical owner ``` rather than: ```text native config contains one copy structured model contains another copy and whichever path is being executed decides which copy wins ``` This is especially relevant to a reported: ```text 4.8.21 -> 5.0.1.5 ``` upgrade because the configuration model changed substantially between those generations. I cannot prove from the source alone yet that this exact user's stored `clientIp` became `.1` during migration, but current architecture makes that mismatch possible and provides the exact path by which a stale/wrong structured value would reach `utun`. ### There is also a separate macOS point-to-point address bug `IPUtilsMacos::addIP4AddressToDevice()` receives: ```cpp config.m_deviceIpv4Address ``` and correctly uses that as the local interface address. So if this function receives: ```text 10.8.1.3 ``` it does not independently replace it with: ```text 10.8.1.1 ``` However, the point-to-point destination setup itself is problematic. The code explicitly creates a `/32` mask: ```cpp memset( &ifrMask->sin_addr, 0xff, sizeof(ifrMask->sin_addr)); ``` and then calculates `ifra_broadaddr` from the local address: ```cpp ifrBcast->sin_addr.s_addr = ifrAddr->sin_addr.s_addr | ~ifrMask->sin_addr.s_addr; ``` With a `/32`: ```text ~mask = 0 ``` therefore: ```text destination/broadaddr = local address ``` So if the correct client address were `.3`, this code naturally describes: ```text 10.8.1.3 -> 10.8.1.3 ``` rather than: ```text 10.8.1.3 -> 10.8.1.1 ``` The tunnel peer/gateway is not involved in this calculation. I also do not see a separate `SIOCSIFDSTADDR` operation establishing the intended point-to-point peer address. ### `serverIpv4Gateway` cannot currently fix that directly either There is another semantic problem in the daemon input. `LocalSocketController` currently does: ```cpp json.insert( "serverIpv4Gateway", wgConfig.value(amnezia::configKey::hostName)); ``` But `hostName` in this configuration represents the public VPN endpoint, e.g.: ```text 203.0.113.50 ``` not the inner tunnel peer/gateway: ```text 10.8.1.1 ``` So the model currently conflates concepts that should be distinct: ```text public VPN endpoint client tunnel address server/peer tunnel address ``` Before wiring `serverIpv4Gateway` into the macOS point-to-point configuration, its semantics need to be corrected. ### Why the WireGuard handshake can still succeed A successful handshake does not validate the inner tunnel address. The control plane needs approximately: ```text server endpoint server public key client private key PSK AWG parameters ``` It can therefore produce: ```text handshake = OK ``` while the inner interface is configured with an invalid/conflicting source address. For example: ```text server awg0 = 10.8.1.1 client utun = 10.8.1.1 ``` can still permit encrypted WireGuard transport to the public server endpoint while making the inner routed data plane unusable. So: ```text HANDSHAKE_OK ``` must not be treated as proof that: ```text CLIENT_TUNNEL_ADDRESS_VALID ``` ### One diagnostic would identify the exact `.1` origin Before changing anything, I would log these values immediately before sending the activation request to the daemon: ```text structured clientIp native [Interface] Address deviceIpv4Address sent to daemon ``` For this report the interesting outcomes are: ```text Case A native Address = 10.8.1.3 structured clientIp = 10.8.1.1 deviceIpv4Address = 10.8.1.1 => structured/native configuration drift ``` ```text Case B native Address = 10.8.1.1 structured clientIp = 10.8.1.1 fresh export = 10.8.1.3 => export created a separate peer; active stored profile itself is .1 ``` ```text Case C native Address = 10.8.1.3 structured clientIp = 10.8.1.3 deviceIpv4Address = 10.8.1.3 but ifconfig local = 10.8.1.1 => corruption occurs after the controller boundary ``` Current source makes Case C look much less likely because `IPUtilsMacos` directly consumes `m_deviceIpv4Address`. I would also compare the active peer against the server: ```text awg show awg0 allowed-ips ``` and the server `[Interface] Address`. If both server interface and the active client claim: ```text 10.8.1.1 ``` that should be detected as an invalid configuration immediately. ### Suggested fix boundary I would address this as an address-identity contract rather than patching one macOS ioctl. Conceptually separate: ```text endpointAddress = public server IP/domain clientTunnelAddress = e.g. 10.8.1.3 serverTunnelAddress = e.g. 10.8.1.1 ``` and give each exactly one owner. Then: ```text native AWG config ``` should be generated from the canonical structured state, or the structured state should be parsed once from the native config. They should not remain two independently mutable authoritative representations. Before activation: ```text parse(native Address) == structured clientTunnelAddress ``` should either be guaranteed by construction or validated explicitly. A mismatch should not silently choose one representation. ### macOS should explicitly establish point-to-point semantics For a desired configuration: ```text client = 10.8.1.3 peer = 10.8.1.1 ``` the resulting interface state should deterministically be: ```text inet 10.8.1.3 --> 10.8.1.1 ``` The peer destination should come from an explicit tunnel-peer value. It should not be derived as the `/32` broadcast address of the client IP. ### Activation should reject address conflicts At minimum these states should be forbidden: ```text clientTunnelAddress == serverTunnelAddress ``` and: ```text clientTunnelAddress already assigned to another peer on this server ``` A connection should fail before `Connected` rather than successfully handshaking with an invalid inner address. ### Export semantics are also worth making clearer Because exporting a native config currently creates/registers another client peer, an exported native config should not be used diagnostically as: ```text "this is the config of my currently active desktop connection" ``` unless the UI explicitly offers such an operation. There are two different actions: ```text export current connection and create/export new client ``` They should ideally have different semantics/naming. ### Regression cases 1. macOS self-hosted AWG: ```text server tunnel IP = 10.8.1.1 client tunnel IP = 10.8.1.3 ``` Expected: ```text ifconfig: 10.8.1.3 --> 10.8.1.1 ``` 2. Force: ```text native Address = 10.8.1.3 structured clientIp = 10.8.1.2 ``` Expected: ```text configuration rejected/reconciled deterministically ``` not silent selection of one copy. 3. Upgrade an existing AWG profile from the 4.8.x storage format to the current model. Verify after migration: ```text stored clientIp native Address server peer AllowedIPs runtime interface address ``` all identify the same client. 4. Server interface: ```text 10.8.1.1 ``` and stored client: ```text 10.8.1.1 ``` Expected: ```text activation rejected as address conflict ``` even if the AWG handshake itself would succeed. 5. Export a new guest/native config while another connection is active. Expected: ```text new peer allocation does not modify the active connection's clientTunnelAddress ``` and diagnostics clearly distinguish the two peers. 6. Reconnect repeatedly. The local address and point-to-point peer must remain stable. 7. Split tunnel and full tunnel should produce the same inner interface identity: ```text local client address peer tunnel address ``` must not depend on route mode. So my current classification would be: **partially confirmed, with two source-confirmed address-state bugs.** What is not yet proven is the exact operation that changed this reporter's active structured `clientIp` to `10.8.1.1`. What is confirmed in current `dev` is: 1. **the runtime client address comes from a structured `clientIp`, while the native AWG config stores another copy of the same address with no enforced equality invariant;** 2. **the macOS `/32` interface setup derives the point-to-point destination from the local address itself and does not explicitly use the inner server tunnel address.** The three-value diagnostic above should identify the exact `.1` origin in one reproduction.
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#1427
No description provided.