apple / apple/containerization
[Bug]: LinuxContainer installs a link-scope default route when ipv4Gateway is nil
- Dominant language
- Swift
- Stars
- 8.9k
- Forks
- 359
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 13
Description
### I have done the following
- [x] I have searched the existing issues
- [x] I reproduced the issue with Containerization 0.33.1 and confirmed the same logic remains on `main`
### Steps to reproduce
1. Create a custom type conforming to `Containerization.Interface`.
2. Supply an IPv4 address and return `nil` from `ipv4Gateway`:
```swift
struct GatewaylessInterface: Interface, VZInterface {
let base: any Interface & VZInterface
var ipv4Address: CIDRv4 { base.ipv4Address }
var ipv4Gateway: IPv4Address? { nil }
var macAddress: MACAddress? { base.macAddress }
var mtu: UInt32 { base.mtu }
func device() throws -> VZVirtioNetworkDeviceConfiguration { try base.device() }
}
```
3. Start a `LinuxContainer` whose first and only interface is this gatewayless interface.
4. Inside the guest, run:
```sh
ip -4 route show
ip route get 1.1.1.1
```
The issue is deterministic in a real Virtualization.framework Linux microVM.
The 0.33.1 public contract documents `ipv4Gateway` as “The IP address for the default route, or nil for no default route”:
https://github.com/apple/containerization/blob/0.33.1/Sources/Containerization/Interface.swift#L25-L26
However, `LinuxContainer` calls `routeAddDefault(name:ipv4Gateway:)` with `nil` for the first interface:
https://github.com/apple/containerization/blob/0.33.1/Sources/Containerization/LinuxContainer.swift#L631-L654
Current `main` retains the same semantic behavior through `setupInterface`: when both gateways are nil it logs “no gateway” and still calls `routeAddDefault`:
https://github.com/apple/containerization/blob/main/Sources/Containerization/VirtualMachineAgent%2BInterface.swift#L76-L82
### Current behavior
The guest receives an on-link default route even though `ipv4Gateway` is nil:
```text
default dev eth0 scope link
172.16.0.0/24 dev eth0 scope link src 172.16.0.3
```
Consequently, route lookup treats arbitrary external destinations as directly reachable on `eth0` and attempts neighbor resolution on that link.
This does not necessarily provide external connectivity when the backing attachment is private and has no uplink, but it contradicts the public `Interface` contract and prevents callers from creating a first interface with no default route.
### Expected behavior
When `ipv4Gateway` is nil, `LinuxContainer` should configure the IPv4 address and link route without installing an IPv4 default route. IPv4 and IPv6 default-route installation should follow their respective optional gateway values.
### Environment
- OS: macOS 26.5.2 (25F84)
- Xcode: 26.6 (17F113)
- Swift: Apple Swift 6.3.1
- Containerization: 0.33.1
- Architecture: Apple silicon / arm64
### Relevant log output
```text
default dev eth0 scope link
172.16.0.0/24 dev eth0 scope link src 172.16.0.3
```
### Code of Conduct
- [x] I agree to follow this projects Code of Conduct
Contributor guide
Assessment
This issue has not been assessed yet.