[GH-ISSUE #403] --native-main main tunnel never completes the WireGuard handshake (gateway 100% unreachable) on self-hosted Pangolin 1.19.4; netstack mode works #7943

Open
opened 2026-07-12 11:28:34 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @pauldovi on GitHub (Jul 6, 2026).
Original GitHub issue: https://github.com/fosrl/newt/issues/403

Originally assigned to: @oschwartz10612 on GitHub.

Describe the Bug

Claude generated this bug report as it helps me work through updating my newt instance to 1.14 and try to use kernel mode wireguard.

Summary
Newt 1.14.0's new --native-main mode brings up the kernel TUN interface and the control websocket, assigns the tunnel IP, and adds routes — but the main tunnel's WireGuard data path never comes up: the tunnel gateway is 100% unreachable. The default netstack mode works perfectly against the identical server, binary, and credentials. The failure is isolated to native mode and is not the clients/Olm-mesh subsystem.

Expected
--native-main establishes the main tunnel over a kernel TUN interface (as netstack mode does over gVisor), so the tunnel gateway is reachable.

Actual
The newt TUN interface comes up with the assigned tunnel IP and routes, the websocket connects — but the handshake to Gerbil never completes and the gateway is unreachable:

Process has CAP_NET_ADMIN capability, sufficient permissions for native TUN interface
Server version: 1.19.4
Websocket connected
The tunnel IP is: <TUNNEL_IP>/32
Adding route to <GATEWAY_IP>/32 via interface newt
WARN: Initial reliable ping failed, but continuing: all 5 ping attempts failed,
      last error: native ping to <GATEWAY_IP> failed: exit status 1

Manual ping over the interface confirms 100% loss:

$ ping -I newt <GATEWAY_IP>
3 packets transmitted, 0 received, 100% packet loss

IWhat it is NOT (isolation)

  • Not the server / creds / config. Netstack mode (default) works perfectly with the same binary, server, and creds.
  • Not the clients/Olm-mesh subsystem. Adding -disable-clients removes the newt/wg/get-config timeout entirely — but the gateway is still 100% unreachable — so the failure is in the main-tunnel data path under native mode, independent of the clients service.
  • Not permissions/devices. The kernel TUN device, the UAPI socket, CAP_NET_ADMIN, and /dev/net/tun are all present; native mode passes every permission check.

Hypothesis
Under --native-main the WG UDP socket is owned by the kernel/native interface, so Newt's userspace hole-punch may be unable to emit from the correct source port → Gerbil never learns the site endpoint → the peer handshake never completes. (clientsStartDirectRelay() also appears to be skipped when UseNativeMainInterface is set.) The 1.14.0 commit history describes this as a "first draft on native on main tunnel," so it may be known-incomplete. Happy to run any diagnostic — wg dump, tcpdump of the WG UDP, or a debug build.

Environment

  • Newt: 1.14.0 (official native arm64 release binary; run as an unprivileged systemd service — no Docker)
  • Pangolin: 1.19.4 · Gerbil: 1.4.2 (self-hosted)
  • Host: Raspberry Pi 5, aarch64, Debian 13 ("trixie" / RPi OS), kernel 6.18

To Reproduce

  1. On a self-hosted Pangolin 1.19.4 server (Gerbil 1.4.2), create a site with a Newt connector (Community edition, single site).
  2. On the client host, install Newt 1.14.0 and run it in native mode, with creds in the environment:

NEWT_ID=… NEWT_SECRET=… PANGOLIN_ENDPOINT=https://pangolin.example.com
newt --native-main -disable-ssh -dns

Run as root, or unprivileged with CAP_NET_ADMIN + /dev/net/tun present + a writable /run/wireguard and $HOME.

  1. Watch the log: the newt TUN interface is created and assigned the tunnel IP, the websocket connects, routes are added — but the WireGuard handshake to Gerbil never completes.
  2. Try the tunnel gateway: ping -I newt → 100% packet loss; Newt's own reliability ping logs native ping … failed: exit status 1.
  3. Contrast: drop --native-main (default netstack mode), same server + creds → Tunnel connection to server established successfully! and the gateway is reachable.

Expected Behavior

--native-main establishes the main tunnel over a kernel TUN interface (as netstack mode does over gVisor), so the tunnel gateway is reachable.

Originally created by @pauldovi on GitHub (Jul 6, 2026). Original GitHub issue: https://github.com/fosrl/newt/issues/403 Originally assigned to: @oschwartz10612 on GitHub. ### Describe the Bug Claude generated this bug report as it helps me work through updating my newt instance to 1.14 and try to use kernel mode wireguard. **Summary** Newt 1.14.0's new --native-main mode brings up the kernel TUN interface and the control websocket, assigns the tunnel IP, and adds routes — but the main tunnel's WireGuard data path never comes up: the tunnel gateway is 100% unreachable. The default netstack mode works perfectly against the identical server, binary, and credentials. The failure is isolated to native mode and is not the clients/Olm-mesh subsystem. **Expected** --native-main establishes the main tunnel over a kernel TUN interface (as netstack mode does over gVisor), so the tunnel gateway is reachable. **Actual** The newt TUN interface comes up with the assigned tunnel IP and routes, the websocket connects — but the handshake to Gerbil never completes and the gateway is unreachable: ``` Process has CAP_NET_ADMIN capability, sufficient permissions for native TUN interface Server version: 1.19.4 Websocket connected The tunnel IP is: <TUNNEL_IP>/32 Adding route to <GATEWAY_IP>/32 via interface newt WARN: Initial reliable ping failed, but continuing: all 5 ping attempts failed, last error: native ping to <GATEWAY_IP> failed: exit status 1 ``` Manual ping over the interface confirms 100% loss: ``` $ ping -I newt <GATEWAY_IP> 3 packets transmitted, 0 received, 100% packet loss ``` **IWhat it is NOT (isolation)** - Not the server / creds / config. Netstack mode (default) works perfectly with the same binary, server, and creds. - Not the clients/Olm-mesh subsystem. Adding -disable-clients removes the newt/wg/get-config timeout entirely — but the gateway is still 100% unreachable — so the failure is in the main-tunnel data path under native mode, independent of the clients service. - Not permissions/devices. The kernel TUN device, the UAPI socket, CAP_NET_ADMIN, and /dev/net/tun are all present; native mode passes every permission check. **Hypothesis** Under --native-main the WG UDP socket is owned by the kernel/native interface, so Newt's userspace hole-punch may be unable to emit from the correct source port → Gerbil never learns the site endpoint → the peer handshake never completes. (clientsStartDirectRelay() also appears to be skipped when UseNativeMainInterface is set.) The 1.14.0 commit history describes this as a "first draft on native on main tunnel," so it may be known-incomplete. Happy to run any diagnostic — wg dump, tcpdump of the WG UDP, or a debug build. ### Environment - Newt: 1.14.0 (official native arm64 release binary; run as an unprivileged systemd service — no Docker) - Pangolin: 1.19.4 · Gerbil: 1.4.2 (self-hosted) - Host: Raspberry Pi 5, aarch64, Debian 13 ("trixie" / RPi OS), kernel 6.18 ### To Reproduce 1. On a self-hosted Pangolin 1.19.4 server (Gerbil 1.4.2), create a site with a Newt connector (Community edition, single site). 2. On the client host, install Newt 1.14.0 and run it in native mode, with creds in the environment: NEWT_ID=… NEWT_SECRET=… PANGOLIN_ENDPOINT=https://pangolin.example.com \ newt --native-main -disable-ssh -dns <lan-resolver> Run as root, or unprivileged with CAP_NET_ADMIN + /dev/net/tun present + a writable /run/wireguard and $HOME. 3. Watch the log: the newt TUN interface is created and assigned the tunnel IP, the websocket connects, routes are added — but the WireGuard handshake to Gerbil never completes. 4. Try the tunnel gateway: ping -I newt <tunnel-gateway> → 100% packet loss; Newt's own reliability ping logs native ping … failed: exit status 1. 5. Contrast: drop --native-main (default netstack mode), same server + creds → Tunnel connection to server established successfully! and the gateway is reachable. ### Expected Behavior --native-main establishes the main tunnel over a kernel TUN interface (as netstack mode does over gVisor), so the tunnel gateway is reachable.
GiteaMirror added the needs investigating label 2026-07-12 11:28:34 -05:00
Author
Owner

@oschwartz10612 commented on GitHub (Jul 7, 2026):

I would caution that the native modes are pretty experimental right now. I would only use them if needed. Will look into this as soon as possible.

<!-- gh-comment-id:4905511757 --> @oschwartz10612 commented on GitHub (Jul 7, 2026): I would caution that the native modes are pretty experimental right now. I would only use them if needed. Will look into this as soon as possible.
Author
Owner

@AstralDestiny commented on GitHub (Jul 7, 2026):

Well the native method wouldn't be using a /dev/net/tun, It uses the SYS_MODULE which you' have to pass to it if you want it to auto load the module if not loaded by the host system already however when it's in userspace it'll piggyback off /dev/net/tun. lsmod | grep wireguard

To make sure the kernel is loaded and it won't use a tun interface as that's not how a native wireguard functions.

Will look in a bit, need some food first.

<!-- gh-comment-id:4906277366 --> @AstralDestiny commented on GitHub (Jul 7, 2026): Well the native method wouldn't be using a /dev/net/tun, It uses the SYS_MODULE which you' have to pass to it if you want it to auto load the module if not loaded by the host system already however when it's in userspace it'll piggyback off /dev/net/tun. ``lsmod | grep wireguard`` To make sure the kernel is loaded and it won't use a tun interface as that's not how a native wireguard functions. Will look in a bit, need some food first.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/newt#7943