0

A little background for the question:

I recently had a near-death experience with Microsoft and socket binding. I was testing production code and one of the test PCs kept failing. I eventually suggested that there was a bug in the bind() function, one of the oldest functions out there.

I submitted the error (see CAsyncSocket Create's bind implementation has a bug in Visual Studio's Developer Community feedback forum), but got handed off to the Windows team (see "__imp_bind implementation has a long-standing situational bug in it" in their Feedback Hub), who never did anything about it.

Since I couldn't debug bind(), and Microsoft refused to assist, I eventually discovered after 2 weeks of dev work, that the test machine in question had Hyper-V enabled and my interface resolution code was picking up this spurious AF_INET address and resolving on it instead of on the real IP address.

I can't expect my customers to turn off the unwanted Hyper-V feature just to run my software, so I need to make my resolution code more granular.

My question:

What I need to do is to be able to get a particular address's verbose name, like for ipconfig /all. I can see that others have asked this question, like Ivan's how to determine interface name and tez's Linux getting all network interface names. Ivan's answer was to use getsockname() and tez's answer was to use if_nameindex(). Neither one of which returns the verbose interface name as seen in ipconfig.

So, does someone know what function call that would be?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
rtischer8277
  • 496
  • 6
  • 27
  • 2
    On Windows, look at `GetAdaptersInfo()` (XP and earlier) and `GetAdaptersAddresses()` (Vista and later), `GetInterfaceInfo()`, etc. You can get the socket's real local IP from `getsockname()` only after it has been `bind()`ed to a specific IP, or after `accept()`ed or `connect()`ed if bound to a wildcard IP, and then you can lookup the IP in the address tables to find its interface index, and then lookup that index in the interface tables to get its human-readable name. – Remy Lebeau Aug 30 '19 at 19:26
  • That being said, what exactly about Hyper-V is breaking your code? Can you elaborate on that? 99% of socket code in the world doesn't do anything special about Hyper-V and it "just works" fine, so what exactly is Hyper-V breaking in your particular environment? Can you provide a [mcve] that doesn't work for you? How is your code setting up the socket? What is the desired result? What is the actual result? – Remy Lebeau Aug 30 '19 at 19:26
  • **GetAdaptersAddresses()** is going to work fine. My interface resolution code has not been very sophisticated and merely grabbed the first **AF_INET** interface that resolved. Of course, now that Ipv6 is present and there are many more interfaces that un-explain-ably show up like **Npcap Loopback Adapter** and **Hyper-V...** then **family** is not a good enough key for resolving. The problem was not a bug in **bind()**, but in not being able to better discriminate while resolving. Once I do that using **GetAdaptersAddresses()** the phantom **bind()** problem will go away. – rtischer8277 Aug 30 '19 at 21:48
  • So, you are trying to `bind()` a socket via an interface name? Why not just `bind()` it by IP, and then require the user to provide the correct IP to use? A network interface can have multiple IPs assigned to it, so a name alone may not be enough, unless you `bind()` a separate socket to every IP the interface actually has. – Remy Lebeau Aug 30 '19 at 21:50
  • The problem occurred on my ASUS test machine, but not on a Dell test machine. Both these machines had Hyper-V turned on. Only after much debugging did I realize that the incorrect interface was being resolved on for the ASUS. If I remember correctly, on the ASUS, the linked-list interface order was different than on the Dell, which tripped up my sequentially resolving interface code, where the Hyper-V interface came first on the ASUS. Why the linked-list interfaces order was different for the two hardware platforms, I do not know. But clearly, my code should not be sensitive to that variation. – rtischer8277 Aug 30 '19 at 22:03
  • No, you definitely should not rely on the particular order of interfaces. It could change order dynamically, even when queried multiple times on the same machine. – Remy Lebeau Aug 30 '19 at 22:05
  • "So, you are trying to bind() a socket via an interface name?" I am binding by IP. I will now be using the extra info in **Description** and **Friendly Name** to weed out the interfaces in the same family that I don't want to bind to, like Hyper-V. – rtischer8277 Aug 30 '19 at 22:08
  • That is not a good idea, either. There are MANY MANY interfaces in the world, are you really going to try to filter them out individually? Why not just present the interface list to the user and let them decide which one(s) to bind to? – Remy Lebeau Aug 30 '19 at 22:11
  • I see your point. Unfortunately, my users will all be application level, so I'm going to have to figure this one out programmatically. What about the reverse set? Perhaps there's a characteristic I can discriminate on that guaranteed would give me a bind-able IP. – rtischer8277 Aug 30 '19 at 22:15
  • If I understand, there's neither a bug in `CAysncSocket` nor `bind()`. Is that correct? – IInspectable Sep 02 '19 at 13:02
  • That is correct. In my defense, I simply could not "see" any further into the code since I couldn't debug without the bind source. Had I been able to do that, I would have immediately seen that it was binding fine to an interloper Hyper-V socket interface. Maybe there were other ways to observe that faulty binding case. I only discovered the workaround solution (remove Hyper-V feature) by brute force debugging (trying all cases until something gives). By then I had reached out to StackOverflow as a last resort. See `Selecting a socket interface for any unknown environment` for current state. – rtischer8277 Sep 02 '19 at 15:06

1 Answers1

0

Remy Lebeau's answer was to use GetAdaptersAddresses. The sample code for that function shows how to iterate through socket adapter interfaces and get copious amounts of interface data. To answer the question (ie, get ipconfig-like verbosity), however, you need the individual ip addresses. These are available in the LPSOCKADDR lpSockaddr members, which are outputs of the GetAdaptersAddresses call, an example of which is pUnicast->Address.lpSockaddr.

rtischer8277
  • 496
  • 6
  • 27