0

Using getifaddrs() function I'm wanting to extract the network ip and mask in CIDR format (i.e. 24 instead of 255.255.255.0) which is different than other questions. But I'm having difficulty with the mask part.

For example:

192.168.0.114/24

This is what I have be messing around with so far. But I must be reading the netmask incorrectly. It's completely wrong.

#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

unsigned int cidrMask(unsigned int n) {
    unsigned int count = 0;
    while (n) {
        count += n & 1;
        n >>= 1;
    }
    return 32-count;
}


int main (int argc, const char * argv[]) {
    struct ifaddrs * ifAddrStruct=NULL;
    struct ifaddrs * ifa=NULL;
    void * tmpAddrPtr=NULL;
    unsigned int tmpMask;

    getifaddrs(&ifAddrStruct);

    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr) {
            continue;
        }

        if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
            // is a valid IP4 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
            memcpy(&tmpMask, &(*(struct sockaddr_in *)&ifa->ifa_netmask).sin_addr, 4);

            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s, mask=%u, %u\n", ifa->ifa_name, addressBuffer, ifa->ifa_netmask, cidrMask(tmpMask));
                printf("tmpmask=%d\n", tmpMask);
        }
    }
    if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    return 0;
}

So the output for the netmask is completely wrong.

lo IP Address 127.0.0.1, mask=3106544572, 22
tmpmask=21982
enp0s25 IP Address 192.168.0.114, mask=3106544756, 22
tmpmask=21982
docker0 IP Address 172.17.0.1, mask=3106544940, 22
tmpmask=21982

How do I read the netmask and produce correct output?

hookenz
  • 36,432
  • 45
  • 177
  • 286
  • Apologies. It looks like you know that, but why print `ifa->ifa_netmask` as an integer? – user4581301 Jul 03 '18 at 06:00
  • Lol. Some code I was looking at referenced that field but in a different way. It was before I looked up what it was really. But still not sure why it's messed up. – hookenz Jul 03 '18 at 06:29
  • Possible duplicate of [Obtaining SubnetMask in C](https://stackoverflow.com/a/18101149/608639). See Keine's answer and the discussion of `ifa_netmask`. – jww Jul 03 '18 at 11:38
  • @jww - not a duplicate. Those answers and question want it in the text form 255.255.255.0. And that's simply output but calling a C library function. That's not what I want. – hookenz Jul 04 '18 at 21:47

1 Answers1

1

Your assignment of tmpMask is wrong, because you are type-casting ifa_netmask wrong, so you are accessing its sin_addr member through an invalid pointer.

You are taking the address of ifa_netmask and type-casting that to sockaddr_in*, but you need to type-cast its value instead, just like you do for ifa_addr:

memcpy(&tmpMask, &(((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr), 4); 

Which can be simplified by removing memcpy():

tmpMask = ((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr;

When you are printing out ifa_netmask, you are printing out its raw pointer value (using %u, which is undefined behavior for a pointer). You should format ifa_netmask to a human-readable string the same way you are formatting ifa_addr, since they are both pointers to sockaddr_in structs:

char addressBuffer[INET_ADDRSTRLEN];
char maskBuffer[INET_ADDRSTRLEN];

tmpAddrPtr = &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);

tmpAddrPtr = &((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, maskBuffer, INET_ADDRSTRLEN);

tmpMask = ((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr;

printf("%s IP Address %s, Mask %s, %u\n", ifa->ifa_name, addressBuffer, maskBuffer, cidrMask(tmpMask));
printf("tmpmask=%u\n", tmpMask);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770