Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef WIN32
#include "addrs-win32.h"
#include <csi_platform.h>
#include <assert.h>
#include <string.h>
#include "util.h"
#include "stun_util.h"
#include "util.h"
#include <r_macros.h>
#include "nr_crypto.h"
#include <iphlpapi.h>
#define NR_MD5_HASH_LENGTH 16
static int stun_win32_address_disallowed(IP_ADAPTER_UNICAST_ADDRESS *addr)
{
return (addr->DadState != NldsPreferred) &&
(addr->DadState != IpDadStatePreferred);
}
static int stun_win32_address_temp_v6(IP_ADAPTER_UNICAST_ADDRESS *addr)
{
return (addr->Address.lpSockaddr->sa_family == AF_INET6) &&
(addr->SuffixOrigin == IpSuffixOriginRandom);
}
int
stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count)
{
int r, _status;
PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
static const ULONG initialBufLen = 15000;
ULONG buflen = initialBufLen;
char bin_hashed_ifname[NR_MD5_HASH_LENGTH];
char hex_hashed_ifname[MAXIFNAME];
int n = 0;
*count = 0;
if (maxaddrs <= 0)
ABORT(R_BAD_ARGS);
/* According to MSDN (see above) we have try GetAdapterAddresses() multiple times */
for (n = 0; n < 5; n++) {
AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
if (AdapterAddresses == NULL) {
r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
ABORT(R_NO_MEMORY);
}
r = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, AdapterAddresses, &buflen);
if (r == NO_ERROR) {
break;
}
r_log(NR_LOG_STUN, LOG_ERR, "GetAdaptersAddresses() returned error (%d)", r);
RFREE(AdapterAddresses);
AdapterAddresses = NULL;
}
if (n >= 5) {
r_log(NR_LOG_STUN, LOG_ERR, "5 failures calling GetAdaptersAddresses()");
ABORT(R_INTERNAL);
}
n = 0;
/* Loop through the adapters */
for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
if (tmpAddress->OperStatus != IfOperStatusUp)
continue;
if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
IP_ADAPTER_UNICAST_ADDRESS *u = 0;
if(r=nr_crypto_md5((UCHAR *)tmpAddress->FriendlyName,
wcslen(tmpAddress->FriendlyName) * sizeof(wchar_t),
(UCHAR *)bin_hashed_ifname))
ABORT(r);
if(r=nr_bin2hex((UCHAR*)bin_hashed_ifname, sizeof(bin_hashed_ifname),
(UCHAR*)hex_hashed_ifname))
ABORT(r);
for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
SOCKET_ADDRESS *sa_addr = &u->Address;
if ((sa_addr->lpSockaddr->sa_family != AF_INET) &&
(sa_addr->lpSockaddr->sa_family != AF_INET6)) {
r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for address on adapter %lu", tmpAddress->IfIndex);
continue;
}
if (stun_win32_address_disallowed(u)) {
continue;
}
if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr)))) {
ABORT(r);
}
strlcpy(addrs[n].addr.ifname, hex_hashed_ifname, sizeof(addrs[n].addr.ifname));
if (tmpAddress->IfType == IF_TYPE_ETHERNET_CSMACD) {
addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
} else if (tmpAddress->IfType == IF_TYPE_IEEE80211) {
/* Note: this only works for >= Win Vista */
addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
} else {
addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
}
addrs[n].interface.estimated_speed = tmpAddress->TransmitLinkSpeed / 1000;
if (stun_win32_address_temp_v6(u)) {
addrs[n].flags |= NR_ADDR_FLAG_TEMPORARY;
}
if (++n >= maxaddrs)
goto done;
}
}
}
done:
*count = n;
_status = 0;
abort:
RFREE(AdapterAddresses);
return _status;
}
#endif //WIN32