LRN: new code for GNUNET_OS_network_interfaces_list on W32 improving support for...
authorChristian Grothoff <christian@grothoff.org>
Tue, 29 Nov 2011 11:47:40 +0000 (11:47 +0000)
committerChristian Grothoff <christian@grothoff.org>
Tue, 29 Nov 2011 11:47:40 +0000 (11:47 +0000)
src/include/winproc.h
src/util/Makefile.am
src/util/os_network.c
src/util/win.cc
src/util/winproc.c

index 05c4ac1bf4a7ac774e268bf03f019440860eb707..ac4eecdfb37947485b9ee546b4b36726adf36a26 100644 (file)
@@ -62,6 +62,10 @@ extern "C"
                                            PULONG pdwSize, BOOL bOrder);
   typedef DWORD WINAPI (*TGetIfTable) (PMIB_IFTABLE pIfTable, PULONG pdwSize,
                                        BOOL bOrder);
+  typedef DWORD WINAPI (*TGetBestInterfaceEx) (struct sockaddr *, PDWORD);
+  /* TODO: Explicitly import -A variants (i.e. TCreateHardLinkA) or -W
+   * variants (TCreateHardLinkW), etc.
+   */
   typedef DWORD WINAPI (*TCreateHardLink) (LPCTSTR lpFileName,
                                            LPCTSTR lpExistingFileName,
                                            LPSECURITY_ATTRIBUTES
@@ -99,8 +103,6 @@ extern "C"
   typedef SC_HANDLE WINAPI (*TOpenService) (SC_HANDLE hSCManager,
                                             LPCTSTR lpServiceName,
                                             DWORD dwDesiredAccess);
-  typedef DWORD WINAPI (*TGetBestInterface) (IPAddr dwDestAddr,
-                                             PDWORD pdwBestIfIndex);
   typedef DWORD WINAPI (*TGetAdaptersInfo) (PIP_ADAPTER_INFO pAdapterInfo,
                                             PULONG pOutBufLen);
   typedef NET_API_STATUS WINAPI (*TNetUserAdd) (LPCWSTR, DWORD, PBYTE, PDWORD);
@@ -158,6 +160,7 @@ extern "C"
                                                 PSID psidGroup, PACL pDacl,
                                                 PACL pSacl);
 
+  extern TGetBestInterfaceEx GNGetBestInterfaceEx;
   extern TNtQuerySystemInformation GNNtQuerySystemInformation;
   extern TGetIfEntry GNGetIfEntry;
   extern TGetIpAddrTable GNGetIpAddrTable;
@@ -172,8 +175,7 @@ extern "C"
   extern TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher;
   extern TControlService GNControlService;
   extern TOpenService GNOpenService;
-  extern TGetBestInterface GNGetBestInterface;
-  extern TGetAdaptersInfo GGetAdaptersInfo;
+  extern TGetAdaptersInfo GNGetAdaptersInfo;
   extern TNetUserAdd GNNetUserAdd;
   extern TNetUserSetInfo GNNetUserSetInfo;
   extern TLsaOpenPolicy GNLsaOpenPolicy;
@@ -202,6 +204,23 @@ extern "C"
                             DWORD dwAccessMask);
   char *winErrorStr (const char *prefix, int dwErr);
   void EnumNICs (PMIB_IFTABLE * pIfTable, PMIB_IPADDRTABLE * pAddrTable);
+
+#define ENUMNICS3_MASK_OK 0x01
+#define ENUMNICS3_BCAST_OK 0x02
+
+struct EnumNICs3_results
+{
+  unsigned char flags;
+  int is_default;
+  char pretty_name[1001];
+  size_t addr_size;
+  struct sockaddr address;
+  struct sockaddr mask;
+  struct sockaddr broadcast;
+};
+
+  int EnumNICs3 (struct EnumNICs3_results **, int *EnumNICs3_results_count);
+  void EnumNICs3_free (struct EnumNICs3_results *);
   int GNInitWinEnv ();
   void GNShutdownWinEnv ();
 
index c62fc4246fa0e8b36dc92b8ccf3ee33e7563234a..a2e7f2449455ccdc556a6374b7c4a27395f682cf 100644 (file)
@@ -17,7 +17,7 @@ libgnunetutilwin_la_LDFLAGS = \
   -no-undefined -Wl,--export-all-symbols 
 libgnunetutilwin_la_LIBADD = \
   -lshell32 -liconv -lstdc++ \
-  -lcomdlg32 -lgdi32
+  -lcomdlg32 -lgdi32 -liphlpapi
 WINLIB = libgnunetutilwin.la
 endif
 
index 54a4e7577d803fa256c39d8e04dbba3004696df3..a4758496e8c296bea20886a11ca1513cc9bf86c4 100644 (file)
@@ -25,6 +25,7 @@
  * @author Nils Durner
  * @author Heikki Lindholm
  * @author Jake Dust
+ * @author LRN
  */
 
 #include "platform.h"
@@ -46,128 +47,26 @@ GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc,
                                    void *proc_cls)
 {
 #ifdef MINGW
-  PMIB_IFTABLE pTable;
-  PMIB_IPADDRTABLE pAddrTable;
-  DWORD dwIfIdx, dwExternalNIC;
-  IPAddr theIP;
+  int r;
+  int i;
+  struct EnumNICs3_results *results = NULL;
+  int results_count;
 
-  /* Determine our external NIC  */
-  theIP = inet_addr ("192.0.34.166");   /* www.example.com */
-  if ((!GNGetBestInterface) ||
-      (GNGetBestInterface (theIP, &dwExternalNIC) != NO_ERROR))
-  {
-    dwExternalNIC = 0;
-  }
-
-  /* Enumerate NICs */
-  EnumNICs (&pTable, &pAddrTable);
+  r = EnumNICs3 (&results, &results_count);
+  if (r != GNUNET_OK)
+    return;
 
-  if (pTable)
+  for (i = 0; i < results_count; i++)
   {
-    for (dwIfIdx = 0; dwIfIdx <= pTable->dwNumEntries; dwIfIdx++)
-    {
-      char szEntry[1001];
-      DWORD dwIP = 0;
-      PIP_ADAPTER_INFO pAdapterInfo;
-      PIP_ADAPTER_INFO pAdapter = NULL;
-      DWORD dwRetVal = 0;
-
-      /* Get IP-Address */
-      int i;
-
-      for (i = 0; i < pAddrTable->dwNumEntries; i++)
-      {
-        if (pAddrTable->table[i].dwIndex == pTable->table[dwIfIdx].dwIndex)
-        {
-          dwIP = pAddrTable->table[i].dwAddr;
-          break;
-        }
-      }
-
-      if (dwIP)
-      {
-        BYTE bPhysAddr[MAXLEN_PHYSADDR];
-        char *pszIfName = NULL;
-        char dst[INET_ADDRSTRLEN];
-        struct sockaddr_in sa;
-
-        /* Get friendly interface name */
-        pAdapterInfo = (IP_ADAPTER_INFO *) malloc (sizeof (IP_ADAPTER_INFO));
-        ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
-
-        /* Make an initial call to GetAdaptersInfo to get
-         * the necessary size into the ulOutBufLen variable */
-        if (GGetAdaptersInfo (pAdapterInfo, &ulOutBufLen) ==
-            ERROR_BUFFER_OVERFLOW)
-        {
-          free (pAdapterInfo);
-          pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
-        }
-
-        if ((dwRetVal =
-             GGetAdaptersInfo (pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
-        {
-          pAdapter = pAdapterInfo;
-          while (pAdapter)
-          {
-            if (pTable->table[dwIfIdx].dwIndex == pAdapter->Index)
-            {
-              char szKey[251];
-              long lLen = 250;
-
-              sprintf (szKey,
-                       "SYSTEM\\CurrentControlSet\\Control\\Network\\"
-                       "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
-                       pAdapter->AdapterName);
-              pszIfName = (char *) malloc (251);
-              if (QueryRegistry
-                  (HKEY_LOCAL_MACHINE, szKey, "Name", pszIfName,
-                   &lLen) != ERROR_SUCCESS)
-              {
-                free (pszIfName);
-                pszIfName = NULL;
-              }
-            }
-            pAdapter = pAdapter->Next;
-          }
-        }
-        free (pAdapterInfo);
-
-        /* Set entry */
-        memset (bPhysAddr, 0, MAXLEN_PHYSADDR);
-        memcpy (bPhysAddr, pTable->table[dwIfIdx].bPhysAddr,
-                pTable->table[dwIfIdx].dwPhysAddrLen);
-
-        snprintf (szEntry, 1000, "%s (%s - %I64u)",
-                  pszIfName ? pszIfName : (char *) pTable->
-                  table[dwIfIdx].bDescr, inet_ntop (AF_INET, &dwIP, dst,
-                                                    INET_ADDRSTRLEN),
-                  *((unsigned long long *) bPhysAddr));
-        szEntry[1000] = 0;
-
-        if (pszIfName)
-          free (pszIfName);
-
-        sa.sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-        sa.sin_len = (u_char) sizeof (struct sockaddr_in);
-#endif
-        sa.sin_addr.S_un.S_addr = dwIP;
-
-        if (GNUNET_OK !=
-            proc (proc_cls, szEntry,
-                  pTable->table[dwIfIdx].dwIndex == dwExternalNIC,
-                  (const struct sockaddr *) &sa,
-                  NULL,
-                  NULL,
-                  sizeof (sa)))
-          break;
-      }
-    }
-    GlobalFree (pAddrTable);
-    GlobalFree (pTable);
+    if (GNUNET_OK != proc (proc_cls, results[i].pretty_name,
+        results[i].is_default,
+        &results[i].address,
+        results[i].flags & ENUMNICS3_MASK_OK ? &results[i].mask : NULL,
+        results[i].flags & ENUMNICS3_BCAST_OK ? &results[i].broadcast : NULL,
+        results[i].addr_size))
+      break;
   }
-
+  EnumNICs3_free (results);
   return;
 
 #elif HAVE_GETIFADDRS && HAVE_FREEIFADDRS
index b462033b921dec64a6b0ba087420bdf10b1c3fdd..594b9a2109f4e2e90585da2157b8c9b04ad42b9b 100644 (file)
@@ -44,161 +44,608 @@ extern "C" {
 \r
 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);\r
 \r
-/**\r
- * Enumerate all network adapters\r
- */\r
-void EnumNICs(PMIB_IFTABLE *pIfTable, PMIB_IPADDRTABLE *pAddrTable)\r
-{\r
-  DWORD dwSize, dwRet;\r
+#define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \\r
+  union { \\r
+    struct { \\r
+      ULONG Length; \\r
+      DWORD Flags; \\r
+    }; \\r
+  }; \\r
+\r
+#define _IP_ADAPTER_UNICAST_ADDRESS_BASE \\r
+  SOCKET_ADDRESS                     Address; \\r
+  IP_PREFIX_ORIGIN                   PrefixOrigin; \\r
+  IP_SUFFIX_ORIGIN                   SuffixOrigin; \\r
+  IP_DAD_STATE                       DadState; \\r
+  ULONG                              ValidLifetime; \\r
+  ULONG                              PreferredLifetime; \\r
+  ULONG                              LeaseLifetime;\r
+\r
+#define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \\r
+  UINT8                              OnLinkPrefixLength;\r
+\r
+\r
+#define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \\r
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \\r
+  _IP_ADAPTER_UNICAST_ADDRESS_HEAD \\r
+  struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \\r
+  _IP_ADAPTER_UNICAST_ADDRESS_BASE \\r
+  addition \\r
+} IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;\r
+\r
+/* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */\r
+_IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)\r
+\r
+\r
+typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {\r
+  union {\r
+    ULONGLONG Alignment;\r
+    struct {\r
+      ULONG Length;\r
+      DWORD Reserved;\r
+    };\r
+  };\r
+  struct _IP_ADAPTER_WINS_SERVER_ADDRESS  *Next;\r
+  SOCKET_ADDRESS                         Address;\r
+} IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;\r
+\r
+typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {\r
+  union {\r
+    ULONGLONG Alignment;\r
+    struct {\r
+      ULONG Length;\r
+      DWORD Reserved;\r
+    };\r
+  };\r
+  struct _IP_ADAPTER_GATEWAY_ADDRESS  *Next;\r
+  SOCKET_ADDRESS                     Address;\r
+} IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;\r
+\r
+typedef UINT32 NET_IF_COMPARTMENT_ID;\r
+typedef GUID NET_IF_NETWORK_GUID;\r
+\r
+typedef enum _NET_IF_CONNECTION_TYPE {\r
+  NET_IF_CONNECTION_DEDICATED   = 1,\r
+  NET_IF_CONNECTION_PASSIVE,\r
+  NET_IF_CONNECTION_DEMAND,\r
+  NET_IF_CONNECTION_MAXIMUM \r
+} NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;\r
+\r
+typedef enum  {\r
+  TUNNEL_TYPE_NONE      = 0,\r
+  TUNNEL_TYPE_OTHER,\r
+  TUNNEL_TYPE_DIRECT,\r
+  TUNNEL_TYPE_6TO4,\r
+  TUNNEL_TYPE_ISATAP,\r
+  TUNNEL_TYPE_TEREDO,\r
+  TUNNEL_TYPE_IPHTTPS \r
+} TUNNEL_TYPE, *PTUNNEL_TYPE;\r
 \r
-  *pIfTable = NULL;\r
+/*\r
+A DUID consists of a two-octet type code represented in network byte\r
+   order, followed by a variable number of octets that make up the\r
+   actual identifier.  A DUID can be no more than 128 octets long (not\r
+   including the type code).\r
+*/\r
+#define MAX_DHCPV6_DUID_LENGTH 130\r
+\r
+typedef union _NET_LUID {\r
+  ULONG64 Value;\r
+  struct {\r
+    ULONG64 Reserved  :24;\r
+    ULONG64 NetLuidIndex  :24;\r
+    ULONG64 IfType  :16;\r
+  } Info;\r
+} NET_LUID, *PNET_LUID, IF_LUID;\r
+\r
+#define MAX_DNS_SUFFIX_STRING_LENGTH 246\r
+\r
+typedef struct _IP_ADAPTER_DNS_SUFFIX {\r
+  struct _IP_ADAPTER_DNS_SUFFIX  *Next;\r
+  WCHAR                         String[MAX_DNS_SUFFIX_STRING_LENGTH];\r
+} IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;\r
+\r
+\r
+\r
+#define _IP_ADAPTER_ADDRESSES_HEAD \\r
+  union { \\r
+    ULONGLONG Alignment; \\r
+    struct { \\r
+      ULONG Length; \\r
+      DWORD IfIndex; \\r
+    }; \\r
+  };\r
+\r
+#define _IP_ADAPTER_ADDRESSES_BASE \\r
+  PCHAR                              AdapterName; \\r
+  PIP_ADAPTER_UNICAST_ADDRESS        FirstUnicastAddress; \\r
+  PIP_ADAPTER_ANYCAST_ADDRESS        FirstAnycastAddress; \\r
+  PIP_ADAPTER_MULTICAST_ADDRESS      FirstMulticastAddress; \\r
+  PIP_ADAPTER_DNS_SERVER_ADDRESS     FirstDnsServerAddress; \\r
+  PWCHAR                             DnsSuffix; \\r
+  PWCHAR                             Description; \\r
+  PWCHAR                             FriendlyName; \\r
+  BYTE                               PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \\r
+  DWORD                              PhysicalAddressLength; \\r
+  DWORD                              Flags; \\r
+  DWORD                              Mtu; \\r
+  DWORD                              IfType; \\r
+  IF_OPER_STATUS                     OperStatus;\r
+\r
+#define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \\r
+  DWORD                              Ipv6IfIndex; \\r
+  DWORD                              ZoneIndices[16]; \\r
+  PIP_ADAPTER_PREFIX                 FirstPrefix; \\r
+\r
+\r
+#define _IP_ADAPTER_ADDRESSES_ADD_VISTA \\r
+  _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \\r
+  ULONG64                            TransmitLinkSpeed; \\r
+  ULONG64                            ReceiveLinkSpeed; \\r
+  PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \\r
+  PIP_ADAPTER_GATEWAY_ADDRESS_LH     FirstGatewayAddress; \\r
+  ULONG                              Ipv4Metric; \\r
+  ULONG                              Ipv6Metric; \\r
+  IF_LUID                            Luid; \\r
+  SOCKET_ADDRESS                     Dhcpv4Server; \\r
+  NET_IF_COMPARTMENT_ID              CompartmentId; \\r
+  NET_IF_NETWORK_GUID                NetworkGuid; \\r
+  NET_IF_CONNECTION_TYPE             ConnectionType; \\r
+  TUNNEL_TYPE                        TunnelType; \\r
+  SOCKET_ADDRESS                     Dhcpv6Server; \\r
+  BYTE                               Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \\r
+  ULONG                              Dhcpv6ClientDuidLength; \\r
+  ULONG                              Dhcpv6Iaid;\r
+\r
+#define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \\r
+  _IP_ADAPTER_ADDRESSES_ADD_VISTA \\r
+  PIP_ADAPTER_DNS_SUFFIX             FirstDnsSuffix;\r
+\r
+#define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \\r
+typedef struct _IP_ADAPTER_ADDRESSES##suffix { \\r
+  _IP_ADAPTER_ADDRESSES_HEAD \\r
+  struct _IP_ADAPTER_ADDRESSES##suffix *Next; \\r
+  _IP_ADAPTER_ADDRESSES_BASE \\r
+  addition \\r
+} IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;\r
+  \r
+\r
+/* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */\r
+_IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)\r
+_IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)\r
+_IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)\r
+\r
+static int\r
+EnumNICs_IPv6_get_ifs_count (SOCKET s)\r
+{\r
+  DWORD dwret = 0, err;\r
+  int iret;\r
+  iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,\r
+      &dwret, NULL, NULL);\r
+  err = GetLastError ();\r
+  if (iret == SOCKET_ERROR && err == WSAEFAULT)\r
+    return dwret;\r
+  else if (iret == 0)\r
+    return 0;\r
+  return GNUNET_SYSERR;\r
+}\r
 \r
-  if (pAddrTable)\r
-    *pAddrTable = NULL;\r
+static int\r
+EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)\r
+{\r
+  int iret;\r
+  DWORD dwret = 0;\r
+  iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,\r
+      &dwret, NULL, NULL);\r
 \r
-  if (GNGetIfTable)\r
+  if (iret != 0 || dwret != size)\r
   {\r
-    dwSize = dwRet = 0;\r
+    /* It's supposed to succeed! And size should be the same */\r
+    return GNUNET_SYSERR;\r
+  }\r
+  return GNUNET_OK;\r
+}\r
 \r
-    *pIfTable = (MIB_IFTABLE *) GlobalAlloc(GPTR, sizeof(MIB_IFTABLE));\r
+#undef GNUNET_malloc\r
+#define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \\r
+    HEAP_GENERATE_EXCEPTIONS, a)\r
 \r
-    /* Get size of table */\r
-    if (GNGetIfTable(*pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)\r
-    {\r
-      GlobalFree(*pIfTable);\r
-      *pIfTable = (MIB_IFTABLE *) GlobalAlloc(GPTR, dwSize);\r
-    }\r
+#undef GNUNET_free\r
+#define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)\r
 \r
-    if ((dwRet = GNGetIfTable(*pIfTable, &dwSize, 0)) == NO_ERROR &&\r
-      pAddrTable)\r
-    {\r
-      DWORD dwIfIdx, dwSize = sizeof(MIB_IPADDRTABLE);\r
-      *pAddrTable = (MIB_IPADDRTABLE *) GlobalAlloc(GPTR, dwSize);\r
+#undef GNUNET_free_non_null\r
+#define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)\r
 \r
-      /* Make an initial call to GetIpAddrTable to get the\r
-         necessary size */\r
-      if (GNGetIpAddrTable(*pAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)\r
+static int\r
+EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)\r
+{\r
+  int iret;\r
+  DWORD dwret = 0;\r
+  DWORD error;\r
+  INTERFACE_INFO *ii = NULL;\r
+  DWORD ii_size = sizeof (INTERFACE_INFO) * 15;\r
+  while (TRUE)\r
+  {\r
+    if (ii_size >= sizeof (INTERFACE_INFO) * 1000)\r
+      return GNUNET_SYSERR;\r
+    ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);\r
+    dwret = 0;\r
+    iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,\r
+        &dwret, NULL, NULL);\r
+    error = GetLastError ();\r
+    if (iret == SOCKET_ERROR)\r
+    {\r
+      if (error == WSAEFAULT)\r
       {\r
-        GlobalFree(*pAddrTable);\r
-        *pAddrTable = (MIB_IPADDRTABLE *) GlobalAlloc(GPTR, dwSize);\r
+        GNUNET_free (ii);\r
+        ii_size *= 2;\r
+        continue;\r
       }\r
-      GNGetIpAddrTable(*pAddrTable, &dwSize, 0);\r
+      GNUNET_free (ii);\r
+      return GNUNET_SYSERR;\r
+    }\r
+    else\r
+    {\r
+      *inf = ii;\r
+      *size = dwret;\r
+      return GNUNET_OK;\r
     }\r
   }\r
+  return GNUNET_SYSERR;\r
+}\r
+\r
+int\r
+EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)\r
+{\r
+  int result = 0;\r
+  SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;\r
+  DWORD dwret1 = 0, dwret2;\r
+  DWORD err1, err2;\r
+  int ifs4len = 0, ifs6len = 0;\r
+  INTERFACE_INFO *interfaces4 = NULL;\r
+  SOCKET_ADDRESS_LIST *interfaces6 = NULL;\r
+  SetLastError (0);\r
+  s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
+  err1 = GetLastError ();\r
+  SetLastError (0);\r
+  s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);\r
+  err2 = GetLastError ();\r
+  if (s6 != INVALID_SOCKET)\r
+  {\r
+    ifs6len = EnumNICs_IPv6_get_ifs_count (s6);\r
+    if (ifs6len > 0)\r
+    {\r
+      interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);\r
+      result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;\r
+    }\r
+    closesocket (s6);\r
+    s6 = INVALID_SOCKET;\r
+  }\r
+\r
+  if (s4 != INVALID_SOCKET)\r
+  {\r
+    result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;\r
+    closesocket (s4);\r
+    s4 = INVALID_SOCKET;\r
+  }\r
+  if (ifs6len + ifs4len == 0)\r
+    goto error;\r
+\r
+  if (!result)\r
+  {\r
+    *ifs4 = interfaces4;\r
+    *ifs4_len = ifs4len;\r
+    *ifs6 = interfaces6;\r
+    return GNUNET_OK;\r
+  }\r
+error:\r
+  if (interfaces4 != NULL)\r
+    GNUNET_free (interfaces4);\r
+  if (interfaces6 != NULL)\r
+    GNUNET_free (interfaces6);\r
+  if (s4 != INVALID_SOCKET)\r
+    closesocket (s4);\r
+  if (s6 != INVALID_SOCKET)\r
+    closesocket (s6);\r
+  return GNUNET_SYSERR;\r
 }\r
 \r
 /**\r
- * Lists all network interfaces in a combo box\r
- * Used by the basic GTK configurator\r
- *\r
- * @param callback function to call for each NIC\r
- * @param callback_cls closure for callback\r
+ * Returns GNUNET_OK on OK, GNUNET_SYSERR on error\r
  */\r
-  int ListNICs(void (*callback) (void *, const char *, int), void * callback_cls)\r
+int\r
+EnumNICs3 (struct EnumNICs3_results **results, int *results_count)\r
 {\r
-  PMIB_IFTABLE pTable;\r
-  PMIB_IPADDRTABLE pAddrTable;\r
-  DWORD dwIfIdx, dwExternalNIC;\r
-  IPAddr theIP;\r
-\r
-  /* Determine our external NIC  */\r
-  theIP = inet_addr("192.0.34.166"); /* www.example.com */\r
-  if ((! GNGetBestInterface) ||\r
-      (GNGetBestInterface(theIP, &dwExternalNIC) != NO_ERROR))\r
+  DWORD dwRetVal = 0;\r
+  int count = 0;\r
+  ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |\r
+      GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;\r
+  struct sockaddr_in6 examplecom6;\r
+  IPAddr examplecom;\r
+  DWORD best_interface = 0;\r
+  DWORD best_interface6 = 0;\r
+\r
+  int use_enum2 = 0;\r
+  INTERFACE_INFO *interfaces4 = NULL;\r
+  int interfaces4_len = 0;\r
+  SOCKET_ADDRESS_LIST *interfaces6 = NULL;\r
+\r
+  unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);\r
+  IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;\r
+  IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);\r
+\r
+  if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)\r
+      == ERROR_BUFFER_OVERFLOW)\r
+  {\r
+    GNUNET_free (pAddresses);\r
+    pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);\r
+  }\r
+\r
+  dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);\r
+\r
+  if (dwRetVal != NO_ERROR)\r
+  {\r
+    GNUNET_free (pAddresses);\r
+    return GNUNET_SYSERR;\r
+  }\r
+\r
+  if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))\r
+  {\r
+    use_enum2 = 1;\r
+\r
+    /* Enumerate NICs using WSAIoctl() */\r
+    if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))\r
+    {\r
+      GNUNET_free (pAddresses);\r
+      return GNUNET_SYSERR;\r
+    }\r
+  }\r
+\r
+  examplecom = inet_addr("192.0.34.166"); /* www.example.com */\r
+  if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)\r
+    best_interface = 0;\r
+\r
+  if (GNGetBestInterfaceEx != NULL)\r
   {\r
-    dwExternalNIC = 0;\r
+    examplecom6.sin6_family = AF_INET6;\r
+    examplecom6.sin6_port = 0;\r
+    examplecom6.sin6_flowinfo = 0;\r
+    examplecom6.sin6_scope_id = 0;\r
+    inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",\r
+        (struct sockaddr *) &examplecom6.sin6_addr);\r
+    dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,\r
+        &best_interface6);\r
+    if (dwRetVal != NO_ERROR)\r
+      best_interface6 = 0;\r
   }\r
 \r
-  /* Enumerate NICs */\r
-  EnumNICs(&pTable, &pAddrTable);\r
+  /* Give IPv6 a priority */\r
+  if (best_interface6 != 0)\r
+    best_interface = best_interface6;\r
 \r
-  if (pTable)\r
+  count = 0;\r
+  for (pCurrentAddress = pAddresses;\r
+      pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)\r
   {\r
-    for(dwIfIdx=0; dwIfIdx <= pTable->dwNumEntries; dwIfIdx++)\r
+    if (pCurrentAddress->OperStatus == IfOperStatusUp)\r
     {\r
-      char szEntry[1001];\r
-      DWORD dwIP = 0;\r
-      int iItm;\r
-               PIP_ADAPTER_INFO pAdapterInfo;\r
-               PIP_ADAPTER_INFO pAdapter = NULL;\r
-               DWORD dwRetVal = 0;\r
-\r
-      /* Get IP-Address */\r
-      int i;\r
-      for(i = 0; i < pAddrTable->dwNumEntries; i++)\r
+      IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;\r
+      for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;\r
+          unicast = unicast->Next)\r
       {\r
-        if (pAddrTable->table[i].dwIndex == pTable->table[dwIfIdx].dwIndex)\r
+        if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||\r
+            unicast->Address.lpSockaddr->sa_family == AF_INET6) &&\r
+            (unicast->DadState == IpDadStateDeprecated ||\r
+            unicast->DadState == IpDadStatePreferred))\r
+          count += 1;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (count == 0)\r
+  {\r
+    *results = NULL;\r
+    *results_count = 0;\r
+    GNUNET_free (pAddresses);\r
+    GNUNET_free_non_null (interfaces4);\r
+    GNUNET_free_non_null (interfaces6);\r
+    return GNUNET_OK;\r
+  }\r
+\r
+  *results = (struct EnumNICs3_results *) GNUNET_malloc (\r
+      sizeof (struct EnumNICs3_results) * count);\r
+  *results_count = count;\r
+\r
+  count = 0;\r
+  for (pCurrentAddress = pAddresses;\r
+      pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)\r
+  {\r
+    struct EnumNICs3_results *r;\r
+    IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;\r
+    if (pCurrentAddress->OperStatus != IfOperStatusUp)\r
+      continue;\r
+    for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;\r
+        unicast = unicast->Next)\r
+    {\r
+      int i, j;\r
+      int mask_length = -1;\r
+      char dst[INET6_ADDRSTRLEN + 1];\r
+\r
+      if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&\r
+          unicast->Address.lpSockaddr->sa_family != AF_INET6) ||\r
+          (unicast->DadState != IpDadStateDeprecated &&\r
+          unicast->DadState != IpDadStatePreferred))\r
+        continue;\r
+\r
+      r = &(*results)[count];\r
+      r->flags = 0;\r
+      if (pCurrentAddress->IfIndex > 0 &&\r
+          pCurrentAddress->IfIndex == best_interface &&\r
+          unicast->Address.lpSockaddr->sa_family == AF_INET)\r
+        r->is_default = 1;\r
+      else if (pCurrentAddress->Ipv6IfIndex > 0 &&\r
+          pCurrentAddress->Ipv6IfIndex == best_interface6 &&\r
+          unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
+        r->is_default = 1;\r
+      else\r
+        r->is_default = 0;\r
+\r
+      /* Don't choose default interface twice */\r
+      if (r->is_default)\r
+        best_interface = best_interface6 = 0;\r
+\r
+      if (!use_enum2)\r
+      {\r
+        memcpy (&r->address, unicast->Address.lpSockaddr,\r
+            unicast->Address.iSockaddrLength);\r
+        memset (&r->mask, 0, sizeof (struct sockaddr));\r
+        mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->\r
+              OnLinkPrefixLength;\r
+        /* OnLinkPrefixLength is the number of leading 1s in the mask.\r
+         * OnLinkPrefixLength is available on Vista and later (hence use_enum2).\r
+         */\r
+        if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
         {\r
-          dwIP = pAddrTable->table[i].dwAddr;\r
-          break;\r
+          struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
+          for (i = 0; i < mask_length; i++)\r
+              ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);\r
         }\r
+        else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
+        {\r
+          struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;\r
+          struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;\r
+          for (i = 0; i < mask_length; i++)\r
+            ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);\r
+          memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);\r
+          for (i = mask_length; i < 128; i++)\r
+            ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);\r
+        }\r
+        r->flags |= ENUMNICS3_MASK_OK;\r
       }\r
-\r
-      if (dwIP)\r
+      else\r
       {\r
-        BYTE bPhysAddr[MAXLEN_PHYSADDR];\r
-                 char *pszIfName = NULL;\r
-        char dst[INET_ADDRSTRLEN];\r
-\r
-        /* Get friendly interface name */\r
-                       pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));\r
-                       ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);\r
-\r
-                       /* Make an initial call to GetAdaptersInfo to get\r
-                          the necessary size into the ulOutBufLen variable */\r
-                       if (GGetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {\r
-                         free(pAdapterInfo);\r
-                         pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);\r
-                       }\r
-\r
-                       if ((dwRetVal = GGetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {\r
-                         pAdapter = pAdapterInfo;\r
-                         while (pAdapter) {\r
-                               if (pTable->table[dwIfIdx].dwIndex == pAdapter->Index)\r
-                               {\r
-                                       char szKey[251];\r
-                                       long lLen = 250;\r
-\r
-                                       sprintf(szKey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"\r
-                                               "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",\r
-                                               pAdapter->AdapterName);\r
-                                       pszIfName = (char *) malloc(251);\r
-                                       if (QueryRegistry(HKEY_LOCAL_MACHINE, szKey, "Name", pszIfName,\r
-                                               &lLen) != ERROR_SUCCESS)\r
-                                       {\r
-                                               free(pszIfName);\r
-                                               pszIfName = NULL;\r
-                                       }\r
-                               }\r
-                           pAdapter = pAdapter->Next;\r
-                         }\r
-                       }\r
-                       free(pAdapterInfo);\r
-\r
-                       /* Set entry */\r
-        memset(bPhysAddr, 0, MAXLEN_PHYSADDR);\r
-        memcpy(bPhysAddr,\r
-          pTable->table[dwIfIdx].bPhysAddr,\r
-          pTable->table[dwIfIdx].dwPhysAddrLen);\r
-\r
-        snprintf(szEntry, 1000, "%s (%s - %I64u)",\r
-          pszIfName ? pszIfName : (char *) pTable->table[dwIfIdx].bDescr,\r
-          inet_ntop (AF_INET, &dwIP, dst, INET_ADDRSTRLEN),\r
-          *((unsigned long long *) bPhysAddr));\r
-        szEntry[1000] = 0;\r
-\r
-        if (pszIfName)\r
-               free(pszIfName);\r
-\r
-        callback(callback_cls,\r
-                szEntry, \r
-                pAddrTable->table[dwIfIdx].dwIndex == dwExternalNIC);\r
+        int found = 0;\r
+        if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
+        {\r
+          for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)\r
+          {\r
+            struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
+            if (memcpy (&interfaces4[i].iiAddress.Address,\r
+                unicast->Address.lpSockaddr,\r
+                unicast->Address.iSockaddrLength) != 0)\r
+              continue;\r
+            found = 1;\r
+            memcpy (&r->address, &interfaces4[i].iiAddress.Address,\r
+                sizeof (struct sockaddr_in));\r
+            memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,\r
+                sizeof (struct sockaddr_in));\r
+            for (mask_length = 0;\r
+                ((unsigned char *) &m->sin_addr)[mask_length / 8] &\r
+                0x80 >> (mask_length % 8); mask_length++)\r
+            {\r
+            }\r
+            r->flags |= ENUMNICS3_MASK_OK;\r
+          }\r
+        }\r
+        else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
+        {\r
+          for (i = 0;\r
+              interfaces6 != NULL && !found && i < interfaces6->iAddressCount;\r
+              i++)\r
+          {\r
+            if (memcpy (interfaces6->Address[i].lpSockaddr,\r
+                unicast->Address.lpSockaddr,\r
+                unicast->Address.iSockaddrLength) != 0)\r
+              continue;\r
+            found = 1;\r
+            memcpy (&r->address, interfaces6->Address[i].lpSockaddr,\r
+                sizeof (struct sockaddr_in6));\r
+            /* TODO: Find a way to reliably get network mask for IPv6 on XP */\r
+            memset (&r->mask, 0, sizeof (struct sockaddr));\r
+            r->flags &= ~ENUMNICS3_MASK_OK;\r
+          }\r
+        }\r
+        if (!found)\r
+        {\r
+          DebugBreak ();\r
+        }\r
+      }\r
+      if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
+      {\r
+        struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
+        struct sockaddr_in *a = (struct sockaddr_in *) &r->address;\r
+        /* copy address to broadcast, then flip all the trailing bits not\r
+         * falling under netmask to 1,\r
+         * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.\r
+         */\r
+        memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);\r
+        for (i = mask_length; i < 32; i++)\r
+          ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);\r
+        r->flags |= ENUMNICS3_BCAST_OK;\r
+        r->addr_size = sizeof (struct sockaddr_in);\r
+        inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);\r
+      }\r
+      else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
+      {\r
+        struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;\r
+        /* for IPv6 broadcast is not defined, zero it down */\r
+        memset (&r->broadcast, 0, sizeof (struct sockaddr));\r
+        r->flags &= ~ENUMNICS3_BCAST_OK;\r
+        r->addr_size = sizeof (struct sockaddr_in6);\r
+        inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);\r
       }\r
+\r
+      i = 0;\r
+      i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,\r
+          "%S (%s", pCurrentAddress->FriendlyName, dst);\r
+      for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)\r
+        i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,\r
+            "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);\r
+      i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");\r
+      r->pretty_name[1000] = '\0';\r
+      count += 1;\r
     }\r
-    GlobalFree(pAddrTable);\r
-    GlobalFree(pTable);\r
   }\r
 \r
+  if (use_enum2)\r
+  {\r
+    GNUNET_free_non_null (interfaces4);\r
+    GNUNET_free_non_null (interfaces6);\r
+  }\r
+\r
+  GNUNET_free (pAddresses);\r
+  return GNUNET_OK;\r
+}\r
+\r
+void\r
+EnumNICs3_free (struct EnumNICs3_results *r)\r
+{\r
+  GNUNET_free (r);\r
+}\r
+\r
+\r
+/**\r
+ * Lists all network interfaces in a combo box\r
+ * Used by the basic GTK configurator\r
+ *\r
+ * @param callback function to call for each NIC\r
+ * @param callback_cls closure for callback\r
+ */\r
+int\r
+ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)\r
+{\r
+  int r;\r
+  int i;\r
+  struct EnumNICs3_results *results = NULL;\r
+  int results_count;\r
+\r
+  r = EnumNICs3 (&results, &results_count);\r
+  if (r != GNUNET_OK)\r
+    return GNUNET_NO;\r
+\r
+  for (i = 0; i < results_count; i++)\r
+    callback (callback_cls, results[i].pretty_name, results[i].is_default);\r
+  GNUNET_free_non_null (results);\r
   return GNUNET_YES;\r
 }\r
 \r
index 252cacbfba0cf229c417d48fd9751f4d4a09099a..b5245313aa70b2bd9d47f15f57d092e02ad0175a 100644 (file)
@@ -46,8 +46,8 @@ TSetServiceStatus GNSetServiceStatus;
 TStartServiceCtrlDispatcher GNStartServiceCtrlDispatcher;
 TControlService GNControlService;
 TOpenService GNOpenService;
-TGetBestInterface GNGetBestInterface;
-TGetAdaptersInfo GGetAdaptersInfo;
+TGetBestInterfaceEx GNGetBestInterfaceEx;
+TGetAdaptersInfo GNGetAdaptersInfo;
 TNetUserAdd GNNetUserAdd;
 TNetUserSetInfo GNNetUserSetInfo;
 TLsaOpenPolicy GNLsaOpenPolicy;
@@ -117,9 +117,9 @@ GNInitWinEnv ()
     GNGetIpAddrTable =
         (TGetIpAddrTable) GetProcAddress (hIphlpapi, "GetIpAddrTable");
     GNGetIfTable = (TGetIfTable) GetProcAddress (hIphlpapi, "GetIfTable");
-    GNGetBestInterface =
-        (TGetBestInterface) GetProcAddress (hIphlpapi, "GetBestInterface");
-    GGetAdaptersInfo =
+    GNGetBestInterfaceEx =
+        (TGetBestInterfaceEx) GetProcAddress (hIphlpapi, "GetBestInterfaceEx");
+    GNGetAdaptersInfo =
         (TGetAdaptersInfo) GetProcAddress (hIphlpapi, "GetAdaptersInfo");
   }
   else
@@ -127,8 +127,8 @@ GNInitWinEnv ()
     GNGetIfEntry = NULL;
     GNGetIpAddrTable = NULL;
     GNGetIfTable = NULL;
-    GNGetBestInterface = NULL;
-    GGetAdaptersInfo = NULL;
+    GNGetBestInterfaceEx = NULL;
+    GNGetAdaptersInfo = NULL;
   }
 
   /* Service & Account functions */