Generating packets - c

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.

Related

UDP checksum calculation not working with newer version of gcc

The code included below is a stripped-down implementation of a function that generates a UDP packet for a given fixed-size payload and sends it.
After switching to a newer version of gcc this code suddenly shows an error: the UDP checksum is not calculated correctly, and this can be traced down to the line
pseudoHeader->protocol = IPPROTO_UDP;
for which the compiler seemingly does not generate an instruction if at least -O2 optimization is used.
The following workarounds resolve the issue (each suggestion works independently, i.e. you do not to have to apply all of them at once!):
move the mentioned line before the two calls to inet_pton
remove the call to memset(ipHeader, 0, sizeof(struct ip)) after the checksum calculation
make ip_checksum() an external function outside of this translation unit
The fact that the code makes heavy use of casting together with the error only appearing for -O2 or higher and the nature of the workarounds virtually calls for this to be an aliasing error in the code. Is there an actual error and if so, how can it be fixed?
#include <string.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netpacket/packet.h>
#define UDP_PORT 2345
#define REPLY_PAYLOAD_SIZE 360
typedef struct UDPPseudoHeader
{
unsigned long int source_ip;
unsigned long int dest_ip;
unsigned char reserved;
unsigned char protocol;
unsigned short int udp_length;
} UDPPseudoHeader;
void sendPacket(unsigned char* packet, int len);
static unsigned short ip_checksum(unsigned short *ptr, int len)
{
int sum = 0;
unsigned short answer = 0;
unsigned short *w = ptr;
int nleft = len;
while(nleft > 1) {
sum += *w++;
nleft -= 2;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
void sendBroadcastPacket(uint16_t destPort, char* packet) {
unsigned char buffer[REPLY_PAYLOAD_SIZE + sizeof(struct ip) + sizeof(struct udphdr)];
int bufferLen = REPLY_PAYLOAD_SIZE + sizeof(struct ip) + sizeof(struct udphdr);
/* initialize header pointers */
struct udphdr* udpHeader = (struct udphdr*)(buffer + sizeof(struct ip));
UDPPseudoHeader* pseudoHeader = (UDPPseudoHeader*)(buffer + sizeof(struct ip) - sizeof(UDPPseudoHeader));
struct ip* ipHeader = (struct ip*)(buffer);
memset(buffer, 0, bufferLen);
/* copy user data */
memcpy(buffer + sizeof(struct ip) + sizeof(struct udphdr), packet, REPLY_PAYLOAD_SIZE);
/* fill in UDP header */
udpHeader->source = htons(UDP_PORT);
udpHeader->dest = htons(destPort);
udpHeader->len = htons(sizeof(struct udphdr) + REPLY_PAYLOAD_SIZE);
udpHeader->check = 0;
/* create UDP pseudo header for checksum calculation */
inet_pton(AF_INET, "0.0.0.0", &pseudoHeader->source_ip);
inet_pton(AF_INET, "255.255.255.255", &pseudoHeader->dest_ip);
pseudoHeader->reserved = 0;
pseudoHeader->protocol = IPPROTO_UDP;
pseudoHeader->udp_length = htons(sizeof(struct udphdr) + REPLY_PAYLOAD_SIZE);
/* calculate UDP checksum */
udpHeader->check = ip_checksum((unsigned short*) pseudoHeader, bufferLen - sizeof(struct ip) + sizeof(UDPPseudoHeader));
/* fill in IP header */
memset(ipHeader, 0, sizeof(struct ip));
ipHeader->ip_v = 4;
ipHeader->ip_hl = 5;
ipHeader->ip_tos = IPTOS_LOWDELAY;
ipHeader->ip_len = htons(bufferLen);
ipHeader->ip_off = htons(IP_DF);
ipHeader->ip_id = 0;
ipHeader->ip_ttl = 16;
ipHeader->ip_p = IPPROTO_UDP;
inet_pton(AF_INET, "0.0.0.0", &ipHeader->ip_src);
inet_pton(AF_INET, "255.255.255.255", &ipHeader->ip_dst);
ipHeader->ip_sum = 0;
/* calculate IP checksum */
ipHeader->ip_sum = ip_checksum((unsigned short*) ipHeader, ipHeader->ip_hl * 4);
sendPacket(buffer, bufferLen);
}
The code indeed violates the strict aliasing rule. The compiler assumes that the call to ip_checksum() does not depend on the assignments to the struct members reserved and protocol because these modify chars and ip_checksum() is calculated over an array of unsigned shorts. Therefore the assignments are completely optimized away since the following call to memset() overwrites the memory anyway.
A possible solution is to declare the pseudo header as
typedef union {
struct {
unsigned long int source_ip;
unsigned long int dest_ip;
unsigned char reserved;
unsigned char protocol;
unsigned short int udp_length;
} hdr;
unsigned short as_short[6];
} UDPPseudoHeader;
and replace the generation of the pseudo header and the checksum calculation by
/* create UDP pseudo header for checksum calculation */
inet_pton(AF_INET, "0.0.0.0", &pseudoHeader->hdr.source_ip);
inet_pton(AF_INET, "255.255.255.255", &pseudoHeader->hdr.dest_ip);
pseudoHeader->hdr.reserved = 0;
pseudoHeader->hdr.protocol = IPPROTO_UDP;
pseudoHeader->hdr.udp_length = htons(sizeof(struct udphdr) + REPLY_PAYLOAD_SIZE);
/* calculate UDP checksum */
udpHeader->check = ip_checksum(pseudoHeader->as_short, bufferLen - sizeof(struct ip) + sizeof(UDPPseudoHeader));
Another issue:
Alignment
unsigned char buffer[REPLY_PAYLOAD_SIZE + sizeof(struct ip) + sizeof(struct udphdr)];
...
struct ip* ipHeader = (struct ip*)(buffer);
buffer is not certainly aligned for a struct ip.

How can I set the TCP options for sending packets?

I'm programming software which can send tcp packets to an host.
I'm able to create a packet with IP header, TCP Headers and data but I can't manage how to add TCP options like MSS, NOP, STACK, Window scaling or Timestamp.
I mean i'm not able to add options to the TCP header, calculate the correct checksum to send a good TCP packet to the host.
I can just send correct TCP packets without TCP options.
Do you think I'm on the correct patch? Could somebody please help me?
/* TCP Header structure */
struct tcphdr
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t th_ack; /* acknowledgement number */
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t th_x2:4; /* (unused) */
u_int8_t th_off:4; /* data offset */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
u_int8_t th_off:4; /* data offset */
u_int8_t th_x2:4; /* (unused) */
#endif
u_int8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
# define TH_ECE 0x40
# define TH_CWR 0x80
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
struct tcp_option_mss
{
uint8_t kind; /* 2 */
uint8_t len; /* 4 */
uint16_t mss;
} __attribute__((packed));
struct tcphdr_mss
{
struct tcphdr tcphdr;
struct tcp_option_mss mss;
};
/* IP Header structure */
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
# define IP_RF 0x8000 /* reserved fragment flag */
# define IP_DF 0x4000 /* dont fragment flag */
# define IP_MF 0x2000 /* more fragments flag */
# define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
int send_packet(int sock, long dest_ip , long source_ip, long port, u_int8_t th_flags, unsigned long seq, unsigned long ack, unsigned long port1, unsigned char * data, unsigned long data_i)
{
char * packet;
struct ip * pkt_ip;
struct tcphdr * pkt_tcp;
struct tcphdr_mss * tcp_header;
struct sockaddr_in sin;
packet = malloc(sizeof(struct ip) + sizeof(struct tcphdr_mss) + data_i);
if (packet == NULL)
{
if (ECHO)
fprintf(stderr, "Error in allocating memory\n");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(struct ip) + sizeof(struct tcphdr_mss));
pkt_ip = (struct ip *) packet;
pkt_tcp = (struct tcphdr *) (packet + sizeof(struct ip));
pkt_tcp->th_sport = htons(port1);
pkt_tcp->th_dport = htons(port);
pkt_tcp->th_seq = htonl(seq);
pkt_tcp->th_ack = htonl(ack);
pkt_tcp->th_off = sizeof(struct tcphdr) / 4 + 1;
pkt_tcp->th_flags = th_flags;
pkt_tcp->th_win = htons(32768);
pkt_tcp->th_sum = 0;
tcp_header = malloc(sizeof(struct tcphdr));
tcp_header->tcphdr = *pkt_tcp;
tcp_header->mss.kind = 2;
tcp_header->mss.len = 4;
tcp_header->mss.mss = htons(32000);
pkt_ip->ip_v = 4;
pkt_ip->ip_hl = sizeof(struct ip) >> 2;
pkt_ip->ip_tos = 0;
pkt_ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + data_i);
if (ipid > 65000)
ipid = 0;
ipid++;
pkt_ip->ip_id = ipid;
pkt_ip->ip_off = 0;
pkt_ip->ip_ttl = 64;
pkt_ip->ip_p = IPPROTO_TCP ;
pkt_ip->ip_sum = 0;
pkt_ip->ip_src.s_addr = source_ip;
pkt_ip->ip_dst.s_addr = dest_ip;
pkt_ip->ip_sum = checksum((unsigned short*)pkt_ip, sizeof( struct ip) );
pkt_tcp->th_sum = in_cksum_tcp(pkt_ip->ip_src.s_addr, pkt_ip->ip_dst.s_addr, (unsigned short *) pkt_tcp, sizeof(struct tcphdr_mss), data, data_i);
memcpy(((char *)pkt_tcp + sizeof(struct tcphdr_mss)), data, data_i);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = pkt_ip->ip_dst.s_addr;
if (sendto(sock, packet, sizeof(struct ip) + sizeof(struct tcphdr_mss) + data_i, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0)
{
perror("sendto");
free(packet);
return -1;
}
free(packet);
return 0;
}
In the line:
pkt_tcp->th_sum = in_cksum_tcp(pkt_ip->ip_src.s_addr, pkt_ip->ip_dst.s_addr, (unsigned short *) pkt_tcp, sizeof(struct tcphdr_mss), data, data_i);
According to the in_cksum_tcp function that i've seen in the wild:
unsigned short in_cksum_tcp(int src, int dst, unsigned short *addr, int len, unsigned char * data, int data_i)
You are passing the size of the options header (sizeof(struct tcphdr_mss)), instead the size of the complete TCP header (sizeof (tcphdr) + sizeof(tcphdr_mss)). I think this could be the problem (you don't compute correctly the TCP checksum).
A good way to check wich is the problem creating raw packets is to save the packet with libpcap to a pcap file and open with the wireshark. You could check easily the integrity of the packet.
Below is a function which calculate correct checksum for a packet
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);
}
call the function to get checksum for ip and tcp.
other then this inorder to use option like options like MSS, NOP, STACK you need to declare all this in your TCP header. and when you are using all this in your program you have to set the value of th_off accordingly

raw sockets in c - bogus header length

#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.

Raw socket sendto failed using C on Linux

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.

Raw socket NOT sending

I am trying to write a sample Raw socket program to clear my understanding of raw sockets. I create a Raw UDP socket and then call sendto. My sendto succeeds but I never see the packet received by the other side. I don't have any receive side running so I am relying on Wireshark running on both the sender and receiver.
I am pasting the code snippet here. Please point out any errors.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include "protHeaders.x"
#include "gen.h"
U16 csum(U16* buf, S32 nwords)
{
U32 sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}/*csum*/
int main(int argc,char** argv)
{
U8 datagram[MAX_IPPACKET];
U8 udpPayLoad[MAX_UDPPAYLOAD];
CustIpHeader* ipH;
CustUdpHeader* udpH;
struct sockaddr_in sin;
S32 sockFd;
S32 one = 1;
const S32* val = &one;
ipH = (CustIpHeader *)datagram;
udpH = (CustUdpHeader *)(datagram + sizeof(CustIpHeader));
memset(datagram,0,sizeof(datagram));
memset(udpPayLoad,0,sizeof(udpPayLoad));
memset(&sin,0,sizeof(struct sockaddr_in));
strcpy(udpPayLoad,"<<<<Aditya>>>>");
sin.sin_family = AF_INET;
sin.sin_port = htons(atoi(argv[4]));
/* fill the Ip header */
ipH->ip_hl = 5;
ipH->ip_v = 4;
ipH->ip_tos = 0;
ipH->ip_len = sizeof(CustIpHeader) + sizeof(CustUdpHeader) + strlen(udpPayLoad);
ipH->ip_id = htonl(54321);
ipH->ip_off = 0;
ipH->ip_p = 17;
ipH->ip_ttl = 65;
ipH->ip_sum = 0;
ipH->ip_src.s_addr = inet_addr(argv[1]);
ipH->ip_dst.s_addr = inet_addr(argv[3]);
/* fill the Udp header */
udpH->uh_sport = htons(atoi(argv[2]));
udpH->uh_dport = htons(atoi(argv[4]));
udpH->uh_len = sizeof(CustUdpHeader) + strlen(udpPayLoad);
udpH->uh_check = 0;
printf("Checksum = %u\n",udpH->uh_check);
/* copy udpPayLoad */
strcpy(datagram+sizeof(CustIpHeader)+sizeof(CustUdpHeader),udpPayLoad);
#if 1
printf("Datagram %p,UdpPayload %p\n",(void *)datagram,(void *)datagram+sizeof(CustIpHeader)+sizeof(CustUdpHeader));
printf("IpHeader %p, UdpHeader %p\n",(void *)ipH,udpH);
#endif
/* fill in the checksum */
ipH->ip_sum = csum((U16 *)datagram,ipH->ip_len >> 1);
printf("Checksum = %u\n",ipH->ip_sum);
if ((sockFd = socket(PF_INET,SOCK_RAW,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETURN(RFAILED);
}
/* doing the IP_HDRINCL call */
if (setsockopt(sockFd,IPPROTO_IP,IP_HDRINCL,val,sizeof(one)) < 0)
{
perror("Client:setsockopt");
}
while(1)
{
if ( sendto(sockFd,
datagram,
ipH->ip_len,
0,
(struct sockaddr *)&sin,
sizeof (sin)) < 0)
{ perror("Client:sendto"); }
else
printf(".");
}
RETURN(ROK);
}
The IP and UDP headers are:
typedef struct _ipheader
{
U8 ip_hl:4,ip_v:4; /* ip_hl: the ip header length in 32bit octets.
* ip_v : ip version (always 4 for our case).
*/
U8 ip_tos; /* reliability of the service. 0x00 is Normal */
U16 ip_len; /* totoal length including ip header,icmp/tcp/udp header
* and payload size in bytes
*/
U16 ip_id; /* sequence no. used for reassembly of fragmented IP packets */
U16 ip_off; /* the fragment offset used for reassembly of fragmented packets */
U16 ip_p; /* the transport layer protocol. can be tcp (6), udp(17) */
U8 ip_ttl; /* time to live */
U16 ip_sum; /* the datagram checksum for the whole IP packet */
struct in_addr ip_src; /* the source IP address, converted to a long format */
struct in_addr ip_dst; /* the desitnation IP address, converted to a long format */
}CustIpHeader; /* total ip header length: 20 bytes */
typedef struct _udpheader
{
U16 uh_sport; /* The source port that a client bind()s to */
U16 uh_dport; /* The desination port that a server bind()s to*/
U16 uh_len; /* The length of udp header and payload data in bytes */
U16 uh_check; /* The checksum of header and data */
}CustUdpHeader; /* total udp header length: 8 bytes (=64 bits) */
I am running as root user, so privileges is not a problem.
Language: C
Os: Linux
I had the wireshark running on a slow system. The packets were indeed being send but the Wireshark could only show them after a gap of 6 minutes or so. Moving to a faster system helped. I am therefore closing this myself.
This may help you to get started http://www.securitytube.net/Raw-Sockets-Basics-Presentation-video.aspx.
if you are using libcap/wincap i would have helped. but above video help you get started.

Resources