tags:

views:

1154

answers:

4

Possible Duplicate:
Getting the MAC address of the remote host

I'm working on a module which has a client server architecture. And i have to authenticate the connecting peer machine on the basis of Mac address.

At the time of installation i store a encrypted list of valid Mac addresses.

Please note that i have no control on this peer machine and some third party application will be running on this and i can not install any application on this peer machine.

At run time when socket connection happens i need to know the Mac Id for the IP used in connection, so that i can validate it against the previously stored Mac address.

Are there any C/C++ API available which can help me to get mac address from the ip address. This m/c usually be connected in a LAN but can be on different subnets.

My module is multiplatform and runs on windows , Solaris and Linux and the similarly the peer m/c can be running on any os.

A: 

Do not authenticate by MAC address. It is easy to spoof them. Use an HTTP authentication library like Chilkat.

mcandre
The peer applications are , simple tcp/ip based socket application on which i don't have any control. I can not install any of my application on this peer m/c.
nurxb01
+7  A: 

Unfortunately, the simple answer is really "don't do that".

If your peer machines are on a different subnet (and therefore traffic between you and the peer is passing through a router), then there's no way to do what you want -- the MAC address of the packets you receive will be the MAC address of the router which forwarded them to you, as that's the link-layer device you're communicating with. Only the router nearest to the peer machine will know what the MAC address of the peer is -- and this information isn't passed on.

If the peer machines are on the same subnet, then the incoming packets will contain the MAC address of the peer in the Ethernet header... but this gets stripped off before the packet is delivered to your application. Your options are pretty much limited to either packet-capturing on the network interface you're listening on to get the entire packet, or using whatever tools your system provides to check the local ARP table. Both of these options are very platform-dependent!

Also, neither option is likely to continue working without modification if the interfaces you're dealing with aren't Ethernet interfaces (perhaps they're PPP links, or WiFi, or a funky virtualized interface of some sort, ...), nor will they work with IPv6.

If after all that, you're still determined, look into libpcap/WinPCap for packet capturing, which is the most portable option which comes to mind. To check the local ARP tables, Linux, OS X, Solaris and Windows all provide an arp command-line utility, but the syntax is likely to vary. If an API is available, I wouldn't expect any commonality between the platforms -- there's no standard for this sort of thing, because you really shouldn't be doing it!

Stephen Veiss
Stephen , i guess now will change my strategy. :)and thanks for the mention of libpcap link.
nurxb01
A: 

As mcandre mentioned, it's incredibly easy to spoof mac addresses, but to still answer your question, I think you can do this on all OS's through BSD-style sockets if you're on the same LAN:

Here's some example code from this forum post

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    struct ifreq ifr;
    int sock, j, k;
    char *p, addr[32], mask[32], mac[32];

    if (argc<2) {
        fprintf(stderr,"missing argument, example: eth0\n");
        return 1;
    }

    sock=socket(PF_INET, SOCK_STREAM, 0);
    if (-1==sock) {
        perror("socket() ");
        return 1;
    }

    strncpy(ifr.ifr_name,argv[1],sizeof(ifr.ifr_name)-1);
    ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0';

    if (-1==ioctl(sock, SIOCGIFADDR, &ifr)) {
        perror("ioctl(SIOCGIFADDR) ");
        return 1;
    }
    p=inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr);
    strncpy(addr,p,sizeof(addr)-1);
    addr[sizeof(addr)-1]='\0';

    if (-1==ioctl(sock, SIOCGIFNETMASK, &ifr)) {
        perror("ioctl(SIOCGIFNETMASK) ");
            return 1;
        }
        p=inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_netmask))->sin_addr);
        strncpy(mask,p,sizeof(mask)-1);
        mask[sizeof(mask)-1]='\0';

        if (-1==ioctl(sock, SIOCGIFHWADDR, &ifr)) {
        perror("ioctl(SIOCGIFHWADDR) ");
        return 1;
    }
    for (j=0, k=0; j<6; j++) {
        k+=snprintf(mac+k, sizeof(mac)-k-1, j ? ":%02X" : "%02X",
            (int)(unsigned int)(unsigned char)ifr.ifr_hwaddr.sa_data[j]);
    }
    mac[sizeof(mac)-1]='\0';

    printf("\n");
    printf("name:    %s\n",ifr.ifr_name);
    printf("address: %s\n",addr);
    printf("netmask: %s\n",mask);
    printf("macaddr: %s\n",mac);
    printf("\n");

    close(sock);
    return 0;
}
Marc
SIOCGIFADDR gets the local interface's address, the OP was after the remote peer interface's address.
caf
oops - didn't get too look too closely at what I was copying because I was at work. Edited to remove that section since it's extraneous anyways. Thanks
Marc
+2  A: 

This is impossible to do. There is no guarantee that your connecting peer even has a MAC address. It is entirely possible that the peer connects to the network via dial-up (PPP) or some other non-Ethernet interface.

sigjuice