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 :
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
11 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
12 |
| Destination Address | |
13 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
15 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
The structure of a TCP header as given by RFC 793 :
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
7 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
8 |
| Acknowledgment Number | |
9 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
10 |
| Data | |U|A|P|R|S|F| | |
11 |
| Offset| Reserved |R|C|S|S|Y|I| Window | |
13 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
14 |
| Checksum | Urgent Pointer | |
15 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
17 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
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 :
4 |
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
|
5 |
printf ( "Warning: Cannot set HDRINCL!\n" );
|
Below is an example code which constructs a raw TCP packet :
Code :
5 |
#include<netinet/tcp.h> //Provides declarations for tcp header |
6 |
#include<netinet/ip.h> //Provides declarations for ip header |
8 |
//Checksum calculation function |
9 |
unsigned short csum (unsigned short *buf, int nwords)
|
13 |
for (sum = 0; nwords > 0; nwords--)
|
16 |
sum = (sum >> 16) + (sum & 0xffff);
|
25 |
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
|
26 |
//Datagram to represent the packet
|
29 |
struct iphdr *iph = ( struct iphdr *) datagram;
|
31 |
struct tcphdr *tcph = ( struct tcphdr *) (datagram + sizeof ( struct ip));
|
32 |
struct sockaddr_in sin ;
|
34 |
sin .sin_family = AF_INET;
|
35 |
sin .sin_port = htons(40);
|
36 |
sin .sin_addr.s_addr = inet_addr ( "60.61.62.63" );
|
38 |
memset (datagram, 0, 4096); /* zero out the buffer */
|
40 |
//Fill in the IP Header
|
44 |
iph->tot_len = sizeof ( struct ip) + sizeof ( struct tcphdr);
|
45 |
iph->id = htonl (54321); //Id of this packet
|
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;
|
54 |
tcph->source = htons (1234);
|
55 |
tcph->dest = htons (85);
|
56 |
tcph->seq = random ();
|
58 |
tcph->doff = 0; /* first and only tcp segment */
|
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 */
|
65 |
iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
|
67 |
//IP_HDRINCL to tell the kernel that headers are included in the packet
|
70 |
const int *val = &one;
|
71 |
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
|
72 |
printf ( "Warning: Cannot set HDRINCL!\n" );
|
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() */
|
Remember to run the above code with root privileges. Raw sockets require root privileges
User wireshark to check the output.
时间: 2025-01-21 09:26:45