diff --git a/Sources/Containerization/Interface.swift b/Sources/Containerization/Interface.swift index 80eac49b..ad3cc2aa 100644 --- a/Sources/Containerization/Interface.swift +++ b/Sources/Containerization/Interface.swift @@ -25,6 +25,13 @@ public protocol Interface: Sendable { /// The IP address for the default route, or nil for no default route. var ipv4Gateway: IPv4Address? { get } + /// The interface IPv6 address and subnet prefix length, as a CIDR address. + /// Example: `fdef:4eb5:9ccb:341e:fc98:82ff:fe82:4f28/64` + var ipv6Address: CIDRv6? { get } + + /// The IPv6 address for the default route, or nil for no default route. + var ipv6Gateway: IPv6Address? { get } + /// The interface MAC address, or nil to auto-configure the address. var macAddress: MACAddress? { get } @@ -34,4 +41,6 @@ public protocol Interface: Sendable { extension Interface { public var mtu: UInt32 { 1500 } + public var ipv6Address: CIDRv6? { nil } + public var ipv6Gateway: IPv6Address? { nil } } diff --git a/Sources/Containerization/LinuxContainer.swift b/Sources/Containerization/LinuxContainer.swift index f3f0baee..2f87c49f 100644 --- a/Sources/Containerization/LinuxContainer.swift +++ b/Sources/Containerization/LinuxContainer.swift @@ -474,9 +474,11 @@ extension LinuxContainer { } // For every interface asked for: - // 1. Add the address requested + // 1. Add the IPv4 address requested // 2. Online the adapter - // 3. If a gateway IP address is present, add the default route. + // 3. If an IPv4 gateway IP address is present, add the default route. + // 4. Add the IPv6 address if present + // 5. If an IPv6 gateway IP address is present, add the IPv6 default route. for (index, i) in self.interfaces.enumerated() { let name = "eth\(index)" self.logger?.debug("setting up interface \(name) with address \(i.ipv4Address)") @@ -489,6 +491,15 @@ extension LinuxContainer { } try await agent.routeAddDefault(name: name, ipv4Gateway: ipv4Gateway) } + + // Configure IPv6 if address is present + if let ipv6Address = i.ipv6Address { + self.logger?.debug("setting up interface \(name) with IPv6 address \(ipv6Address)") + try await agent.addressAdd(name: name, ipv6Address: ipv6Address) + if let ipv6Gateway = i.ipv6Gateway { + try await agent.routeAddDefault(name: name, ipv6Gateway: ipv6Gateway) + } + } } // Setup /etc/resolv.conf and /etc/hosts if asked for. diff --git a/Sources/Containerization/LinuxPod.swift b/Sources/Containerization/LinuxPod.swift index fafac5d3..3e0e22b5 100644 --- a/Sources/Containerization/LinuxPod.swift +++ b/Sources/Containerization/LinuxPod.swift @@ -424,9 +424,11 @@ extension LinuxPod { } // For every interface asked for: - // 1. Add the address requested + // 1. Add the IPv4 address requested // 2. Online the adapter - // 3. If a gateway IP address is present, add the default route. + // 3. If an IPv4 gateway IP address is present, add the default route. + // 4. Add the IPv6 address if present + // 5. If an IPv6 gateway IP address is present, add the IPv6 default route. for (index, i) in self.interfaces.enumerated() { let name = "eth\(index)" self.logger?.debug("setting up interface \(name) with address \(i.ipv4Address)") @@ -439,6 +441,15 @@ extension LinuxPod { } try await agent.routeAddDefault(name: name, ipv4Gateway: ipv4Gateway) } + + // Configure IPv6 if address is present + if let ipv6Address = i.ipv6Address { + self.logger?.debug("setting up interface \(name) with IPv6 address \(ipv6Address)") + try await agent.addressAdd(name: name, ipv6Address: ipv6Address) + if let ipv6Gateway = i.ipv6Gateway { + try await agent.routeAddDefault(name: name, ipv6Gateway: ipv6Gateway) + } + } } // Setup /etc/resolv.conf and /etc/hosts for each container. diff --git a/Sources/Containerization/NATInterface.swift b/Sources/Containerization/NATInterface.swift index 22383627..c37fbc06 100644 --- a/Sources/Containerization/NATInterface.swift +++ b/Sources/Containerization/NATInterface.swift @@ -19,12 +19,23 @@ import ContainerizationExtras public struct NATInterface: Interface { public var ipv4Address: CIDRv4 public var ipv4Gateway: IPv4Address? + public var ipv6Address: CIDRv6? + public var ipv6Gateway: IPv6Address? public var macAddress: MACAddress? public var mtu: UInt32 - public init(ipv4Address: CIDRv4, ipv4Gateway: IPv4Address?, macAddress: MACAddress? = nil, mtu: UInt32 = 1500) { + public init( + ipv4Address: CIDRv4, + ipv4Gateway: IPv4Address?, + ipv6Address: CIDRv6? = nil, + ipv6Gateway: IPv6Address? = nil, + macAddress: MACAddress? = nil, + mtu: UInt32 = 1500 + ) { self.ipv4Address = ipv4Address self.ipv4Gateway = ipv4Gateway + self.ipv6Address = ipv6Address + self.ipv6Gateway = ipv6Gateway self.macAddress = macAddress self.mtu = mtu } diff --git a/Sources/Containerization/NATNetworkInterface.swift b/Sources/Containerization/NATNetworkInterface.swift index 1255b0c9..a0de5c0d 100644 --- a/Sources/Containerization/NATNetworkInterface.swift +++ b/Sources/Containerization/NATNetworkInterface.swift @@ -29,6 +29,8 @@ import Synchronization public final class NATNetworkInterface: Interface, Sendable { public let ipv4Address: CIDRv4 public let ipv4Gateway: IPv4Address? + public let ipv6Address: CIDRv6? + public let ipv6Gateway: IPv6Address? public let macAddress: MACAddress? public let mtu: UInt32 @@ -40,12 +42,16 @@ public final class NATNetworkInterface: Interface, Sendable { public init( ipv4Address: CIDRv4, ipv4Gateway: IPv4Address?, + ipv6Address: CIDRv6? = nil, + ipv6Gateway: IPv6Address? = nil, reference: sending vmnet_network_ref, macAddress: MACAddress? = nil, mtu: UInt32 = 1500 ) { self.ipv4Address = ipv4Address self.ipv4Gateway = ipv4Gateway + self.ipv6Address = ipv6Address + self.ipv6Gateway = ipv6Gateway self.macAddress = macAddress self.mtu = mtu self.reference = reference @@ -55,11 +61,15 @@ public final class NATNetworkInterface: Interface, Sendable { public init( ipv4Address: CIDRv4, ipv4Gateway: IPv4Address?, + ipv6Address: CIDRv6? = nil, + ipv6Gateway: IPv6Address? = nil, macAddress: MACAddress? = nil, mtu: UInt32 = 1500 ) { self.ipv4Address = ipv4Address self.ipv4Gateway = ipv4Gateway + self.ipv6Address = ipv6Address + self.ipv6Gateway = ipv6Gateway self.macAddress = macAddress self.mtu = mtu self.reference = nil diff --git a/Sources/Containerization/SandboxContext/SandboxContext.grpc.swift b/Sources/Containerization/SandboxContext/SandboxContext.grpc.swift index 39b2bd69..584a2251 100644 --- a/Sources/Containerization/SandboxContext/SandboxContext.grpc.swift +++ b/Sources/Containerization/SandboxContext/SandboxContext.grpc.swift @@ -1,19 +1,3 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025-2026 Apple Inc. and the Containerization project authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//===----------------------------------------------------------------------===// - // // DO NOT EDIT. // swift-format-ignore-file @@ -149,6 +133,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtoc callOptions: CallOptions? ) -> UnaryCall + func ipAddrAdd6( + _ request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, + callOptions: CallOptions? + ) -> UnaryCall + func ipRouteAddLink( _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, callOptions: CallOptions? @@ -159,6 +148,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtoc callOptions: CallOptions? ) -> UnaryCall + func ipRouteAddDefault6( + _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + callOptions: CallOptions? + ) -> UnaryCall + func configureDns( _ request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, callOptions: CallOptions? @@ -603,6 +597,24 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtocol { ) } + /// Add an IPv6 address to a network interface. + /// + /// - Parameters: + /// - request: Request to send to IpAddrAdd6. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func ipAddrAdd6( + _ request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipAddrAdd6.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeIpAddrAdd6Interceptors() ?? [] + ) + } + /// Add an IP route for a network interface. /// /// - Parameters: @@ -639,6 +651,24 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtocol { ) } + /// Add an IPv6 default route for a network interface. + /// + /// - Parameters: + /// - request: Request to send to IpRouteAddDefault6. + /// - callOptions: Call options. + /// - Returns: A `UnaryCall` with futures for the metadata, status and response. + public func ipRouteAddDefault6( + _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + callOptions: CallOptions? = nil + ) -> UnaryCall { + return self.makeUnaryCall( + path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddDefault6.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeIpRouteAddDefault6Interceptors() ?? [] + ) + } + /// Configure DNS resolver. /// /// - Parameters: @@ -889,6 +919,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientP callOptions: CallOptions? ) -> GRPCAsyncUnaryCall + func makeIpAddrAdd6Call( + _ request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + func makeIpRouteAddLinkCall( _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, callOptions: CallOptions? @@ -899,6 +934,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientP callOptions: CallOptions? ) -> GRPCAsyncUnaryCall + func makeIpRouteAddDefault6Call( + _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + callOptions: CallOptions? + ) -> GRPCAsyncUnaryCall + func makeConfigureDnsCall( _ request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, callOptions: CallOptions? @@ -1204,6 +1244,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco ) } + public func makeIpAddrAdd6Call( + _ request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipAddrAdd6.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeIpAddrAdd6Interceptors() ?? [] + ) + } + public func makeIpRouteAddLinkCall( _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, callOptions: CallOptions? = nil @@ -1228,6 +1280,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco ) } + public func makeIpRouteAddDefault6Call( + _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + callOptions: CallOptions? = nil + ) -> GRPCAsyncUnaryCall { + return self.makeAsyncUnaryCall( + path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddDefault6.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeIpRouteAddDefault6Interceptors() ?? [] + ) + } + public func makeConfigureDnsCall( _ request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, callOptions: CallOptions? = nil @@ -1567,6 +1631,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco ) } + public func ipAddrAdd6( + _ request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, + callOptions: CallOptions? = nil + ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response { + return try await self.performAsyncUnaryCall( + path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipAddrAdd6.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeIpAddrAdd6Interceptors() ?? [] + ) + } + public func ipRouteAddLink( _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, callOptions: CallOptions? = nil @@ -1591,6 +1667,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco ) } + public func ipRouteAddDefault6( + _ request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + callOptions: CallOptions? = nil + ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response { + return try await self.performAsyncUnaryCall( + path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddDefault6.path, + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeIpRouteAddDefault6Interceptors() ?? [] + ) + } + public func configureDns( _ request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, callOptions: CallOptions? = nil @@ -1728,12 +1816,18 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientInterc /// - Returns: Interceptors to use when invoking 'ipAddrAdd'. func makeIpAddrAddInterceptors() -> [ClientInterceptor] + /// - Returns: Interceptors to use when invoking 'ipAddrAdd6'. + func makeIpAddrAdd6Interceptors() -> [ClientInterceptor] + /// - Returns: Interceptors to use when invoking 'ipRouteAddLink'. func makeIpRouteAddLinkInterceptors() -> [ClientInterceptor] /// - Returns: Interceptors to use when invoking 'ipRouteAddDefault'. func makeIpRouteAddDefaultInterceptors() -> [ClientInterceptor] + /// - Returns: Interceptors to use when invoking 'ipRouteAddDefault6'. + func makeIpRouteAddDefault6Interceptors() -> [ClientInterceptor] + /// - Returns: Interceptors to use when invoking 'configureDns'. func makeConfigureDnsInterceptors() -> [ClientInterceptor] @@ -1775,8 +1869,10 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata { Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.stopVsockProxy, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipLinkSet, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipAddrAdd, + Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipAddrAdd6, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddLink, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddDefault, + Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.ipRouteAddDefault6, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.configureDns, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.configureHosts, Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.sync, @@ -1923,6 +2019,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata { type: GRPCCallType.unary ) + public static let ipAddrAdd6 = GRPCMethodDescriptor( + name: "IpAddrAdd6", + path: "/com.apple.containerization.sandbox.v3.SandboxContext/IpAddrAdd6", + type: GRPCCallType.unary + ) + public static let ipRouteAddLink = GRPCMethodDescriptor( name: "IpRouteAddLink", path: "/com.apple.containerization.sandbox.v3.SandboxContext/IpRouteAddLink", @@ -1935,6 +2037,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata { type: GRPCCallType.unary ) + public static let ipRouteAddDefault6 = GRPCMethodDescriptor( + name: "IpRouteAddDefault6", + path: "/com.apple.containerization.sandbox.v3.SandboxContext/IpRouteAddDefault6", + type: GRPCCallType.unary + ) + public static let configureDns = GRPCMethodDescriptor( name: "ConfigureDns", path: "/com.apple.containerization.sandbox.v3.SandboxContext/ConfigureDns", @@ -2037,12 +2145,18 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider: Ca /// Add an IPv4 address to a network interface. func ipAddrAdd(request: Com_Apple_Containerization_Sandbox_V3_IpAddrAddRequest, context: StatusOnlyCallContext) -> EventLoopFuture + /// Add an IPv6 address to a network interface. + func ipAddrAdd6(request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, context: StatusOnlyCallContext) -> EventLoopFuture + /// Add an IP route for a network interface. func ipRouteAddLink(request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, context: StatusOnlyCallContext) -> EventLoopFuture /// Add an IP route for a network interface. func ipRouteAddDefault(request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultRequest, context: StatusOnlyCallContext) -> EventLoopFuture + /// Add an IPv6 default route for a network interface. + func ipRouteAddDefault6(request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, context: StatusOnlyCallContext) -> EventLoopFuture + /// Configure DNS resolver. func configureDns(request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, context: StatusOnlyCallContext) -> EventLoopFuture @@ -2275,6 +2389,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider { userFunction: self.ipAddrAdd(request:context:) ) + case "IpAddrAdd6": + return UnaryServerHandler( + context: context, + requestDeserializer: ProtobufDeserializer(), + responseSerializer: ProtobufSerializer(), + interceptors: self.interceptors?.makeIpAddrAdd6Interceptors() ?? [], + userFunction: self.ipAddrAdd6(request:context:) + ) + case "IpRouteAddLink": return UnaryServerHandler( context: context, @@ -2293,6 +2416,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider { userFunction: self.ipRouteAddDefault(request:context:) ) + case "IpRouteAddDefault6": + return UnaryServerHandler( + context: context, + requestDeserializer: ProtobufDeserializer(), + responseSerializer: ProtobufSerializer(), + interceptors: self.interceptors?.makeIpRouteAddDefault6Interceptors() ?? [], + userFunction: self.ipRouteAddDefault6(request:context:) + ) + case "ConfigureDns": return UnaryServerHandler( context: context, @@ -2483,6 +2615,12 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvide context: GRPCAsyncServerCallContext ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpAddrAddResponse + /// Add an IPv6 address to a network interface. + func ipAddrAdd6( + request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, + context: GRPCAsyncServerCallContext + ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response + /// Add an IP route for a network interface. func ipRouteAddLink( request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, @@ -2495,6 +2633,12 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvide context: GRPCAsyncServerCallContext ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultResponse + /// Add an IPv6 default route for a network interface. + func ipRouteAddDefault6( + request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + context: GRPCAsyncServerCallContext + ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response + /// Configure DNS resolver. func configureDns( request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, @@ -2746,6 +2890,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvider { wrapping: { try await self.ipAddrAdd(request: $0, context: $1) } ) + case "IpAddrAdd6": + return GRPCAsyncServerHandler( + context: context, + requestDeserializer: ProtobufDeserializer(), + responseSerializer: ProtobufSerializer(), + interceptors: self.interceptors?.makeIpAddrAdd6Interceptors() ?? [], + wrapping: { try await self.ipAddrAdd6(request: $0, context: $1) } + ) + case "IpRouteAddLink": return GRPCAsyncServerHandler( context: context, @@ -2764,6 +2917,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvider { wrapping: { try await self.ipRouteAddDefault(request: $0, context: $1) } ) + case "IpRouteAddDefault6": + return GRPCAsyncServerHandler( + context: context, + requestDeserializer: ProtobufDeserializer(), + responseSerializer: ProtobufSerializer(), + interceptors: self.interceptors?.makeIpRouteAddDefault6Interceptors() ?? [], + wrapping: { try await self.ipRouteAddDefault6(request: $0, context: $1) } + ) + case "ConfigureDns": return GRPCAsyncServerHandler( context: context, @@ -2900,6 +3062,10 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextServerInterc /// Defaults to calling `self.makeInterceptors()`. func makeIpAddrAddInterceptors() -> [ServerInterceptor] + /// - Returns: Interceptors to use when handling 'ipAddrAdd6'. + /// Defaults to calling `self.makeInterceptors()`. + func makeIpAddrAdd6Interceptors() -> [ServerInterceptor] + /// - Returns: Interceptors to use when handling 'ipRouteAddLink'. /// Defaults to calling `self.makeInterceptors()`. func makeIpRouteAddLinkInterceptors() -> [ServerInterceptor] @@ -2908,6 +3074,10 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextServerInterc /// Defaults to calling `self.makeInterceptors()`. func makeIpRouteAddDefaultInterceptors() -> [ServerInterceptor] + /// - Returns: Interceptors to use when handling 'ipRouteAddDefault6'. + /// Defaults to calling `self.makeInterceptors()`. + func makeIpRouteAddDefault6Interceptors() -> [ServerInterceptor] + /// - Returns: Interceptors to use when handling 'configureDns'. /// Defaults to calling `self.makeInterceptors()`. func makeConfigureDnsInterceptors() -> [ServerInterceptor] @@ -2953,8 +3123,10 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata { Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.stopVsockProxy, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipLinkSet, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipAddrAdd, + Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipAddrAdd6, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipRouteAddLink, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipRouteAddDefault, + Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.ipRouteAddDefault6, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.configureDns, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.configureHosts, Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.sync, @@ -3101,6 +3273,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata { type: GRPCCallType.unary ) + public static let ipAddrAdd6 = GRPCMethodDescriptor( + name: "IpAddrAdd6", + path: "/com.apple.containerization.sandbox.v3.SandboxContext/IpAddrAdd6", + type: GRPCCallType.unary + ) + public static let ipRouteAddLink = GRPCMethodDescriptor( name: "IpRouteAddLink", path: "/com.apple.containerization.sandbox.v3.SandboxContext/IpRouteAddLink", @@ -3113,6 +3291,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata { type: GRPCCallType.unary ) + public static let ipRouteAddDefault6 = GRPCMethodDescriptor( + name: "IpRouteAddDefault6", + path: "/com.apple.containerization.sandbox.v3.SandboxContext/IpRouteAddDefault6", + type: GRPCCallType.unary + ) + public static let configureDns = GRPCMethodDescriptor( name: "ConfigureDns", path: "/com.apple.containerization.sandbox.v3.SandboxContext/ConfigureDns", diff --git a/Sources/Containerization/SandboxContext/SandboxContext.pb.swift b/Sources/Containerization/SandboxContext/SandboxContext.pb.swift index 7b2fcaf1..928ebff2 100644 --- a/Sources/Containerization/SandboxContext/SandboxContext.pb.swift +++ b/Sources/Containerization/SandboxContext/SandboxContext.pb.swift @@ -1,19 +1,3 @@ -//===----------------------------------------------------------------------===// -// Copyright © 2025-2026 Apple Inc. and the Containerization project authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//===----------------------------------------------------------------------===// - // DO NOT EDIT. // swift-format-ignore-file // swiftlint:disable all @@ -1051,6 +1035,54 @@ public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultResponse: S public init() {} } +public struct Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var interface: String = String() + + public var ipv6Address: String = String() + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var interface: String = String() + + public var ipv6Gateway: String = String() + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -3305,6 +3337,120 @@ extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefaultResponse: Swift } } +extension Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".IpAddrAdd6Request" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "interface"), + 2: .same(proto: "ipv6Address"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.interface) }() + case 2: try { try decoder.decodeSingularStringField(value: &self.ipv6Address) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.interface.isEmpty { + try visitor.visitSingularStringField(value: self.interface, fieldNumber: 1) + } + if !self.ipv6Address.isEmpty { + try visitor.visitSingularStringField(value: self.ipv6Address, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, rhs: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request) -> Bool { + if lhs.interface != rhs.interface {return false} + if lhs.ipv6Address != rhs.ipv6Address {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".IpAddrAdd6Response" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response, rhs: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".IpRouteAddDefault6Request" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "interface"), + 2: .same(proto: "ipv6Gateway"), + ] + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.interface) }() + case 2: try { try decoder.decodeSingularStringField(value: &self.ipv6Gateway) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.interface.isEmpty { + try visitor.visitSingularStringField(value: self.interface, fieldNumber: 1) + } + if !self.ipv6Gateway.isEmpty { + try visitor.visitSingularStringField(value: self.ipv6Gateway, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, rhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request) -> Bool { + if lhs.interface != rhs.interface {return false} + if lhs.ipv6Gateway != rhs.ipv6Gateway {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".IpRouteAddDefault6Response" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response, rhs: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ConfigureDnsRequest" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ diff --git a/Sources/Containerization/SandboxContext/SandboxContext.proto b/Sources/Containerization/SandboxContext/SandboxContext.proto index ef35545a..dab0bb08 100644 --- a/Sources/Containerization/SandboxContext/SandboxContext.proto +++ b/Sources/Containerization/SandboxContext/SandboxContext.proto @@ -57,10 +57,14 @@ service SandboxContext { rpc IpLinkSet(IpLinkSetRequest) returns (IpLinkSetResponse); // Add an IPv4 address to a network interface. rpc IpAddrAdd(IpAddrAddRequest) returns (IpAddrAddResponse); + // Add an IPv6 address to a network interface. + rpc IpAddrAdd6(IpAddrAdd6Request) returns (IpAddrAdd6Response); // Add an IP route for a network interface. rpc IpRouteAddLink(IpRouteAddLinkRequest) returns (IpRouteAddLinkResponse); // Add an IP route for a network interface. rpc IpRouteAddDefault(IpRouteAddDefaultRequest) returns (IpRouteAddDefaultResponse); + // Add an IPv6 default route for a network interface. + rpc IpRouteAddDefault6(IpRouteAddDefault6Request) returns (IpRouteAddDefault6Response); // Configure DNS resolver. rpc ConfigureDns(ConfigureDnsRequest) returns (ConfigureDnsResponse); // Configure /etc/hosts. @@ -298,6 +302,20 @@ message IpRouteAddDefaultRequest { message IpRouteAddDefaultResponse {} +message IpAddrAdd6Request { + string interface = 1; + string ipv6Address = 2; +} + +message IpAddrAdd6Response {} + +message IpRouteAddDefault6Request { + string interface = 1; + string ipv6Gateway = 2; +} + +message IpRouteAddDefault6Response {} + message ConfigureDnsRequest { string location = 1; repeated string nameservers = 2; diff --git a/Sources/Containerization/VirtualMachineAgent.swift b/Sources/Containerization/VirtualMachineAgent.swift index b7ce1086..2a9e0538 100644 --- a/Sources/Containerization/VirtualMachineAgent.swift +++ b/Sources/Containerization/VirtualMachineAgent.swift @@ -89,8 +89,10 @@ public protocol VirtualMachineAgent: Sendable { func up(name: String, mtu: UInt32?) async throws func down(name: String) async throws func addressAdd(name: String, ipv4Address: CIDRv4) async throws + func addressAdd(name: String, ipv6Address: CIDRv6) async throws func routeAddLink(name: String, dstIPv4Addr: IPv4Address, srcIPv4Addr: IPv4Address?) async throws func routeAddDefault(name: String, ipv4Gateway: IPv4Address) async throws + func routeAddDefault(name: String, ipv6Gateway: IPv6Address) async throws func configureDNS(config: DNS, location: String) async throws func configureHosts(config: Hosts, location: String) async throws @@ -107,6 +109,14 @@ extension VirtualMachineAgent { throw ContainerizationError(.unsupported, message: "configureHosts") } + public func addressAdd(name: String, ipv6Address: CIDRv6) async throws { + throw ContainerizationError(.unsupported, message: "addressAdd IPv6") + } + + public func routeAddDefault(name: String, ipv6Gateway: IPv6Address) async throws { + throw ContainerizationError(.unsupported, message: "routeAddDefault IPv6") + } + public func writeFile(path: String, data: Data, flags: WriteFileFlags, mode: UInt32) async throws { throw ContainerizationError(.unsupported, message: "writeFile") } diff --git a/Sources/Containerization/Vminitd.swift b/Sources/Containerization/Vminitd.swift index f2caa15e..c3406390 100644 --- a/Sources/Containerization/Vminitd.swift +++ b/Sources/Containerization/Vminitd.swift @@ -373,7 +373,7 @@ extension Vminitd { _ = try await client.sysctl(request) } - /// Add an IP address to the sandbox's network interfaces. + /// Add an IPv4 address to the sandbox's network interfaces. public func addressAdd(name: String, ipv4Address: CIDRv4) async throws { _ = try await client.ipAddrAdd( .with { @@ -382,6 +382,15 @@ extension Vminitd { }) } + /// Add an IPv6 address to the sandbox's network interfaces. + public func addressAdd(name: String, ipv6Address: CIDRv6) async throws { + _ = try await client.ipAddrAdd6( + .with { + $0.interface = name + $0.ipv6Address = ipv6Address.description + }) + } + /// Add a route in the sandbox's environment. public func routeAddLink(name: String, dstIPv4Addr: IPv4Address, srcIPv4Addr: IPv4Address? = nil) async throws { let dstCIDR = "\(dstIPv4Addr.description)/32" @@ -395,7 +404,7 @@ extension Vminitd { }) } - /// Set the default route in the sandbox's environment. + /// Set the IPv4 default route in the sandbox's environment. public func routeAddDefault(name: String, ipv4Gateway: IPv4Address) async throws { _ = try await client.ipRouteAddDefault( .with { @@ -404,6 +413,15 @@ extension Vminitd { }) } + /// Set the IPv6 default route in the sandbox's environment. + public func routeAddDefault(name: String, ipv6Gateway: IPv6Address) async throws { + _ = try await client.ipRouteAddDefault6( + .with { + $0.interface = name + $0.ipv6Gateway = ipv6Gateway.description + }) + } + /// Configure DNS within the sandbox's environment. public func configureDNS(config: DNS, location: String) async throws { _ = try await client.configureDns( diff --git a/Sources/ContainerizationNetlink/NetlinkSession.swift b/Sources/ContainerizationNetlink/NetlinkSession.swift index e10acb35..5a779461 100644 --- a/Sources/ContainerizationNetlink/NetlinkSession.swift +++ b/Sources/ContainerizationNetlink/NetlinkSession.swift @@ -201,6 +201,34 @@ public struct NetlinkSession { /// - interface: The name of the interface. /// - ipv4Address: The CIDRv4 address describing the interface IP and subnet prefix length. public func addressAdd(interface: String, ipv4Address: CIDRv4) throws { + try addressAddInternal( + interface: interface, + addressBytes: ipv4Address.address.bytes, + prefixLength: ipv4Address.prefix.length, + family: UInt8(AddressFamily.AF_INET) + ) + } + + /// Adds an IPv6 address to an interface. + /// - Parameters: + /// - interface: The name of the interface. + /// - ipv6Address: The CIDRv6 address describing the interface IP and subnet prefix length. + public func addressAdd(interface: String, ipv6Address: CIDRv6) throws { + try addressAddInternal( + interface: interface, + addressBytes: ipv6Address.address.bytes, + prefixLength: ipv6Address.prefix.length, + family: UInt8(AddressFamily.AF_INET6) + ) + } + + /// Internal implementation for adding an IP address to an interface. + /// - Parameters: + /// - interface: The name of the interface. + /// - addressBytes: The IP address bytes (4 for IPv4, 16 for IPv6). + /// - prefixLength: The prefix length. + /// - family: The address family (AF_INET or AF_INET6). + private func addressAddInternal(interface: String, addressBytes: [UInt8], prefixLength: UInt8, family: UInt8) throws { // ip addr add [addr] dev [interface] // ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ] [ CONFFLAG-LIST ] // IFADDR := PREFIX | ADDR peer PREFIX @@ -213,8 +241,7 @@ public struct NetlinkSession { // LFT := forever | SECONDS let interfaceIndex = try getInterfaceIndex(interface) - let ipAddressBytes = ipv4Address.address.bytes - let addressAttrSize = RTAttribute.size + MemoryLayout.size * ipAddressBytes.count + let addressAttrSize = RTAttribute.size + MemoryLayout.size * addressBytes.count let requestSize = NetlinkMessageHeader.size + AddressInfo.size + 2 * addressAttrSize var requestBuffer = [UInt8](repeating: 0, count: requestSize) var requestOffset = 0 @@ -229,8 +256,8 @@ public struct NetlinkSession { requestOffset = try header.appendBuffer(&requestBuffer, offset: requestOffset) let requestInfo = AddressInfo( - family: UInt8(AddressFamily.AF_INET), - prefixLength: ipv4Address.prefix.length, + family: family, + prefixLength: prefixLength, flags: 0, scope: NetlinkScope.RT_SCOPE_UNIVERSE, index: UInt32(interfaceIndex)) @@ -238,13 +265,13 @@ public struct NetlinkSession { let ipLocalAttr = RTAttribute(len: UInt16(addressAttrSize), type: AddressAttributeType.IFA_LOCAL) requestOffset = try ipLocalAttr.appendBuffer(&requestBuffer, offset: requestOffset) - guard var requestOffset = requestBuffer.copyIn(buffer: ipAddressBytes, offset: requestOffset) else { + guard var requestOffset = requestBuffer.copyIn(buffer: addressBytes, offset: requestOffset) else { throw BindError.sendMarshalFailure(type: "RTAttribute", field: "IFA_LOCAL") } let ipAddressAttr = RTAttribute(len: UInt16(addressAttrSize), type: AddressAttributeType.IFA_ADDRESS) requestOffset = try ipAddressAttr.appendBuffer(&requestBuffer, offset: requestOffset) - guard let requestOffset = requestBuffer.copyIn(buffer: ipAddressBytes, offset: requestOffset) else { + guard let requestOffset = requestBuffer.copyIn(buffer: addressBytes, offset: requestOffset) else { throw BindError.sendMarshalFailure(type: "RTAttribute", field: "IFA_ADDRESS") } @@ -352,10 +379,41 @@ public struct NetlinkSession { public func routeAddDefault( interface: String, ipv4Gateway: IPv4Address + ) throws { + try routeAddDefaultInternal( + interface: interface, + gatewayBytes: ipv4Gateway.bytes, + family: UInt8(AddressFamily.AF_INET) + ) + } + + /// Adds a default IPv6 route to an interface. + /// - Parameters: + /// - interface: The name of the interface. + /// - ipv6Gateway: The gateway address. + public func routeAddDefault( + interface: String, + ipv6Gateway: IPv6Address + ) throws { + try routeAddDefaultInternal( + interface: interface, + gatewayBytes: ipv6Gateway.bytes, + family: UInt8(AddressFamily.AF_INET6) + ) + } + + /// Internal implementation for adding a default route to an interface. + /// - Parameters: + /// - interface: The name of the interface. + /// - gatewayBytes: The gateway address bytes (4 for IPv4, 16 for IPv6). + /// - family: The address family (AF_INET or AF_INET6). + private func routeAddDefaultInternal( + interface: String, + gatewayBytes: [UInt8], + family: UInt8 ) throws { // ip route add default via [dst-address] src [src-address] - let dstAddrBytes = ipv4Gateway.bytes - let dstAddrAttrSize = RTAttribute.size + dstAddrBytes.count + let dstAddrAttrSize = RTAttribute.size + gatewayBytes.count let interfaceAttrSize = RTAttribute.size + MemoryLayout.size let interfaceIndex = try getInterfaceIndex(interface) @@ -373,7 +431,7 @@ public struct NetlinkSession { requestOffset = try header.appendBuffer(&requestBuffer, offset: requestOffset) let requestInfo = RouteInfo( - family: UInt8(AddressFamily.AF_INET), + family: family, dstLen: 0, srcLen: 0, tos: 0, @@ -386,7 +444,7 @@ public struct NetlinkSession { let dstAddrAttr = RTAttribute(len: UInt16(dstAddrAttrSize), type: RouteAttributeType.GATEWAY) requestOffset = try dstAddrAttr.appendBuffer(&requestBuffer, offset: requestOffset) - guard var requestOffset = requestBuffer.copyIn(buffer: dstAddrBytes, offset: requestOffset) else { + guard var requestOffset = requestBuffer.copyIn(buffer: gatewayBytes, offset: requestOffset) else { throw BindError.sendMarshalFailure(type: "RTAttribute", field: "RTA_GATEWAY") } let interfaceAttr = RTAttribute(len: UInt16(interfaceAttrSize), type: RouteAttributeType.OIF) diff --git a/vminitd/Sources/vminitd/Server+GRPC.swift b/vminitd/Sources/vminitd/Server+GRPC.swift index df057689..2e2cac06 100644 --- a/vminitd/Sources/vminitd/Server+GRPC.swift +++ b/vminitd/Sources/vminitd/Server+GRPC.swift @@ -943,6 +943,33 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvid return .init() } + func ipAddrAdd6( + request: Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Request, context: GRPC.GRPCAsyncServerCallContext + ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpAddrAdd6Response { + log.debug( + "ipAddrAdd6", + metadata: [ + "interface": "\(request.interface)", + "ipv6Address": "\(request.ipv6Address)", + ]) + + do { + let socket = try DefaultNetlinkSocket() + let session = NetlinkSession(socket: socket, log: log) + let ipv6Address = try CIDRv6(request.ipv6Address) + try session.addressAdd(interface: request.interface, ipv6Address: ipv6Address) + } catch { + log.error( + "ipAddrAdd6", + metadata: [ + "error": "\(error)" + ]) + throw GRPCStatus(code: .internalError, message: "ip-addr-add6: \(error)") + } + + return .init() + } + func ipRouteAddLink( request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkRequest, context: GRPC.GRPCAsyncServerCallContext ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpRouteAddLinkResponse { @@ -1004,6 +1031,34 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvid return .init() } + func ipRouteAddDefault6( + request: Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Request, + context: GRPC.GRPCAsyncServerCallContext + ) async throws -> Com_Apple_Containerization_Sandbox_V3_IpRouteAddDefault6Response { + log.debug( + "ipRouteAddDefault6", + metadata: [ + "interface": "\(request.interface)", + "ipv6Gateway": "\(request.ipv6Gateway)", + ]) + + do { + let socket = try DefaultNetlinkSocket() + let session = NetlinkSession(socket: socket, log: log) + let ipv6Gateway = try IPv6Address(request.ipv6Gateway) + try session.routeAddDefault(interface: request.interface, ipv6Gateway: ipv6Gateway) + } catch { + log.error( + "ipRouteAddDefault6", + metadata: [ + "error": "\(error)" + ]) + throw GRPCStatus(code: .internalError, message: "ip-route-add-default6: \(error)") + } + + return .init() + } + func configureDns( request: Com_Apple_Containerization_Sandbox_V3_ConfigureDnsRequest, context: GRPC.GRPCAsyncServerCallContext