Raw socket with device bind using setsockopt() system is not working in Fedora core 6(2.6.18-1.2798.fc6)

viswanathan J picture viswanathan J · Mar 29, 2012 · Viewed 13.7k times · Source

Please any one could help on this issue. Please

In the below sample code,we had bind raw sock with eth0. but while running the program the recvfrom of raw sock is receiving packets from eth0 & eth1 on same machine(xx_86). It is not clear to me why,could help one on this issue. I hope the setsockopt is not working properly OS: Fedora core 6(2.6.18-1.2798.fc6)

Sampe code:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h> 
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char **argv) {
int sock, i;
unsigned char buffer[2048];
unsigned char tbuff[2048];
unsigned char *iphead, *ethhead,*phead;
struct ifreq ethreq;

// NOTE: use TCPDUMP to build the filter array.
// set filter to sniff only port 443
// $ sudo tcpdump -dd port 443

// raw for recvfrom eth0

if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
    perror("socket");
    exit(1);
}
  // set network card to promiscuos
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS, &ethreq) == -1) {
    perror("ioctl");
    close(sock);
    exit(1);
}
ethreq.ifr_flags |= IFF_PROMISC;
if (ioctl(sock, SIOCSIFFLAGS, &ethreq) == -1) {
    perror("ioctl");
    close(sock);
    exit(1);
}

//bind to sock with eth0 

 struct ifreq Interface;
 memset(&Interface, 0, sizeof(Interface));
 strncpy(Interface.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &Interface, sizeof(Interface)) < 0)    { close(sock); }


    //open the RAW socket for sendto

 int s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);

     struct sockaddr_in sin;
     memset(&sin,0,sizeof(sin));
     sin.sin_family = AF_INET;
     sin.sin_port = htons(0);
     sin.sin_addr.s_addr = inet_addr ("10.3.161.104");

  // inform kernal don't fill IP and Transport header

     int one = 1;
     const int *val = &one;
     if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
     printf ("Warning: Cannot set HDRINCL!\n");

     //bind the sock descriptor with eth0

     struct ifreq Interface1;
     memset(&Interface1, 0, sizeof(Interface1));
     strncpy(Interface1.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
     if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &Interface1, sizeof(Interface1)) < 0) { close(s); }


while (1) {
    printf("----------------------\n");
    i = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL);
    printf("%d bytes read\n", i);

    // check header size: Ethernet = 14, IP = 20, TCP = 8 (sum = 42)
    if (i < 42) {
        perror("recvfrom():");
        printf("Incomplete packet (errno is %d)\n", errno);
        close(sock);
        exit(0);
    }

    phead = buffer + 14; // (skip ethernet  header)
    memcpy(tbuff,phead,i-14); 
    iphead=tbuff;
    if (*iphead == 0x45) {
        int ptrindex= iphead[9];
        switch(ptrindex){

         case 1:
                printf("The transport protocl is:ICMP\n");
                break;
         case 2:
                printf("The transport protol is:IGMP\n");
                break;
         case 6:
               printf("The transport protocol is:TCP\n");
               break;
         case 17:
               printf("The transport protocol is:UDP\n");
               break;
         case 103:
              printf("The transport protocol is:PIM\n"); 
              break; 
         default:
             printf("The transport protocol is:%d\n",iphead[9]);
        }           
        //printf("%d",*ptrindex);
       // printf("\n The transport protocol is :%u\n",iphead[9]);
        printf("Source Address: %d.%d.%d.%d, Port: %d\n",
            iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8) + iphead[21]);
        printf("Dest Address: %d.%d.%d.%d, Port: %d\n",
            iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8) + iphead[23]);


     if(sendto(s,tbuff,i-14,0,(struct sockaddr *)&sin,sizeof(sin))<0)
      printf("error\n");

     else{printf("\nThe received packet is send\n");}

     memset(buffer,0,sizeof(buffer));
     memset(tbuff,0,sizeof(tbuff));

    }
   else{ printf("The non ip had received");}

    }
       close(sock);
}

Answer

llj098 picture llj098 · Mar 29, 2012

In the linux man page (http://linux.die.net/man/7/socket) :

SO_BINDTODEVICE

Bind this socket to a particular device like "eth0", as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket device binding is removed. The passed option is a variable-length null-terminated interface name string with the maximum size of IFNAMSIZ. If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).

So, try the bind instead.