title: No output when using raw socket to send spoofed packets via multicast to different subnet
body: <p>My application is a specialized user space UDP router that uses raw sockets to produce unicast and multicast output with actual or spoofed source addresses in the IP packet headers of the sent packets.</p>
  
  <p>Briefly, there is one permutation of the outputs that fails to reach some of the destination hosts.</p>
  
  <p>My question:  is there some subtle logic in the Linux stack that prevents certain routing permutations, or is the output function I am using missing something?</p>
  
  <p>I can't create a UDP packet writer that successfully sends packets that (1) contain a spoofed source address, (2) to a multicast address, (3) if sending host is on subnet A, (4) receiving host is on subnet B, if the (valid) spoofed source address is on subnet A.</p>
  
  <p>Subnet A = 10.200.xx.nn
  Subnet B = 10.200.yy.nn</p>
  
  <p>Source address in packet = sending host</p>
  
  <pre><code>                           Subnet                
  Src addr = sender addr  A   A   B   B   
  Receiver                A   B   A   B   
  Result                  Yes Yes Yes Yes 
  </code></pre>
  
  <p>Source address in packet != sending host</p>
  
  <pre><code>                                 Subnet                
  Sender                  A   A   A   A   B   B   B   B    
  Spoofed src addr        A   A   B   B   A   A   B   B
  Receiver                A   B   A   B   A   B   A   B
  Result                  Yes Yes Yes No  No  Yes Yes Yes
  </code></pre>
  
  <p>The spoof addresses are to existing network devices.</p>
  
  <p>Wireshark run on the failing destinations shows no UDP data.</p>
  
  <p>My raw socket class is derived very closely from the example program I found at Stack Overflow kindly donated by user Peter O. on March 11, 2012 - question 3737612 "Raw socket sendto failed using C on Linux".  I have appended my version of it, with a
  couple of enhancements/fixes.  I compiled and ran it on RedHat 5, gcc 4.1.2.</p>
  
  <p>I checked /etc/sysctl.conf entries that might be relevant, and set the following with no discernable effect:</p>
  
  <pre><code>  sudo /sbin/sysctl -w net.ipv4.conf.default.rp_filter=0
    sudo /sbin/sysctl -w net.ipv4.conf.eth2.rp_filter=0
    sudo /sbin/sysctl -w net.ipv4.conf.lo.rp_filter=0
    sudo /sbin/sysctl -w net.ipv4.conf.all.rp_filter=0
  
    sudo /sbin/sysctl -w net.ipv4.ip_forward=1
  
    sudo /sbin/sysctl -w net.ipv4.conf.default.accept_source_route=1
    sudo /sbin/sysctl -w net.ipv4.conf.all.accept_source_route=1
  </code></pre>
  
  <p>My modified version of the example from 3737612 is appended.</p>
  
  <pre><code>#include &lt;unistd.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;netinet/ip.h&gt;
  #include &lt;netinet/udp.h&gt;
  
  #include &lt;string.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;arpa/inet.h&gt;
  
  #include &lt;netinet/in.h&gt;
  #include &lt;net/if.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;time.h&gt;
  
  //The packet length in byes
  #define PCKT_LEN 50
  
  //Date size in bytes
  #define DATA_SIZE 15
  
  //PseudoHeader struct used to calculate UDP checksum.
  typedef struct PseudoHeader{
      unsigned long int source_ip;
      unsigned long int dest_ip;
      unsigned char reserved;
      unsigned char protocol;
      unsigned short int udp_length;
  }PseudoHeader;
  
  // Ripped from Richard Stevans Book
  unsigned short ComputeChecksum(unsigned char *data, int len)
  {
      long sum = 0;  /* assume 32 bit long, 16 bit short */
      unsigned short *temp = (unsigned short *)data;
  
      while(len &gt; 1){
      sum += *temp++;
      if(sum &amp; 0x80000000)   /* if high order bit set, fold */
          sum = (sum &amp; 0xFFFF) + (sum &gt;&gt; 16);
      len -= 2;
      }
  
      if(len)   /* take care of left over byte */
      sum += (unsigned short) *((unsigned char *)temp);
  
      while(sum&gt;&gt;16)
      sum = (sum &amp; 0xFFFF) + (sum &gt;&gt; 16);
  
      return ~sum;
  }
  
  int BindRawSocketToInterface(int rawsock, char *addr, short int port)
  {
      struct sockaddr_in s_addr;
      s_addr.sin_family = AF_INET;
      s_addr.sin_addr.s_addr = inet_addr(addr);
      s_addr.sin_port = htons(port);
  
      if((bind(rawsock, (struct sockaddr *)&amp;s_addr, sizeof(s_addr)))== -1)
      {
      perror("Error binding raw socket to interface\n");
      exit(-1);
      }
  
      return 1;
  }
  
  // Fabricate the IP header or we can use the
  // standard header structures but assign our own values.
  struct ip *CreateIPHeader(char *srcip, char *destip)
  {
      struct ip *ip_header;
  
      ip_header = (struct ip *)malloc(sizeof(struct ip));
  
      ip_header-&gt;ip_v = 4;
      ip_header-&gt;ip_hl = 5;
      ip_header-&gt;ip_tos = 0;
      ip_header-&gt;ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
      ip_header-&gt;ip_id = htons(111);
      ip_header-&gt;ip_off = 0;
      ip_header-&gt;ip_ttl = 111;
      ip_header-&gt;ip_p = IPPROTO_UDP;
      ip_header-&gt;ip_sum = 0; /* We will calculate the checksum later */
      inet_pton(AF_INET, srcip, &amp;ip_header-&gt;ip_src);
      inet_pton(AF_INET, destip, &amp;ip_header-&gt;ip_dst);
  
      /* Calculate the IP checksum now :
      The IP Checksum is only over the IP header */
      ip_header-&gt;ip_sum = ComputeChecksum((unsigned char *)ip_header, ip_header-&gt;ip_hl*4);
  
      return (ip_header);
  }
  
  // Creates a the UDP header.
  struct udphdr *CreateUdpHeader(char *srcport, char *destport )
  {
      struct udphdr *udp_header;
  
      /* Check netinet/udp.h for header definiation */
  
      udp_header = (struct udphdr *)malloc(sizeof(struct udphdr));
  
      udp_header-&gt;source = htons(atoi(srcport));
      udp_header-&gt;dest = htons(atoi(destport));
      udp_header-&gt;len = htons(sizeof(struct udphdr) + DATA_SIZE); //TODO: need to specify this
      udp_header-&gt;check = htons(0);
  
      return (udp_header);
  }
  
  void CreatePseudoHeaderAndComputeUdpChecksum(struct udphdr *udp_header, struct ip *ip_header, unsigned char *data)
  {
  
      /*The TCP Checksum is calculated over the PseudoHeader + TCP header +Data*/
  
      /* Find the size of the TCP Header + Data */
      int segment_len = ntohs(ip_header-&gt;ip_len) - ip_header-&gt;ip_hl*4;
  
      /* Total length over which TCP checksum will be computed */
      int header_len = sizeof(PseudoHeader) + segment_len;
  
      /* Allocate the memory */
  
      unsigned char *hdr = (unsigned char *)malloc(header_len);
  
      /* Fill in the pseudo header first */
  
      PseudoHeader *pseudo_header = (PseudoHeader *)hdr;
  
      pseudo_header-&gt;source_ip = ip_header-&gt;ip_src.s_addr;
      pseudo_header-&gt;dest_ip = ip_header-&gt;ip_dst.s_addr;
      pseudo_header-&gt;reserved = 0;
      pseudo_header-&gt;protocol = ip_header-&gt;ip_p;
      pseudo_header-&gt;udp_length = htons(segment_len);
  
  
      /* Now copy TCP */
  
      memcpy((hdr + sizeof(PseudoHeader)), (void *)udp_header, 8);
  
      /* Now copy the Data */
  
      memcpy((hdr + sizeof(PseudoHeader) + 8), data, DATA_SIZE);
  
      /* Calculate the Checksum */
  
      udp_header-&gt;check = ComputeChecksum(hdr, header_len);
  
      /* Free the PseudoHeader */
      free(hdr);
  }
  
  // Source IP, source port, target IP, target port from the command line arguments
  int main(int argc, char *argv[])
  {
      int sd, ix;
      char buffer[PCKT_LEN];
      char data[DATA_SIZE];
      int one = 1;
      char interface[100];
      struct ifreq ifr;
      time_t the_time;
  
      // Source and destination addresses: IP and port
      struct sockaddr_in to_addr;
      const int *val = &amp;one;
  
      printf("IP Header Size: %u \n", sizeof(struct ip));
      printf("UDP Header Size: %u \n", sizeof(struct udphdr));
      printf("Data Size: %d\n", DATA_SIZE);
      printf("IP Total: %u \n", sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
  
      memset(buffer, 0, PCKT_LEN);
  
      if(argc != 5 &amp;&amp; argc != 6)
      {
      printf("- Invalid parameters!!!\n");
      printf("- Usage %s &lt;source hostname/IP&gt; &lt;source port&gt; &lt;target hostname/IP&gt; &lt;target port&gt; [interface]\n", argv[0]);
      exit(-1);
      }
      if (argc == 6)
        strcpy(interface, argv[5]);
      else
        strcpy(interface, "eth0");
      printf("Interface:  %s\n", interface);
  
      // bind() fails in BindRawSocketToInterface() above if it is passed a source address that
      // is not the actual host sending (i.e. spoofing):  "Cannot assign requested address"
      #if 0
      // Create a raw socket with UDP protocol
      sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
      if(sd &lt; 0)
      {
      perror("socket() error");
      exit(-1);
      }
      else
      printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
  
      //Bind the socket to the source address and port.
      BindRawSocketToInterface(sd, argv[1], atoi(argv[2]));
      #else
      sd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
      if(sd &lt; 0)
      {
      perror("socket() error");
      exit(-1);
      }
      else
      printf("socket() - Using SOCK_RAW socket and RAW protocol is OK.\n");
      memset (&amp;ifr, 0, sizeof (ifr));
      snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
      if (ioctl(sd, SIOCGIFINDEX, &amp;ifr))
      {
      perror("ioctl() error ");
      exit(-1);
      }
      if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, &amp;ifr, sizeof (ifr)) &lt; 0)
      {
      perror("setsockopt() error (#2)");
      exit(-1);
      }
      #endif
      // Inform the kernel do not fill up the packet structure. we will build our own...
      if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)) &lt; 0)
      {
      perror("setsockopt() error");
      close(sd);
      exit(-1);
      }
      else
      printf("setsockopt() is OK.\n");
  
      // The source is redundant, may be used later if needed
      // The address family
      to_addr.sin_family = AF_INET;
      to_addr.sin_addr.s_addr = inet_addr(argv[3]);
      to_addr.sin_port = htons(atoi(argv[4]));
  
      //Create the IP header.
      struct ip *ip_header = CreateIPHeader(argv[1], argv[3]);
      //Create the UDP header.
      struct udphdr *udp_header = CreateUdpHeader(argv[2], argv[4]);
  
      printf("Using raw socket and UDP protocol\n");
      printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
  
  
      // include a timestamp
      memset(data, ' ', sizeof(data));
      the_time = htonl(time(NULL));
      memcpy(data, &amp;the_time, sizeof(the_time));
  
      //Compute UDP checksum
      CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);
  
      for (ix = 0; ix &lt; 1000000; ++ix)
      {
  
        //Copy IP header, UDP header, and data to the packet buffer.
        memcpy(buffer, ip_header, sizeof(struct ip));
        memcpy(buffer + sizeof(struct ip), udp_header, 8 /*sizeof(struct udphdr)*/);
        memcpy(buffer + sizeof(struct ip) + 8, data, DATA_SIZE);
  
      // length must include header sizes
      #if 0
        if(sendto(sd, buffer, 20/*ip_header-&gt;ip_len*/, 0, (struct sockaddr *)&amp;to_addr, sizeof(to_addr)) &lt; 0)
      #else
        if(sendto(sd, buffer, sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE, 0, 
              (struct sockaddr *)&amp;to_addr, sizeof(to_addr)) &lt; 0)
      #endif
        {
      perror("sendto() error");
      break;
        }
        else
        {
            printf("sendto() is OK.\n");
        }
        sleep(1);
      } // loop
      free(ip_header);
      free(udp_header);
      close(sd);
      return 0;
  }
  </code></pre>