]> git.meshlink.io Git - catta/blobdiff - src/iface-windows.c
skip transient ("cluster") addresses on Windows, as per MSDN
[catta] / src / iface-windows.c
index e3ca771b212c02dc8af671b72c48fa14d2774558..729e3c4635617bad29ec6b7618054f6348f4e1ad 100644 (file)
@@ -20,6 +20,7 @@
 #include "iface-windows.h"
 #include "iface.h"
 
+#include <stdlib.h> // wcstombs
 #include <catta/malloc.h>
 #include <catta/log.h>
 #include <iphlpapi.h>
 #include "util.h"   // catta_format_mac_address
 
 
-// for the luid-to-idx hashmap
-static unsigned luid_hash(const void *data)
+// integrate the information from an IP_ADAPTER_UNICAST_ADDRESS structure for
+// given CattaHwInterface into the CattaInterfaceMonitor
+static void ip_adapter_unicast_address(CattaInterfaceMonitor *m,
+                                       CattaHwInterface *hw,
+                                       IP_ADAPTER_UNICAST_ADDRESS *a)
 {
-    return ((NET_LUID *)data)->Info.NetLuidIndex;
-}
-static int luid_equal(const void *a, const void *b)
-{
-    return (((NET_LUID *)a)->Value == ((NET_LUID *)b)->Value);
-}
+    CattaInterface *iface;
+    CattaAddress addr;
+    CattaInterfaceAddress *ifaddr;
+    struct sockaddr *sa = a->Address.lpSockaddr;
+
+    // skip transient addresses; to quote MSDN: "The IP address is a cluster
+    // address and should not be used by most applications."
+    // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366066(v=vs.85).aspx
+    if(a->Flags & IP_ADAPTER_ADDRESS_TRANSIENT)
+        return;
 
-static CattaIfIndex find_ifindex(CattaInterfaceMonitor *m, NET_LUID luid)
-{
-    CattaIfIndex *pi = NULL;
-    NET_LUID *key = NULL;
-
-    if((pi = catta_hashmap_lookup(m->osdep.idxmap, &luid)) == NULL) {
-        // allocate memory for the hashmap key and value
-        key = catta_malloc(sizeof(luid));
-        pi = catta_malloc(sizeof(CattaIfIndex));
-        if(!key || !pi)
-            goto fail;
-
-        *key = luid;
-            
-        // find an index for this luid
-        *pi = m->osdep.nidx;
-        if(*pi < 0)  // overflow
-            goto fail;
-
-        // register the index
-        if(catta_hashmap_replace(m->osdep.idxmap, key, pi) < 0)
-            goto fail;
-        m->osdep.nidx++;
+    // fill addr struct for address lookup
+    switch(sa->sa_family) {
+    case AF_INET:
+        memcpy(addr.data.data, &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr));
+        break;
+    case AF_INET6:
+        memcpy(addr.data.data, &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr));
+        break;
+    default:
+        catta_log_debug("unexpected address family on interface %d: %u", hw->index, sa->sa_family);
+        return;
+    }
+    addr.proto = catta_af_to_proto(sa->sa_family);
+
+    // get protocol-specific CattaInterface object
+    if(!(iface = catta_interface_monitor_get_interface(m, hw->index, addr.proto))) {
+        catta_log_error("CattaInterface (index %d, proto %d) not found", hw->index, addr.proto);
+        return;
+    }
+
+    // find or allocate a CattaInterfaceAddress struct for this address
+    if(!(ifaddr = catta_interface_monitor_get_address(m, iface, &addr))) {
+        if(!(ifaddr = catta_interface_address_new(m, iface, &addr, a->OnLinkPrefixLength))) {
+            catta_log_error("out of memory in ip_adapter_unicast_address");
+            return;
+        }
     }
 
-    return *pi;
+    // set global scope flag
+    if(addr.proto == CATTA_PROTO_INET6)
+        ifaddr->global_scope = !(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr.data.data)
+                                 || IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr.data.data));
+    else
+        ifaddr->global_scope = 1;
 
-fail:
-    catta_free(key);
-    catta_free(pi);
-    return -1;
+    // XXX debugging, remove
+    {
+        char s[CATTA_ADDRESS_STR_MAX];
+        catta_log_debug(" address: %s\n"
+                        "   global_scope: %d\n"
+                        "   flags: 0x%.4x",
+            catta_address_snprint(s, sizeof(s), &addr),
+            ifaddr->global_scope,
+            (unsigned int)a->Flags);
+    }
 }
 
 // integrate the information from an IP_ADAPTER_ADDRESSES structure
 // as returned by GetAdaptersAddresses into the CattaInterfaceMonitor
-static void ip_adapter_address(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
+static void ip_adapter(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p)
 {
+    IP_ADAPTER_UNICAST_ADDRESS *a;
     CattaIfIndex idx;
     CattaHwInterface *hw;
-
-    // look up the interface index by LUID
-    if((idx = find_ifindex(m, p->Luid)) < 0) {
-        catta_log_error("could not allocate index ip_adapter_address");
+    size_t n;
+
+    // we want an index specific to the hardware interface, but Windows
+    // has one for IPv4 and one for IPv6. it seems like these are always the
+    // same unless one of the protocols is not available. let's have a bunch of
+    // checks...
+    if(!p->IfIndex && !p->Ipv6IfIndex) {
+        return; // no usable protocols
+    } else if(!p->IfIndex) {
+        idx = p->Ipv6IfIndex;   // IPv6 but no IPv4 (huh!)
+    } else if(!p->Ipv6IfIndex) {
+        idx = p->IfIndex;       // IPv4 but no IPv6
+    } else if(p->IfIndex == p->Ipv6IfIndex) {
+        idx = p->IfIndex;       // same index for both protocols
+    } else {
+        // both indexes valid but not equal
+        catta_log_error("unsupported interface: %ls (IfIndex and Ipv6IfIndex differ: %u/%u)",
+            p->FriendlyName, (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex);
         return;
     }
 
@@ -93,44 +130,60 @@ static void ip_adapter_address(CattaInterfaceMonitor *m, IP_ADAPTER_ADDRESSES *p
 
     // fill the CattaHwInterface struct with data
     hw->flags_ok =
-        (p->OperStatus & IfOperStatusUp) &&
-        !(p->IfType & IF_TYPE_SOFTWARE_LOOPBACK) &&
+        (p->OperStatus == IfOperStatusUp) &&
+        !(p->IfType == IF_TYPE_SOFTWARE_LOOPBACK) &&
         !(p->Flags & IP_ADAPTER_NO_MULTICAST) &&
-        (m->server->config.allow_point_to_point || !(p->IfType & IF_TYPE_PPP));
+        (m->server->config.allow_point_to_point || !(p->IfType == IF_TYPE_PPP));
             // XXX what about IF_TYPE_TUNNEL?
 
+    n = wcstombs(NULL, p->FriendlyName, 0) + 1;
     catta_free(hw->name);
-    hw->name = catta_strdup(p->AdapterName);
+    hw->name = catta_new(char, n);
+    wcstombs(hw->name, p->FriendlyName, n);
 
     hw->mtu = p->Mtu;
 
     hw->mac_address_size = p->PhysicalAddressLength;
-    if (hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
-      hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
+    if(hw->mac_address_size > CATTA_MAC_ADDRESS_MAX)
+        hw->mac_address_size = CATTA_MAC_ADDRESS_MAX;
     memcpy(hw->mac_address, p->PhysicalAddress, hw->mac_address_size);
 
-    // XXX process addresses
-
     // XXX debugging, remove
-   { 
-     char mac[256]; 
-     catta_log_debug("======\n name: %s\n index:%d\n mtu:%d\n mac:%s\n flags_ok:%d\n======",  
-                   hw->name, hw->index,  
-                   hw->mtu,  
-                   catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size), 
-                   hw->flags_ok); 
-   } 
+    {
+        char mac[256];
+        catta_log_debug(" name: %s\n"
+                        " index: %d\n"
+                        "   IfIndex: %u\n"
+                        "   Ipv6IfIndex: %u\n"
+                        " mtu: %d\n"
+                        " mac: %s\n"
+                        " flags_ok: %d\n"
+                        "   type: %u\n"
+                        "   status: %u\n"
+                        "   multicast: %d\n"
+                        "   flags: 0x%.4x",
+            hw->name, hw->index,
+            (unsigned int)p->IfIndex, (unsigned int)p->Ipv6IfIndex,
+            hw->mtu,
+            catta_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size),
+            hw->flags_ok,
+            (unsigned int)p->IfType,
+            (unsigned int)p->OperStatus,
+            !(p->Flags & IP_ADAPTER_NO_MULTICAST),
+            (unsigned int)p->Flags);
+    }
+
+    // process addresses
+    // XXX remove addresses that are no longer in the list
+    for(a=p->FirstUnicastAddress; a; a=a->Next)
+        ip_adapter_unicast_address(m, hw, a);
+    catta_log_debug("=====");
 }
 
 
 int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m)
 {
-    m->osdep.nidx = 0;
-    m->osdep.idxmap = catta_hashmap_new(luid_hash, luid_equal, catta_free, catta_free);
-    if(m->osdep.idxmap == NULL) {
-        catta_log_error("out of memory in catta_interface_monitor_init_osdep");
-        return -1;
-    }
+    (void)*m;   // silence "unused paramter" warning
 
     // XXX register callbacks to get notified of interface/address changes
 
@@ -139,7 +192,7 @@ int catta_interface_monitor_init_osdep(CattaInterfaceMonitor *m)
 
 void catta_interface_monitor_free_osdep(CattaInterfaceMonitor *m)
 {
-    catta_hashmap_free(m->osdep.idxmap);
+    (void)*m;   // silence "unused paramter" warning
 }
 
 void catta_interface_monitor_sync(CattaInterfaceMonitor *m)
@@ -170,7 +223,7 @@ void catta_interface_monitor_sync(CattaInterfaceMonitor *m)
 
     // create 'CattaInterface's for every adapter
     for(p=buf; p; p=p->Next)
-        ip_adapter_address(m, p);
+        ip_adapter(m, p);
 
     catta_free(buf);