How to determine the default network adapter through WinApi? - winapi

Is there a way through Windows API to determine which is the primary/default network adapter?
For example, if I have a PC with two network cards, I need to know which one is used by the system to access internet, similarly if I have a network adapter and a virtual adapter.
I tried with GetAdaptersAddresses but it doesn't show which is the favourite one, maybe with GetBestInterface?

How about using GetAdaptersInfo and looking for an IP range that satisfies your requirement?
Alternatively, came across this (WMI):
https://msdn.microsoft.com/en-us/library/windows/desktop/aa394216(v=vs.85).aspx
~snip:
Once you have done so, you will likely have reduced your list to one
or two configured adapters.
You can also use the following procedure to find the default adapter:
Run the following query: "SELECT InterfaceIndex, Destination FROM Win32_IP4RouteTable WHERE Destination='0.0.0.0'" You should only have
one default network destination 0.0.0.0.
Use the InterfaceIndex to retrieve the Network Adapter you want. "SELECT * FROM Win32_NetworkAdapter WHERE InterfaceIndex=" +
insertVariableHere
Here's a CodeProject article claiming to determine the default:
http://www.codeproject.com/Articles/13421/Getting-the-Physical-MAC-address-of-a-Network-Inte
Getting the Physical (MAC) address of a Network Interface Card and finding out if it is the primary adapter on a multi-homed system
Finding out if the adapter with the given index is the primary adapter
In order to find out if the adapter with the given index is the
primary adapter, I had to add a function to the dialog class
CNetCfgDlg. This code iterates over the m_pAdapters array, comparing
the given adapter index with the index for each adapter in the array.
If the given adapter index is equal to the smallest index of all
adapters in the array, then it is the primary adapter
And one more thing to consider, is there's the 'Automatic Metric' setting for each adapter which seems to choose the lowest setting as the preferred (although not sure how to access this metric setting programmatically):
http://www.softminer.net/2011/09/setting-default-network-adapter-in.html

This SO Answer explains how to determine the local IP address used to connect to the Internet (like Google's DNS servers), you can then compare this local IP address with the list returned by GetAdaptersAddresses to determine which network card was used for Internet Access.

Related

IPv6: Interface IP operations are stopped with floating IP in HA failover

When a main node fails, its IP (IPv6) floats to standby node. The standby node is supposed to provide service henceforth on that IP.
Given that both these nodes co-exist in the same LAN, often it is seen that the standby node becomes unreachable. The interface is UP and RUNNING with the IPv6 address assigned, but all the IP operations are stopped.
One possibility is Duplicate Address Detection (DAD) is kicking in when the IP is getting configured on standby. The RFC says all IP operations must be stopped.
My question is regarding the specifics in Linux kernel IPv6 implementation. Previously, from kernel code, I supposed the sysctl variable "disable_ipv6" must be getting set. But the kernel is not disabling IPv6, it is just stops all IP operations on that interface.
Can anyone explain what Linux kernel IPv6 does when it "disables these IP operations" on DAD failure? Can this be reset to normal without doing the interface DOWN & UP? Any pointers in the code will be very helpful.
This article elaborates the specification and behavior w.r.t. what really is happening in the kernel w.r.t. IPv6 implementation and the floating IP configuration. It also suggests a solution:
http://criticalindirection.com/2015/06/30/ipv6_dad_floating_ips/
It mentions for "user-assigned link-local", the IPv6 allocation gets stuck in tentative state, marked by IFA_F_TENTATIVE in the kernel. This state implies DAD is in progress and the IP is not yet validated. For "auto-assigned link-local", if the DAD fails it retries accept_dad times (with new auto-generated IP each time), and after that it disables IPv6 on that interface.
Solution it suggests is: Disable DAD before configuring the floating IP and enable it back when it is out of the tentative state.
For more details refer above link.
This is related to a bug in nova, bug #101134
The documentation for accept_dad says:
accept_dad - INTEGER
Whether to accept DAD (Duplicate Address Detection).
0: Disable DAD
1: Enable DAD (default)
2: Enable DAD, and disable IPv6 operation if MAC-based
duplicate link-local address has been found.
So you can use sysctl -w net.ipv6.conf.default.accept_dad=0 to workaround the bug and disable DAD.
Alternatively, you can fix this bug by implementing the proposing patches to nova/virt/libvirt/firewall.py from that same bug report.
If it is not already present in the NWFilterFirewall class, add the following staticmethod:
def nova_no_nd_reflection_filter(self):
"""This filter protects false positives on IPv6 Duplicate Address
Detection(DAD).
"""
uuid = self._get_filter_uuid('nova-no-nd-reflection')
return '''<filter name='nova-no-nd-reflection' chain='ipv6'>
<!-- no nd reflection -->
<!-- drop if destination mac is v6 mcast mac addr and
we sent it. -->
<uuid>%s</uuid>
<rule action='drop' direction='in'>
<mac dstmacaddr='33:33:00:00:00:00'
dstmacmask='ff:ff:00:00:00:00' srcmacaddr='$MAC'/>
</rule>
</filter>''' % uuid
Then, add this filter to your filter lists in _ensure_static_filters() by adding:
self._define_filter(self.nova_no_nd_reflection_filter())
after filter_set is defined.

Windows limitation on number of simultaneously opened sockets/connections per machine

Let's say I have Windows 7 with one real network interface and few loopback interfaces.
I have IOCP enabled server that accepts connections from clients.
I'm trying to simulate as much as possible real client connections to the server.
My client code simply establishes X amount of socket connections
(note that client binds to a given interface):
const Int32 remotePort = 12345;
const Int32 MaxSockets = 60000;
Socket[] s = new Socket[MaxSockets];
IPEndPoint bindEndpoint = new IPEndPoint(IPAddress.Parse(args[0]), 0);
for (Int32 i = 0; i < MaxSockets; i++)
{
s[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s[i].SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
s[i].Bind(bindEndpoint);
s[i].Connect(args[1], remotePort);
IPEndPoint socketInfo = (IPEndPoint)s[i].LocalEndPoint;
Console.WriteLine(String.Format("Connected socket {0} {1} : {2}", i, socketInfo.Address, socketInfo.Port));
}
On a loopback interface I have several IPs that I use for binding.
In addition, I also use real interface to bind on.
I ran into a problem when amount of opened sockets is around 64K per machine:
Unhandled Exception: System.Net.Sockets.SocketException: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full
I've tried several helpless things like:
- setting MaxUserPort to max value and some other recommended TCPIP settings in the registry.
- trying to run two servers on different interfaces (real interfaces and loopback) and using several clients.
Is it a known limitation in Windows or its possible to overcome it somehow?
Thanks for the help!
I have found on some Microsoft page that:
... HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort
registry subkey is defined as the maximum port up to which ports may be allocated for wildcard binds. The value of the MaxUserPort registry entry defines the dynamic port range...
So, if I force the endpoint to use a certain port, e.g.
IPEndPoint bindEndpoint = new IPEndPoint(IPAddress.Parse(args[0]), 54321);
Then I can open more than 64K simultaneous sockets in the system.
In your code example, you are calling Bind(bindEndpoint), but you do not show how bindEndpoint is defined. Check that :
Your system actually has multiple IP addresses (loopback does not count)
You are actually setting the IP Address of the endpoint to an IP address (not loopback)
The binds are being spread across multiple IP addresses
The loopback address does not count because many systems treat it specially for routing and binding purposes. So binding to ports in loopback may be sucking up the ports across all addresses the same as if you were binding to INADDR_ANY (0.0.0.0).
Both TCP and UDP use an unsigned 16-bit integer to designate port number. I don't imagine any implementation in any operating system is going to be able to open more than 65535 sockets per bound address at best. Additionally, I wouldn't be surprised if Windows doesn't implement fully isolated state tables for each adapter or each bound address but instead relies on a global state table. If that is the case, it would be a Windows network architecture limit instead of a soft, configurable limit.
I've developed a load testing tool.
Running on Windows 10/16G RAM, it could created 60,000 connections with server successfully.
But when try to create more connections, the tool will report "socket WinError 10055 No Buffer Space Available" soon.
Accord to this article, I think the limitation is the overall socket buffer size of whole OS, not the number of opened file.

Obtaining MACs on a Layer 3 port via SNMP?

I'm working on a script to map servers that are connected into our switches and routers. I have it working to map layer two ports, using the algorithm listed at http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a00801c9199.shtml to pull out the MAC addresses.
Layer 3 ports are another matter. These are ports that don't show up in the 'sh vlan' command on a router/layer 3 switch. Ideally, I'd like to use the MAC addresses present in these ports, underlying the layer 3 connection, as that's a bit more 'permanent' than the IP address - these do show up in the MAC-address table on the device. However, the fact that these ports don't have an associated VLAN, and that the MAC retrieval via SNMP is VLAN-indexed, makes it quite difficult.
I've been banging my head against this for about a week or so, but nothing I try/find seems to allow me to get the non-VLAN MAC addresses. Is it possible to map the layer three ports this way, or will I need to use layer 3 (IP address) mapping?
If you are connected via layer 2 to the device, you could just use a ping on the layer 3 address to generate an arp lookup and then look in the arp cache for the mac... This would work for any layer 3 port, even logical ports like the layer 3 version of Portchannels.
This is probably the easiest way.
If you want to be 100% in the realm of SNMP:
To get the interface table for that device, walk the below oid. It will return
the list of all interfaces on that device. This should work on any device (even a server) runnning a SNMP agent:
.1.3.6.1.2.1.2.2.1.2
This will give you a list of interface numbers (last digit in OID), and the interface descriptions. It works for SVI and physical interfaces, not sure about logical types other than SVI.
Then for each interface, to get it's mac (where x is the value in the interface table):
.1.3.6.1.2.1.2.2.1.6.x
This gives you the mac. (Leading 0's can be truncated on some devices.)
However, you will need atleast 1 layer 3 address on each device to do the snmpwalk and get.
If you just want all the macs, then walk this oid:
.1.3.6.1.2.1.2.2.1.6
I use this approach to do something similar on a large network.

How to add persistent IPv6 address in Vista/Windows7?

I want to add a persistent IPv6 address using just API calls or with Registry edits. I have currently implemented a code which uses CreateUnicastIpAddressEntry API to add the IPv6 address successfully, but the IP address is destroyed when the adapter is reset or machine rebooted (as mentioned in MSDN docs).
With IPv4, it was easy to do. Just use AddIPAddress API combined with registry entries to get the desired result.
I have tried to find any entry in the Windows Registry which is being used to save the IPv6 address without any success. The MSDN docs suggests to use netsh.exe to do the task, but then I am quite sure netsh.exe is doing some API call or Registry entry to achieve this task (which is not documented by Microsoft anywhere).
How can this be achieved?
Well, after some reverse engineering of netsh.exe and detailed analysis I think there is sufficient info to create a persistent ipv6 address.
The ipv6 address (UNICAST) is stored in following registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nsi\{eb004a01-9b1a-11d4-9123-0050047759bc}\10
For every ipv6 address to be added, create a REG_BINARY value such that the name of the value contains NET_LUID concatenated with the ipv6 address in full. Like for example, if the ipv6 address is 2001::1, the name of the value will be 000000090000060020010000000000000000000000000001, where the first 16 characters is the NET_LUID of the network adapter and the rest the ipv6 address in full.
This registry value data is made of a 48 byte long structure given below:
typedef struct _UNKNOWN {
ULONG ValidLifetime;
ULONG PreferredLifetime;
NL_PREFIX_ORIGIN PrefixOrigin;
NL_SUFFIX_ORIGIN SuffixOrigin;
UINT8 OnLinkPrefixLength;
BOOLEAN SkipAsSource;
UCHAR Unknown[28];
} UNKNOWN;
The last 28 bytes of this structure is unknown and must be initialized to 0xFF.
Refer to MIB_UNICASTIPADDRESS_ROW structure info in msdn for more info on the UNKNOWN structure members.
While doing this, I also figured out that ipv6 ANYCAST addresses are stored similarly in registry key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nsi\{eb004a01-9b1a-11d4-9123-0050047759bc}\8`\

SNMP - get complete Mac table in one call

For my project I need to download mac table from switch and do it as fast as possible. Official solution is kind of slow. It requires to get list of all Vlan's, and for each one trigger separate call of snmpwalk with OID=.1.3.6.1.2.1.17.4.3.1.1 and community string indexed with vlan number. It can take significant amount of time, since number of vlan's on our switches ranges in tens.
Is there a way to get all mac addresses from mac table at once(some special community index representing all available vlan indexes)?
Thanks in advance..
I think BRIDGE-MIB::dot1dTpFdbTable (1.3.6.1.2.1.17.4.3) will do the job. One can simply retrieve dot1dTpFdbPort (1.3.6.1.2.1.17.4.3.1.2) to retrieve learned MAC -> PORT table. For my DLINK DGS-1216T I can get mac-to-port table from my Linux box by this command:
$ snmpwalk -O0sUX -v2c -Cc -c public 192.168.0.1 BRIDGE-MIB::dot1dTpFdbPort
Additionally I found extra (17th) port number for maintenance MAC.
Do you try to retreive the ipNetToMediaTable ({iso(1) identified-organization(3) dod(6) internet(1) mgmt(2) mib-2(1) ip(4) ipNetToMediaTable(22)} or 1.3.6.1.2.1.4.22) from your switch management address. It represents the IP Address Translation table used for mapping from IP addresses to physical addresses.
----EDIT----
If you want to Use SNMP to Find a Port Number from a MAC Address on a Catalyst Switch with a minimum of frames you can us a Get-Bulk PDU, it assume that you switch is SNMP V2c.

Resources