How to add persistent IPv6 address in Vista/Windows7? - winapi

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`\

Related

getaddrinfo with flag AI_NUMERICHOST

Please tell me something I can't understand. There is a function getaddrinfo() and there is a flag AI_NUMERICHOST. MSDN says that in getaddrinfo() with this flag, you need to send the numeric value of the IP address, and not the domain name. But why?
I already have an IP address, why should I ask DNS for an IP address?
getaddrinfo() outputs sockaddr_... structs (sockaddr_in or sockaddr_in6) for the requested host/service. It is not just about IP addresses, it is also about other things, like socket types, service ports, etc, depending on your input and hint values.
So, if you already have an IP address in a string format, you can have getaddrinfo() parse that string for you (specifying AI_NUMERICHOST to avoid DNS) into a binary format in the output sockaddr_..., as well as fill in other sockaddr_... fields at the same time.

How to determine the default network adapter through 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.

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.

ipv6calc outputs wrong address when converting from ipv4 to ipv6?

Having a strange issue while trying to convert an ipv4 list file to ipv6:
ipv6calc -q --action conv6to4 --in ipv4 1.1.23.1 --out ipv6
2002:101:1701::
Trying to validate that result is correct, I used some online converters and it seems that 1.1.23.1 is 2002:0:0:0:0:0:101:1701 (or else 2002::101:1701).
So the last "::" should be removed & 2002 should have extra ":".
I really don't want to use sed/awk commands in order to manipulate this result, so the questions are:
is there alternative cmd/linux SW?
is this somehow fixed inside ipv6 calc, am I doing something wrong?
Thanks
This is the correct 6to4 address. A 6to4 subnet is on the format 2002:IP4_HI:IP4_LO::/48. IP4_HI is the top 16 bits of the IPv4 address, while IP4_LO is the low 16 bits of the address.
For example, the IPv4 address 1.2.3.4 gives you the 6to4 subnet 2002:0102:0304::/48.
See 6to4 address block allocation for more details.
A different question is whether this is actually the address you want? There are other ways to map IPv4 addresses to IPv6 addresses. For example, there are IPv4-mapped IPv6 addresses, which are typically written as ::ffff:1.2.3.4.
The address format you need depends on what you are going to use it for.

Is this a valid IPv6 address, 74DC::02BA?

Is 74DC::02BA a valid IPv6 address?
I am trying to break it down, but the various shortcuts are confusing me.
Valid address, yes. See this question. Also, this validator breaks it down nicely.
Correct address, probably not. See RFC 4291, section 2.4, where this address is defined as a Global Unicast address. (the first bits are 0111 0100, which falls under "everything else" in the table) Then see the IPv6 address assignments. You'll notice this address range has not been assigned for use.
Normally you wouldn't see an address written like this, since it contains extra information. (the leading 0 in the second group of digits) So you would probably see it written like 74dc::2ba. (The IETF makes recommendations about how to print IPv6 addresses in RFC 5952.)
If you want to know the rules for IPv6 address shortening, they are specified in RFC 4291, section 2.2.
Here's what I believe to be the best online IPv6 validator (and not just because I wrote it). It will show you the various address forms and show you how the different representations relate to each other (try hovering over each address group).
The "::" means there's all 0s in between the colons. The address expands to 74dc:0000:0000:0000:0000:0000:0000:02ba
IPv6 Address Validator

Resources