No output when using a raw socket to send fake packets through multicast to different subnets

My application is a dedicated custom spatial UDP router that uses raw sockets to create unicast and multicast output with actual or fake source addresses in the packet headers of the IP packets sent.

In short, there is one permutation of outputs that do not reach some destination hosts.

My question is: is there some kind of subtle logic on the Linux stack that prevents certain routing redirects or is the output function that I use something missing?

I cannot create a UDP packet writer that successfully sends packets that (1) contain a fake source address, (2) for a multicast address, (3) if the sending host is on subnet A, (4) the receiving host is on the subnet B if the (valid) fake source address is on subnet A.

Subnet A = 10.200.xx.nn Subnet B = 10.200.yy.nn

Source address in packet = sending host

                           Subnet                
Src addr = sender addr  A   A   B   B   
Receiver                A   B   A   B   
Result                  Yes Yes Yes Yes 

Source address in packet! = Sending host

                                 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

Spoofing addresses refer to existing network devices.

Wireshark running on failed destinations does not display UDP data.

, Stack Overflow, Peter O. 11 2012 . - 3737612 " C Linux". , /. RedHat 5, gcc 4.1.2.

/etc/sysctl.conf, , :

  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

​​ 3737612.

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>

#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>

#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <time.h>

//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 > 1){
    sum += *temp++;
    if(sum & 0x80000000)   /* if high order bit set, fold */
        sum = (sum & 0xFFFF) + (sum >> 16);
    len -= 2;
    }

    if(len)   /* take care of left over byte */
    sum += (unsigned short) *((unsigned char *)temp);

    while(sum>>16)
    sum = (sum & 0xFFFF) + (sum >> 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 *)&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->ip_v = 4;
    ip_header->ip_hl = 5;
    ip_header->ip_tos = 0;
    ip_header->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
    ip_header->ip_id = htons(111);
    ip_header->ip_off = 0;
    ip_header->ip_ttl = 111;
    ip_header->ip_p = IPPROTO_UDP;
    ip_header->ip_sum = 0; /* We will calculate the checksum later */
    inet_pton(AF_INET, srcip, &ip_header->ip_src);
    inet_pton(AF_INET, destip, &ip_header->ip_dst);

    /* Calculate the IP checksum now :
    The IP Checksum is only over the IP header */
    ip_header->ip_sum = ComputeChecksum((unsigned char *)ip_header, ip_header->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->source = htons(atoi(srcport));
    udp_header->dest = htons(atoi(destport));
    udp_header->len = htons(sizeof(struct udphdr) + DATA_SIZE); //TODO: need to specify this
    udp_header->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->ip_len) - ip_header->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->source_ip = ip_header->ip_src.s_addr;
    pseudo_header->dest_ip = ip_header->ip_dst.s_addr;
    pseudo_header->reserved = 0;
    pseudo_header->protocol = ip_header->ip_p;
    pseudo_header->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->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 = &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 && argc != 6)
    {
    printf("- Invalid parameters!!!\n");
    printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port> [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 < 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 < 0)
    {
    perror("socket() error");
    exit(-1);
    }
    else
    printf("socket() - Using SOCK_RAW socket and RAW protocol is OK.\n");
    memset (&ifr, 0, sizeof (ifr));
    snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
    if (ioctl(sd, SIOCGIFINDEX, &ifr))
    {
    perror("ioctl() error ");
    exit(-1);
    }
    if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 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)) < 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, &the_time, sizeof(the_time));

    //Compute UDP checksum
    CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);

    for (ix = 0; ix < 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->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
    #else
      if(sendto(sd, buffer, sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE, 0, 
            (struct sockaddr *)&to_addr, sizeof(to_addr)) < 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;
}
+4

All Articles