c raw sockets and 64 bit issue - c

I'm still struggling to get my sample code working on a 64 bit machine. My previous problem was solved because of missing/outdated headers/libraries.
I compile this code as follow: gcc -Wall -g -o server server.c and gcc -Wall -g -o client client.c
I run them on 2 linux machines(both 32bit) and it works fine. When I recompile this code on 64 bit machines then it seems that no packets go through from the client to the server. Putting tcpdump on the client it seems that it is sending malformed headers that gets rejected all the time. Can anybody enlighten me?
#include "client.h"
#include "util.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <asm/types.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#define BUF_SIZE ETH_FRAME_TOTALLEN
#define NUMBER_OF_MESUREMENTS_PER_AMOUNT_OF_DATA 100000 /*how often to measure travelling time with one certain amount of data*/
int s = 0; /*Socketdescriptor*/
void* buffer = NULL;
long total_sent_packets = 0;
int main(int argc, char* argv[])
{
buffer = (void*)malloc(BUF_SIZE); /*Buffer for ethernet frame*/
unsigned char* etherhead = buffer; /*Pointer to ethenet header*/
unsigned char* data = buffer + 14; /*Userdata in ethernet frame*/
struct ethhdr *eh = (struct ethhdr *)etherhead; /*Another pointer to ethernet header*/
unsigned char src_mac[6]; /*our MAC address */
unsigned char dest_mac[6] = {0x00, 0x1E, 0x4F, 0xB1, 0xCB, 0x43}; /*MAC address, hardcoded...... :-(*/
struct ifreq ifr;
struct sockaddr_ll socket_address;
int ifindex = 0; /*Ethernet Interface index*/
int i,j,k;
int length; /*length of received packet*/
int sent; /*length of sent packet*/
/*stuff for time measuring: */
struct timeval begin;
struct timeval end;
struct timeval result;
unsigned long long allovertime;
printf("Client started, entering initialiation phase...\n");
/*open socket*/
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s == -1) {
perror("socket():");
exit(1);
}
printf("Successfully opened socket: %i\n", s);
/*retrieve ethernet interface index*/
strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
ifindex = ifr.ifr_ifindex;
printf("Successfully got interface index: %i\n", ifindex);
/*retrieve corresponding MAC*/
if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
for (i = 0; i < 6; i++) {
src_mac[i] = ifr.ifr_hwaddr.sa_data[i];
}
printf("Successfully got our MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);
/*prepare sockaddr_ll*/
socket_address.sll_family = PF_PACKET;
socket_address.sll_protocol = htons(ETH_P_IP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = ARPHRD_ETHER;
socket_address.sll_pkttype = PACKET_OTHERHOST;
socket_address.sll_halen = ETH_ALEN;
socket_address.sll_addr[0] = dest_mac[0];
socket_address.sll_addr[1] = dest_mac[1];
socket_address.sll_addr[2] = dest_mac[2];
socket_address.sll_addr[3] = dest_mac[3];
socket_address.sll_addr[4] = dest_mac[4];
socket_address.sll_addr[5] = dest_mac[5];
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
/*establish signal handler*/
signal(SIGINT, sigint);
printf("Successfully established signal handler for SIGINT\n");
/*init random number generator*/
srand(time(NULL));
printf("We are in production state, sending packets to: %02X:%02X:%02X:%02X:%02X:%02X\n",
dest_mac[0],dest_mac[1],dest_mac[2],dest_mac[3],dest_mac[4],dest_mac[5]);
for (i = 50; i <= 1500; i += 50) {
allovertime = 0;
for (k = 0; k < NUMBER_OF_MESUREMENTS_PER_AMOUNT_OF_DATA; k++) {
/*prepare buffer*/
memcpy((void*)buffer, (void*)dest_mac, ETH_MAC_LEN);
memcpy((void*)(buffer+ETH_MAC_LEN), (void*)src_mac, ETH_MAC_LEN);
eh->h_proto = ETH_P_NULL;
/*fill it with random data....*/
for (j = 0; j < i; j++) {
data[j] = (unsigned char)((int) (256.0*rand()/(RAND_MAX+1.0)));
}
/*clear the timers:*/
timerclear(&begin);
timerclear(&end);
/*get time before sending.....*/
gettimeofday(&begin,NULL);
/*send packet*/
sent = sendto(s, buffer, i+ETH_HEADER_LEN, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
if (sent == -1) {
perror("sendto():");
exit(1);
}
/*Wait for incoming packet...*/
length = recvfrom(s, buffer, BUF_SIZE, 0, NULL, NULL);
if (length == -1) {
perror("recvfrom():");
exit(1);
}
/*get time after sending.....*/
gettimeofday(&end,NULL);
/*...and calculate difference.........*/
timersub(&end,&begin,&result);
allovertime += ((result.tv_sec * 1000000 ) + result.tv_usec );
total_sent_packets++;
}
printf("Sending %i bytes takes %lld microseconds in average\n",i ,allovertime/NUMBER_OF_MESUREMENTS_PER_AMOUNT_OF_DATA);
}
return (0);
}
void sigint(int signum) {
/*Clean up.......*/
struct ifreq ifr;
if (s == -1)
return;
strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
ioctl(s, SIOCGIFFLAGS, &ifr);
ifr.ifr_flags &= ~IFF_PROMISC;
ioctl(s, SIOCSIFFLAGS, &ifr);
close(s);
free(buffer);
printf("Client terminating....\n");
printf("Totally sent: %ld packets\n", total_sent_packets);
exit(0);
}
------------------server.c---------------------
#include "server.h"
#include "util.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <asm/types.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#define BUF_SIZE ETH_FRAME_TOTALLEN
int s = 0; /*Socketdescriptor*/
void* buffer = NULL;
long total_packets = 0;
long answered_packets = 0;
int main(int argc, char* argv[])
{
buffer = (void*)malloc(BUF_SIZE); /*Buffer for Ethernet Frame*/
unsigned char* etherhead = buffer; /*Pointer to Ethenet Header*/
struct ethhdr *eh = (struct ethhdr *)etherhead; /*Another pointer to ethernet header*/
unsigned char src_mac[6]; /*our MAC address*/
struct ifreq ifr;
struct sockaddr_ll socket_address;
int ifindex = 0; /*Ethernet Interface index*/
int i;
int length; /*length of received packet*/
int sent;
printf("Server started, entering initialiation phase...\n");
/*open socket*/
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s == -1) {
perror("socket():");
exit(1);
}
printf("Successfully opened socket: %i\n", s);
/*retrieve ethernet interface index*/
strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
ifindex = ifr.ifr_ifindex;
printf("Successfully got interface index: %i\n", ifindex);
/*retrieve corresponding MAC*/
if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
for (i = 0; i < 6; i++) {
src_mac[i] = ifr.ifr_hwaddr.sa_data[i];
}
printf("Successfully got our MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);
/*prepare sockaddr_ll*/
socket_address.sll_family = PF_PACKET;
socket_address.sll_protocol = htons(ETH_P_IP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = ARPHRD_ETHER;
socket_address.sll_pkttype = PACKET_OTHERHOST;
socket_address.sll_halen = ETH_ALEN;
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
/*establish signal handler (keyboard)*/
signal(SIGINT, sigint);
printf("Successfully established signal handler for SIGINT\n");
printf("We are in production state, waiting for incoming packets....\n");
while (1) {
/*Wait for incoming packet...*/
length = recvfrom(s, buffer, BUF_SIZE, 0, NULL, NULL);
if (length == -1) {
perror("recvfrom():");
exit(1);
}
/*See if we should answer (Ethertype == 0x0 && destination address == our MAC)*/
if (eh->h_proto == ETH_P_NULL && memcmp( (const void*)eh->h_dest, (const void*)src_mac, ETH_MAC_LEN) == 1 )
{
/*exchange addresses in buffer*/
memcpy( (void*)etherhead, (const void*)(etherhead+ETH_MAC_LEN), ETH_MAC_LEN);
memcpy( (void*)(etherhead+ETH_MAC_LEN), (const void*)src_mac, ETH_MAC_LEN);
/*prepare sockaddr_ll*/
socket_address.sll_addr[0] = eh->h_dest[0];
socket_address.sll_addr[1] = eh->h_dest[1];
socket_address.sll_addr[2] = eh->h_dest[2];
socket_address.sll_addr[3] = eh->h_dest[3];
socket_address.sll_addr[4] = eh->h_dest[4];
socket_address.sll_addr[5] = eh->h_dest[5];
/*send answer*/
sent = sendto(s, buffer, length-4, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
if (sent == -1) {
perror("sendto():");
exit(1);
}
answered_packets++;
}
total_packets++;
}
}
void sigint(int signum) {
/*Clean up.......*/
struct ifreq ifr;
if (s == -1)
return;
strncpy(ifr.ifr_name, ETH0, IFNAMSIZ);
ioctl(s, SIOCGIFFLAGS, &ifr);
ifr.ifr_flags &= ~IFF_PROMISC;
ioctl(s, SIOCSIFFLAGS, &ifr);
close(s);
free(buffer);
printf("Server terminating....\n");
printf("Totally received: %ld packets\n", total_packets);
printf("Answered %ld packets\n", answered_packets);
exit(0);
}

Sorry for all the code, but I didn't know how to make it shorter as i wasn't sure where the error was. Anyway, I found the problem, so apologies for the "wall of code" guys!
It turns out the problem was how our switches are configured. After I got 2 machines on the same subnet the code worked beautiful!

Related

Linux: receive data from Bluetooth LE

I want send/receive data to microcontroller using Bluetooth LE.
I have been trying to use socket using BTPROTO_HCI protocol
sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)
addr.hci_family = AF_BLUETOOTH;
hci_dev = hci_devid( "XX:XX:XX:XX:XX:XX" ); // Replace with actual MAC of device
bind(sock, (struct sockaddr *)&addr, sizeof(addr)
and for receiving data I am doing
recvmsg(sock, &msg, 0))
but I can't received msg.
In Android there is Serial Bluetooth Terminal which can connect to Bluetooth LE device and send/receive data over Bluetooth LE. In this application I am receiving data from microcontroller.
Code
#include <sys/types.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
struct dump_hdr
{
__u16 len;
__u8 in;
__u8 pad;
__u32 ts_sec;
__u32 ts_usec;
} __attribute__ ((packed));
#define DUMP_HDR_SIZE (sizeof(struct dump_hdr))
struct frame
{
void *data;
int data_len;
void *ptr;
int len;
int in;
int handle;
long flags;
struct timeval ts;
};
int main(void)
{
printf("Starting...");
struct sockaddr_hci addr;
struct hci_filter filter;
int sock, one = 1;
char packet[HCI_MAX_FRAME_SIZE];
struct cmsghdr *cmsg;
struct msghdr msg;
struct iovec iv;
struct dump_hdr *dh;
struct frame frm;
char *buf, *ctrl;
if((sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
{
perror("socket");
exit(1);
}
if(setsockopt(sock, SOL_HCI, HCI_DATA_DIR, &one, sizeof(one)) < 0)
{
perror("Can't enable data direction info");
exit(1);
}
if(setsockopt(sock, SOL_HCI, HCI_TIME_STAMP, &one, sizeof(one)) < 0)
{
perror("Can't enable time stamp");
exit(1);
}
hci_filter_clear(&filter);
hci_filter_all_ptypes(&filter);
hci_filter_all_events(&filter);
if(setsockopt(sock, SOL_HCI, HCI_FILTER, &filter, sizeof(filter)) < 0)
{
perror("Can't set HCI filter");
exit(1);
}
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = hci_devid( "XX:XX:XX:XX:XX:XX" );//eplace with actual MAC of device
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(1);
}
if (!(buf = malloc(DUMP_HDR_SIZE)))
{
perror("Can't allocate data buffer");
exit(1);
}
dh = (void *) buf;
frm.data = buf + DUMP_HDR_SIZE;
if (!(ctrl = malloc(100)))
{
perror("Can't allocate control buffer");
exit(1);
}
memset(&msg, 0, sizeof(msg));
while (1)
{
printf(".");
iv.iov_base = frm.data;
iv.iov_len = sizeof(frm.data);//snap_len;
msg.msg_iov = &iv;
msg.msg_iovlen = 1;
msg.msg_control = ctrl;
msg.msg_controllen = 100;
if ((frm.data_len = recvmsg(sock, &msg, 0)) < 0)
{
perror("Receive failed");
exit(1);
}
/* Process control message */
frm.in = 0;
cmsg = CMSG_FIRSTHDR(&msg);
while (cmsg)
{
printf("%s\r\n", cmsg);
switch (cmsg->cmsg_type)
{
case HCI_CMSG_DIR:
frm.in = *((int *)CMSG_DATA(cmsg));
break;
case HCI_CMSG_TSTAMP:
frm.ts = *((struct timeval *)CMSG_DATA(cmsg));
break;
}
cmsg = CMSG_NXTHDR(&msg, cmsg);
}
frm.ptr = frm.data;
frm.len = frm.data_len;
/* Parse and print */
hci_dump(&frm);
}
close(sock);
return 0;
}
void hci_dump(struct frame *frm)
{
__u8 type = *(__u8 *)frm->ptr;
frm->ptr++; frm->len--;
if(type == HCI_ACLDATA_PKT)
{
hci_acl_hdr *hdr = (void *) frm->ptr;
__u16 handle = btohs(hdr->handle);
__u16 dlen = btohs(hdr->dlen);
__u8 flags = acl_flags(handle);
printf("ACL data: handle 0x%4.4x flags 0x%2.2x dlen %d\n",
acl_handle(handle), flags, dlen);
}
}
You need to use the result of hci_devid.
hci_dev = hci_devid( "XX:XX:XX:XX:XX:XX" );
should become
addr.hci_dev = hci_devid( "XX:XX:XX:XX:XX:XX" );
Although I wouldn't expect hci_dev to be defined in the current scope as a separate variable.

Custom IP header for ICMP packet not working

I'm trying to make an ICMP packet with a custom IP header.
When I disable IP_HDRINCL to use the default IP header and cut out all the IP header related code, it works (I checked the checksums of the code below and the code that works with default headers, the ICMP packet is definitely valid in the code below).
The issue arrives when trying to use my own IP header, I don't receive any ICMP packets, indicating the packet didn't properly transmit or something went wrong.
I'm on Ubuntu 16.04 and compiling with GCC with the flags -std=c11 -Wall -Wextra -pedantic
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#define PACKETSIZE 256
// Packet struct
struct packet {
struct iphdr ip; // IP Header
struct icmphdr hdr; // ICMP Header
char msg[PACKETSIZE - sizeof(struct icmphdr) - sizeof(struct iphdr)]; // Message
};
// Checksum function
unsigned short checksum(void *b, int len) {
unsigned short *buf = b;
unsigned int sum = 0;
unsigned short result;
for (sum = 0; len > 1; len -= 2) {
sum += *buf++;
}
if (len == 1) sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
int main(int argc, char* argv[])
{
// Enough arguments
if (argc < 2) {
printf("usage: ./tracert <server>\n");
return EXIT_FAILURE;
}
// Variables
struct hostent *hname;
struct sockaddr_in addr;
unsigned int i;
int sockfd, seq = 1;
struct packet pckt;
socklen_t len;
char buf[1024];
// Get host from domain
hname = gethostbyname(argv[1]);
memset(&addr, 0, sizeof(addr));
addr.sin_family = hname->h_addrtype;
addr.sin_port = htons(6969);
addr.sin_addr.s_addr = *(long *)hname->h_addr_list[0];
// Create ICMP RAW socket
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0) {
printf("error on socket creation\n");
return EXIT_FAILURE;;
}
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &seq, sizeof(seq)) < 0) {
printf("error on default ip header settings\n");
return EXIT_FAILURE;
}
// Loop and receive/send packets
while (1) {
// Make packet
memset(&pckt, 0, sizeof(pckt));
// IP Header
pckt.ip.version = 4;
pckt.ip.ihl = 5;
pckt.ip.tot_len = htons(sizeof(pckt));
pckt.ip.ttl = 255;
pckt.ip.protocol = IPPROTO_ICMP;
pckt.ip.saddr = inet_addr("192.168.1.1");
pckt.ip.daddr = addr.sin_addr.s_addr;
pckt.ip.check = checksum(&pckt, sizeof(struct iphdr));
// ICMP Header
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = 0;
for (i = 0; i < sizeof(pckt.msg) - 1; i++) {
pckt.msg[i] = i+'0';
}
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = seq;
pckt.hdr.checksum = checksum(&pckt.hdr, sizeof(struct icmphdr) + sizeof(pckt.msg));
// Send packet
if (sendto(sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&addr, sizeof(addr)) <= 0) {
printf("error on sending packet\n");
return EXIT_FAILURE;
}
// Receive packet
len = sizeof(addr);
memset(buf, 0, sizeof(buf));
if (recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len) > 0) {
printf("packet received\n");
// Do more stuff here later...
}
// The while is there for later, for now I just want to send one packet
return EXIT_SUCCESS;
}
close(sockfd);
return EXIT_SUCCESS;
}

How to listen to IGMPv3 frames

I need to get IGMPv3 Frames for this I'm using a socket like following:
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
the problem is that my program is filtring IGMPv3 Frames, i don't know why !! I don't get IGMP frames although I'm getting them when using wireshark. I tried also to use :
sockfd = socket(PF_PACKET, SOCK_RAW, htons(0x0800));
but I was capable of getting only ICMP frames and not IGMP ones.
PS: I tried my program on another machine and it worked, so I think the problem is with my kernel, does anyone know if there is any configuration to do with the socket ?
Here is the whole code:
#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>
#include <unistd.h>
#define DEST_MAC0 0x01
#define DEST_MAC1 0x00
#define DEST_MAC2 0x5e
#define DEST_MAC3 0x00
#define DEST_MAC4 0x00
#define DEST_MAC5 0x16
#define ETHER_TYPE 0x0800
#define DEFAULT_IF "eth1"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
char sender[INET6_ADDRSTRLEN];
int sockfd, ret, i, counter;
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;
// }
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE));
if (sockfd == -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 Frame = {",(unsigned long int) numbytes);
for( counter = 0; counter < numbytes; counter++)
printf( "%02X ", buf[counter]);
printf( "}");
/* 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;
}
Please note that the address mac that I'm initializing is the address that I get from IGMP frame on wireshark. this code actually allows me to detect only ICMP frames.
When using:
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
instead of:
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE);
I don't get nothing !
On wireshark I'm getting all the frames that I want including IGMP and ICMP!!

compressing multicast packets with zlib library

I am listening packets from a multicast ip port and trying to compress that packet using zlib library, ( want to know the compression ratio from zlib in the live packets, as this is the requirement from our client). I have implemented zlib compression code as below, but length of outputDataBuffer is not printing correct, I dont know what I am missing.
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <zlib.h>
using namespace std;
struct sockaddr_in localSock;
struct ip_mreq group;
int maxpacketsize = 1500;
void connectSocket(int &sd,char *multicastIP,int multicastPort,char *interfaceIP);
void listenSocket(int &sd,const short &structureSize,const short &compressionType);
void compressZlib(char *inputDataBuffer,int inputDataLength,z_stream &defstream)
int main(int argc, char *argv[])
{
int sd = 0;
char multicastIP[16]="230.0.0.50";
char interfaceIP[16]="192.168.225.132";
int multicastPort = 13551;
short structureSize = 0;
connectSocket(sd,multicastIP,multicastPort,interfaceIP);
listenSocket(sd,structureSize);
return 0;
}
void connectSocket(int &sd,char *multicastIP,int multicastPort,char *interfaceIP)
{
int reuse = 1;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
printf("Opening datagram socket....OK.\n");
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
printf("Setting SO_REUSEADDR...OK.\n");
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(multicastPort);
localSock.sin_addr.s_addr = INADDR_ANY;
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(sd);
exit(1);
}
printf("Binding datagram socket...OK.\n");
group.imr_multiaddr.s_addr = inet_addr(multicastIP);
group.imr_interface.s_addr = inet_addr(interfaceIP);
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(sd);
exit(1);
}
printf("Adding multicast group...OK.\n");
}
void compressZlib(char *inputDataBuffer,int inputDataLength,z_stream &defstream)
{
char *outputDataBuffer = new char[inputDataLength];
memset(outputDataBuffer,0,inputDataLength);
defstream.avail_in = (uInt)strlen(inputDataBuffer)+1;
defstream.next_in = (Bytef *)inputDataBuffer;
defstream.avail_out = (uInt)sizeof(outputDataBuffer);
defstream.next_out = (Bytef *)outputDataBuffer;
if(deflate(&defstream, Z_FINISH) != Z_OK )
{
cout<<"Error"<<endl;
}
//printf("%lu %lu\n", inputDataLength,defstream.total_in);
printf("%lu %lu\n", inputDataLength,strlen(outputDataBuffer));
}
void listenSocket(int &sd,const short &structureSize)
{
char databuf[5000] = "";
int receivedBytes = 0;
z_stream defstream;
defstream.zalloc = Z_NULL ;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
deflateInit(&defstream, Z_FULL_FLUSH);
while(1)
{
int socklen = sizeof(struct sockaddr_in);
struct sockaddr_in saddr;
receivedBytes = recvfrom(sd, databuf, maxpacketsize, 0, (struct sockaddr *)&saddr, (socklen_t*)&socklen);
if(receivedBytes < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
compressZlib(databuf,receivedBytes,defstream);
//compressZlib(databuf1,strlen(databuf1));
//compressZlib();
//cout<<receivedBytes<<endl;
}
deflateEnd(&defstream);
}
I also used compress2() function which is as below:
compress2((unsigned char*)outputBuffer,&outputDataLength,(const unsigned char*)inputBuffer,(unsigned long)inputBufferLength,Z_DEFAULT_COMPRESSION);
but this is also not working, outputDataLength is 0 all the time.
Calling deflate() with Z_FINISH means that you are or have already fed deflate the last of the input data. deflate will then terminate the stream. Once it has been provided enough output space to write the last of the compressed data, which may very well be on the first such call, deflate() will return Z_STREAM_END, not Z_OK. Then the deflate() engine is done and can't be used again unless you do a deflateEnd() followed by a deflateInit(), or equivalently and faster, a deflateReset().
It would seem that what you are missing are the rewards that come from having read the documentation.

arp request and reply using c socket programming

I am trying to receive and send arp packets using c programming in Linux (Ubuntu)
My program works fine (i.e. runs without any error), but I cannot trace the packets using Wireshark.
source code:
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <asm/types.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#define BUF_SIZE 42
#define DEVICE "eth0"
#define ETH_P_NULL 0x0
#define ETH_MAC_LEN ETH_ALEN
#define ETH_ARP 0x0806
int s = 0; /*Socketdescriptor*/
void* buffer = NULL;
long total_packets = 0;
long answered_packets = 0;
void sigint(int signum);
struct __attribute__((packed)) arp_header
{
unsigned short arp_hd;
unsigned short arp_pr;
unsigned char arp_hdl;
unsigned char arp_prl;
unsigned short arp_op;
unsigned char arp_sha[6];
unsigned char arp_spa[4];
unsigned char arp_dha[6];
unsigned char arp_dpa[4];
};
int main(void) {
buffer = (void*)malloc(BUF_SIZE); /*Buffer for Ethernet Frame*/
unsigned char* etherhead = buffer; /*Pointer to Ethenet Header*/
struct ethhdr *eh = (struct ethhdr *)etherhead; /*Another pointer to
ethernet header*/
unsigned char* arphead = buffer + 14;
struct arp_header *ah;
unsigned char src_mac[6]; /*our MAC address*/
struct ifreq ifr;
struct sockaddr_ll socket_address;
int ifindex = 0; /*Ethernet Interface index*/
int i;
int length; /*length of received packet*/
int sent;
printf("Server started, entering initialiation phase...\n");
/*open socket*/
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s == -1) {
perror("socket():");
exit(1);
}
printf("Successfully opened socket: %i\n", s);
/*retrieve ethernet interface index*/
strncpy(ifr.ifr_name, DEVICE, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
ifindex = ifr.ifr_ifindex;
printf("Successfully got interface index: %i\n", ifindex);
/*retrieve corresponding MAC*/
if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
for (i = 0; i < 6; i++) {
src_mac[i] = ifr.ifr_hwaddr.sa_data[i];
}
printf("Successfully got our MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);
/*prepare sockaddr_ll*/
socket_address.sll_family = PF_PACKET;
socket_address.sll_protocol = htons(ETH_P_IP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = ARPHRD_ETHER;
socket_address.sll_pkttype = PACKET_OTHERHOST;
socket_address.sll_halen = 0;
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
/*establish signal handler*/
signal(SIGINT, sigint);
printf("Successfully established signal handler for SIGINT\n");
printf("We are in production state, waiting for incoming packets....\n");
while (1) {
/*Wait for incoming packet...*/
length = recvfrom(s, buffer, BUF_SIZE, 0, NULL, NULL);
if (length == -1)
{
perror("recvfrom():");
exit(1);
}
if(htons(eh->h_proto) == 0x806)
{
unsigned char buf_arp_dha[6];
unsigned char buf_arp_dpa[4];
ah = (struct arp_header *)arphead;
if(htons(ah->arp_op) != 0x0001)
continue;
printf("buffer is---------------- %s \n",(char*)ah);
printf("H/D TYPE : %x PROTO TYPE : %x \n",ah->arp_hd,ah->arp_pr);
printf("H/D leng : %x PROTO leng : %x \n",ah->arp_hdl,ah->arp_prl);
printf("OPERATION : %x \n", ah->arp_op);
printf("SENDER MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
ah->arp_sha[0],
ah->arp_sha[1],
ah->arp_sha[2],
ah->arp_sha[3],
ah->arp_sha[4],
ah->arp_sha[5]
);
printf("SENDER IP address: %02d:%02d:%02d:%02d\n",
ah->arp_spa[0],
ah->arp_spa[1],
ah->arp_spa[2],
ah->arp_spa[3]
);
if(ah->arp_spa[0]==10&&ah->arp_spa[1]==00&&ah->arp_spa[2]==00&&ah->arp_spa[3]==01)
{
printf("Sender ip is .............bam bam..........................................\n");
system("sudo arp -s 10.0.0.1 00:1e:73:91:04:0d");
}
printf("TARGET MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
ah->arp_dha[0],
ah->arp_dha[1],
ah->arp_dha[2],
ah->arp_dha[3],
ah->arp_dha[4],
ah->arp_dha[5]
);
printf("TARGET IP address: %02d:%02d:%02d:%02d\n",
ah->arp_dpa[0],
ah->arp_dpa[1],
ah->arp_dpa[2],
ah->arp_dpa[3]
);
printf("+++++++++++++++++++++++++++++++++++++++\n" );
printf("ETHER DST MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
eh->h_dest[0],
eh->h_dest[1],
eh->h_dest[2],
eh->h_dest[3],
eh->h_dest[4],
eh->h_dest[5]
);
printf("ETHER SRC MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
eh->h_source[0],
eh->h_source[1],
eh->h_source[2],
eh->h_source[3],
eh->h_source[4],
eh->h_source[5]
);
memcpy( (void*)etherhead, (const void*)(etherhead+ETH_MAC_LEN),
ETH_MAC_LEN);
memcpy( (void*)(etherhead+ETH_MAC_LEN), (const void*)src_mac,
ETH_MAC_LEN);
eh->h_proto = ETH_ARP;
printf("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& \n");
printf("ETHER DST MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
eh->h_dest[0],
eh->h_dest[1],
eh->h_dest[2],
eh->h_dest[3],
eh->h_dest[4],
eh->h_dest[5]
);
printf("ETHER SRC MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
eh->h_source[0],
eh->h_source[1],
eh->h_source[2],
eh->h_source[3],
eh->h_source[4],
eh->h_source[5]
);
ah->arp_hd = ntohs(ah->arp_hd);
ah->arp_pr = ntohs(ah->arp_pr);
ah->arp_op = 0x0002;
buf_arp_dpa[0] = ah->arp_dpa[0];
buf_arp_dpa[1] = ah->arp_dpa[1];
buf_arp_dpa[2] = ah->arp_dpa[2];
buf_arp_dpa[3] = ah->arp_dpa[3];
ah->arp_dha[0] = ah->arp_sha[0];
ah->arp_dha[1] = ah->arp_sha[1];
ah->arp_dha[2] = ah->arp_sha[2];
ah->arp_dha[3] = ah->arp_sha[3];
ah->arp_dha[4] = ah->arp_sha[4];
ah->arp_dha[5] = ah->arp_sha[5];
ah->arp_dpa[0] = ah->arp_spa[0];
ah->arp_dpa[1] = ah->arp_spa[1];
ah->arp_dpa[2] = ah->arp_spa[2];
ah->arp_dpa[3] = ah->arp_spa[3];
ah->arp_spa[0] = buf_arp_dpa[0];
ah->arp_spa[1] = buf_arp_dpa[1];
ah->arp_spa[2] = buf_arp_dpa[2];
ah->arp_spa[3] = buf_arp_dpa[3];
//change the sender mac address
ah->arp_sha[0] = 0x00;
ah->arp_sha[1] = 0x1e;
ah->arp_sha[2] = 0x73;
ah->arp_sha[3] = 0x78;
ah->arp_sha[4] = 0x9a;
ah->arp_sha[5] = 0x0d;
socket_address.sll_addr[0] = eh->h_dest[0];
socket_address.sll_addr[1] = eh->h_dest[1];
socket_address.sll_addr[2] = eh->h_dest[2];
socket_address.sll_addr[3] = eh->h_dest[3];
socket_address.sll_addr[4] = eh->h_dest[4];
socket_address.sll_addr[5] = eh->h_dest[5];
printf("=======================================\n" );
printf("SENDER MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
ah->arp_sha[0],
ah->arp_sha[1],
ah->arp_sha[2],
ah->arp_sha[3],
ah->arp_sha[4],
ah->arp_sha[5]
);
printf("SENDER IP address: %02d:%02d:%02d:%02d\n",
ah->arp_spa[0],
ah->arp_spa[1],
ah->arp_spa[2],
ah->arp_spa[3]
);
if((ah->arp_spa[0]==10 && ah->arp_spa[1]==0 && ah->arp_spa[2]==0 && ah->arp_spa[3]==1))
printf("------------------------------------------10.0.0.1-----------------------------------------\n");
printf("TARGET MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
ah->arp_dha[0],
ah->arp_dha[1],
ah->arp_dha[2],
ah->arp_dha[3],
ah->arp_dha[4],
ah->arp_dha[5]
);
printf("TARGET IP address: %02d:%02d:%02d:%02d\n",
ah->arp_dpa[0],
ah->arp_dpa[1],
ah->arp_dpa[2],
ah->arp_dpa[3]
);
printf("H/D TYPE : %x PROTO TYPE : %x \n",ah->arp_hd,ah->arp_pr);
printf("H/D leng : %x PROTO leng : %x \n",ah->arp_hdl,ah->arp_prl);
printf("OPERATION : %x \n", ah->arp_op);
sent = sendto(s, buffer, BUF_SIZE, 0, (struct
sockaddr*)&socket_address, sizeof(socket_address));
if (sent == -1)
{
perror("sendto():");
exit(1);
}
answered_packets++;
}
total_packets++;
}
}
void sigint(int signum) {
/*Clean up.......*/
struct ifreq ifr;
if (s == -1)
return;
strncpy(ifr.ifr_name, DEVICE, IFNAMSIZ);
ioctl(s, SIOCGIFFLAGS, &ifr);
ifr.ifr_flags &= ~IFF_PROMISC;
ioctl(s, SIOCSIFFLAGS, &ifr);
close(s);
free(buffer);
printf("Server terminating....\n");
printf("Totally received: %ld packets\n", total_packets);
printf("Answered %ld packets\n", answered_packets);
exit(0);
}
I took user6343961's code, did some cleaning and splicing and implemented support for automatically getting interface IP address.
Also the parameters come from CLI instead of hardcoding.
bind() is also used to get only ARP from the interface we want.
Have fun. This code works for me.
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <arpa/inet.h> //htons etc
#define PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define MAC_LENGTH 6
#define IPV4_LENGTH 4
#define ARP_REQUEST 0x01
#define ARP_REPLY 0x02
#define BUF_SIZE 60
#define debug(x...) printf(x);printf("\n");
#define info(x...) printf(x);printf("\n");
#define warn(x...) printf(x);printf("\n");
#define err(x...) printf(x);printf("\n");
struct arp_header {
unsigned short hardware_type;
unsigned short protocol_type;
unsigned char hardware_len;
unsigned char protocol_len;
unsigned short opcode;
unsigned char sender_mac[MAC_LENGTH];
unsigned char sender_ip[IPV4_LENGTH];
unsigned char target_mac[MAC_LENGTH];
unsigned char target_ip[IPV4_LENGTH];
};
/*
* Converts struct sockaddr with an IPv4 address to network byte order uin32_t.
* Returns 0 on success.
*/
int int_ip4(struct sockaddr *addr, uint32_t *ip)
{
if (addr->sa_family == AF_INET) {
struct sockaddr_in *i = (struct sockaddr_in *) addr;
*ip = i->sin_addr.s_addr;
return 0;
} else {
err("Not AF_INET");
return 1;
}
}
/*
* Formats sockaddr containing IPv4 address as human readable string.
* Returns 0 on success.
*/
int format_ip4(struct sockaddr *addr, char *out)
{
if (addr->sa_family == AF_INET) {
struct sockaddr_in *i = (struct sockaddr_in *) addr;
const char *ip = inet_ntoa(i->sin_addr);
if (!ip) {
return -2;
} else {
strcpy(out, ip);
return 0;
}
} else {
return -1;
}
}
/*
* Writes interface IPv4 address as network byte order to ip.
* Returns 0 on success.
*/
int get_if_ip4(int fd, const char *ifname, uint32_t *ip) {
int err = -1;
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
if (strlen(ifname) > (IFNAMSIZ - 1)) {
err("Too long interface name");
goto out;
}
strcpy(ifr.ifr_name, ifname);
if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
perror("SIOCGIFADDR");
goto out;
}
if (int_ip4(&ifr.ifr_addr, ip)) {
goto out;
}
err = 0;
out:
return err;
}
/*
* Sends an ARP who-has request to dst_ip
* on interface ifindex, using source mac src_mac and source ip src_ip.
*/
int send_arp(int fd, int ifindex, const unsigned char *src_mac, uint32_t src_ip, uint32_t dst_ip)
{
int err = -1;
unsigned char buffer[BUF_SIZE];
memset(buffer, 0, sizeof(buffer));
struct sockaddr_ll socket_address;
socket_address.sll_family = AF_PACKET;
socket_address.sll_protocol = htons(ETH_P_ARP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = htons(ARPHRD_ETHER);
socket_address.sll_pkttype = (PACKET_BROADCAST);
socket_address.sll_halen = MAC_LENGTH;
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
struct ethhdr *send_req = (struct ethhdr *) buffer;
struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
int index;
ssize_t ret, length = 0;
//Broadcast
memset(send_req->h_dest, 0xff, MAC_LENGTH);
//Target MAC zero
memset(arp_req->target_mac, 0x00, MAC_LENGTH);
//Set source mac to our MAC address
memcpy(send_req->h_source, src_mac, MAC_LENGTH);
memcpy(arp_req->sender_mac, src_mac, MAC_LENGTH);
memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);
/* Setting protocol of the packet */
send_req->h_proto = htons(ETH_P_ARP);
/* Creating ARP request */
arp_req->hardware_type = htons(HW_TYPE);
arp_req->protocol_type = htons(ETH_P_IP);
arp_req->hardware_len = MAC_LENGTH;
arp_req->protocol_len = IPV4_LENGTH;
arp_req->opcode = htons(ARP_REQUEST);
debug("Copy IP address to arp_req");
memcpy(arp_req->sender_ip, &src_ip, sizeof(uint32_t));
memcpy(arp_req->target_ip, &dst_ip, sizeof(uint32_t));
ret = sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address));
if (ret == -1) {
perror("sendto():");
goto out;
}
err = 0;
out:
return err;
}
/*
* Gets interface information by name:
* IPv4
* MAC
* ifindex
*/
int get_if_info(const char *ifname, uint32_t *ip, char *mac, int *ifindex)
{
debug("get_if_info for %s", ifname);
int err = -1;
struct ifreq ifr;
int sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
if (sd <= 0) {
perror("socket()");
goto out;
}
if (strlen(ifname) > (IFNAMSIZ - 1)) {
printf("Too long interface name, MAX=%i\n", IFNAMSIZ - 1);
goto out;
}
strcpy(ifr.ifr_name, ifname);
//Get interface index using name
if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
perror("SIOCGIFINDEX");
goto out;
}
*ifindex = ifr.ifr_ifindex;
printf("interface index is %d\n", *ifindex);
//Get MAC address of the interface
if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
perror("SIOCGIFINDEX");
goto out;
}
//Copy mac address to output
memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH);
if (get_if_ip4(sd, ifname, ip)) {
goto out;
}
debug("get_if_info OK");
err = 0;
out:
if (sd > 0) {
debug("Clean up temporary socket");
close(sd);
}
return err;
}
/*
* Creates a raw socket that listens for ARP traffic on specific ifindex.
* Writes out the socket's FD.
* Return 0 on success.
*/
int bind_arp(int ifindex, int *fd)
{
debug("bind_arp: ifindex=%i", ifindex);
int ret = -1;
// Submit request for a raw socket descriptor.
*fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
if (*fd < 1) {
perror("socket()");
goto out;
}
debug("Binding to ifindex %i", ifindex);
struct sockaddr_ll sll;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifindex;
if (bind(*fd, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll)) < 0) {
perror("bind");
goto out;
}
ret = 0;
out:
if (ret && *fd > 0) {
debug("Cleanup socket");
close(*fd);
}
return ret;
}
/*
* Reads a single ARP reply from fd.
* Return 0 on success.
*/
int read_arp(int fd)
{
debug("read_arp");
int ret = -1;
unsigned char buffer[BUF_SIZE];
ssize_t length = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, NULL);
int index;
if (length == -1) {
perror("recvfrom()");
goto out;
}
struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
struct arp_header *arp_resp = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
if (ntohs(rcv_resp->h_proto) != PROTO_ARP) {
debug("Not an ARP packet");
goto out;
}
if (ntohs(arp_resp->opcode) != ARP_REPLY) {
debug("Not an ARP reply");
goto out;
}
debug("received ARP len=%ld", length);
struct in_addr sender_a;
memset(&sender_a, 0, sizeof(struct in_addr));
memcpy(&sender_a.s_addr, arp_resp->sender_ip, sizeof(uint32_t));
debug("Sender IP: %s", inet_ntoa(sender_a));
debug("Sender MAC: %02X:%02X:%02X:%02X:%02X:%02X",
arp_resp->sender_mac[0],
arp_resp->sender_mac[1],
arp_resp->sender_mac[2],
arp_resp->sender_mac[3],
arp_resp->sender_mac[4],
arp_resp->sender_mac[5]);
ret = 0;
out:
return ret;
}
/*
*
* Sample code that sends an ARP who-has request on
* interface <ifname> to IPv4 address <ip>.
* Returns 0 on success.
*/
int test_arping(const char *ifname, const char *ip) {
int ret = -1;
uint32_t dst = inet_addr(ip);
if (dst == 0 || dst == 0xffffffff) {
printf("Invalid source IP\n");
return 1;
}
int src;
int ifindex;
char mac[MAC_LENGTH];
if (get_if_info(ifname, &src, mac, &ifindex)) {
err("get_if_info failed, interface %s not found or no IP set?", ifname);
goto out;
}
int arp_fd;
if (bind_arp(ifindex, &arp_fd)) {
err("Failed to bind_arp()");
goto out;
}
if (send_arp(arp_fd, ifindex, mac, src, dst)) {
err("Failed to send_arp");
goto out;
}
while(1) {
int r = read_arp(arp_fd);
if (r == 0) {
info("Got reply, break out");
break;
}
}
ret = 0;
out:
if (arp_fd) {
close(arp_fd);
arp_fd = 0;
}
return ret;
}
int main(int argc, const char **argv) {
int ret = -1;
if (argc != 3) {
printf("Usage: %s <INTERFACE> <DEST_IP>\n", argv[0]);
return 1;
}
const char *ifname = argv[1];
const char *ip = argv[2];
return test_arping(ifname, ip);
}
A couple of things to get your packets on the wire/air.
The proper .sll_protocol for the arp reply is ETH_P_ARP, from <linux/if_ether.h>
There was an error in endianness when setting ah->arp_op. It is a network byteorder field of 2 octets, so use htons().
In general, the code is a little confused about network and host byteorder. It currently sends out the reply very mangled, but it is unclear to me whether that is the malicious intent of the code, or an accident. In the case that you want to send real, correct IP addresses, use htonl and htons, when building the reply.
To fix endianness:
Properly include <arpa/inet.h>
Use htons(), htonl() ntohs() and ntohl(), always. Their implementation makes it a NOP, if its not needed on your platform.
When setting up data to be sent out from host, always process it with hton*()
When interpreting data from the network, always ntoh*() it before comparing with local variables.
In summary, the changes I did were 1) .sll_protocol = htons(ETH_P_ARP). (when sending data) 2) ah->arp_op = htons(ARPOP_REPLY) (in the reply arp) 3) Removed the nonsensical ntohs() on ah->arp_hd and ah->arp_pr. You dont want to convert data to host byteorder when populating the send buffer (unless you really really actually do) 4) Added ntohs() conversions and proper defines in some of the comparisons 5) some other small fixes 6) disabled the bit doing system("sudo...")!
Full code at pastebin. Here is a diff:
thuovila#glx:~/src/so/arp$ diff arp2.c arp_orig.c
13d12
< #include <arpa/inet.h>
20c19
< #define DEVICE "eth1"
---
> #define DEVICE "eth0"
25c24
< int s = -1; /*Socketdescriptor*/
---
> int s = 0; /*Socketdescriptor*/
92c91
< socket_address.sll_protocol = htons(ETH_P_ARP);
---
> socket_address.sll_protocol = htons(ETH_P_IP);
95c94
< socket_address.sll_pkttype = 0; //PACKET_OTHERHOST;
---
> socket_address.sll_pkttype = PACKET_OTHERHOST;
112c111
< if(ntohs(eh->h_proto) == ETH_P_ARP)
---
> if(htons(eh->h_proto) == 0x806)
119c118
< if(ntohs(ah->arp_op) != ARPOP_REQUEST)
---
> if(htons(ah->arp_op) != 0x0001)
139d137
< #if 0
145d142
< #endif
182c179
< eh->h_proto = htons(ETH_P_ARP);
---
> eh->h_proto = ETH_ARP;
200,201c197,198
< //ah->arp_hd = ntohs(ah->arp_hd);
< //ah->arp_pr = ntohs(ah->arp_pr);
---
> ah->arp_hd = ntohs(ah->arp_hd);
> ah->arp_pr = ntohs(ah->arp_pr);
203c200
< ah->arp_op = htons(ARPOP_REPLY);
---
> ah->arp_op = 0x0002;
EDIT Some wireshark advice. Capture ether proto 0x0806 (or arp for short). Use the pseudo device that captures any packets. Your packets should become visible.
On linux, if you want to stop the network stack from interfering, use: echo "8" > /proc/sys/net/ipv4/conf/all/arp_ignore
EDIT #2 I am not completely sure about the ETH_P_ARP. It might have been a snap judgement on my part. Using ETH_P_IP is correct in the ARP header field, but Im not sure which one to use for the packet socket sll_protocol. Also notice that socket_address.sll_pkttype = PACKET_OTHERHOST;has no effect when sending (see man 7 packet). Also the mandatory SO observation, that you should always use at least -Wall (when using gcc or clang) as a compilation flag.
EDIT #3 I changed the program a little more. and updated the answer and diff accordingly. Surprisingly it does indeed seem, that .sll_protocol needs to be ETH_P_ARP. My copy of the man 7 packet doesnt even say it is used for anything, but the packet doesnt go out on the wire as ARP without it.
I know this is a very old post. This code helped me a lot. I have modified the code to send an ARP request to an IP and extract the MAC address from the reply. Please find below my code
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <asm/types.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#define PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define PROTOCOL_TYPE 0x800
#define MAC_LENGTH 6
#define IPV4_LENGTH 4
#define ARP_REQUEST 0x01
#define ARP_REPLY 0x02
#define BUF_SIZE 60
struct arp_header
{
unsigned short hardware_type;
unsigned short protocol_type;
unsigned char hardware_len;
unsigned char protocol_len;
unsigned short opcode;
unsigned char sender_mac[MAC_LENGTH];
unsigned char sender_ip[IPV4_LENGTH];
unsigned char target_mac[MAC_LENGTH];
unsigned char target_ip[IPV4_LENGTH];
};
int main()
{
int sd;
unsigned char buffer[BUF_SIZE];
unsigned char source_ip[4] = {10,222,190,160};
unsigned char target_ip[4] = {10,222,190,139};
struct ifreq ifr;
struct ethhdr *send_req = (struct ethhdr *)buffer;
struct ethhdr *rcv_resp= (struct ethhdr *)buffer;
struct arp_header *arp_req = (struct arp_header *)(buffer+ETH2_HEADER_LEN);
struct arp_header *arp_resp = (struct arp_header *)(buffer+ETH2_HEADER_LEN);
struct sockaddr_ll socket_address;
int index,ret,length=0,ifindex;
memset(buffer,0x00,60);
/*open socket*/
sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sd == -1) {
perror("socket():");
exit(1);
}
strcpy(ifr.ifr_name,"eth1.30");
/*retrieve ethernet interface index*/
if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
ifindex = ifr.ifr_ifindex;
printf("interface index is %d\n",ifindex);
/*retrieve corresponding MAC*/
if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
perror("SIOCGIFINDEX");
exit(1);
}
close (sd);
for (index = 0; index < 6; index++)
{
send_req->h_dest[index] = (unsigned char)0xff;
arp_req->target_mac[index] = (unsigned char)0x00;
/* Filling the source mac address in the header*/
send_req->h_source[index] = (unsigned char)ifr.ifr_hwaddr.sa_data[index];
arp_req->sender_mac[index] = (unsigned char)ifr.ifr_hwaddr.sa_data[index];
socket_address.sll_addr[index] = (unsigned char)ifr.ifr_hwaddr.sa_data[index];
}
printf("Successfully got eth1 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
send_req->h_source[0],send_req->h_source[1],send_req->h_source[2],
send_req->h_source[3],send_req->h_source[4],send_req->h_source[5]);
printf(" arp_reqMAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
arp_req->sender_mac[0],arp_req->sender_mac[1],arp_req->sender_mac[2],
arp_req->sender_mac[3],arp_req->sender_mac[4],arp_req->sender_mac[5]);
printf("socket_address MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
socket_address.sll_addr[0],socket_address.sll_addr[1],socket_address.sll_addr[2],
socket_address.sll_addr[3],socket_address.sll_addr[4],socket_address.sll_addr[5]);
/*prepare sockaddr_ll*/
socket_address.sll_family = AF_PACKET;
socket_address.sll_protocol = htons(ETH_P_ARP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = htons(ARPHRD_ETHER);
socket_address.sll_pkttype = (PACKET_BROADCAST);
socket_address.sll_halen = MAC_LENGTH;
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
/* Setting protocol of the packet */
send_req->h_proto = htons(ETH_P_ARP);
/* Creating ARP request */
arp_req->hardware_type = htons(HW_TYPE);
arp_req->protocol_type = htons(ETH_P_IP);
arp_req->hardware_len = MAC_LENGTH;
arp_req->protocol_len =IPV4_LENGTH;
arp_req->opcode = htons(ARP_REQUEST);
for(index=0;index<5;index++)
{
arp_req->sender_ip[index]=(unsigned char)source_ip[index];
arp_req->target_ip[index]=(unsigned char)target_ip[index];
}
// Submit request for a raw socket descriptor.
if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
perror ("socket() failed ");
exit (EXIT_FAILURE);
}
buffer[32]=0x00;
ret = sendto(sd, buffer, 42, 0, (struct sockaddr*)&socket_address, sizeof(socket_address));
if (ret == -1)
{
perror("sendto():");
exit(1);
}
else
{
printf(" Sent the ARP REQ \n\t");
for(index=0;index<42;index++)
{
printf("%02X ",buffer[index]);
if(index % 16 ==0 && index !=0)
{printf("\n\t");}
}
}
printf("\n\t");
memset(buffer,0x00,60);
while(1)
{
length = recvfrom(sd, buffer, BUF_SIZE, 0, NULL, NULL);
if (length == -1)
{
perror("recvfrom():");
exit(1);
}
if(htons(rcv_resp->h_proto) == PROTO_ARP)
{
//if( arp_resp->opcode == ARP_REPLY )
printf(" RECEIVED ARP RESP len=%d \n",length);
printf(" Sender IP :");
for(index=0;index<4;index++)
printf("%u.",(unsigned int)arp_resp->sender_ip[index]);
printf("\n Sender MAC :");
for(index=0;index<6;index++)
printf(" %02X:",arp_resp->sender_mac[index]);
printf("\nReceiver IP :");
for(index=0;index<4;index++)
printf(" %u.",arp_resp->target_ip[index]);
printf("\n Self MAC :");
for(index=0;index<6;index++)
printf(" %02X:",arp_resp->target_mac[index]);
printf("\n :");
break;
}
}
return 0;
}
Thanks a lot once more
Arun Kumar P

Resources