Skip to content

Feature Request: Bridged Networking Support (--network bridged) #1007

@festen

Description

@festen

Feature Request: Bridged Networking Support (--network bridged)

Summary

Add support for bridged networking as an alternative to the current NAT-only networking. This would allow VMs to get their own IP address directly on the LAN via DHCP, bypassing the host's routing table entirely.

Problem

Lume currently hardcodes VZNATNetworkDeviceAttachment() as the only networking mode. NAT networking relies on the host's vmnet NAT daemon and routing table to provide connectivity to the VM. This creates a critical reliability problem when anything on the host modifies the routing table — most commonly a VPN client.

Real-world scenario: VPN breaks VM networking

  1. User starts a Lume VM — networking works fine via NAT (vmnet)
  2. User connects to a VPN (e.g. NordVPN, Cisco AnyConnect, OpenVPN) on the host
  3. VPN client overwrites the host's routing table to route traffic through the VPN tunnel
  4. VM immediately loses all network connectivity — the vmnet NAT gateway is no longer reachable through the modified routes
  5. User disconnects VPN — VM networking does NOT recover. The vmnet NAT daemon doesn't automatically restore its routing entries
  6. Only fix: reboot the host, or manually restart vmnet daemons (sudo pfctl -F all && sudo killall -HUP vmnet-natd && sudo killall -HUP bootpd)

This is particularly painful for users running always-on VMs (e.g. development servers, AI agent sandboxes, CI runners) on machines that also need occasional VPN access.

Why NAT-only is limiting

  • VPN incompatibility: As described above, any VPN that modifies routing breaks VM networking, often irreversibly until reboot
  • No split tunneling: Many corporate VPN clients (NordVPN macOS, Cisco AnyConnect) don't support split tunneling, making it impossible to exclude vmnet traffic
  • No direct LAN access: Other devices on the network can't reach the VM directly (e.g. for testing network services, IoT development)
  • Port forwarding complexity: Exposing VM services to the LAN requires manual port forwarding on the host

Proposed Solution

Add a --network option to lume run (and lume create) that supports:

# Current behavior (default)
lume run my-vm --network nat

# New: bridged networking
lume run my-vm --network bridged

# New: bridged to a specific interface
lume run my-vm --network bridged:en0

How Virtualization.framework supports this

Apple's Virtualization.framework already provides everything needed:

1. VZBridgedNetworkDeviceAttachment — the bridged equivalent of VZNATNetworkDeviceAttachment

// Current code (libs/lume/src/Virtualization/VMVirtualizationService.swift:134-143)
static func createNetworkDeviceConfiguration(macAddress: String) throws
    -> VZNetworkDeviceConfiguration
{
    let network = VZVirtioNetworkDeviceConfiguration()
    guard let vzMacAddress = VZMACAddress(string: macAddress) else {
        throw VMConfigError.invalidMachineIdentifier
    }
    network.attachment = VZNATNetworkDeviceAttachment()  // ← hardcoded NAT
    network.macAddress = vzMacAddress
    return network
}

The change to support bridged:

static func createNetworkDeviceConfiguration(
    macAddress: String,
    networkMode: NetworkMode = .nat
) throws -> VZNetworkDeviceConfiguration {
    let network = VZVirtioNetworkDeviceConfiguration()
    guard let vzMacAddress = VZMACAddress(string: macAddress) else {
        throw VMConfigError.invalidMachineIdentifier
    }
    
    switch networkMode {
    case .nat:
        network.attachment = VZNATNetworkDeviceAttachment()
    case .bridged(let interfaceName):
        guard let interface = VZBridgedNetworkInterface.networkInterfaces.first(where: {
            interfaceName.map { name in $0.identifier == name } ?? true
        }) else {
            throw VMConfigError.noBridgeInterfaceFound
        }
        network.attachment = VZBridgedNetworkDeviceAttachment(interface: interface)
    }
    
    network.macAddress = vzMacAddress
    return network
}

2. VZBridgedNetworkInterface.networkInterfaces — discover available host interfaces

This static property returns all bridgeable network interfaces on the host. Could be exposed via:

lume config network interfaces   # List available interfaces for bridging

3. Entitlement requirement: com.apple.vm.networking

This is the main effort. Bridged networking requires the com.apple.vm.networking entitlement, which is a restricted entitlement that must be:

  1. Requested from Apple (via Apple Developer representative or DTS TSI)
  2. Authorized via a provisioning profile
  3. Code-signed into the binary

The current entitlements file (libs/lume/resources/lume.entitlements) only has:

<key>com.apple.security.virtualization</key>
<true/>

It would need:

<key>com.apple.security.virtualization</key>
<true/>
<key>com.apple.vm.networking</key>
<true/>

Important notes about this entitlement:

  • NAT and host-only networking do NOT require this entitlement (current behavior is fine)
  • Only bridged mode requires it
  • It cannot be prototyped without the entitlement (unlike vmnet's bridged mode which works as root) — VZVirtualMachineConfiguration.validate() will fail
  • Apple's process: request via Apple Developer representative (docs)
  • Other tools like UTM have obtained this entitlement for their App Store distribution

4. VM config persistence

Store the network mode in the VM config (VMConfig), so it persists across restarts:

{
  "networkMode": "nat",        // or "bridged" or "bridged:en0"
  "macAddress": "..."
}

Suggested Implementation Plan

  1. Add NetworkMode enumnat | bridged(interface: String?)
  2. Add --network CLI option to Run.swift and Create.swift
  3. Modify createNetworkDeviceConfiguration() in VMVirtualizationService.swift to accept network mode
  4. Add lume config network interfaces subcommand to list bridgeable interfaces
  5. Persist network mode in VMConfig / VMConfig.swift
  6. Request com.apple.vm.networking entitlement from Apple
  7. Update entitlements file and signing configuration
  8. Add documentation for the --network flag and bridged networking setup

Steps 1-5 are straightforward code changes. Step 6 is the main blocker and should be initiated early since Apple's process takes time.

Relevant Source Files

File What to change
libs/lume/src/Virtualization/VMVirtualizationService.swift createNetworkDeviceConfiguration() — add bridged attachment support
libs/lume/src/Commands/Run.swift Add --network option
libs/lume/src/Commands/Create.swift Add --network option
libs/lume/src/FileSystem/VMConfig.swift Add networkMode field
libs/lume/resources/lume.entitlements Add com.apple.vm.networking
libs/lume/src/VM/VM.swift Pass network mode through to virtualization service

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions