Playground for Network Interfaces
Just messing around with network interfaces in an attempt to understand some of the low-level OS fundamentals. I was led in this direction when looking at Wireguard’s packages and getting a fun,system-level example of how to run system calls and file descriptors to configure network interfaces in Go.
Wireguard’s TUN interface
Referenced code can be found in the TUN project.
Setting Up
The TUN interface is created at /dev/net/tun and represents the tunnel
used to communicate with the external service. When running through
Cloudflare’s Understanding TUN/TAP, it made more sense that this TUN
device represented a local point-to-point connection with the Wireguard
service. Found this fun rhyme to remember the difference between the device
types:
Tap is like a switch,
Ethernet headers it’ll hitch.
Tun is like a tunnel,
VPN connections it’ll funnel.
Ethernet headers it won’t hold,
Tap uses, tun does not, we’re told.
To see Wireguard create the TUN interface, a lot of the code in FirstExample()
is pulled directly from the Wireguard Mirror’s main.go function. See the
example with the following:
# In one terminal, run FirstExampe() to create the TUN interface:
sudo go run main.go
# Then in another terminal, view the TUN interface using iproute2:
# (Should output louis0: tun vnet_hdr)
ip tuntap list
ip -s link show dev louis0When the device is being setup, Wireguard goes through the following stages:
- Open
/dev/net/tunto request new interface device - Generate a new device request through
ioctl()(OS dependent) with flags - Send
ioctl()device request - Set file descriptor to non-blocking
- Create a new file from fd to
/dev/net/tun?? - Create the TUN from the generated file => the NativeTun is the software interface used to interact with the application
Understanding NativeTun
TODO
Will want to understand how Wireguard actually interacts with TUN once created. Will be a bit different than the TAP document, but should be able to pull references from there and Tailscale.