Win32 Netzwerk-Setup

Besonders für “Lizenzen” hatte ich schon öfter den Auftrag, Hardware-Infos auszulesen. Sehr beliebt sind dafür MAC-Adressen. Aber auch für manche Server braucht man die Liste der aktuellen IP Adressen, damit man sich daran binden kann.

Leider hat Windows in den letzten 30 Jahren da einiges geändert und somit braucht man oft mehrere Schnittstellen. ————————————————————

Zu Zeiten von WinNT 4 war die Welt noch einfach.
Grundsätzlich sollte der User gar keine Details über das Netzwerk wissen, sondern nur Laufwerke darüber verbinden und dann “transparent” mit anderen Systemen im Netzwerk Daten austauschen.
Ob da jetzt ein NetBEUI, IPX/SPX oder TCP/IP dahinter benutzt wurde, sollte niemanden interessieren.

Und dann kam das Internet und TCP/IP wurde DER Standard.

Und dann wurde es noch komplizierter:

  • Wir erhielten mehrere IP’s pro physischen Adapter
  • Dann tauchten virtuelle Netzwerkgeräte auf
  • IPv6 kam auch noch dazu
  • Und spätestens mit Hyper-V wurde ein Adapter in mehrere aufgeteilt.

Wir müssen heute also zuerst mal unterscheiden, ob wir Netzwerkgeräte oder Endknoten (wie IP Adressen) auflisten wollen. Und wegen möglicher virtualisieren kann durchaus eine MAC-Adresse auch mehrfach vorkommen.

Die NT APIs

Mit GetIfTable kommt man bis ins Jahr 1998 zurück, als NT4 SP4 und Windows 98 die API eingeführt haben.
Sie liefert alle “Interfaces” als MIB_IFROW zurück, die im System installiert sind. Früher war das mal das eine IP-Interface, das an den einen Netzwerkadapter gebunden war. Heute liefert die Funktion leider eine Vielzahl von virtuellen und deaktivierten Schnittstellen, womit man erst viele Flags und andere Kriterien auswerten muss, bis man die relevanten Schnittstellen ausgefiltert bekommen hat.

Im Feld wszName finden wir heute die Interface-GUID, mit der man bevorzugt arbeiten sollte, wenn man die Infos mit anderen Schnittstellen abgleichen will. Zu NT4 Zeiten gab es die GUID auf der Ebene noch nicht, sondern man musste über den dwIndex (Netzwerk-Interface-Index) das Gerät eindeutig identifizieren.
Das bDescr Feld gibt uns einen anzeigbaren Namen der Netzwerkschnittstelle zurück und bPhysAddr enthält die MAC-Adresse des verbundenen Adapters.

Die API GetIpAddrTable listet alles in einer struct MIB_IPADDRTABLE auf, was eine IP-Adresse hat oder haben könnte.
Hier kann man eine Verbindung zu GetIfTable über dwIndex herstellen und somit einen Eintrag der “Interface-Table” mit der “IP-Addr-Table” verknüpfen.

Windows 2000 (und teils Win98)

Mit GetAdaptersInfo erhalten wir in Win2K und teils Win98 bereits eine Combo aus Adapter und IP Adressen in der IP_ADAPTER_INFO Struktur. Hier sind dann sogar Gateways und DHCP Infos mit dabei, wie auch die gute alte MAC-Adresse.

Fast könnte man glauben, diese wäre die perfekte API, doch leider listet sie nur “aktivierte” Adapter mit IPs auf. Das reicht für Socket-Bindungen, aber MAC-Adressen für Lizenzen sind dann ein Problem. Außerdem fehlt der Support für IPv6, da es dieses Protokoll damals noch nicht gab.

Windows XP

XP brachte uns daher GetAdaptersAddresses, welches uns auch IPv6 Daten in seinen IP_ADAPTER_ADDRESSES Strukturen liefert.
Hier wird es wieder kompliziert, wenn es um die Verknüpfung mit anderen APIs geht. Der Interface-Index liegt hier nämlich entweder im Feld IfIndex oder in Ipv6IfIndex.

Ich nutze die API daher nur für IPv6 Adressen und hole die anderen Daten über GetAdaptersInfo ab.

Von Windows Vista bis heute

Am Ende kam dann mit GetIfTable2 und der MIB_IF_TABLE2 ab Windows Vista eine aktualisierte Variante von GetIfTable auf den Markt, die uns mehr Flags und Details über die Hardware liefert. So wissen wir, ob es ein WLAN oder Ethernet-Gerät ist, oder ob es nur eine virtuelle Verbindungsbrücke zwischen zB. IPv4 und IPv6 ist.

Die klassischen NT-APIs liefern heute im schlimmsten Fall 60 Geräte, wie bei mir, wenn Hyper-V, WSL und Docker läuft, und dann weiß kein Mensch mehr, welches davon ein Adapter ist, über den eine lokale Anwendung ihre Daten hinausschicken würde.

Andere APIs

Eine hervorragende Alternative zu alle dem ist übrigens WMI, denn dort kann man sich die vielen APIs schenken und WMI-Queries absetzen und die Ergebnisse einsammeln.
Ein paar interessante Queries sind:

1SELECT __Path, Name, GUID, PNPDeviceID FROM Win32_NetworkAdapter WHERE NetConnectionID IS NOT NULL;
2SELECT __Path FROM Win32_NetworkAdapter WHERE GUID='{nif-guid}';
3SELECT __Path, SettingID FROM Win32_NetworkAdapterConfiguration WHERE SettingID='{set-guid}";
4

Die WMI Objekte unterstützen Methoden wie Disable, EnableStatic EnableDHCP oder SetGateways und somit kann man auch gleich die Netzwerkeinstellungen nach Belieben abändern.

Die COM API der Internet-Connection-Sharing Umgebung stellt auch ein paar Methoden bereit, um Netzwerkeinstellungen auszulesen. Ich habe allerdings stets nur das Interface INetConnection zum Ein- und Ausschalten eines Netzwerkadapters benutzt.

Fazit

Im GATE Projekt nutze ich alle nativen Win32 APIs, aber optional. Auf einem modernen Host bekomme ich so also IPv6 Details und Infos, welche Adapter zu streichen sind.
Und dann wird bis zur alten NT4-API alles aufgerufen, was da ist, um den Datensatz anzureichern, der dann am Ende ausgegeben wird.

Ja, die Windows Netzwerk APIs sind kompliziert … aber sie bilden eben 30 Jahre Softwaregeschichte ab … und Geschichte ist immer auch ein bisschen kompliziert.