ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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.
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/.
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 ...
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;
}
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.
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
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
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.