LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 04-11-2006, 05:32 PM   #1
eljofi
LQ Newbie
 
Registered: Apr 2006
Posts: 5

Rep: Reputation: 1
Question Getting MAC address from Ethernet packet in C++


Hi,
I am writing a C++ program to receive UDP datagrams and I need to know not only the IP address of the computer that sent the datagram but also the MAC address.

What I do is to create a socket:
int sockd;
sockd = socket(PF_INET, SOCK_DGRAM, 0);

Then bind it to a port and ip adress:
struct sockaddr_in sin;
.... populate sin with port, ip_address, etc...
bind(sockd,(struct sockaddr *)&sin, sizeof(sin));

Then wait for an UDP datagram:
int dsize, sin_len;
char buff[256];
dsize = recvfrom(sockd,buff,256,0(struct sockaddr *)&sin, (socklen_t *)&sin_len);

And to get the IP address I do:
std::cout << "\nIP: " << inet_ntoa(sin.sin_addr);

But, do any one knows how to get the MAC of the equipment that generated the UDP datagram I received?

I know the MAC address is on the ARP table as it is inserted in it together with the corresponding IP when a Ethernet packet is received for that IP for the first time, but it would be great to get it from the Ethernet header itself to save time, as my program will be doing this several thousands of times per minute.

Thanks in advance,
Jorge
 
Old 04-11-2006, 06:07 PM   #2
leadazide
Member
 
Registered: Apr 2004
Location: Germany
Distribution: SuSE 11.0, Ubuntu 7.10
Posts: 390

Rep: Reputation: 30
I'm not really an expert in network programming, but I know that nmap does such a thing so you could take a look at nmap source. Get it at http://insecure.org/nmap/.
 
Old 04-12-2006, 02:54 AM   #3
alred
Member
 
Registered: Mar 2005
Location: singapore
Distribution: puppy and Ubuntu and ... erh ... redhat(sort of) :( ... + the venerable bsd and solaris ^_^
Posts: 658
Blog Entries: 8

Rep: Reputation: 31
heres a code snipplet which i copied and pasted from somewhere quite some time ago(i couldnt locate the original web link to the source) , i think is in c , can get the mac address(from internal lan only ??) ..

Code:
   #include <stdlib.h>
    #include <string.h>
#include <stdio.h>
#include <errno.h>  
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>  
#include <netinet/in.h>
#include <netinet/if_ether.h>
  #include <netdb.h>
 
int _get_MAC(char *addr,char *dport) {
  int sock,sockfd, n;
  char buffer[2048];
    unsigned char *iphead, *ethhead;
    struct hostent *he;
           struct sockaddr_in their_addr; // connector's address information 
// struct ifreq iface;
 // struct sockaddr_in *addr;
  struct ether_addr ether;
  

  if ( (sock=socket(PF_PACKET, SOCK_RAW,htons(ETH_P_IP)))<0) {//
    perror("socket");
    exit(1);
  }
    
      
    if ((he=gethostbyname(addr)) == NULL) {  // get the host info 
            perror("gethostbyname");
            exit(1);
    }
      if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(1);
        }

        their_addr.sin_family = AF_INET;    // host byte order 
        their_addr.sin_port = htons(atoi(dport));  // short, network byte order 
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);
        memset(&(their_addr.sin_zero), '\0', 8);  // zero the rest of the struct 

        if (connect(sockfd, (struct sockaddr *)&their_addr,
                                              sizeof(struct sockaddr)) == -1) {
            perror("connect");
            exit(1);
}  
while (1) {
if (n = recvfrom(sock,buffer,2048,0,NULL,NULL)== -1) {
    perror("recvfrom");
     close(sock);
            exit(1);
} 
 
// n = recv(sock,buffer,2048,0);
    ethhead = buffer;
    if (ethhead != NULL)
              {
     
    printf("Source MAC address: "
           "%02x:%02x:%02x:%02x:%02x:%02x\n",
           ethhead[0],ethhead[1],ethhead[2],
           ethhead[3],ethhead[4],ethhead[5]);
    printf("Destination MAC address: "
           "%02x:%02x:%02x:%02x:%02x:%02x\n",
           ethhead[6],ethhead[7],ethhead[8],
           ethhead[9],ethhead[10],ethhead[11]);  
              }
       iphead = buffer+14; /* Skip Ethernet header */
    if (*iphead==0x45) { /* Double check for IPv4 
                          * and no options present */
      printf("Source host %d.%d.%d.%d\n",
             iphead[12],iphead[13],
             iphead[14],iphead[15]);
      printf("Dest host %d.%d.%d.%d\n",
             iphead[16],iphead[17],
             iphead[18],iphead[19]);
      printf("Source,Dest ports %d,%d\n",
             (iphead[20]<<8)+iphead[21],
             (iphead[22]<<8)+iphead[23]);
      printf("Layer-4 protocol %d\n",iphead[9]);
    }
 }    
 return 0;
}


int main(int argc, char **argv) 
{
    // cc=argv[1];
    _get_MAC(argv[1],argv[2]);
      return 0;
}
as your possible reference ...
hope it helps you in some way ...


.
 
1 members found this post helpful.
Old 04-12-2006, 04:09 AM   #4
nx5000
Senior Member
 
Registered: Sep 2005
Location: Out
Posts: 3,307

Rep: Reputation: 52
Here's an algorithm, not requiring SOCK_RAW (SOCK_RAW is possible only as root)
http://www.linuxquestions.org/questi...47#post2094647
 
Old 04-14-2006, 02:17 PM   #5
eljofi
LQ Newbie
 
Registered: Apr 2006
Posts: 5

Original Poster
Rep: Reputation: 1
Thanks nx5000,
I took a look at that solution and looks great in case I cannot run the tool as root.

Regards,
Jorge
 
Old 04-14-2006, 02:28 PM   #6
eljofi
LQ Newbie
 
Registered: Apr 2006
Posts: 5

Original Poster
Rep: Reputation: 1
Thanks a lot alred,
I used the code you sent me and worked great. It had a lot of not-needed code. So here it is without the extra code, for future references.

Code:
#include <iostream>
#include <stdio.h>
#include <netdb.h>
#include <netinet/if_ether.h>

int _get_MAC(void) {
	int sock,sockfd, n, cnt;
	char buffer[2048];
	unsigned char *iphead, *ethhead;
	struct ether_addr ether;
  
	if ( (sock=socket(PF_PACKET, SOCK_RAW,htons(ETH_P_IP)))<0){
		perror("socket");
		exit(1);
	}

	while (1) {
		if (n = recvfrom(sock,buffer,2048,0,NULL,NULL)== -1) {
			perror("recvfrom");
			close(sock);
			exit(1);
		} 
	
		ethhead = (unsigned char *)buffer;
		
		if (ethhead != NULL){
			iphead = (unsigned char *)(buffer+14); // Skip Ethernet header
			printf("\n--------------------------------------"
				"\nMAC destino (server): "
				"%02x:%02x:%02x:%02x:%02x:%02x\n",
				ethhead[0],ethhead[1],ethhead[2],
				ethhead[3],ethhead[4],ethhead[5]);
			printf("MAC origen  (CAL30x): "
				"%02x:%02x:%02x:%02x:%02x:%02x\n",
				ethhead[6],ethhead[7],ethhead[8],
				ethhead[9],ethhead[10],ethhead[11]);  

			if (*iphead==0x45) { // Double check for IPv4 and no options present
				printf("IP destino  (server): %d.%d.%d.%d\n",
					iphead[12],iphead[13],
					iphead[14],iphead[15]);
				printf("IP origen   (CAL30x): %d.%d.%d.%d\n",
					iphead[16],iphead[17],
					iphead[18],iphead[19]);
				printf("Protocolo   (UDP=11): %02x Hex\n",iphead[9]);
			}
		}    
	}
	return 0;
}


int main(int argc, char **argv) 
{
    _get_MAC();
      return 0;
}
Regards,
Jorge

Last edited by eljofi; 04-14-2006 at 02:29 PM.
 
1 members found this post helpful.
Old 03-09-2009, 04:15 PM   #7
foxed
LQ Newbie
 
Registered: Mar 2009
Posts: 1

Rep: Reputation: 0
hi!
can someone help me to transform the sniffer code of eljofi, with the promiscuous mode?
i try but not work properly.
thank you in advance
 
Old 01-24-2010, 02:27 AM   #8
DaveQB
Member
 
Registered: Oct 2003
Location: Sydney, Australia.
Distribution: PCLinuxOS 2010.12, Debian Lenny
Posts: 387

Rep: Reputation: 38
http://www.daniweb.com/forums/thread196899.html

For anyone looking into using this.


Quote:
The cstdlib header contains the definition for the exit function as csurfer said, however up until recently this header was generally included by dependency - often unnecessarily - by other headers. So you are likely to see tutorials and books that rely on this - and other - header dependencies that have now been cleaned up.

For example you may just #include <iostream> to use the exit function in gcc 3.4 because iostream includes cstdlib however in gcc 4.3 this dependency has been removed so you need to #include <cstdlib> to utilise it.
 
Old 10-09-2013, 06:47 AM   #9
Jürgen Lambrecht
LQ Newbie
 
Registered: Mar 2011
Location: Belgium
Distribution: LMDE
Posts: 3

Rep: Reputation: 0
correction

The IP dst and src are mixed.
I also don't see the point in checking ethhead; it is from a static buffer; better check number of received bytes.
I fixed it, see below.

Mark that this shows the MAC source and destination addresses from the received packet. The destination address should be from the device were this program is running.
But if you need the MAC address of your device, use ioctl( s, SIOCGIFHWADDR, &ifr ) instead as pointed out in another reply.

Regards,
Juergen

Quote:
Originally Posted by eljofi View Post
Thanks a lot alred,
I used the code you sent me and worked great. It had a lot of not-needed code. So here it is without the extra code, for future references.

Code:
#include <iostream>
#include <stdio.h>
#include <netdb.h>
#include <netinet/if_ether.h>

int _get_MAC(void) {
	int sock,sockfd, n, cnt;
	char buffer[2048];
	unsigned char *iphead, *ethhead;
	struct ether_addr ether;
  
	if ( (sock=socket(PF_PACKET, SOCK_RAW,htons(ETH_P_IP)))<0){
		perror("socket");
		exit(1);
	}

	while (1) {
		if (n = recvfrom(sock,buffer,2048,0,NULL,NULL)== -1) {
			perror("recvfrom");
			close(sock);
			exit(1);
		} 
	
		ethhead = (unsigned char *)buffer;
		
		if (n>34){ //#bytes returned; -1 if error; 14(mac)+20(ip)+1data byte
			iphead = (unsigned char *)(buffer+14); // Skip Ethernet header
			printf("\n--------------------------------------"
				"\nMAC dst: "
				"%02x:%02x:%02x:%02x:%02x:%02x\n",
				ethhead[0],ethhead[1],ethhead[2],
				ethhead[3],ethhead[4],ethhead[5]);
			printf("MAC src: "
				"%02x:%02x:%02x:%02x:%02x:%02x\n",
				ethhead[6],ethhead[7],ethhead[8],
				ethhead[9],ethhead[10],ethhead[11]);  

			if (*iphead==0x45) { // Double check for IPv4 and no options present
				printf("IP src: %d.%d.%d.%d\n",
					iphead[12],iphead[13],
					iphead[14],iphead[15]);
				printf("IP dst: %d.%d.%d.%d\n",
					iphead[16],iphead[17],
					iphead[18],iphead[19]);
				printf("Protocolo   (UDP=11): %02x Hex\n",iphead[9]);
			}
		}    
	}
	return 0;
}


int main(int argc, char **argv) 
{
    _get_MAC();
      return 0;
}
Regards,
Jorge

Last edited by Jürgen Lambrecht; 10-09-2013 at 07:03 AM. Reason: add extra info
 
Old 10-13-2013, 02:21 AM   #10
AnanthaP
Member
 
Registered: Jul 2004
Location: Chennai, India
Distribution: UBUNTU 5.10 since Jul-18,2006 on Intel 820 DC
Posts: 606

Rep: Reputation: 127Reputation: 127
For the more curious, here is one link to the entire format.

http://en.wikipedia.org/wiki/Ethernet_frame

OK
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
changing ethernet mac address and retaining the same after reboot guy24x Linux - Hardware 3 02-06-2009 06:51 AM
Possible to change ethernet MAC address using kernel parameters? rollo Linux - Networking 2 02-23-2006 05:16 PM
How to find an IP address from the MAC address of a remote machine ? jitz Linux - General 3 01-03-2006 07:55 AM
how to get ip address, broadcast address, mac address of a machine sumeshstar Programming 2 03-12-2005 04:33 AM
DHCP Server MAC Address found, IP address not assigned wmburke Linux - Wireless Networking 17 11-17-2004 10:33 AM


All times are GMT -5. The time now is 05:18 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration