Hi, Sometimes people say things like, "I want to make an application that connects to the server over WireGuard" or "I want to host this service application behind WireGuard" or "I want this small utility to initiate an SSH connection to a specific server over WireGuard." The usual answer to this is to simply bring up a WireGuard interface on the computer, and then do networking as usual. And making WireGuard easy enough that people can pull up ad-hoc interfaces trivially has been a big motivating factor for the simplicity of the tooling, such as `ip link add wg0 type wireguard && wg set wg0 ...` and similar commands.
On Linux, adding an interface is easy to do and is a solution that fits nearly all circumstances. Even if you're unprivileged and want a WireGuard interface for just a single application that's bound to the lifetime of that application, you can still use WireGuard's normal kernel interface inside of a user namespace + a network namespace, and get a private process-specific WireGuard interface. Pretty cool stuff. It's not like that's an accident, of course -- WireGuard was originally developed with Linux's model in mind. But not all operating systems are as neat as Linux. To that end, we've tried very hard to make WireGuard integrate as natively as possible into other operating systems, with native clients for every platform, as well as APIs for every platform to allow application developers to embed tunnels: https://www.wireguard.com/embedding/ . This is great and works well. WireGuard's design centers around the "network interface" as the central object, and that's what these libraries enable. But still, some people do not want to think about network interfaces or operating systems when writing code. To that end, I've recently written some code that couples a userspace networking stack (from gVisor) with a userspace WireGuard implementation (from wireguard-go), along with a little custom DNS client implementation, so that Go applications can use an in-process WireGuard interface directly to make TCP and UDP connections and listeners. From the operating system's point of view, the application just sends and receives encrypted UDP packets, and never sees the inner TCP or UDP packets or knows about WireGuard at all. Here's a quick example of what's possible: package main import ( "io" "log" "net" "net/http" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun" ) func main() { tun, tnet, err := tun.CreateNetTUN( []net.IP{net.ParseIP("192.168.4.29")}, []net.IP{net.ParseIP("8.8.8.8")}, 1420) if err != nil { log.Panic(err) } dev := device.NewDevice(tun, &device.Logger{log.Default(), log.Default(), log.Default()}) dev.IpcSet(`private_key=a8dac1d8a70a751f0f699fb14ba1cff7b79cf4fbd8f09f44c6e6a90d0369604f public_key=25123c5dcd3328ff645e4f2a3fce0d754400d3887a0cb7c56f0267e20fbf3c5b endpoint=163.172.161.0:12912 allowed_ip=0.0.0.0/0 `) dev.Up() client := http.Client{ Transport: &http.Transport{ DialContext: tnet.DialContext, }, } resp, err := client.Get("https://www.zx2c4.com/ip") if err != nil { log.Panic(err) } body, err := io.ReadAll(resp.Body) if err != nil { log.Panic(err) } log.Println(string(body)) } This snippet prints out: 163.172.161.0 demo.wireguard.com Go-http-client/1.1 , because that HTTPS request is going through the demo box. Other use cases of this include cloud VM providers to bundle an ssh client directly into their tooling that connects to a "cloud private network" over WireGuard. Or hosting utilities that allow people to run web apps from their own computers that are then accessible on the Internet by connecting in reverse through WireGuard. Or maybe other use cases. The API and the code is new, and potentially incomplete. Please take it for a spin and let me know your feedback. Enjoy, Jason PS: While the gophers on the list might be happy about this, the rustaceans may well be left wondering, "what about us?" I hope to have some positive news about wireguard-rs not before too long.