Files
fips/docs/design/fips-tun-driver.md
T
Johnathan Corgan ca24ba02b7 Add TUN driver design document
- docs/design/fips-tun-driver.md: comprehensive TUN interface documentation
- Architecture diagrams, component descriptions, packet flow
- Implementation status checklist (completed vs planned)
- Testing instructions and configuration reference
2026-01-30 05:38:58 +00:00

8.7 KiB

FIPS TUN Driver Design

This document describes the design and implementation of the TUN interface driver that connects FIPS to the local system's network stack.

Overview

The TUN driver provides the interface between local applications and the FIPS mesh network. It presents a virtual network interface (fips0) with the node's FIPS address, allowing standard socket applications to communicate over the mesh transparently.

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Local System                              │
│  ┌──────────────┐                                               │
│  │ Applications │  (sockets using fd00::/8 addresses)           │
│  └──────┬───────┘                                               │
│         │                                                        │
│  ┌──────▼───────┐                                               │
│  │    Kernel    │  routing: fd00::/8 → fips0                    │
│  │  IPv6 Stack  │  local table intercepts traffic to self       │
│  └──────┬───────┘                                               │
└─────────┼───────────────────────────────────────────────────────┘
          │ raw IPv6 packets
┌─────────▼───────────────────────────────────────────────────────┐
│                      TUN Device (fips0)                          │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │                    File Descriptor                          ││
│  │              (duplicated for reader/writer)                 ││
│  └──────────┬─────────────────────────────┬────────────────────┘│
│             │                             │                      │
│      ┌──────▼──────┐               ┌──────▼──────┐              │
│      │   Reader    │               │   Writer    │              │
│      │   Thread    │               │   Thread    │              │
│      │ (blocking)  │               │ (blocking)  │              │
│      └──────┬──────┘               └──────▲──────┘              │
│             │                             │                      │
└─────────────┼─────────────────────────────┼──────────────────────┘
              │                             │
              ▼                             │
       ┌─────────────┐              ┌───────┴───────┐
       │   Packet    │              │   TX Queue    │
       │  Processing │──────────────▶   (mpsc)      │
       │  (routing)  │              │               │
       └─────────────┘              └───────▲───────┘
                                            │
                                    (future: transports)

Components

TunDevice (src/tun.rs)

The main TUN device wrapper that handles creation, configuration, and lifecycle.

Responsibilities:

  • Create TUN interface via tun crate
  • Configure IPv6 address via netlink (rtnetlink)
  • Set MTU and bring interface up
  • Provide read access for incoming packets
  • Create writer handle via fd duplication

Lifecycle:

  1. Startup: Delete existing interface if present, create new
  2. Active: Reader and writer threads operate independently
  3. Shutdown: Delete interface via netlink, threads exit on I/O error

TunWriter (src/tun.rs)

Services a queue of outbound packets and writes them to the TUN device.

Design rationale:

Multiple sources will need to write to TUN:

  • ICMPv6 error responses (from packet processing)
  • Inbound mesh traffic from peers (future: transports)
  • Locally-generated control traffic (future)

A single writer thread with an mpsc queue provides:

  • No contention on TUN writes
  • Clean separation of concerns
  • Easy addition of new packet sources via TunTx::clone()

ICMPv6 Module (src/icmp.rs)

Generates RFC 4443 compliant ICMPv6 error messages.

Currently implemented:

  • Type 1 Code 0: Destination Unreachable - No route

Validation (when NOT to send errors):

  • Original packet was an ICMPv6 error (types 0-127)
  • Source address is multicast (0xff prefix)
  • Source address is unspecified (::)

Response format:

  • Total size ≤ 1280 bytes (IPv6 minimum MTU)
  • Includes as much of original packet as fits
  • Proper checksum with pseudo-header

Packet Flow

Outbound (local → mesh)

  1. Application sends to fd00::/8 address
  2. Kernel routes to fips0 (requires manual route addition)
  3. TUN reader receives raw IPv6 packet
  4. Packet processing determines next hop
  5. If routable: forward to transport (future)
  6. If not routable: send ICMPv6 Destination Unreachable via TX queue

Inbound (mesh → local)

  1. Transport receives packet from peer (future)
  2. Check destination address
  3. If destination is self: write to TUN via TX queue
  4. If destination is other: forward to next hop (transit)

Local Address Guarantee

Packets arriving at the TUN reader are guaranteed NOT to be destined for local addresses. The Linux kernel routing order ensures this:

  1. Local routing table - intercepts traffic to addresses on this machine
  2. Main routing table - routes fd00::/8 to fips0

This means every packet in the TUN reader requires a routing decision. No "is this for me?" check needed on the read path.

Configuration

From fips.yaml:

tun:
  enabled: true
  name: fips0
  mtu: 1400

Parameters:

Field Default Description
enabled true Enable TUN interface
name fips0 Interface name
mtu 1400 Maximum transmission unit

Privileges

TUN device creation requires CAP_NET_ADMIN. Options:

  1. Run as root: sudo ./fips
  2. Set capability: sudo setcap cap_net_admin+ep ./target/debug/fips
  3. Pre-created device: Admin creates persistent TUN, FIPS just opens it

Route Configuration

The kernel route must be added manually (not done by FIPS):

sudo ip -6 route add fd00::/8 dev fips0

This routes all FIPS addresses through the TUN interface.

Implementation Status

Completed

  • TUN device creation and configuration
  • IPv6 address assignment via netlink
  • Interface lifecycle (startup cleanup, graceful shutdown)
  • Reader thread with blocking I/O
  • Writer thread with mpsc queue
  • fd duplication for independent read/write
  • ICMPv6 Destination Unreachable (Type 1 Code 0)
  • Packet validation for ICMPv6 error generation

Planned

  • ICMPv6 Echo Reply (respond to ping)
  • ICMPv6 Packet Too Big (PMTUD support)
  • ICMPv6 Time Exceeded (hop limit)
  • Rate limiting for ICMPv6 errors
  • Integration with routing/forwarding logic
  • Transit packet handling (decrement hop limit, forward)
  • Automatic route management (add/remove fd00::/8 route)

Testing

Manual Testing

# Terminal 1: Run FIPS with debug logging
sudo RUST_LOG=debug ./target/debug/fips

# Terminal 2: Add route and test
sudo ip -6 route add fd00::/8 dev fips0
ping6 -c 1 fd00::1

# Expected: "Destination unreachable: No route" (not timeout)

Verifying Local Routing

# Check that local address goes via loopback, not TUN
ip -6 route get <your-fips-address>
# Should show: local ... dev lo

Dependencies

Crate Purpose
tun TUN device creation
rtnetlink Netlink interface configuration
libc fd duplication (dup)
futures Async netlink operations

References

  • RFC 4443: ICMPv6 for IPv6
  • RFC 4291: IPv6 Addressing Architecture
  • Linux TUN/TAP documentation