Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Receive raw Ethernet frames in Linux
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define DEST_MAC0 0x00
#define DEST_MAC1 0x00
#define DEST_MAC2 0x00
#define DEST_MAC3 0x00
#define DEST_MAC4 0x00
#define DEST_MAC5 0x00
#define ETHER_TYPE 0x0800
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
char sender[INET6_ADDRSTRLEN];
int sockfd, ret, i;
int sockopt;
ssize_t numbytes;
struct ifreq ifopts; /* set promiscuous mode */
struct ifreq if_ip; /* get ip addr */
struct sockaddr_storage their_addr;
uint8_t buf[BUF_SIZ];
char ifName[IFNAMSIZ];
/* Get interface name */
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Header structures */
struct ether_header *eh = (struct ether_header *) buf;
struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct iphdr) + sizeof(struct ether_header));
memset(&if_ip, 0, sizeof(struct ifreq));
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
perror("listener: socket");
return -1;
}
/* Set interface to promiscuous mode - do we need to do this every time? */
strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
/* Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(sockfd);
exit(EXIT_FAILURE);
}
/* Bind to device */
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(sockfd);
exit(EXIT_FAILURE);
}
repeat: printf("listener: Waiting to recvfrom...\n");
numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
printf("listener: got packet %lu bytes\n", numbytes);
/* Check the packet is for me */
if (eh->ether_dhost[0] == DEST_MAC0 &&
eh->ether_dhost[1] == DEST_MAC1 &&
eh->ether_dhost[2] == DEST_MAC2 &&
eh->ether_dhost[3] == DEST_MAC3 &&
eh->ether_dhost[4] == DEST_MAC4 &&
eh->ether_dhost[5] == DEST_MAC5) {
printf("Correct destination MAC address\n");
} else {
printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
eh->ether_dhost[0],
eh->ether_dhost[1],
eh->ether_dhost[2],
eh->ether_dhost[3],
eh->ether_dhost[4],
eh->ether_dhost[5]);
ret = -1;
goto done;
}
/* Get source IP */
((struct sockaddr_in *)&their_addr)->sin_addr.s_addr = iph->saddr;
inet_ntop(AF_INET, &((struct sockaddr_in*)&their_addr)->sin_addr, sender, sizeof sender);
/* Look up my device IP addr if possible */
strncpy(if_ip.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFADDR, &if_ip) >= 0) { /* if we can't check then don't */
printf("Source IP: %s\n My IP: %s\n", sender,
inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
/* ignore if I sent it */
if (strcmp(sender, inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)) == 0) {
printf("but I sent it :(\n");
ret = -1;
goto done;
}
}
/* UDP payload length */
ret = ntohs(udph->len) - sizeof(struct udphdr);
/* Print packet */
printf("\tData:");
for (i=0; i<numbytes; i++) printf("%02x:", buf[i]);
printf("\n");
done: goto repeat;
close(sockfd);
return ret;
}
@ashmew2

This comment has been minimized.

Copy link

commented Dec 28, 2014

Thanks for this receiver!

Really helps with receiving raw frames with the sender program on the other end.

@ant-fx

This comment has been minimized.

Copy link

commented Jan 14, 2015

thanks for this, great starting point!

@codergr

This comment has been minimized.

Copy link

commented Apr 25, 2015

Thanks for sharing.

@workerNumber88

This comment has been minimized.

Copy link

commented Oct 20, 2015

Thanks for the software. This really helped to get input from the eth0 to my c program quick.

@rskrda

This comment has been minimized.

Copy link

commented Jun 16, 2016

perhaps #include <unistd.h> is missing as a compiler warning for implicit close definition occurs.

i've expanded this code significantly and joined it with the send example to relay packets. i'm adding thread support next for two-way relaying or a handy bridge.

one bug i've run into is that the kernel seems to re-assmble the TCP segments into large packets (>1500 bytes) requiring jumbo frames on the tx side. any comments on addressing this is appreciated.

@nnovzver

This comment has been minimized.

Copy link

commented Jul 8, 2016

Label "done" should be on a next line.

@abrodkin

This comment has been minimized.

Copy link

commented Jul 26, 2016

Nice example.
I updated it a little-bit with addition of ability to set DST MAC in command line like ./sendRawEth enp0s29u1u1u2 2E:58:2F:73:73:40
If of any interest please find it here https://gist.github.com/abrodkin/8854874f3b34e92f71653a7fa35c9900

@Dambe

This comment has been minimized.

Copy link

commented Jan 3, 2017

Suggesting to use
#define ETHER_TYPE ETHERTYPE_IP
instead of
#define ETHER_TYPE 0x0800
ETHERTYPE_IP is already defined when including netinet/ether.h

@CurlyMoo

This comment has been minimized.

Copy link

commented Jun 18, 2017

You should set sockopt to 1 because at this moment it is undefined if SO_REUSEADDR is set or not.

@marian-pritsak

This comment has been minimized.

Copy link

commented Mar 19, 2018

SO_BINDTODEVICE works only with AF_INET

@AdrianTay

This comment has been minimized.

Copy link

commented May 2, 2018

HI. I am getting an error of "SO_BINDTODEVICE : NO SUCH DEVICE". Would deeply appreciate if I can get help from anybody here. I had tried googling the error but i still cant find a prominent solution.

@csBlueChip

This comment has been minimized.

Copy link

commented May 24, 2018

Thanks.
PS. I think your "done:" label is on the wrong line ;)

@sundeep95

This comment has been minimized.

Copy link

commented Sep 9, 2018

Can you please explain how to run these codes on both sender and receiver end using wlan0?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.