Search code examples
clinuxsocketsethernetmac-address

C reading mac address - undefined behavior


I would like to read the MAC address of my target. So I am using the following code

TS32 get_mac_address(TU8 ** aps8Mac)
{
    TS32 fd;
    struct ifreq ifr;
    CHAR *iface = "eth0";
    TU8 *mac;

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name , iface , IFNAMSIZ-1);

    ioctl(fd, SIOCGIFHWADDR, &ifr);

    close(fd);

    mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;
    *aps8Mac = mac;

    return 0;
}

int main(int argc, char **argv)
{
    TU8   *s8Mac = NULL;
    get_mac_address(&s8Mac);
    fprintf(stdout, "MAC address : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n" , s8Mac[0], s8Mac[1], s8Mac[2], s8Mac[3], s8Mac[4], s8Mac[5]); 
    fprintf(stdout, "MAC address : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n" , s8Mac[0], s8Mac[1], s8Mac[2], s8Mac[3], s8Mac[4], s8Mac[5]);
    return 0;
}

Once executed on the target I am getting :

MAC address : 00:01:02:03:00:76
MAC address : FE:76:9C:8C:AB:7E

Why I do not read

MAC address : 00:01:02:03:00:76
MAC address : 00:01:02:03:00:76

EDIT 1 : get_mac_address modified regarding to advices given as answer

TS32 get_mac_address(TU8 ** aps8Mac)
{
    TS32 fd;
    struct ifreq ifr;
    CHAR *iface = "eth0";

    TU8 *mac = malloc(sizeof(TU8) * 17);

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name , iface , IFNAMSIZ-1);

  ioctl(fd, SIOCGIFHWADDR, &ifr);

    close(fd);

    mac = (TU8 *)ifr.ifr_hwaddr.sa_data;
    *aps8Mac = mac;
    return 0;
}

Solution

  • After your edit, you have allocated 17 bytes for your mac address.
    (I am unsure why you wanted 17 bytes... a typical MAC address is only 6-bytes long!)

    However, you do not fill in that data properly.

    You tried to fill it in on line:

    mac = (TU8 *)ifr.ifr_hwaddr.sa_data;
    

    But all that does is give the mac pointer the same pointer as sa_data, while simultaneously leaking the memory you allocated before.

    I believe you want to copy the data from one structure to another:

    // Copy 17 bytes from the sa_data to the allocated, reserved space for mac-address
    // After this, ifr-->sa_data can be overwritten or destroyed; we don't care
    // We have our own copy of the data in mac.
    memcpy(mac, (TU8 *)ifr.ifr_hwaddr.sa_data, 17*sizeof(TU8) );
    

    I would attempt to re-write it like this:

    TS32 get_mac_address(TU8 ** aps8Mac)
    {
        TS32 fd;
        struct ifreq ifr;
        CHAR *iface = "eth0";
        const int MAC_SIZE = 6; // MAC addresses are 6-bytes.
    
        *aps8Mac = malloc(sizeof(TU8) * MAC_SIZE);
    
        fd = socket(AF_INET, SOCK_DGRAM, 0);
    
        ifr.ifr_addr.sa_family = AF_INET;
        strncpy(ifr.ifr_name , iface , IFNAMSIZ-1);
    
        ioctl(fd, SIOCGIFHWADDR, &ifr);
        close(fd);
    
        // Copy the 6-byte address to the output.
        memcpy(*aps8Mac, ifr.ifr_hwaddr.sa_data, MAC_SIZE);
    
        return 0;
    }