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>
#define PCKT_LEN 50
#define DATA_SIZE 15
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;
unsigned short ComputeChecksum(unsigned char *data, int len)
{
long sum = 0;
unsigned short *temp = (unsigned short *)data;
while(len > 1){
sum += *temp++;
if(sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
if(len)
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;
}
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;
inet_pton(AF_INET, srcip, &ip_header->ip_src);
inet_pton(AF_INET, destip, &ip_header->ip_dst);
ip_header->ip_sum = ComputeChecksum((unsigned char *)ip_header, ip_header->ip_hl*4);
return (ip_header);
}
struct udphdr *CreateUdpHeader(char *srcport, char *destport )
{
struct udphdr *udp_header;
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);
udp_header->check = htons(0);
return (udp_header);
}
void CreatePseudoHeaderAndComputeUdpChecksum(struct udphdr *udp_header, struct ip *ip_header, unsigned char *data)
{
int segment_len = ntohs(ip_header->ip_len) - ip_header->ip_hl*4;
int header_len = sizeof(PseudoHeader) + segment_len;
unsigned char *hdr = (unsigned char *)malloc(header_len);
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);
memcpy((hdr + sizeof(PseudoHeader)), (void *)udp_header, 8);
memcpy((hdr + sizeof(PseudoHeader) + 8), data, DATA_SIZE);
udp_header->check = ComputeChecksum(hdr, header_len);
free(hdr);
}
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;
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);
#if 0
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");
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
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)) < 0)
{
perror("setsockopt() error");
close(sd);
exit(-1);
}
else
printf("setsockopt() is OK.\n");
to_addr.sin_family = AF_INET;
to_addr.sin_addr.s_addr = inet_addr(argv[3]);
to_addr.sin_port = htons(atoi(argv[4]));
struct ip *ip_header = CreateIPHeader(argv[1], argv[3]);
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]));
memset(data, ' ', sizeof(data));
the_time = htonl(time(NULL));
memcpy(data, &the_time, sizeof(the_time));
CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);
for (ix = 0; ix < 1000000; ++ix)
{
memcpy(buffer, ip_header, sizeof(struct ip));
memcpy(buffer + sizeof(struct ip), udp_header, 8 );
memcpy(buffer + sizeof(struct ip) + 8, data, DATA_SIZE);
#if 0
if(sendto(sd, buffer, 20, 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);
}
free(ip_header);
free(udp_header);
close(sd);
return 0;
}