Logo Search packages:      
Sourcecode: libupnp4 version File versions  Download package

int UpnpGetIfInfo ( const char *  IfName  ) 

Retrieve interface information and keep it in global variables. If NULL, we'll find the first suitable interface for operation.

The interface must fulfill these requirements:

  • Be UP.
  • Not be LOOPBACK.
  • Support MULTICAST.
  • Have a valid IPv4 or IPv6 address.
We'll retrieve the following information from the interface:
  • gIF_NAME -> Interface name (by input or found).
  • gIF_IPV4 -> IPv4 address (if any).
  • gIF_IPV6 -> IPv6 address (if any).
  • gIF_INDEX -> Interface index number.
Returns:
UPNP_E_SUCCESS on success.
Parameters:
IfName  [in] Interface name (can be NULL).

Definition at line 2849 of file upnpapi.c.

References gIF_INDEX, gIF_IPV4, gIF_IPV6, gIF_NAME, UPNP_E_INIT, UPNP_E_INVALID_INTERFACE, UPNP_E_OUTOF_MEMORY, and UpnpPrintf().

Referenced by UpnpInit2().

{
#ifdef WIN32
    // ----------------------------------------------------
    // WIN32 implementation will use the IpHlpAPI library.
    // ----------------------------------------------------
    PIP_ADAPTER_ADDRESSES adapts = NULL;
    PIP_ADAPTER_ADDRESSES adapts_item;
    PIP_ADAPTER_UNICAST_ADDRESS uni_addr;
    SOCKADDR* ip_addr;
    struct in_addr v4_addr;
    struct in6_addr v6_addr;
    ULONG adapts_sz = 0;
    ULONG ret;
    int ifname_found = 0;
    int valid_addr_found = 0;

    // Get Adapters addresses required size.
    ret = GetAdaptersAddresses(AF_UNSPEC,
        GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER,
      NULL, adapts, &adapts_sz );
    if( ret != ERROR_BUFFER_OVERFLOW ) {
        UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
            "GetAdaptersAddresses failed to find list of adapters\n" );
        return UPNP_E_INIT;
    }

    // Allocate enough memory.
    adapts = (PIP_ADAPTER_ADDRESSES)malloc( adapts_sz );
    if( adapts == NULL ) {
        return UPNP_E_OUTOF_MEMORY;
    }

    // Do the call that will actually return the info.
    ret = GetAdaptersAddresses( AF_UNSPEC,
      GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER,
      NULL, adapts, &adapts_sz );
    if( ret != ERROR_SUCCESS ) {
        free( adapts );
        UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
            "GetAdaptersAddresses failed to find list of adapters\n" );
        return UPNP_E_INIT;
    }

    // Copy interface name, if it was provided.
    if( IfName != NULL ) {
        if( strlen(IfName) > sizeof(gIF_NAME) )
            return UPNP_E_INVALID_INTERFACE;

        strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) );
        ifname_found = 1;
    }

    adapts_item = adapts;
    while( adapts_item != NULL ) {

        if( adapts_item->Flags & IP_ADAPTER_NO_MULTICAST ) {
            continue;
        }

        if( ifname_found == 0 ) {
            // We have found a valid interface name. Keep it.
            strncpy( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) );
            ifname_found = 1;
        } else {
            if( strncmp( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) ) != 0 ) {
                // This is not the interface we're looking for.
                continue;
            }
        }

        // Loop thru this adapter's unicast IP addresses.
        uni_addr = adapts_item->FirstUnicastAddress;
        while( uni_addr ) {
            ip_addr = uni_addr->Address.lpSockaddr;
            switch( ip_addr->sa_family ) {
            case AF_INET:
                memcpy( &v4_addr, &((struct sockaddr_in *)ip_addr)->sin_addr, sizeof(v4_addr) );
                valid_addr_found = 1;
                break;
            case AF_INET6:
                // Only keep IPv6 link-local addresses.
                if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ip_addr)->sin6_addr) ) {
                    memcpy( &v6_addr, &((struct sockaddr_in6 *)ip_addr)->sin6_addr, sizeof(v6_addr) );
                    valid_addr_found = 1;
                }
                break;
            default:
                if( valid_addr_found == 0 ) {
                    // Address is not IPv4 or IPv6 and no valid address has 
                    // yet been found for this interface. Discard interface name.
                    ifname_found = 0;
                }
                break;
            }

            // Next address.
            uni_addr = uni_addr->Next;
        }

        if( valid_addr_found == 1 ) {
            gIF_INDEX = adapts_item->IfIndex;
            break;
        }
        
        // Next adapter.
        adapts_item = adapts_item->Next;
    }

    // Failed to find a valid interface, or valid address.
    if( ifname_found == 0  || valid_addr_found == 0 ) {
        UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
            "Failed to find an adapter with valid IP addresses for use.\n" );
        return UPNP_E_INVALID_INTERFACE;
    }

    inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4));
    inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6));
#elif (defined(BSD) && BSD >= 199306)
    struct ifaddrs *ifap, *ifa;
    struct in_addr v4_addr;
    struct in6_addr v6_addr;
    int ifname_found = 0;
    int valid_addr_found = 0;

    // Copy interface name, if it was provided.
    if( IfName != NULL ) {
        if( strlen(IfName) > sizeof(gIF_NAME) )
            return UPNP_E_INVALID_INTERFACE;

        strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) );
        ifname_found = 1;
    }

    // Get system interface addresses.
    if( getifaddrs(&ifap) != 0 ) {
        UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
            "getifaddrs failed to find list of addresses\n" );
        return UPNP_E_INIT;
    }

    // cycle through available interfaces and their addresses.
    for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
    {
        // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that 
        // don't support MULTICAST.
        if( ( ifa->ifa_flags & IFF_LOOPBACK )
            || ( !( ifa->ifa_flags & IFF_UP ) ) 
            || ( !( ifa->ifa_flags & IFF_MULTICAST ) ) ) {
            continue;
        }

        if( ifname_found == 0 ) {
            // We have found a valid interface name. Keep it.
            strncpy( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) );
            ifname_found = 1;
        } else {
            if( strncmp( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) ) != 0 ) {
                // This is not the interface we're looking for.
                continue;
            }
        }

        // Keep interface addresses for later.
        switch( ifa->ifa_addr->sa_family )
        {
        case AF_INET:
            memcpy( &v4_addr, &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, sizeof(v4_addr) );
            valid_addr_found = 1;
            break;
        case AF_INET6:
            // Only keep IPv6 link-local addresses.
            if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr) ) {
                memcpy( &v6_addr, &((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr, sizeof(v6_addr) );
                valid_addr_found = 1;
            }
            break;
        default:
            if( valid_addr_found == 0 ) {
                // Address is not IPv4 or IPv6 and no valid address has 
                // yet been found for this interface. Discard interface name.
                ifname_found = 0;
            }
            break;
        }
    }
    freeifaddrs(ifap);

    // Failed to find a valid interface, or valid address.
    if( ifname_found == 0  || valid_addr_found == 0 ) {
        UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
            "Failed to find an adapter with valid IP addresses for use.\n" );
        return UPNP_E_INVALID_INTERFACE;
    }

    inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4));
    inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6));
    gIF_INDEX = if_nametoindex(gIF_NAME);
#else
    char szBuffer[MAX_INTERFACES * sizeof( struct ifreq )];
    struct ifconf ifConf;
    struct ifreq ifReq;
    FILE* inet6_procfd;
    int i;
    int LocalSock;
    struct in6_addr v6_addr;
    int if_idx;
    char addr6[8][5];
    char buf[65]; // INET6_ADDRSTRLEN
    int ifname_found = 0;
    int valid_addr_found = 0;

    // Copy interface name, if it was provided.
    if( IfName != NULL ) {
        if( strlen(IfName) > sizeof(gIF_NAME) )
            return UPNP_E_INVALID_INTERFACE;

        strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) );
        ifname_found = 1;
    }

    // Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. 
    if( ( LocalSock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ) {
        UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
            "Can't create addrlist socket\n" );
        return UPNP_E_INIT;
    }

    // Get the interface configuration information... 
    ifConf.ifc_len = sizeof szBuffer;
    ifConf.ifc_ifcu.ifcu_buf = ( caddr_t ) szBuffer;

    if( ioctl( LocalSock, SIOCGIFCONF, &ifConf ) < 0 ) {
        UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
            "DiscoverInterfaces: SIOCGIFCONF returned error\n" );
        return UPNP_E_INIT;
    }

    // Cycle through the list of interfaces looking for IP addresses. 
    for( i = 0; i < ifConf.ifc_len ; ) {
        struct ifreq *pifReq =
            ( struct ifreq * )( ( caddr_t ) ifConf.ifc_req + i );
        i += sizeof *pifReq;

        // See if this is the sort of interface we want to deal with.
        strcpy( ifReq.ifr_name, pifReq->ifr_name );
        if( ioctl( LocalSock, SIOCGIFFLAGS, &ifReq ) < 0 ) {
            UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
                "Can't get interface flags for %s:\n",
                ifReq.ifr_name );
        }

        // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that 
        // don't support MULTICAST.
        if( ( ifReq.ifr_flags & IFF_LOOPBACK )
            || ( !( ifReq.ifr_flags & IFF_UP ) ) 
            || ( !( ifReq.ifr_flags & IFF_MULTICAST ) ) ) {
            continue;
        }

        if( ifname_found == 0 ) {
            // We have found a valid interface name. Keep it.
            strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) );
            ifname_found = 1;
        } else {
            if( strncmp( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ) != 0 ) {
                // This is not the interface we're looking for.
                continue;
            }
        }

        // Check address family.
        if( pifReq->ifr_addr.sa_family == AF_INET ) {
            // Copy interface name, IPv4 address and interface index.
            strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) );
            inet_ntop(AF_INET, &((struct sockaddr_in*)&pifReq->ifr_addr)->sin_addr, gIF_IPV4, sizeof(gIF_IPV4));
            gIF_INDEX = if_nametoindex(gIF_NAME);

            valid_addr_found = 1;
            break;
        } else {
            // Address is not IPv4
            ifname_found = 0;
        }
    }
    close( LocalSock );

    // Failed to find a valid interface, or valid address.
    if( ifname_found == 0  || valid_addr_found == 0 ) {
        UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
            "Failed to find an adapter with valid IP addresses for use.\n" );
        return UPNP_E_INVALID_INTERFACE;
    }
    
    // Try to get the IPv6 address for the same interface 
    // from "/proc/net/if_inet6", if possible.
    inet6_procfd = fopen( "/proc/net/if_inet6", "r" );
    if( inet6_procfd != NULL ) {
        while( fscanf(inet6_procfd,
                "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*20s\n",
                addr6[0],addr6[1],addr6[2],addr6[3],
                addr6[4],addr6[5],addr6[6],addr6[7], &if_idx) != EOF) {
            // Get same interface as IPv4 address retrieved.
            if( gIF_INDEX == if_idx ) {
                snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s",
                    addr6[0],addr6[1],addr6[2],addr6[3],
                    addr6[4],addr6[5],addr6[6],addr6[7]);
                // Validate formed address and check for link-local.
                if( inet_pton(AF_INET6, buf, &v6_addr) > 0 &&
                    IN6_IS_ADDR_LINKLOCAL(&v6_addr) ) {
                    // Got valid IPv6 link-local adddress.
                    strncpy( gIF_IPV6, buf, sizeof(gIF_IPV6) );
                    break;
                }
            }
        }
        fclose( inet6_procfd );
    }
#endif

    UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, 
                "Interface name=%s, index=%d, v4=%s, v6=%s\n",
                gIF_NAME, gIF_INDEX, gIF_IPV4, gIF_IPV6 );

    return UPNP_E_SUCCESS;
}


Generated by  Doxygen 1.6.0   Back to index