0

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

  • 2
    First of all always check the return values of each of the function you are using, that will help you whether packets are filter or other problems like processes etc. are closed etc. Moreover if you could paste bit more code, may be you get the help soon. iptables are the linux firewall. use this command to check whether they are being filtered or not. – Mazhar May 16 '16 at 15:30
  • Thanks for your quick response. However I want to ask if I'm seeing IGMP frame on wireshark doesn't that mean that it's not filtered by the firewall ? – swordsabre May 16 '16 at 16:27
  • are you trying as root, normal user, or a user with specials CAPs? – Stian Skjelstad May 16 '16 at 17:35
  • (you can trace the wireshark process, but again, wireshark receives ALL frames, IGMP or not, which is probably not what you want) – Stian Skjelstad May 16 '16 at 17:35
  • I'm running the project with the command sudo and i'm not a root, I didn't get your second remark ?! – swordsabre May 17 '16 at 10:04
  • Ok, I think i have a problem with my virtual machine because even on wireshark I no longer get IGMP frames, when modifying my IGMP listener to make it receive all frames using the protocol : htons(ETH_P_ALL) and running it as a root, I receive all the frames except IGMP ones. So now I think that my machine is filtring IGMP frames. Can I get more explanation on how to check if my linux is filtring IGMP with eventually the command iptables. I don't really see how to check it or modify something in iptables. – swordsabre May 17 '16 at 10:37
  • 1
    Finally problem solved, the problem was with the IP address that I was using with my VM. I just switched the network access on my VM from a **Nat** to a **Bridge access** and the problem was solved. I'm know facing another problem but I think I'm gonna post it on another question because it differs a little from the topic of this question, Thank you guys for your time.@Stian Skjelstad , @Mazhar . – swordsabre May 17 '16 at 16:33
  • Great bro keep it up! – Mazhar May 17 '16 at 18:04

0 Answers0