shovel_coder
shovel_coder

Reputation: 59

Check if Windows Computer on Ethernet Via C++

So I have tried looking at a couple of different answers for this. One that I thought may have promise was this one:

How to check network interface type is Ethernet or Wireless on Windows using Qt?

However, I don't really know too much about Networking or even about Windows. Personally, I cannot understand most of the Microsoft documentation on their websites. I have tried things like INetworkConnection, NativeWiFi, etc. But either they do not do what I want, or I just cannot figure out how to do it from the available documentation.

With that being said, I would like to use C++ to check if the device this program is being run on is connected to the internet via Ethernet cable. Basically, I want to do the following:

However, the problem is that I don't know how to check if the device has Ethernet connected. Is there a way to do this? I am NOT using QT. Thank you!


EDIT: I should also include what I have tried so far.

I tried using GetAdaptersInfo and getting the Type trait from the PIP_ADAPTER_INFO variable type, but that always gives me Unknown type 71 whether I am on Ethernet or not.

The documentation for that GetAdaptersInfo is here: https://msdn.microsoft.com/en-us/library/aa365917%28VS.85%29.aspx

Thanks


EDIT 2: Here is the code I was using for GetAdaptersInfo

bool is_on_ethernet{
    PIP_ADAPTER_INFO pAdapterInfo;
    PIP_ADAPTER_INFO pAdapter = NULL;
    DWORD dwRetVal = 0;
    UINT i;

    struct tm newtime;
    char buffer[32];
    errno_t error;

    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));

    if(pAdapterInfo == NULL)
        printf("Error allocating memory need to call GetAdaptersInfo");

    if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
        free(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
    }

    if((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
        pAdapter = pAdapterInfo;

        switch(pAdapter->Type){
            case MIB_IF_TYPE_OTHER:
                printf("Other\n");
                return false;
                break;
            case MIB_IF_TYPE_ETHERNET:
                printf("Ethernet\h");
                return true;
                break;
            case MIB_IF_TYPE_TOKENRING:
                printf("Token Ring\n");
                return false;
                break;
            case MIB_IF_TYPE_FDDI
                printf("FDDI\n");
                return false;
                break;
            case MIB_IF_TYPE_PPP
                printf("PPP\n");
                return false;
                break;
            case MIB_IF_TYPE_LOOPBACK
                printf("Lookback\n");
                return false;
                break;
            case MIB_IF_TYPE_SLIP
                printf("Slip\n");
                return false;
                break;
            default
                printf("Unknown type %ld\n\n", pAdapter->Type);
                return false;
                break;
        }
    }

    if(pAdapterInfo)
        free(pAdapterInfo);

    return false;
}

Upvotes: 3

Views: 5323

Answers (3)

yuanen cao
yuanen cao

Reputation: 1

Based on @specializt's answer, and with some minor modification, I got it work for me as following:

BOOL getDevices(NDIS_PHYSICAL_MEDIUM type, vector<MIB_IF_ROW2>& vetIFRow)
{
    PMIB_IF_TABLE2 table = NULL;
    if (GetIfTable2Ex(MibIfTableRaw, &table) != NOERROR || !table)
    {
        return FALSE;
    }

    for (ULONG i = 0; i < table->NumEntries; i++)
    {
        MIB_IF_ROW2 row;
        ZeroMemory(&row, sizeof(MIB_IF_ROW2));
        row.InterfaceIndex = i;
        if (GetIfEntry2(&row) == NOERROR && row.PhysicalMediumType == type)
        {
            vetIFRow.push_back(row);
        }
    }

    FreeMibTable(table);
    return TRUE;
}

BOOL isNetIFConnected(const MIB_IF_ROW2& row, IFTYPE Type)
{
    return (row.TunnelType == TUNNEL_TYPE_NONE &&
        row.AccessType != NET_IF_ACCESS_LOOPBACK &&
        row.Type == Type &&
        row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE &&
        row.MediaConnectState == MediaConnectStateConnected);
}

tstring getNetWorkType()
{
    vector<MIB_IF_ROW2> vectRow;
    BOOL bRet = getDevices(NdisPhysicalMedium802_3, vectRow); // ETHERNET adapters
    if (bRet)
    {
        for (auto it = vectRow.begin(); it != vectRow.end(); it++)
        {
            if (isNetIFConnected(*it, IF_TYPE_ETHERNET_CSMACD))
            {
                return L"ETHERNET";
            }
        }
    }

    vectRow.clear();
    bRet = getDevices(NdisPhysicalMediumNative802_11, vectRow); //WLAN adapters
    if (bRet)
    {
        for (auto it = vectRow.begin(); it != vectRow.end(); it++)
        {
            if (isNetIFConnected(*it, IF_TYPE_IEEE80211))
            {
                return L"WIFI";
            }
        }
    }

    return L"Unknown";
}

Thanks to @specializt

Upvotes: 0

specializt
specializt

Reputation: 1911

Your problem is somewhat difficult as it can be really complicated to get the "current" network adapter --- windows routes packets depending on network adapter configuration and destination reachability so your "current" adapter may change at any time ... but since you already know how to retrieve IPs and MACs ("hardware address") of available adapters you could simply use your hack to retrieve a MAC for your current IP and filter/search inside of my second function for it! The field "PhysicalAddress" is what you're looking for, thats the MAC adress

I have made the experience that the only, somewhat reliable way of doing that is via GetIfTable and GetIfTable2, the former returns somewhat superficial adpater info and the latter provides great detail. Heres a sample implementation, as it uses the detailed function you can also query for WLAN adapters :

vector<MIB_IF_ROW2>* getDevices(NDIS_PHYSICAL_MEDIUM type)
    {       
        vector<MIB_IF_ROW2> *v = new vector<MIB_IF_ROW2>();
        PMIB_IF_TABLE2 table = NULL;
        if(GetIfTable2Ex(MibIfTableRaw, &table) == NOERROR && table)
        {
            UINT32 i = 0;
            for(; i < table->NumEntries; i++)
            {
                MIB_IF_ROW2 row;

                ZeroMemory(&row, sizeof(MIB_IF_ROW2));
                row.InterfaceIndex = i;
                if(GetIfEntry2(&row) == NOERROR)
                {                   
                    if(row.PhysicalMediumType == type)
                    {
                        v->push_back(row);
                    }                   
                }           
            }
            FreeMibTable(table);
        }
        return v;
    }

Now all you need to do is iterate over the list and filter out disabled adapters and whatnot :

vector<MIB_IF_ROW2>* wlan = getDevices(NdisPhysicalMediumNative802_11); //WLAN adapters
//see https://msdn.microsoft.com/en-us/library/windows/desktop/aa814491(v=vs.85).aspx, "PhysicalMediumType" for a full list
for(auto &row : *v)
    {
        //do some additional filtering, this needs to be changed for non-WLAN           
        if( row.TunnelType == TUNNEL_TYPE_NONE &&
            row.AccessType != NET_IF_ACCESS_LOOPBACK &&         
            row.Type == IF_TYPE_IEEE80211 &&
            row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE)              
            {
                //HERE BE DRAGONS!                    
            }
    }

Now its quite easy to generate lists of WLAN adapters and non-WLAN adapters (see comment in second function), search for your current MAC and conclude that it is wired or wireless - but be aware that these lists may overlap since 802.11 basically is an extended version of 802.3 but 802.3 does not include 802.11 (since its an extension) - so you will need a tiny bit of if/else logic going on in order to seperate WLAN from non-WLAN adapters.

You could also use WlanEnumInterfaces to get all of the WLAN adapters but thats basically the same as using the above function with NdisPhysicalMediumNative802_11 as parameter ...

Upvotes: 1

shovel_coder
shovel_coder

Reputation: 59

So first, thank you very much to user @Nighthawk441 for pointing me in the right direction for this. Without this user, I would most certainly have not come up with a solution.

That being said, the solution I have right now is, at best, a hack. It seems to work, but I don't think it is even close to the best option. Thus, I will leave this as an answer but I will not accept it for a little while in the event that a better answer is found. I am also very open to any comments anyone may have as it pertains to this answer.

In short, what I did was I looped through all of the Adapters from GetAdaptersInfo. In order to see if the adapter was connected, I compared the IP address of the adapter to the string "0.0.0.0", as if it were something other than this I felt it was safe to say that the adapter was connected. So, without further ado, here is the code that I implemented.

bool is_on_ethernet(){
    PIP_ADAPTER_INFO pAdapterInfo;
    PIP_ADAPTER_INFO pAdapter = NULL;
    DWORD dwRetVal = 0;
    UINT i;

    struct tm newtime;
    char buffer[32];
    errno_t error;

    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));

    if(pAdapterInfo == NULL)
        printf("Error allocating memory needed to call GetAdaptersInfo");

    if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
        free(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
    }

    if((dwRetValue = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
        do{
            pAdapter = pAdapterInfo;

            string ip_string = pAdapter->IpAddressList.IpAddress.String;

            switch(pAdapter->Type){
                case MIB_IF_TYPE_OTHER:
                    printf("Other\n");
                    break;
                ...
                case MIB_IF_TYPE_ETHERNET:
                    printf("Ethernet\n");

                    //new code
                    if(ip_string.compare("0.0.0.0") != 0){
                        free(pAdapterInfo);
                        return true;
                    }

                    break;
                default:
                    printf("Unknown type %ld\n", pAdapter->Type);
                    break;
            }
        }while(pAdapterInfo = pAdapterInfo->Next);
    }

    if(pAdapterInfo)
        free(pAdapterInfo);

    return false;
}

Looking at this reference really helped me:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa365819%28v=vs.85%29.aspx

So thank you to Nighthawk for supplying that information to me. Hopefully this will help someone else! If anyone has any comments or any other answers, feel free to post them! Thanks!

Upvotes: 1

Related Questions