tuntap

package module
v0.4.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 14 Imported by: 0

README

TunTap

Go Reference
Cross-platform TUN (network tunnel) device support for Go.

[!IMPORTANT] This project contains code extracted from the original wireguard-go project with minor modifications. All credit goes to the original wireguard-go authors.

Supported Platforms

  • Linux — via /dev/net/tun with optional batched I/O and TCP/UDP GRO/GSO
  • macOS — via utun control socket
  • FreeBSD — via /dev/tun
  • OpenBSD — via /dev/tunN
  • Windows — via Wintun

Installation

go get github.com/asciimoth/tuntap

Usage

package main

import (
	"fmt"
	"log"

	"github.com/asciimoth/tuntap"
)

func main() {
	// Create a TUN device with the given name and MTU.
	// On macOS use "utun" or "utunN"; on BSDs use "tun" or "tunN";
	// on Linux and Windows, any valid interface name works.
	tun, err := tuntap.CreateTUN("tun0", 1420)
	if err != nil {
		log.Fatal(err)
	}
	defer tun.Close()

	name, _ := tun.Name()
	fmt.Printf("Created TUN interface: %s\n", name)

	// Monitor device events (up/down, MTU changes).
	go func() {
		for event := range tun.Events() {
			fmt.Printf("Event: %v\n", event)
		}
	}()

	// Read IP packets from the TUN device.
	bufs := make([][]byte, tun.BatchSize())
	sizes := make([]int, tun.BatchSize())
	for i := range bufs {
		bufs[i] = make([]byte, 65535)
	}

	n, err := tun.Read(bufs, sizes, 0)
	if err != nil {
		log.Fatal(err)
	}

	// Process each packet.
	for i := 0; i < n; i++ {
		packet := bufs[i][:sizes[i]]
		// packet contains a raw IP frame — route it, decrypt it, etc.
		fmt.Printf("Read packet %d/%d: %d bytes\n", i+1, n, sizes[i])
		_ = packet
	}

	// Write IP packets back to the TUN device.
	// writeBufs := [][]byte{packet}
	// _, err = tun.Write(writeBufs, 0)
}

API

The primary type is NativeTun, which provides:

Method Description
CreateTUN(name string, mtu int) Create a TUN device
Read(bufs, sizes [][]byte, offset int) Read IP packets into buffers
Write(bufs [][]byte, offset int) Write IP packets to the device
Name() (string, error) Get the interface name
MTU() (int, error) Get the MTU
Events() <-chan Event Channel of device state changes
BatchSize() int Max packets per Read/Write call
Close() error Close the TUN device
File() *os.File Get the underlying file (may be nil on some platforms)

Documentation

Overview

Package tuntap provides cross-platform support for creating and managing TUN (network tunnel) devices.

TUN devices operate at layer 3 (network layer), handling raw IP packets without Ethernet framing. They are commonly used to implement VPNs, virtual networks, and other packet tunneling applications.

Supported Platforms

This package supports Linux, macOS (Darwin), FreeBSD, OpenBSD, and Windows. Each platform provides a NativeTun type that implements the tun.Tun interface from github.com/asciimoth/gonnect/tun.

Basic Usage

Create a TUN device by calling CreateTUN with the desired interface name and MTU:

tun, err := tuntap.CreateTUN("utun0", 1420)
if err != nil {
    log.Fatal(err)
}
defer tun.Close()

name, _ := tun.Name()
fmt.Printf("Created interface: %s\n", name)

Reading and Writing Packets

Use the Read and Write methods to exchange IP packets with the TUN device. Read accepts a slice of buffers and populates them with incoming packets, returning the count and the size of each packet:

bufs := make([][]byte, tuntap.IdealBatchSize)
for i := range bufs {
    bufs[i] = make([]byte, 65535)
}
sizes := make([]int, tuntap.IdealBatchSize)

n, err := tun.Read(bufs, sizes, 0)
if err != nil {
    // handle error
}
for i := 0; i < n; i++ {
    packet := bufs[i][0:sizes[i]]
    // process IP packet
}

Write sends one or more IP packets from the provided buffers:

_, err = tun.Write(bufs[:1], 0)

Platform-Specific Batch Sizes

On Linux, when the kernel supports IFF_VNET_HDR, the TUN device enables virtio network header mode. This allows batched I/O (up to IdealBatchSize packets per call) and enables TCP/UDP generic receive offload (GRO) and generic segmentation offload (GSO). On all other platforms, BatchSize() returns 1.

Device Events

The Events method returns a channel that emits device state changes (interface up/down, MTU updates). Callers should consume from this channel in a goroutine:

go func() {
    for event := range tun.Events() {
        // handle event
    }
}()

Windows

On Windows, this package uses the Wintun driver (golang.zx2c4.com/wintun). The global variables WintunTunnelType and WintunStaticRequestedGUID can be set before calling CreateTUN to customize the adapter type and GUID.

Index

Constants

View Source
const (
	// IdealBatchSize is the maximum number of packets that can be processed
	// in a single Read or Write call. On Linux with virtio network header
	// support (IFF_VNET_HDR), NativeTun.BatchSize() returns this value.
	// On all other platforms, BatchSize() returns 1.
	IdealBatchSize = 128
)

Variables

View Source
var (
	// ErrTooManySegments is returned by NativeTun.Read when a virtio GSO
	// frame needs more output buffers than the caller supplied. Read returns
	// no packets and does not change the supplied buffers or sizes when this
	// error occurs. The input frame has already been consumed, so a retry
	// cannot recover that frame.
	ErrTooManySegments = errors.New("too many segments")
)

Functions

func CreateTUN

func CreateTUN(name string, mtu int) (gtun.Tun, error)

CreateTUN creates a TUN device with the given interface name and MTU.

The name must be a valid Linux interface name. If IFF_VNET_HDR is supported by the kernel, the device will automatically enable TCP/UDP offload features (GRO/GSO).

The returned NativeTun starts background goroutines that monitor the device state and emit events on the Events channel.

func CreateTUNFromFile

func CreateTUNFromFile(file *os.File, mtu int) (gtun.Tun, error)

CreateTUNFromFile creates a TUN device from an existing os.File with the given MTU. The file must be a valid TUN file descriptor (e.g., opened from /dev/net/tun). This is useful when the file descriptor has been passed from a parent process or obtained through other means.

Like CreateTUN, this starts background goroutines for device monitoring.

func CreateUnmonitoredTUNFromFD

func CreateUnmonitoredTUNFromFD(fd int) (gtun.Tun, string, error)

CreateUnmonitoredTUNFromFD creates a TUN device from a raw file descriptor without starting any background monitoring goroutines. Unlike CreateTUN and CreateTUNFromFile, no netlink or hack-listener goroutines are spawned, so the Events channel will not receive automatic state updates. This is useful in scenarios where the caller manages the device lifecycle externally or when embedding the TUN fd in an existing event loop.

It returns the Tun device, the interface name, and any error that occurred.

Types

type NativeTun

type NativeTun struct {
	// contains filtered or unexported fields
}

NativeTun is a Linux-specific TUN device. It implements the tun.Tun interface from github.com/asciimoth/gonnect/tun.

On Linux, NativeTun supports batched I/O and TCP/UDP generic receive offload (GRO) / generic segmentation offload (GSO) when the kernel provides IFF_VNET_HDR. These features are detected automatically during construction. Read returns an error that matches io.ErrShortBuffer when a packet does not fit in the visible part of an output buffer. If a GSO frame cannot be split into the supplied buffers, Read returns no packets and does not change the output buffers or sizes. The frame is still consumed.

func (*NativeTun) BatchSize

func (tun *NativeTun) BatchSize() int

BatchSize returns the maximum number of packets that can be processed in a single Read or Write call. On Linux with IFF_VNET_HDR support, this returns IdealBatchSize (128). Otherwise, it returns 1.

func (*NativeTun) Close

func (tun *NativeTun) Close() error

func (*NativeTun) Events

func (tun *NativeTun) Events() <-chan gtun.Event

Events returns a channel that emits device state changes. The channel emits EventUp, EventDown, and EventMTUUpdate values. The channel is closed when the TUN device is closed.

func (*NativeTun) File

func (tun *NativeTun) File() *os.File

func (*NativeTun) IsNative added in v0.3.3

func (t *NativeTun) IsNative() bool

func (*NativeTun) MRO added in v0.1.3

func (tun *NativeTun) MRO() int

func (*NativeTun) MTU

func (tun *NativeTun) MTU() (int, error)

func (*NativeTun) MWO added in v0.1.3

func (tun *NativeTun) MWO() int

func (*NativeTun) Name

func (tun *NativeTun) Name() (string, error)

func (*NativeTun) Read

func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error)

func (*NativeTun) Write

func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error)

Directories

Path Synopsis
Package rwcancel implements cancelable read/write operations on a file descriptor.
Package rwcancel implements cancelable read/write operations on a file descriptor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL