[PATCH v3 0/1] MR10553: iphlpapi: Prefer adapters with valid MAC in GetAdaptersInfo.
### What this changes - Adds a MAC validity predicate for adapter entries. - In GetAdaptersInfo, counts adapters with valid physical MAC. - If valid adapters exist, excludes entries with invalid MAC from returned list. ### Why On macOS, pseudo interfaces without usable physical address can appear before real hardware adapters. Legacy clients that pick the first adapter may send empty MAC and fail auth. ### Scope - Module: iphlpapi - API path: GetAdaptersInfo - Platform impact: mainly macOS-like interface layouts with pseudo/tunnel adapters exposed early. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59614 -- v3: nsiproxy.sys: Filter out macOS tunnel-like interfaces from the interface table. https://gitlab.winehq.org/wine/wine/-/merge_requests/10553
From: Nikolai Abdusamatov <nick.luft.work@gmail.com> On macOS, gif0/stf0 and point-to-point IFT_OTHER interfaces inflate the NSI adapter table and break fixed-buffer GetAdaptersInfo callers. Use getifaddrs()/AF_LINK to identify them by BSD type and flags in nsiproxy.sys. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59614 --- dlls/nsiproxy.sys/ndis.c | 64 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c index 8c15186ed53..84a4d65a493 100644 --- a/dlls/nsiproxy.sys/ndis.c +++ b/dlls/nsiproxy.sys/ndis.c @@ -30,6 +30,10 @@ #include <sys/ioctl.h> #include <unistd.h> +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif + #ifdef HAVE_NET_IF_H #include <net/if.h> #endif @@ -66,6 +70,10 @@ #include <linux/wireless.h> #endif +#if defined(HAVE_IFADDRS_H) && defined(HAVE_NET_IF_DL_H) && defined(HAVE_NET_IF_TYPES_H) +#define HAVE_BSD_IF_INFO 1 +#endif + #include <pthread.h> #include "ntstatus.h" @@ -274,11 +282,48 @@ static WCHAR *strdupAtoW( const char *str ) return ret; } -static struct if_entry *add_entry( UINT index, char *name ) +#ifdef HAVE_BSD_IF_INFO +static void if_get_bsd_info( const struct ifaddrs *ifaddrs, const char *name, UINT *bsd_type, UINT *bsd_flags ) +{ + const struct ifaddrs *entry; + + *bsd_type = 0; + *bsd_flags = 0; + + if (!ifaddrs) return; + + for (entry = ifaddrs; entry; entry = entry->ifa_next) + { + if (!entry->ifa_name || strcmp( entry->ifa_name, name )) continue; + if (!entry->ifa_addr || entry->ifa_addr->sa_family != AF_LINK) continue; + *bsd_type = ((const struct sockaddr_dl *)entry->ifa_addr)->sdl_type; + *bsd_flags = entry->ifa_flags; + return; + } +} + +static BOOL if_should_skip( UINT bsd_type, UINT bsd_flags ) +{ + if (bsd_type == IFT_GIF || bsd_type == IFT_STF) return TRUE; + if (bsd_type == IFT_OTHER && (bsd_flags & IFF_POINTOPOINT)) return TRUE; + + return FALSE; +} +#else +static BOOL if_should_skip( UINT bsd_type, UINT bsd_flags ) +{ + (void)bsd_type; + (void)bsd_flags; + return FALSE; +} +#endif + +static struct if_entry *add_entry( UINT index, char *name, UINT bsd_type, UINT bsd_flags ) { struct if_entry *entry; int name_len = strlen( name ); + if (if_should_skip( bsd_type, bsd_flags )) return NULL; if (name_len >= sizeof(entry->if_unix_name)) return NULL; entry = malloc( sizeof(*entry) ); if (!entry) return NULL; @@ -310,13 +355,28 @@ static unsigned int update_if_table( void ) { struct if_nameindex *indices = if_nameindex(), *entry; unsigned int append_count = 0; +#ifdef HAVE_BSD_IF_INFO + struct ifaddrs *ifaddrs = NULL; + if (getifaddrs( &ifaddrs ) != 0) ifaddrs = NULL; +#endif for (entry = indices; entry->if_index; entry++) { - if (!find_entry_from_index( entry->if_index ) && add_entry( entry->if_index, entry->if_name )) + UINT bsd_type; + UINT bsd_flags; + bsd_type = 0; + bsd_flags = 0; +#ifdef HAVE_BSD_IF_INFO + if_get_bsd_info( ifaddrs, entry->if_name, &bsd_type, &bsd_flags ); +#endif + if (!find_entry_from_index( entry->if_index ) && add_entry( entry->if_index, entry->if_name, bsd_type, bsd_flags )) ++append_count; } +#ifdef HAVE_BSD_IF_INFO + if (ifaddrs) freeifaddrs( ifaddrs ); +#endif + if_freenameindex( indices ); return append_count; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10553
On Mon Apr 6 18:49:26 2026 +0000, Nikolai Abdusamatov wrote:
Regarding your question about interfaces: `gif0` and `stf0` are macOS tunnel interfaces (Generic Tunnel and 6to4). The `utun*` interfaces are used by macOS for system and third-party VPNs. These are macOS-specific interfaces that don't exist in Windows (as far as I can tell). Filtering them out in `nsiproxy.sys` would make the list of adapters more similar to what Windows would return on equivalent hardware, and would also reduce the likelihood that applications would encounter buffer size issues, given the typical number of adapters in Windows. I also considered filtering out these macOS-specific interfaces in `nsiproxy.sys`, but couldn’t find a reliable way to identify them. Hard-coding interface names such as gif0, stf0, and utun seems unreliable, and I don’t know of a better macOS-specific attribute that could be used. Maybe someone knows of one? I found a reliable way to identify these interfaces without hardcoding names, using `getifaddrs()` with `AF_LINK` to obtain BSD-level attributes: `sdl_type` from `sockaddr_dl` and `ifa_flags`. This identifies the problematic interfaces precisely:
* `gif0` → `IFT_GIF`: macOS generic tunnel interface, no Windows equivalent, no MAC address * `stf0` → `IFT_STF`: macOS 6-to-4 tunnel interface, no Windows equivalent, no MAC address * `utun*` → `IFT_OTHER` with `IFF_POINTOPOINT`: macOS userspace tunnel used for system and third-party VPNs, no Windows equivalent, no MAC address These macOS-specific interfaces inflate the NSI adapter table, which causes `GetAdaptersInfo` callers with fixed-size buffers to overflow and receive empty MAC addresses. The issue reproduces regardless of whether WireGuard or any other VPN is active — macOS creates `utun` interfaces unconditionally for system use. Testing was done against a local server, so IP-based rejections are ruled out; the empty MAC is the sole cause of the connection failure. Regarding Windows testing: I don't have a working Windows setup to test equivalent conditions (multiple adapters, VPN active). However, I'm not aware of any reports of this empty-MAC issue from Windows users, even those using VPN — which suggests the problem is macOS-specific and caused by these interfaces being present in the list. I’ll also attach some logs, such as the table of adapters and related information in `macOS_network_interfaces_(AF_LINK).md`, and `netdiag-compare.txt`, which compares the patch with the clean repository and shows how it removes unnecessary macOS-specific adapters, thereby fitting within the required buffer. [netdiag-compare.txt](/uploads/8c9c8b4b65dea31bef8197b1037868a8/netdiag-compare.txt) [macOS_network_interfaces\_(AF_LINK).md](/uploads/96d765b7fc2669d4fc24e3e4fdd7f761/macOS_network_interfaces__AF_LINK_.md) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10553#note_135917
On Sun Apr 12 15:39:29 2026 +0000, Nikolai Abdusamatov wrote:
I found a reliable way to identify these interfaces without hardcoding names, using `getifaddrs()` with `AF_LINK` to obtain BSD-level attributes: `sdl_type` from `sockaddr_dl` and `ifa_flags`. This identifies the problematic interfaces precisely: * `gif0` → `IFT_GIF`: macOS generic tunnel interface, no Windows equivalent, no MAC address * `stf0` → `IFT_STF`: macOS 6-to-4 tunnel interface, no Windows equivalent, no MAC address * `utun*` → `IFT_OTHER` with `IFF_POINTOPOINT`: macOS userspace tunnel used for system and third-party VPNs, no Windows equivalent, no MAC address These macOS-specific interfaces inflate the NSI adapter table, which causes `GetAdaptersInfo` callers with fixed-size buffers to overflow and receive empty MAC addresses. The issue reproduces regardless of whether WireGuard or any other VPN is active — macOS creates `utun` interfaces unconditionally for system use. Testing was done against a local server, so IP-based rejections are ruled out; the empty MAC is the sole cause of the connection failure. Regarding Windows testing: I don't have a working Windows setup to test equivalent conditions (multiple adapters, VPN active). However, I'm not aware of any reports of this empty-MAC issue from Windows users, even those using VPN — which suggests the problem is macOS-specific and caused by these interfaces being present in the list. I’ll also attach some logs, such as the table of adapters and related information in `macOS_network_interfaces_(AF_LINK).md`, and `netdiag-compare.txt`, which compares the patch with the clean repository and shows how it removes unnecessary macOS-specific adapters, thereby fitting within the required buffer. [netdiag-compare.txt](/uploads/8c9c8b4b65dea31bef8197b1037868a8/netdiag-compare.txt) [macOS_network_interfaces\_(AF_LINK).md](/uploads/96d765b7fc2669d4fc24e3e4fdd7f761/macOS_network_interfaces__AF_LINK_.md) Even if there isn't a direct equivalent of an interface on Windows I think we want to allow users to use it with Wine. Windows used to have a 6-to-4 tunnel adapter but it's disabled by default in recent Windows versions, so it's probably fine to filter out IFT_STF interfaces.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10553#note_135918
On Sun Apr 12 16:45:52 2026 +0000, Hans Leidekker wrote:
Even if there isn't a direct equivalent of an interface on Windows I think we want to allow users to use it with Wine. Windows used to have a 6-to-4 tunnel adapter but it's disabled by default in recent Windows versions, so it's probably fine to filter out IFT_STF interfaces. But there are definitely p2p interfaces on Windows, also with zero Mac address.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10553#note_135924
On Sun Apr 12 19:11:16 2026 +0000, Paul Gofman wrote:
But there are definitely p2p interfaces on Windows, also with zero Mac address. But what are the chances that they come first on Windows? I remember seeing other apps use the MAC address of the first (non-loopback) interface. It seems likely to be non-zero on Windows.
Assuming ifconfig interface order is the same as Wine's we get 2 tunnel interfaces between the loopback interface and an ethernet interface: ``` lo0 gif0 stf0 en0 ``` gif0 and stf0 are used for 4-to-6 and 6-to-4 tunneling AFAICT which I don't expect to be used anymore. Windows has deprecated and disabled the analogous adapters for a while now which seems to support this. Maybe it's safe to filter them out. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10553#note_135925
On Sun Apr 12 20:12:33 2026 +0000, Hans Leidekker wrote:
But what are the chances that they come first on Windows? I remember seeing other apps use the MAC address of the first (non-loopback) interface. It seems likely to be non-zero on Windows. Assuming ifconfig interface order is the same as Wine's we get 2 tunnel interfaces between the loopback interface and an ethernet interface: ``` lo0 gif0 stf0 en0 ``` gif0 and stf0 are used for 4-to-6 and 6-to-4 tunneling AFAICT which I don't expect to be used anymore. Windows has deprecated and disabled the analogous adapters for a while now which seems to support this. Maybe it's safe to filter them out. Yes, sorry, I was unclear, I don't know that these Mac specific interfaces need to be exposed in Wine, I only questioned that IFF_POINTOPOINT should be stripped off (surely not on Linux). That is what you suggest as well.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10553#note_135926
participants (4)
-
Hans Leidekker (@hans) -
Nikolai Abdusamatov -
Nikolai Abdusamatov (@n-abdusamatov) -
Paul Gofman (@gofman)