代码改变世界

Raw Sockets programming on Linux with C

2012-07-13 23:52  Rollen Holt  阅读(328)  评论(0编辑  收藏  举报

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.