Wagyu is a user-mode WireGuard library for Elixir.
It allows you to create an encrypted tunnel to another WireGuard peer and then tunnel TCP/UDP/TLS traffic over it using the :gen_tcp, :gen_udp and :ssl respectively, with only addiitional options required in the socket construction. No kernel capabilities or root privileges are required.
# Construct the wireguard interface
{:ok, interface} =
Wagyu.start_link(
name: :wg0,
private_key: local_private_key,
listen: %{address: {0, 0, 0, 0}, port: 51820},
stack: [
addresses: [{{10, 13, 0, 2}, 32}],
routes: [{{0, 0, 0, 0}, 0, {10, 13, 0, 1}}],
mtu: 1280
],
peers: [
%{
public_key: remote_public_key,
endpoint: %{address: {192, 0, 2, 1}, port: 51820},
allowed_ips: [{{0, 0, 0, 0}, 0}]
}
]
)
# Grab the user-mode network stack
{:ok, stack} = Wagyu.stack(:wg0)
# Construct the socket
options = [
{:tcp_module, SmolNet.Inet.Tcp}, # Set the backend module
{:smolnet_stack, stack}, # Set the stack
:inet,
:binary,
{:active, false}
]
{:ok, socket} = :gen_tcp.connect({10, 13, 0, 1}, 443, options, 5_000)
# Use the socket
:ok = :gen_tcp.send(socket, "hello")
{:ok, reply} = :gen_tcp.recv(socket, 0, 5_000)
:ok = :gen_tcp.close(socket)
Tbh, I mostly wrote this just to see if it could be done. The two libraries that underpin it, smolnet and decibel I had written previously for other work-related projects.
I thought it would mostly be a case of just glueing them together. Turns out, I was wrong about that, but getting to the initial release of wagyu resulted in improvements across all three, so I’m glad I tried.


















