LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Getting MAC address from Ethernet packet in C++ (https://www.linuxquestions.org/questions/programming-9/getting-mac-address-from-ethernet-packet-in-c-434241/)

eljofi 04-11-2006 05:32 PM

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

leadazide 04-11-2006 06:07 PM

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/.

alred 04-12-2006 02:54 AM

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 ...


.

nx5000 04-12-2006 04:09 AM

Here's an algorithm, not requiring SOCK_RAW (SOCK_RAW is possible only as root)
http://www.linuxquestions.org/questi...47#post2094647

eljofi 04-14-2006 02:17 PM

Thanks nx5000,
I took a look at that solution and looks great in case I cannot run the tool as root.

Regards,
Jorge

eljofi 04-14-2006 02:28 PM

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

foxed 03-09-2009 04:15 PM

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 ;)

DaveQB 01-24-2010 02:27 AM

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.

Jürgen Lambrecht 10-09-2013 06:47 AM

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 (Post 2199935)
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


AnanthaP 10-13-2013 02:21 AM

For the more curious, here is one link to the entire format.

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

OK


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