Raw sockets or packets contain user defined IP headers. Its as simple as that.
Here we shall consider sending a raw tcp packets. A tcp packets has 3 parts : IP header + TCP header + data
The structure of IP Header as given by RFC 791 is :
1 |
0 1 2 3 |
2 |
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
4 |
|Version| IHL |Type of Service| Total Length | |
5 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
6 |
| Identification |Flags| Fragment Offset | |
7 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
8 |
| Time to Live | Protocol | Header Checksum | |
9 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
10 |
| Source Address | |
11 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
12 |
| Destination Address | |
13 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
14 |
| Options | Padding | |
15 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
The structure of a TCP header as given by RFC 793 :
1 |
0 1 2 3 |
2 |
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
3 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
4 |
| Source Port | Destination Port | |
5 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
6 |
| Sequence Number | |
7 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
8 |
| Acknowledgment Number | |
9 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
10 |
| Data | |U|A|P|R|S|F| | |
11 |
| Offset| Reserved |R|C|S|S|Y|I| Window | |
12 |
| | |G|K|H|T|N|N| | |
13 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
14 |
| Checksum | Urgent Pointer | |
15 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
16 |
| Options | Padding | |
17 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
18 |
| data | |
19 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
To create a raw socket :
1 |
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
|
Another option to make sure the kernel uses the raw headers :
1 |
{ |
2 |
int one = 1;
|
3 |
const int *val = &one;
|
4 |
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
|
5 |
printf ("Warning: Cannot set HDRINCL!\n");
|
6 |
} |
Below is an example code which constructs a raw TCP packet :
Code :
1 |
/* |
2 |
Raw Sockets with LINUX
|
3 |
*/ |
4 |
#include<stdio.h> |
5 |
#include<netinet/tcp.h> //Provides declarations for tcp header |
6 |
#include<netinet/ip.h> //Provides declarations for ip header |
7 |
8 |
//Checksum calculation function |
9 |
unsigned short csum (unsigned short *buf, int nwords)
|
10 |
{ |
11 |
unsigned long sum;
|
12 |
|
13 |
for (sum = 0; nwords > 0; nwords--)
|
14 |
sum += *buf++;
|
15 |
|
16 |
sum = (sum >> 16) + (sum & 0xffff);
|
17 |
sum += (sum >> 16);
|
18 |
|
19 |
return ~sum;
|
20 |
} |
21 |
22 |
int main (void)
|
23 |
{ |
24 |
//Create a raw socket
|
25 |
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
|
26 |
//Datagram to represent the packet
|
27 |
char datagram[4096];
|
28 |
//IP header
|
29 |
struct iphdr *iph = (struct iphdr *) datagram;
|
30 |
//TCP header
|
31 |
struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
|
32 |
struct sockaddr_in sin;
|
33 |
|
34 |
sin.sin_family = AF_INET;
|
35 |
sin.sin_port = htons(40);
|
36 |
sin.sin_addr.s_addr = inet_addr ("60.61.62.63");
|
37 |
|
38 |
memset (datagram, 0, 4096); /* zero out the buffer */
|
39 |
|
40 |
//Fill in the IP Header
|
41 |
iph->ihl = 5;
|
42 |
iph->version = 4;
|
43 |
iph->tos = 0;
|
44 |
iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
|
45 |
iph->id = htonl (54321); //Id of this packet
|
46 |
iph->frag_off = 0;
|
47 |
iph->ttl = 255;
|
48 |
iph->protocol = 6;
|
49 |
iph->check = 0; //Set to 0 before calculating checksum
|
50 |
iph->saddr = inet_addr ("1.2.3.4"); //Spoof the source ip address
|
51 |
iph->daddr = sin.sin_addr.s_addr;
|
52 |
|
53 |
//TCP Header
|
54 |
tcph->source = htons (1234);
|
55 |
tcph->dest = htons (85);
|
56 |
tcph->seq = random ();
|
57 |
tcph->ack_seq = 0;
|
58 |
tcph->doff = 0; /* first and only tcp segment */
|
59 |
tcph->syn = 1;
|
60 |
tcph->window = htonl (65535); /* maximum allowed window size */
|
61 |
tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
|
62 |
should fill in the correct checksum during transmission */
|
63 |
tcph->urg_ptr = 0;
|
64 |
//Now the IP checksum
|
65 |
iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
|
66 |
|
67 |
//IP_HDRINCL to tell the kernel that headers are included in the packet
|
68 |
{
|
69 |
int one = 1;
|
70 |
const int *val = &one;
|
71 |
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
|
72 |
printf ("Warning: Cannot set HDRINCL!\n");
|
73 |
}
|
74 |
|
75 |
while (1)
|
76 |
{
|
77 |
//Send the packet
|
78 |
if (sendto (s, /* our socket */
|
79 |
datagram, /* the buffer containing headers and data */
|
80 |
iph->tot_len, /* total length of our datagram */
|
81 |
0, /* routing flags, normally always 0 */
|
82 |
(struct sockaddr *) &sin, /* socket addr, just like in */
|
83 |
sizeof (sin)) < 0) /* a normal send() */
|
84 |
printf ("error\n");
|
85 |
else
|
86 |
printf (".");
|
87 |
}
|
88 |
|
89 |
return 0;
|
90 |
} |
Remember to run the above code with root privileges. Raw sockets require root privileges
User wireshark to check the output.