No description
Find a file
Jan De Landtsheer e828e6edf1 Add Linux bridge backend and feature-gate OVS dependencies
Replace OVS as the default network backend with Linux bridges and veth
pairs. The OVS backend (rovs-openflow, rovs-ovsdb, rovs-transport) is
now opt-in via --features ovs.

The Linux bridge backend uses kernel proxy ARP/NDP and /32 or /128 host
routes instead of OpenFlow MAC NAT, removing the dependency on a running
OVS daemon for the default build.
2026-02-06 19:18:38 +01:00
docs Refactor DHCP module with pnet and submodule structure 2026-02-05 02:57:02 +01:00
examples Add mosnat=snat auto-detection for default gateway interface 2026-02-05 05:57:25 +01:00
src Add Linux bridge backend and feature-gate OVS dependencies 2026-02-06 19:18:38 +01:00
tests Add integration tests and eliminate panics in production code 2026-02-05 03:11:36 +01:00
.gitignore Update .gitignore for Rust project 2026-02-05 01:03:14 +01:00
Cargo.lock Use proper IPv6 destination matching in MAC NAT flows 2026-02-06 16:31:15 +01:00
Cargo.toml Add Linux bridge backend and feature-gate OVS dependencies 2026-02-06 19:18:38 +01:00
CLAUDE.md Add DHCPv6 client and IPv6 DNS support 2026-02-05 06:20:54 +01:00
README.md Add DHCPv6 client and IPv6 DNS support 2026-02-05 06:20:54 +01:00
static-network-params.md Initial commit: mosnet with OVS bridge module 2026-02-05 00:57:20 +01:00

mosnet

A bare-metal network bootstrap tool for Linux systems, supporting both static IP configuration (with MAC NAT for MAC-restricted environments) and automatic DHCP configuration.

Features

  • Dual-mode operation: Automatically detects whether to use static or DHCP configuration
  • MAC NAT: Transparent MAC address rewriting for MAC-restricted environments (e.g., Hetzner)
  • ARP/NDP Proxy: Responds to ARP (IPv4) and NDP (IPv6) requests for configured IPs
  • Built-in DHCP client: Full DHCP implementation with lease renewal
  • RFC1918 Priority: In DHCP mode, prefers private addresses for interface selection
  • OVS Integration: Creates Open vSwitch bridge for VM/container networking
  • IPv6 Support: Static configuration, SLAAC, or DHCPv6 in DHCP mode
  • nftables Firewall: Configurable firewall with presets (ssh, permissive) or custom ports
  • NAT Support: Masquerading (SNAT) with auto-detection and port forwarding (DNAT)

Installation

Prerequisites

  • Rust 1.85+ (2024 edition)
  • Open vSwitch installed and running
  • Linux with netlink support

Building

cargo build --release

The binary will be at target/release/mosnet.

Usage

mosnet reads configuration from the kernel command line (/proc/cmdline). The operating mode is determined automatically based on which parameters are present.

Static Mode

Use static mode when you have a fixed IP address, especially in MAC-restricted environments like Hetzner dedicated servers.

Kernel parameters:

mosip4=<address>,<gateway>,<netmask>[,<device>]
mosip6=<address>/<prefix>,<gateway>[,<device>]

Examples:

Standard network:

mosip4=192.168.1.10,192.168.1.1,255.255.255.0

Hetzner point-to-point configuration:

mosip4=136.243.10.20,136.243.10.1,255.255.255.255
mosip6=2a01:4f8:c17:1234::1/128,fe80::1

With explicit interface:

mosip4=192.168.1.10,192.168.1.1,255.255.255.0,enp3s0

Dual-stack:

mosip4=192.168.1.10,192.168.1.1,255.255.255.0 mosip6=2001:db8::1/64,2001:db8::ffff

DHCP Mode

Use DHCP mode when no static IP is needed. mosnet will probe all interfaces for DHCP offers and select the best one.

Trigger: Absence of both mosip4 and mosip6 parameters.

Optional parameters:

mosdhcp_timeout=<seconds>           # Probe timeout per interface (default: 10)
mosdhcp_prefer_private=yes|no       # Prefer RFC1918 addresses (default: yes)

Examples:

Default DHCP (no parameters needed):

# Just boot without mosip4/mosip6

Custom timeout:

mosdhcp_timeout=30

Prefer public IPs:

mosdhcp_prefer_private=no

Firewall

mosnet includes an nftables-based firewall that can be configured via kernel cmdline.

Parameter:

mosfirewall=<preset>[,<tcp_ports>][,<udp_ports>]

Presets:

  • ssh - Allow SSH (22/tcp) and ICMP only
  • permissive - Allow SSH, HTTP/HTTPS (22,80,443/tcp) and ICMP
  • none - Disable firewall

Custom ports:

  • TCP ports: tcp:22,80,443
  • UDP ports: udp:53,123

Examples:

SSH only (secure default):

mosfirewall=ssh

Web server:

mosfirewall=permissive

Custom ports:

mosfirewall=ssh,tcp:8080,udp:51820

Full custom:

mosfirewall=none,tcp:22,80,443,8080,udp:53

The firewall creates an nftables table mosnet-firewall with:

  • Default drop policy for input
  • Allow established/related connections
  • Allow ICMP (ping)
  • Allow specified TCP/UDP ports

NAT

mosnet supports Source NAT (masquerading) and port forwarding via nftables.

Parameter:

mosnat=<interface>[,<port_forward>...]

Interface options:

  • snat - Auto-detect default gateway interface (recommended)
  • eth0 - Specific interface name
  • none - Disable NAT

Port forward format:

<external_port>:<internal_ip>:<internal_port>/<protocol>

Examples:

Auto-detect masquerade interface:

mosnat=snat

Masquerade on specific interface:

mosnat=eth0

Masquerade with port forwarding:

mosnat=snat,8080:192.168.1.100:80/tcp

Multiple port forwards:

mosnat=snat,8080:192.168.1.100:80/tcp,2222:192.168.1.100:22/tcp,53:192.168.1.53:53/udp

The NAT creates an nftables table mosnet-nat with:

  • Postrouting chain for masquerading outbound traffic
  • Prerouting chain for DNAT port forwarding

Running

Simply execute the binary as root:

sudo ./mosnet

mosnet will:

  1. Parse the kernel command line
  2. Detect the operating mode
  3. Discover network interfaces
  4. Probe for connectivity (ARP for static, DHCP for dynamic)
  5. Create an OVS bridge
  6. Configure IP addresses
  7. In static mode: run the ARP/NDP proxy controller
  8. In DHCP mode: handle lease renewal in the background

Environment Variables

  • RUST_LOG: Control logging verbosity (e.g., RUST_LOG=debug)
RUST_LOG=debug sudo ./mosnet

Operating Modes Comparison

Aspect Static Mode DHCP Mode
Trigger mosip4 or mosip6 present No static IP params
Interface selection ARP probe to gateway DHCP probe (RFC1918 priority)
Internal OVS port public mos
OpenFlow rules MAC NAT + ARP/NDP intercept Basic forwarding
Controller ARP/NDP proxy (runs) Not needed
IPv4 source Kernel cmdline DHCP lease
IPv6 source Kernel cmdline SLAAC
Lease renewal N/A Background task (T1/T2)
Use case Hetzner, MAC-restricted Standard networks

Architecture

OVS Bridge Structure

Physical NIC (e.g., enp3s0)
     │
     │ (L2 only, no IP configured)
     │
     ▼
┌─────────────────────────────────────────────┐
│           OVS Bridge: br-mosnet             │
│                                             │
│  ┌─────────────────┐  ┌─────────────────┐  │
│  │ Uplink Port     │  │ Internal Port   │  │
│  │ (physical NIC)  │  │ "public"/"mos"  │  │
│  │                 │  │                 │  │
│  │ Type: system    │  │ Type: internal  │  │
│  │ No IP           │  │ Host IP here    │  │
│  └─────────────────┘  └─────────────────┘  │
│                                             │
│  OpenFlow Controller: ptcp:6653             │
└─────────────────────────────────────────────┘

The internal port inherits the physical NIC's MAC address, ensuring all outgoing packets have the correct source MAC.

Static Mode Flow

  1. Parse mosip4/mosip6 from kernel cmdline
  2. Discover physical interfaces via netlink
  3. Send ARP probes to find which interface can reach the gateway
  4. Create OVS bridge with "public" internal port
  5. Configure IP address and routes on "public"
  6. Install MAC NAT OpenFlow rules
  7. Run ARP proxy (responds to ARP requests for our IP)
  8. Run NDP proxy (responds to Neighbor Solicitations for our IPv6)

DHCP Mode Flow

  1. Check for absence of static IP parameters
  2. Discover physical interfaces via netlink
  3. Send DHCP DISCOVER on each interface (raw sockets)
  4. Collect DHCP OFFERs and select best interface:
    • Prefer RFC1918 addresses (10.x, 172.16-31.x, 192.168.x)
    • Fall back to global addresses
  5. Create OVS bridge with "mos" internal port
  6. Run full DHCP client (DISCOVER → OFFER → REQUEST → ACK)
  7. Configure IP/gateway from lease
  8. Enable IPv6 SLAAC (accept_ra=2)
  9. Spawn background task for lease renewal at T1/T2 timers

The Hetzner Problem

Hetzner dedicated servers have MAC-based filtering at the switch level. Any packet with a source MAC different from the physical NIC's MAC is dropped. This causes problems when:

  • Running VMs/containers with their own MAC addresses
  • Using virtual network interfaces

mosnet's solution:

  1. All traffic flows through an OVS bridge
  2. OpenFlow rules rewrite source MACs to the physical NIC's MAC (egress)
  3. OpenFlow rules rewrite destination MACs for incoming VM traffic (ingress)
  4. ARP/NDP proxy responds to requests for all configured IPs using the physical MAC

This allows VMs and containers to have their own MAC addresses internally while appearing to use the physical MAC externally.

Troubleshooting

Check OVS bridge status

ovs-vsctl show

View OpenFlow rules

ovs-ofctl dump-flows br-mosnet

Check interface configuration

ip addr show public  # Static mode
ip addr show mos     # DHCP mode
ip route show

View logs

RUST_LOG=debug sudo ./mosnet

Check firewall rules

nft list table ip mosnet-firewall

Check NAT rules

nft list table ip mosnet-nat

Common issues

"no working interface found"

  • Ensure at least one physical interface is up
  • Check that the gateway is reachable (static mode)
  • Verify DHCP server is available (DHCP mode)

"no DHCP offer received"

  • Increase timeout: mosdhcp_timeout=30
  • Check network connectivity
  • Verify DHCP server is running

OVS errors

  • Ensure Open vSwitch is installed and running: systemctl status openvswitch-switch
  • Check OVS logs: journalctl -u openvswitch-switch

Firewall blocking traffic

  • Check rules: nft list table ip mosnet-firewall
  • Temporarily disable: mosfirewall=none
  • Verify correct ports are open

NAT not working

  • Check masquerade interface: nft list table ip mosnet-nat
  • Verify IP forwarding: sysctl net.ipv4.ip_forward
  • Check routing: ip route

Development

Project Structure

src/
├── main.rs        # Entry point, mode dispatch
├── lib.rs         # Library exports
└── mosnet/
    ├── mode.rs        # Mode detection (Static vs DHCP)
    ├── cmdline.rs     # Kernel parameter parsing
    ├── dhcp/          # DHCP probe and client (modular)
    ├── probe.rs       # Interface discovery, ARP probing
    ├── netlink.rs     # IP/route configuration
    ├── ovs.rs         # OVS bridge management
    ├── controller.rs  # ARP/NDP proxy (static mode)
    ├── firewall.rs    # nftables firewall and NAT
    └── error.rs       # Error types

Running Tests

cargo test

Linting

cargo clippy

License

See LICENSE file.

  • CLAUDE.md - Development guidance
  • docs/adr/001-dhcp-mode-and-interface-probing.md - DHCP mode design
  • docs/adr-hetzner-static-config.md - Static mode kernel parameters
  • static-network-params.md - Full parameter specification