@@ -51,6 +51,9 @@ static WIREGUARD_DLL: LazyLock<Mutex<Wireguard>> = LazyLock::new(|| {
5151 )
5252} ) ;
5353
54+ const IPV4_LABEL : & str = "IPv4" ;
55+ const IPV6_LABEL : & str = "IPv6" ;
56+
5457#[ derive( Debug , Error ) ]
5558pub enum WindowsError {
5659 #[ error( "Empty interface array" ) ]
@@ -304,15 +307,64 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
304307
305308 // Configure the interface
306309 debug ! ( "Applying configuration for adapter {}" , self . ifname) ;
307- let interface = wireguard_nt:: SetInterface {
310+ let mut interface = wireguard_nt:: SetInterface {
308311 listen_port : Some ( config. port ) ,
309312 public_key : None , // derived from private key
310313 private_key : Some ( Key :: from_str ( & config. prvkey ) ?. as_array ( ) ) ,
311314 peers,
312315 } ;
313316 adapter. set_config ( & interface) . map_err ( WindowsError :: from) ?;
314317
315- // Set adapter addresses
318+ // Check which IP families are available on this adapter before attempting
319+ // to create routes.
320+ let adapter_luid = adapter. get_luid ( ) ;
321+ let mut ipv4_available = false ;
322+ let mut ipv6_available = false ;
323+ for ( family_name, family) in [ ( IPV4_LABEL , AF_INET ) , ( IPV6_LABEL , AF_INET6 ) ] {
324+ let mut row = MIB_IPINTERFACE_ROW :: default ( ) ;
325+ unsafe { InitializeIpInterfaceEntry ( & mut row) } ;
326+ row. InterfaceLuid = unsafe { std:: mem:: transmute :: < u64 , NET_LUID_LH > ( adapter_luid) } ;
327+ row. Family = ADDRESS_FAMILY ( family. 0 ) ;
328+ let err = unsafe { GetIpInterfaceEntry ( & mut row) } ;
329+ if err. 0 == 0 {
330+ debug ! (
331+ "IP interface {family_name} for {ifname}: connected={conn}, if_index={idx}, mtu={mtu}" ,
332+ ifname = self . ifname,
333+ conn = row. Connected ,
334+ idx = row. InterfaceIndex ,
335+ mtu = row. NlMtu
336+ ) ;
337+ if family == AF_INET {
338+ ipv4_available = true ;
339+ } else {
340+ ipv6_available = true ;
341+ }
342+ } else {
343+ info ! (
344+ "IP interface {family_name} unavailable on {ifname} (luid={luid:#018x}): {err:#x} - skipping {family_name} routes" ,
345+ ifname = self . ifname,
346+ luid = adapter_luid,
347+ err = err. 0
348+ ) ;
349+ }
350+ }
351+ if !ipv4_available && !ipv6_available {
352+ Err ( WindowsError :: AdapterNotFound ( self . ifname . clone ( ) ) ) ?
353+ }
354+
355+ // Strip allowed IPs for unavailable families so CreateIpForwardEntry2
356+ // inside set_default_route only attempts routes that can succeed.
357+ if !ipv4_available || !ipv6_available {
358+ for peer in & mut interface. peers {
359+ peer. allowed_ips . retain ( |ip| match ip {
360+ IpNet :: V4 ( _) => ipv4_available,
361+ IpNet :: V6 ( _) => ipv6_available,
362+ } ) ;
363+ }
364+ }
365+
366+ // Set adapter addresses. Skip addresses for families that are not
367+ // available on this adapter (e.g. IPv6 disabled system-wide).
316368 debug ! (
317369 "Assigning addresses to adapter {}: {:?}" ,
318370 self . ifname, config. addresses
@@ -321,8 +373,28 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
321373 . addresses
322374 . iter ( )
323375 . filter_map ( |ip| match ip. address {
324- IpAddr :: V4 ( addr) => Some ( IpNet :: V4 ( Ipv4Net :: new ( addr, ip. cidr ) . ok ( ) ?) ) ,
325- IpAddr :: V6 ( addr) => Some ( IpNet :: V6 ( Ipv6Net :: new ( addr, ip. cidr ) . ok ( ) ?) ) ,
376+ IpAddr :: V4 ( addr) => {
377+ if ipv4_available {
378+ Some ( IpNet :: V4 ( Ipv4Net :: new ( addr, ip. cidr ) . ok ( ) ?) )
379+ } else {
380+ debug ! (
381+ "Skipping IPv4 address {}: unavailable on adapter" ,
382+ ip. address
383+ ) ;
384+ None
385+ }
386+ }
387+ IpAddr :: V6 ( addr) => {
388+ if ipv6_available {
389+ Some ( IpNet :: V6 ( Ipv6Net :: new ( addr, ip. cidr ) . ok ( ) ?) )
390+ } else {
391+ debug ! (
392+ "Skipping IPv6 address {}: unavailable on adapter" ,
393+ ip. address
394+ ) ;
395+ None
396+ }
397+ }
326398 } )
327399 . collect ( ) ;
328400 adapter
0 commit comments