Reputation: 1
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!!
Upvotes: 0
Views: 863