coderrr

March 7, 2008

Get the MAC address of a local IP

Filed under: c, network — Tags: , — coderrr @ 7:03 pm

For my latest project I needed to get the MAC address (ethernet hardware address) of a machine on my LAN given the IP of the machine. I did a lot of googling and found no solution which returned the address quickly. Most people said to use the ‘arp’ command but this was very slow and didn’t always work.

I knew from writing a packet sniffer in the past that every packet destined for a local machine had to have its MAC address in the ethernet header portion of the packet. So I decided to write my own tool to get the job done. Here’s the source:

#include <pcap.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h> 

int child_pid = 0;

void print_eth_addr(void *addr) {
  printf("%s\n", ether_ntoa((struct ether_addr *)addr));
  kill(child_pid, 9);
  exit(0);
}

void find_eth_addr(struct in_addr *search_ip, const struct pcap_pkthdr* pkthdr, const u_char *packet) {
  struct ether_header *eth_hdr = (struct ether_header *)packet;

  if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP) {
    struct ip *ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
    if (ip_hdr->ip_dst.s_addr == search_ip->s_addr)
      print_eth_addr(eth_hdr->ether_dhost);
    if (ip_hdr->ip_src.s_addr == search_ip->s_addr)
      print_eth_addr(eth_hdr->ether_shost);
  }
}

int main(int argc, char **argv)
{ 
  char *dev, errbuf[PCAP_ERRBUF_SIZE]; 
  pcap_t* descr;
  bpf_u_int32 maskp, netp;

  if (argc < 2) {
    printf("Usage: %s <ip> [interface]\n", argv[0]);
    return 1;
  }

  if (argc == 2 && !(dev = pcap_lookupdev(errbuf))) {
    fprintf(stderr, "%s\n", errbuf); return 1;
  } else if (argc == 3) {
    dev = argv[2];
  }

  pcap_lookupnet(dev,&netp,&maskp,errbuf);

  if (!(descr = pcap_open_live(dev, BUFSIZ, 1, -1, errbuf))) {
    printf("pcap_open_live(): %s\n", errbuf); return 1;
  }

  struct in_addr search_ip;
  if (!inet_aton(argv[1], &search_ip)) {
    fprintf(stderr, "bad ip\n"); exit(1);
  }

  int pid = fork();
  if (pid == 0) {
    while (1) {
      struct sockaddr_in sin;
      sin.sin_family = PF_INET;
      inet_aton(argv[1], &sin.sin_addr);
      sin.sin_port = htons(1);
      int s = socket(PF_INET, SOCK_STREAM, 0);
      connect(s, (struct sockaddr *)&sin, sizeof(sin));
      usleep(100000);
    }
  } else {
    child_pid = pid;
    pcap_loop(descr, -1, (pcap_handler)find_eth_addr, (void *)&search_ip);
  }

  return 0;
}

Compile it with gcc -o getmac getmac.c -lpcap. You’ll need libpcap and the pcap’s header files to compile it. apt-get install libpcap libpcap-dev should get you them.

You’ll also need to run it with sudo since you need root privileges to be able to open a network device in promiscuous mode: sudo ./getmac 192.168.0.5 or sudo ./getmac 192.168.1.84 eth1 to specify a specific interface.

6 Comments »

  1. I get a “Segment violation” message… :(

    I tried to run it on Debian Etch/amd64 as root.

    gcc (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)

    No compilation problems.

    Thanks

    Comment by Zaphir — May 9, 2008 @ 4:14 am

  2. interesting… you should compile it with debug info and run it with gdb to see where its dieing…

    gcc -g -o getmac getmac.c -lpcap

    sudo gdb ./getmac
    set args IP INTERFACE
    run

    it should then tell you where it’s crashing

    Comment by coderrr — May 9, 2008 @ 12:34 pm

  3. The arp protocol is not slow and unreliable as it is the underlying protocol for basically all netowrking operations to determine the table of MAC – IP

    If you wrote it right I’m sure it would work.

    Comment by Robin — September 14, 2009 @ 3:46 am

  4. Er, he never said the ARP proto was slow, he said the `arp` command is, learn to read yo!

    Comment by Face — March 18, 2010 @ 10:46 pm

  5. I have tried to leave a response here but each time I submit it times out the comment or gives an error. Can the author could possibly check into the reason it keeps messing up?

    Comment by Raymond Alattar — June 25, 2010 @ 8:40 am

  6. i need to get mac address of remote pc on my lan. I have ips of those machines please help me. When i compile this code i get the following linker error collect2: ld returned 1 exit status.

    Comment by Vivek Aggarwal — December 20, 2012 @ 11:26 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 28 other followers

%d bloggers like this: