static int interface_in_recvips_p (const struct nn_interface *interf) { struct ospl_in_addr_node *nodeaddr; for (nodeaddr = gv.recvips; nodeaddr; nodeaddr = nodeaddr->next) { if (os_sockaddrIPAddressEqual ((const os_sockaddr *) &nodeaddr->addr, (const os_sockaddr *) &interf->addr)) return 1; } return 0; }
int find_own_ip (const char *requested_address) { const char *sep = " "; char last_if_name[80] = ""; int quality = -1; os_result res; int i; unsigned int nif; os_ifAttributes *ifs; int maxq_list[MAX_INTERFACES]; int maxq_count = 0; int maxq_strlen = 0; int selected_idx = -1; char addrbuf[INET6_ADDRSTRLEN_EXTENDED]; if ((ifs = os_malloc (MAX_INTERFACES * sizeof (*ifs))) == NULL) { NN_FATAL0 ("ddsi2: insufficient memory for enumerating network interfaces\n"); return 0; } nn_log (LC_CONFIG, "interfaces:"); if (config.useIpv6) res = os_sockQueryIPv6Interfaces (ifs, (os_uint32) MAX_INTERFACES, &nif); else res = os_sockQueryInterfaces (ifs, (os_uint32) MAX_INTERFACES, &nif); if (res != os_resultSuccess) { NN_ERROR1 ("os_sockQueryInterfaces: %d\n", (int) res); os_free (ifs); return 0; } gv.n_interfaces = 0; for (i = 0; i < (int) nif; i++, sep = ", ") { os_sockaddr_storage tmpip, tmpmask; char if_name[sizeof (last_if_name)]; int q = 0; os_strncpy (if_name, ifs[i].name, sizeof (if_name) - 1); if_name[sizeof (if_name) - 1] = 0; if (strcmp (if_name, last_if_name)) nn_log (LC_CONFIG, "%s%s", sep, if_name); os_strcpy (last_if_name, if_name); /* interface must be up */ if ((ifs[i].flags & IFF_UP) == 0) { nn_log (LC_CONFIG, " (interface down)"); continue; } tmpip = ifs[i].address; tmpmask = ifs[i].network_mask; sockaddr_to_string_no_port (addrbuf, &tmpip); nn_log (LC_CONFIG, " %s", addrbuf); if (ifs[i].flags & IFF_LOOPBACK) { /* Loopback device has the lowest priority of every interface available, because the other interfaces at least in principle allow communicating with other machines. */ q += 0; #if OS_SOCKET_HAS_IPV6 if (!(tmpip.ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &tmpip)->sin6_addr))) q += 1; #endif } else { #if OS_SOCKET_HAS_IPV6 /* We accept link-local IPv6 addresses, but an interface with a link-local address will end up lower in the ordering than one with a global address. When forced to use a link-local address, we restrict ourselves to operating on that one interface only and assume any advertised (incoming) link-local address belongs to that interface. FIXME: this is wrong, and should be changed to tag addresses with the interface over which it was received. But that means proper multi-homing support and has quite an impact in various places, not least of which is the abstraction layer. */ if (!(tmpip.ss_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &tmpip)->sin6_addr))) q += 5; #endif /* We strongly prefer a multicast capable interface, if that's not available anything that's not point-to-point, or else we hope IP routing will take care of the issues. */ if (ifs[i].flags & IFF_MULTICAST) q += 4; else if (!(ifs[i].flags & IFF_POINTOPOINT)) q += 3; else q += 2; } nn_log (LC_CONFIG, "(q%d)", q); if (q == quality) { maxq_list[maxq_count] = gv.n_interfaces; maxq_strlen += 2 + strlen (if_name); maxq_count++; } else if (q > quality) { maxq_list[0] = gv.n_interfaces; maxq_strlen += 2 + strlen (if_name); maxq_count = 1; quality = q; } gv.interfaces[gv.n_interfaces].addr = tmpip; gv.interfaces[gv.n_interfaces].netmask = tmpmask; gv.interfaces[gv.n_interfaces].mc_capable = ((ifs[i].flags & IFF_MULTICAST) != 0); gv.interfaces[gv.n_interfaces].point_to_point = ((ifs[i].flags & IFF_POINTOPOINT) != 0); gv.interfaces[gv.n_interfaces].if_index = ifs[i].interfaceIndexNo; gv.interfaces[gv.n_interfaces].name = os_strdup (if_name); gv.n_interfaces++; } nn_log (LC_CONFIG, "\n"); os_free (ifs); if (requested_address == NULL) { if (maxq_count > 1) { const int idx = maxq_list[0]; char *names; sockaddr_to_string_no_port (addrbuf, &gv.interfaces[idx].addr); if ((names = os_malloc (maxq_strlen + 1)) == NULL) NN_WARNING2 ("using network interface %s (%s) out of multiple candidates\n", gv.interfaces[idx].name, addrbuf); else { int p = 0; for (i = 0; i < maxq_count; i++) p += snprintf (names + p, maxq_strlen - p, ", %s", gv.interfaces[maxq_list[i]].name); NN_WARNING3 ("using network interface %s (%s) selected arbitrarily from: %s\n", gv.interfaces[idx].name, addrbuf, names + 2); os_free (names); } } if (maxq_count > 0) selected_idx = maxq_list[0]; else NN_ERROR0 ("failed to determine default own IP address\n"); } else { os_sockaddr_storage req; if (!os_sockaddrStringToAddress (config.networkAddressString, (os_sockaddr *) &req, !config.useIpv6)) { /* Presumably an interface name */ for (i = 0; i < gv.n_interfaces; i++) if (strcmp (gv.interfaces[i].name, config.networkAddressString) == 0) break; } else { /* Try an exact match on the address */ for (i = 0; i < gv.n_interfaces; i++) if (os_sockaddrIPAddressEqual ((os_sockaddr *) &gv.interfaces[i].addr, (os_sockaddr *) &req)) break; if (i == gv.n_interfaces && !config.useIpv6) { /* Try matching on network portion only, where the network portion is based on the netmask of the interface under consideration */ for (i = 0; i < gv.n_interfaces; i++) { os_sockaddr_storage req1 = req, ip1 = gv.interfaces[i].addr; assert (req1.ss_family == AF_INET); assert (ip1.ss_family == AF_INET); /* If the host portion of the requested address is non-zero, skip this interface */ if (((os_sockaddr_in *) &req1)->sin_addr.s_addr & ~((os_sockaddr_in *) &gv.interfaces[i].netmask)->sin_addr.s_addr) continue; ((os_sockaddr_in *) &req1)->sin_addr.s_addr &= ((os_sockaddr_in *) &gv.interfaces[i].netmask)->sin_addr.s_addr; ((os_sockaddr_in *) &ip1)->sin_addr.s_addr &= ((os_sockaddr_in *) &gv.interfaces[i].netmask)->sin_addr.s_addr; if (os_sockaddrIPAddressEqual ((os_sockaddr *) &ip1, (os_sockaddr *) &req1)) break; } } } if (i < gv.n_interfaces) selected_idx = i; else NN_ERROR1 ("%s: does not match an available interface\n", config.networkAddressString); } if (selected_idx < 0) return 0; else { gv.ownip = gv.interfaces[selected_idx].addr; sockaddr_set_port (&gv.ownip, 0); gv.selected_interface = selected_idx; gv.interfaceNo = gv.interfaces[selected_idx].if_index; #if OS_SOCKET_HAS_IPV6 if (config.useIpv6) { assert (gv.ownip.ss_family == AF_INET6); gv.ipv6_link_local = IN6_IS_ADDR_LINKLOCAL (&((os_sockaddr_in6 *) &gv.ownip)->sin6_addr) != 0; } else { gv.ipv6_link_local = 0; } #endif nn_log (LC_CONFIG, "selected interface: %s (index %u)\n", gv.interfaces[selected_idx].name, (unsigned) gv.interfaceNo); return 1; } }
os_result os_sockQueryIPv6Interfaces( os_ifAttributes *ifList, os_uint32 listSize, os_uint32 *validElements) { os_result result = os_resultSuccess; os_result addressInfoResult =0; unsigned long returnedBytes; unsigned int listIndex; os_socket ifcs; int retVal, done; char* errorMessage; os_sockErrno errNo; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; unsigned long outBufLen = 0; /* Set the flags to pass to GetAdaptersAddresses*/ unsigned long flags = GAA_FLAG_INCLUDE_PREFIX; int i = 0; /* IPv6 addition */ SOCKET_ADDRESS_LIST* ipv6InterfaceList; *validElements = 0; listIndex = 0; outBufLen = sizeof (IP_ADAPTER_ADDRESSES); pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen); if (GetAdaptersAddresses(AF_INET6, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { os_free(pAddresses); pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen); } addressInfoResult = GetAdaptersAddresses(AF_INET6, flags, NULL, pAddresses, &outBufLen); /* Now do the IPv6 interfaces */ ifcs = os_sockNew (AF_INET6, SOCK_DGRAM); if (ifcs != INVALID_SOCKET) { /* List returned from this control code query will need to be sized as 1 * SOCKET_ADDRESS_LIST + n * SOCKET_ADDRESS */ ipv6InterfaceList = os_malloc(sizeof(SOCKET_ADDRESS_LIST) + ((MAX_INTERFACES - 1) * sizeof(SOCKET_ADDRESS))); memset(ipv6InterfaceList, 0, sizeof(SOCKET_ADDRESS_LIST) + ((MAX_INTERFACES - 1) * sizeof(SOCKET_ADDRESS))); retVal = WSAIoctl(ifcs, SIO_ADDRESS_LIST_QUERY, NULL, 0, ipv6InterfaceList, sizeof(SOCKET_ADDRESS_LIST) + ((MAX_INTERFACES - 1) * sizeof(SOCKET_ADDRESS)), &returnedBytes, 0, 0); if (retVal == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT) { /* The buffer wasn't big enough. returnedBytes will now contain the required size so we can reallocate & try again */ os_free(ipv6InterfaceList); ipv6InterfaceList = os_malloc(returnedBytes); memset(ipv6InterfaceList, 0, returnedBytes); retVal = WSAIoctl(ifcs, SIO_ADDRESS_LIST_QUERY, NULL, 0, ipv6InterfaceList, returnedBytes, &returnedBytes, 0, 0); } if (retVal == SOCKET_ERROR) { errNo = os_sockError(); errorMessage = os_sockErrnoToString(errNo); os_report(OS_ERROR, "os_sockQueryInterfaces", __FILE__, __LINE__, 0, "Socket error calling WSAIoctl for IPv6 interfaces: %d %s", errNo, errorMessage); os_free(errorMessage); /* @todo Is it right to return a fail here ? Need to check on box w/ no IPv6 interfaces */ result = os_resultFail; } else { for (i = 0; i < ipv6InterfaceList->iAddressCount; ++i) { if (ipv6InterfaceList->Address[i].lpSockaddr->sa_family == AF_INET6 && ! (IN6_IS_ADDR_UNSPECIFIED(&((os_sockaddr_in6 *)&ipv6InterfaceList->Address[i].lpSockaddr)->sin6_addr))) { done = 0; if (addressInfoResult == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses && !done) { /* adapter needs to be enabled*/ if (pCurrAddresses->OperStatus == IfOperStatusUp) { pUnicast = pCurrAddresses->FirstUnicastAddress; while (pUnicast && !done) { /* check if interface ip matches adapter ip */ if (os_sockaddrIPAddressEqual((os_sockaddr*) ipv6InterfaceList->Address[i].lpSockaddr, (os_sockaddr*) pUnicast->Address.lpSockaddr)) { snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddresses->FriendlyName); ifList[listIndex].interfaceIndexNo = (os_uint) pCurrAddresses->Ipv6IfIndex; done = 1; } pUnicast = pUnicast->Next; } } pCurrAddresses = pCurrAddresses->Next; } } /* if no name was found set this interface name to string representation of the IPv6 address */ if (!done) { os_sockaddrAddressToString((os_sockaddr*) ipv6InterfaceList->Address[i].lpSockaddr, ifList[listIndex].name, OS_IFNAMESIZE); os_report(OS_WARNING, "os_sockQueryInterfaces", __FILE__, __LINE__, 0, "Unable to determine IPv6 adapter name. Setting instead to adapter address %s", ifList[listIndex].name); } ifList[listIndex].flags = 0; ifList[listIndex].address = *((os_sockaddr_storage*) ipv6InterfaceList->Address[i].lpSockaddr); listIndex++; ++(*validElements); } } } os_sockFree (ifcs); } if (addressInfoResult == NO_ERROR) { os_free(pAddresses); } return result; }
os_result os_sockQueryInterfaces( os_ifAttributes *ifList, os_uint listSize, os_uint *validElements) { os_result result = os_resultSuccess; os_result addressInfoResult =0; INTERFACE_INFO *allInterfacesBuf; INTERFACE_INFO *intf; unsigned long returnedBytes; unsigned int listIndex; os_socket ifcs; int retVal, done; char* errorMessage; os_sockErrno errNo; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; unsigned long outBufLen = 0; /* Set the flags to pass to GetAdaptersAddresses*/ unsigned long flags = GAA_FLAG_INCLUDE_PREFIX; /* Doesn't matter what value of family you use. WSAIoctl w/ SIO_GET_INTERFACE_LIST only returns IPv4 addresses */ unsigned long family = AF_UNSPEC; int i = 0; *validElements = 0; listIndex = 0; outBufLen = sizeof (IP_ADAPTER_ADDRESSES); pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen); if (GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { os_free(pAddresses); pAddresses = (IP_ADAPTER_ADDRESSES *) os_malloc(outBufLen); } addressInfoResult = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); /* List the IPv4 interfaces */ ifcs = os_sockNew (AF_INET, SOCK_DGRAM); if (ifcs != INVALID_SOCKET) { allInterfacesBuf = os_malloc(MAX_INTERFACES * sizeof(INTERFACE_INFO)); memset(allInterfacesBuf, 0, MAX_INTERFACES * sizeof(INTERFACE_INFO)); retVal = WSAIoctl(ifcs, SIO_GET_INTERFACE_LIST, NULL, 0, allInterfacesBuf, MAX_INTERFACES * sizeof(INTERFACE_INFO), &returnedBytes, 0, 0); if (retVal == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT) { /* The buffer wasn't big enough. returnedBytes will now contain the required size so we can reallocate & try again */ os_free(allInterfacesBuf); allInterfacesBuf = os_malloc(returnedBytes); memset(allInterfacesBuf, 0, returnedBytes); retVal = WSAIoctl(ifcs, SIO_GET_INTERFACE_LIST, NULL, 0, allInterfacesBuf, returnedBytes, &returnedBytes, 0, 0); } if (retVal == SOCKET_ERROR) { errNo = os_sockError(); errorMessage = os_sockErrnoToString(errNo); os_report(OS_ERROR, "os_sockQueryInterfaces", __FILE__, __LINE__, 0, "Socket error calling WSAIoctl for IPv4 interfaces: %d %s", errNo, errorMessage); os_free(errorMessage); /* @todo Is it right to return a fail here ? Need to check on box w/ no IPv4 interfaces */ result = os_resultFail; } else { *validElements = returnedBytes/sizeof(INTERFACE_INFO); } while ((listIndex < listSize) && (listIndex < *validElements)) { done = 0; intf = &allInterfacesBuf[listIndex]; if (addressInfoResult == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses && !done) { /* adapter needs to be enabled*/ if (pCurrAddresses->OperStatus == IfOperStatusUp) { pUnicast = pCurrAddresses->FirstUnicastAddress; while (pUnicast && !done) { /* check if interface ip matches adapter ip */ if (os_sockaddrIPAddressEqual((os_sockaddr*) &intf->iiAddress.AddressIn, (os_sockaddr*) pUnicast->Address.lpSockaddr)) { snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "%wS", pCurrAddresses->FriendlyName); ifList[listIndex].interfaceIndexNo = (os_uint) pCurrAddresses->Ipv6IfIndex; done = 1; } pUnicast = pUnicast->Next; } } pCurrAddresses = pCurrAddresses->Next; } } /* if no name is found set this */ if (!done) { snprintf(ifList[listIndex].name, OS_IFNAMESIZE, "0x%x", ntohl(intf->iiAddress.AddressIn.sin_addr.S_un.S_addr)); os_report(OS_WARNING, "os_sockQueryInterfaces", __FILE__, __LINE__, 0, "Unable to determine IPv4 adapter name. Setting instead to adapter address %s", ifList[listIndex].name); } ifList[listIndex].flags = intf->iiFlags; ifList[listIndex].address = *((os_sockaddr_storage*) &intf->iiAddress); ifList[listIndex].broadcast_address = *((os_sockaddr_storage*) &intf->iiBroadcastAddress); ((os_sockaddr_in *)(&(ifList[listIndex].broadcast_address)))->sin_addr.S_un.S_addr = ((os_sockaddr_in *)(&(ifList[listIndex].address)))->sin_addr.S_un.S_addr | ~(intf->iiNetmask.AddressIn.sin_addr.S_un.S_addr); ifList[listIndex].network_mask = *((os_sockaddr_storage*) &intf->iiNetmask); listIndex++; } os_sockFree (ifcs); } if (addressInfoResult == NO_ERROR) { os_free(pAddresses); } return result; }