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.