@@ -62,6 +62,14 @@ public struct Utility {
6262        } 
6363    } 
6464
65+     public  static  func  validMACAddress( _ macAddress:  String )  throws  { 
66+         let  pattern  =  #"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"# 
67+         let  regex  =  try   Regex ( pattern) 
68+         if  try   regex. firstMatch ( in:  macAddress)  ==  nil  { 
69+             throw  ContainerizationError ( . invalidArgument,  message:  " invalid MAC address format  \( macAddress) , expected format: XX:XX:XX:XX:XX:XX " ) 
70+         } 
71+     } 
72+ 
6573    public  static  func  containerConfigFromFlags( 
6674        id:  String , 
6775        image:  String , 
@@ -176,13 +184,15 @@ public struct Utility {
176184
177185        config. virtualization =  management. virtualization
178186
187+         // Parse network specifications with properties
188+         let  parsedNetworks  =  try   management. networks. map  {  try   Parser . network ( $0)  } 
179189        if  management. networks. contains ( ClientNetwork . noNetworkName)  { 
180190            guard  management. networks. count ==  1  else  { 
181191                throw  ContainerizationError ( . unsupported,  message:  " no other networks may be created along with network  \( ClientNetwork . noNetworkName) " ) 
182192            } 
183193            config. networks =  [ ] 
184194        }  else  { 
185-             config. networks =  try   getAttachmentConfigurations ( containerId:  config. id,  networkIds :  management . networks ) 
195+             config. networks =  try   getAttachmentConfigurations ( containerId:  config. id,  networks :  parsedNetworks ) 
186196            for  attachmentConfiguration  in  config. networks { 
187197                let  network :  NetworkState  =  try   await  ClientNetwork . get ( id:  attachmentConfiguration. network) 
188198                guard  case . running( _,  _)  =  network else  { 
@@ -220,7 +230,14 @@ public struct Utility {
220230        return  ( config,  kernel) 
221231    } 
222232
223-     static  func  getAttachmentConfigurations( containerId:  String ,  networkIds:  [ String ] )  throws  ->  [ AttachmentConfiguration ]  { 
233+     static  func  getAttachmentConfigurations( containerId:  String ,  networks:  [ Parser . ParsedNetwork ] )  throws  ->  [ AttachmentConfiguration ]  { 
234+         // Validate MAC addresses if provided
235+         for  network  in  networks { 
236+             if  let  mac =  network. macAddress { 
237+                 try   validMACAddress ( mac) 
238+             } 
239+         } 
240+ 
224241        // make an FQDN for the first interface
225242        let  fqdn :  String ? 
226243        if  !containerId. contains ( " . " )  { 
@@ -235,22 +252,33 @@ public struct Utility {
235252            fqdn =  " \( containerId) . " 
236253        } 
237254
238-         guard  networkIds. isEmpty else  { 
239-             // networks may only be specified for macOS 26+
240-             guard  #available( macOS 26 ,  * )  else  { 
241-                 throw  ContainerizationError ( . invalidArgument,  message:  " non-default network configuration requires macOS 26 or newer " ) 
255+         guard  networks. isEmpty else  { 
256+             // Check if this is only the default network with properties (e.g., MAC address)
257+             let  isOnlyDefaultNetwork  =  networks. count ==  1  && networks [ 0 ] . name ==  ClientNetwork . defaultNetworkName
258+ 
259+             // networks may only be specified for macOS 26+ (except for default network with properties)
260+             if  !isOnlyDefaultNetwork { 
261+                 guard  #available( macOS 26 ,  * )  else  { 
262+                     throw  ContainerizationError ( . invalidArgument,  message:  " non-default network configuration requires macOS 26 or newer " ) 
263+                 } 
242264            } 
243265
244266            // attach the first network using the fqdn, and the rest using just the container ID
245-             return  networkIds . enumerated ( ) . map  {  item in 
267+             return  networks . enumerated ( ) . map  {  item in 
246268                guard  item. offset ==  0  else  { 
247-                     return  AttachmentConfiguration ( network:  item. element,  options:  AttachmentOptions ( hostname:  containerId) ) 
269+                     return  AttachmentConfiguration ( 
270+                         network:  item. element. name, 
271+                         options:  AttachmentOptions ( hostname:  containerId,  macAddress:  item. element. macAddress) 
272+                     ) 
248273                } 
249-                 return  AttachmentConfiguration ( network:  item. element,  options:  AttachmentOptions ( hostname:  fqdn ??  containerId) ) 
274+                 return  AttachmentConfiguration ( 
275+                     network:  item. element. name, 
276+                     options:  AttachmentOptions ( hostname:  fqdn ??  containerId,  macAddress:  item. element. macAddress) 
277+                 ) 
250278            } 
251279        } 
252280        // if no networks specified, attach to the default network
253-         return  [ AttachmentConfiguration ( network:  ClientNetwork . defaultNetworkName,  options:  AttachmentOptions ( hostname:  fqdn ??  containerId) ) ] 
281+         return  [ AttachmentConfiguration ( network:  ClientNetwork . defaultNetworkName,  options:  AttachmentOptions ( hostname:  fqdn ??  containerId,  macAddress :   nil ) ) ] 
254282    } 
255283
256284    private  static  func  getKernel( management:  Flags . Management )  async  throws  ->  Kernel  { 
0 commit comments