WireGuard 是两件事。
WireGuard Is Two Things

原始链接: https://www.proxylity.com/articles/wireguard-is-two-things.html

## WireGuard 超越 VPN:一个新的 .NET 库 WireGuard 经常被认为是 VPN 应用程序,但其核心是一个现代加密协议,基于 Noise 和 ChaCha20-Poly1305 构建,旨在加密 UDP 数据报。该协议可以在*没有* VPN 的情况下使用,为任何基于 UDP 的应用程序提供精简的加密层。 传统的加密传输依赖于基于 TCP 的 TLS,但 TCP 会引入诸如队头阻塞、移动期间的连接重置以及在丢包链路上的拥塞控制问题等问题——所有这些都会导致延迟和可靠性问题。WireGuard 通过**无状态**设计解决了这些问题:没有复杂的握手,不依赖 PKI,以及自动密钥轮换。 一个新的开源 .NET 库 `WireGuardClient` 简化了该协议的集成。它与 `UdpClient` API 兼容,只需最少的代码更改即可添加加密。这对于物联网、移动和游戏应用程序尤其有价值,在这些应用程序中,可靠的低延迟通信至关重要。 结合 Proxylity 的 UDP 网关等服务,`WireGuardClient` 提供了一种轻量级的 VPN 和复杂 TLS 设置的替代方案,以最小的运营足迹提供安全的 UDP 传输。该库可在 GitHub 和 NuGet 上获得,提供了一个简单且可审计的增强安全解决方案。

最近一篇Hacker News上的帖子讨论了WireGuard,一种现代VPN协议及其Linux内核实现。虽然普遍受到好评,但有用户报告在使用移动数据时WireGuard性能出现问题,怀疑移动运营商通过流量整形优先处理TCP流量(OpenVPN使用),而非UDP(WireGuard使用)。 另一位评论者澄清,WireGuard不仅仅是一个协议,它的设计与内核实现的安全性目标紧密相连,特别是旨在提高效率——甚至在数据包处理过程中避免动态内存分配(尽管客户端管理会使用)。 这次讨论强调了WireGuard在移动网络上可能存在的实际性能限制,并凸显了该协议与其核心实现之间的密切关系。
相关文章

原文

WireGuard VPN App wg · network-manager · tunnelblick Your Application WireGuardClient · any UDP workload WireGuard Protocol Noise Protocol Framework · ChaCha20-Poly1305 · Stateless · No PKI UDP Datagrams

Ask a developer what WireGuard is, and you'll almost certainly hear: "It's a VPN." That's accurate, but it's only half the answer — and the less interesting half.

WireGuard is actually two things:

  • A VPN application — the wg tool, kernel module, and associated ecosystem that creates encrypted network tunnels between machines. This is what most people use, and what most articles describe.
  • A cryptographic protocol — a clean, modern specification built on the Noise Protocol Framework and ChaCha20-Poly1305, designed to encrypt UDP datagrams. This part is independent of VPNs, IP tunneling, and routing tables entirely.

The protocol is where the interesting engineering lives. And it turns out you can use it as a library — as a drop-in encryption layer for any application that moves data over UDP — without running a VPN at all. We just open sourced a .NET library that does exactly that.

Why This Matters: Problems with TCP

Before getting into what the library does, it's worth being honest about why we need better options here. The standard answer to "I need encrypted transport" is TLS over TCP, and it works well for a large class of problems. But TCP has structural costs that show up as real user-facing issues whenever latency, mobility, or lossy links are involved. Three in particular keep coming up in support queues.

Head-of-line blocking

TCP guarantees ordered delivery. When a single packet is lost in transit, every subsequent packet waits in a queue until the missing one is retransmitted — even if those later packets have already arrived. For a telemetry stream, game state update, or sensor reading, you almost certainly don't care about ordering. You want the latest value. TCP gives you stale data delivered in strict sequence.

The symptom is familiar: a stream that occasionally "locks up" briefly before catching up, jitter in audio or video, or a latency spike that appears to come from nowhere, a "hang" in the application when it gets blocked waiting for a packet. It comes from a single packet forcing the entire pipeline to pause. The underlying network recovered quickly; TCP's ordering guarantee is what made it visible.

Connection state resets

TCP connections are tied to a 4-tuple: source IP, source port, destination IP, destination port. When a mobile client roams from Wi-Fi to cellular, its IP address changes, every open TCP connection is torn down, and the TLS session with it. Your application absorbs the cost of reconnecting, re-negotiating TLS, and re-establishing application-level state.

For devices that move — phones, vehicles, field equipment — this isn't an edge case. It's routine. The RST arrives, the error propagates up the stack, and somewhere a retry loop starts counting. If you've ever wondered why a mobile app occasionally takes an extra few seconds to resume after switching networks, this is usually why.

Congestion control on lossy links

TCP's congestion control treats packet loss as a signal that the network is congested, and backs off accordingly — reducing its sending rate. On a genuinely lossy link (cellular IoT, satellite uplink, industrial RF), this creates a damaging feedback loop: the link drops a packet due to interference, the stack backs off as if the network is saturated, and throughput collapses even though the only problem was a momentary burst of noise.

The users on the other end of that IoT dashboard see stale readings — not because the device stopped sending, but because congestion control throttled delivery in response to interference.

These aren't exotic failure modes. They're the source of a significant class of complaints in gaming, voice, video conferencing, IoT monitoring, and any application that runs over mobile infrastructure. Developers who've shipped in these domains recognize all three immediately.

Security: TCP got TLS, UDP got a VPN

The conventional response to "I need encryption for my UDP traffic" has historically been "put it in a VPN." That works, but it's operationally heavy. A VPN is an entire network abstraction — its own routing, its own address space, its own operational surface to manage. It bundles two distinct concerns together: which packets to route and how to encrypt them. For most use cases, you only need the second one.

DTLS (TLS-over-UDP) exists and is a legitimate option, but it inherits TLS's complexity: certificate chains, PKI infrastructure, cipher-suite negotiation, and a multi-round-trip handshake. That's a meaningful operational burden to impose on an embedded device with 256 KB of RAM, or a team that just wants to encrypt a data channel without standing up a certificate authority.

WireGuard's protocol is a fundamentally different design point. It's stateless — there's no connection to establish upfront, no session to track, and no certificate authority in the picture. Two keys, a compact handshake, and you're encrypting. And unlike TLS, WireGuard's cryptographic choices are fixed: Noise_IKpsk2 for key exchange, ChaCha20-Poly1305 for authenticated encryption. There's nothing to misconfigure.

The Library: WireGuardClient

The wg-client library is API-compatible with .NET's built-in UdpClient. The send/receive patterns are the same, and adding encryption to a plain UDP send loop is a small change:

// Before: plain UDP
using var udp = new UdpClient();
var endpoint = IPEndPoint.Parse("gateway.example.com:51820");
var payload = Encoding.UTF8.GetBytes("temp=23.4,hum=61");
await udp.SendAsync(payload, payload.Length, endpoint);
// After: WireGuard-encrypted UDP
var endpoint   = IPEndPoint.Parse("gateway.example.com:51820");
var serverKey  = Convert.FromBase64String("<server public key>");
var clientKey  = Convert.FromBase64String("<client private key>");
await using var wg = new WireGuardClient(endpoint, serverKey, clientKey);
var payload = Encoding.UTF8.GetBytes("temp=23.4,hum=61");
await wg.SendAsync(payload, CancellationToken.None); // encrypted on the wire

The library handles the WireGuard handshake, key rotation, and message framing. The calling code doesn't change. The wire format is standard WireGuard, so it's compatible with any conformant backend — a Linux wg interface, a Proxylity WireGuard Listener, or any other implementation that follows the spec.

The implementation is around 800 lines of C# — small enough to read in a single sitting and audit meaningfully. The only external dependency is NSec, a managed NuGet package that provides a .NET wrapper around libsodium. The Noise handshake and ChaCha20-Poly1305 transport are implemented on top of that foundation, with no other third-party code involved.

What "Stateless" Actually Means in Practice

The word "stateless" appears often in WireGuard's design documentation, and it's worth being precise about what it means for application developers.

In TLS, a session has a lifecycle: the handshake creates shared state — session keys, sequence numbers, a cipher context — that must be maintained for the duration of the connection. If the connection drops (due to a network change, a server restart, or a timeout), that state is gone. Both sides must negotiate from scratch before encrypted communication resumes.

WireGuard handles this differently. Sessions exist and keys rotate, but if packets stop flowing and a session expires, the next outbound message silently triggers a fresh handshake. There's no error to handle, no reconnect to orchestrate, no application-level retry logic to write. The library sends data; when the session needs refreshing, it happens underneath. From the application's perspective, it never went away.

This matters especially for devices that sleep between transmissions, move between networks, or operate in environments where connectivity is intermittent. The same properties that make WireGuard resilient in a VPN context make it resilient here too — and they apply regardless of whether the payload is tunneled IP or something else entirely.

Beyond Tunneled IP

WireGuard the VPN uses the protocol to tunnel IP packets. The inner payload is an IP datagram — a packet in the normal internet sense. That's the VPN use case.

WireGuard the protocol just encrypts a byte array. It doesn't inspect, validate, or interpret the contents. The inner payload can be tunneled IP, or it can be UTF-8 text, a binary sensor reading, a proprietary control protocol, syslog, NTP, or anything else. Once you separate the protocol from the VPN application, arbitrary payloads stop feeling unusual and start feeling like the obvious way to use the thing.

This means you can protect a data channel with WireGuard exactly the way you'd use TLS — without any of the VPN machinery involved. HTTP over WireGuard works. Our syslog-over-WireGuard examples work. Any protocol you'd currently protect with TLS can in principle be protected with WireGuard instead, with a simpler operational model and no PKI to manage.

The Proxylity Side of the Story

Proxylity UDP Gateway has supported WireGuard Listeners since early in the product. The Gateway terminates WireGuard tunnels, decapsulates packets, and routes the inner payload to Lambda, SQS, Kinesis, CloudWatch Logs, and other Destinations. Earlier this year we added Decapsulated Delivery, which moves the unpacking step to the Gateway so Destinations receive a clean inner payload without writing any code.

The wg-client library is the natural client-side complement to that picture. An IoT device, worker process, or edge node using WireGuardClient can send WireGuard-encrypted datagrams directly to a Proxylity WireGuard Listener, and the payload arrives at the Destination clean and decrypted, ready to process. No VPN infrastructure. No overlay network. No separate key management service.

The combination covers a use case that is genuinely common but surprisingly underserved: embedded or edge software that needs transport encryption and has UDP available, but where TLS is too heavy for the environment, a full VPN is too much infrastructure to justify, and DTLS is too complex to configure correctly under operational pressure.

The library is open source under the MIT license and available at github.com/proxylity/wg-client. Install via NuGet: dotnet add package Proxylity.WireGuardClient. It's around 800 lines with a little work still to go. Contributions, issue reports, and feedback welcome.

联系我们 contact @ memedata.com