]> sjero.net Git - dccp2tcp/blob - encap.c
Checksum computation!
[dccp2tcp] / encap.c
1 /******************************************************************************
2 Utility to convert a DCCP flow to a TCP flow for DCCP analysis via
3                 tcptrace. Encapsulation Functions for DCCP conversion to TCP.
4
5 Copyright (C) 2012  Samuel Jero <sj323707@ohio.edu>
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 Author: Samuel Jero <sj323707@ohio.edu>
21 Date: 11/2012
22
23 Notes:
24         1)CCID2 ONLY
25         2)DCCP MUST use 48 bit sequence numbers
26         3)DCCP DATA packets are not implemented (Linux doesn't use them)
27         4)DCCP Ack packets show up as TCP packets containing one byte
28 ******************************************************************************/
29 #include "dccp2tcp.h"
30 #include "encap.h"
31 #include "checksums.h"
32 #include <pcap/sll.h>
33 #include <netinet/ip6.h>
34
35 /*Encapsulation start point and link layer selector*/
36 int do_encap(int link, struct packet *new, const struct const_packet *old)
37 {
38         switch(link){
39                 case DLT_EN10MB:
40                                 /*Ethernet*/
41                                 if(!ethernet_encap(new, old)){
42                                                 return 0;
43                                 }
44                                 break;
45                 case DLT_RAW:
46                                 /*Raw. Just IP*/
47                                 if(!ipv4_encap(new, old)){
48                                                 return 0;
49                                 }
50                                 break;
51                 case DLT_LINUX_SLL:
52                                 /*Linux Cooked Capture*/
53                                 if(!linux_cooked_encap(new, old)){
54                                         return 0;
55                                 }
56                                 break;
57                 default:
58                                 dbgprintf(0, "Unknown Link Layer\n");
59                                 return 0;
60         }
61
62         /*Adjust libpcap header*/
63         if(new->h->caplen >= new->h->len || new->h->caplen >= new->length){
64                 new->h->caplen=new->length;
65         }
66         new->h->len=new->length;
67
68 return 1;
69 }
70
71 /*Standard Ethernet Encapsulation*/
72 int ethernet_encap(struct packet *new, const struct const_packet *old)
73 {
74                 struct ether_header     *ethh;
75                 struct const_packet nold;
76                 struct packet           nnew;
77
78                 /*Safety checks*/
79                 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
80                         dbgprintf(0,"Error: Ethernet Encapsulation Function given bad data!\n");
81                         return 0;
82                 }
83                 if(old->length < sizeof(struct ether_header) || new->length < sizeof(struct ether_header)){
84                         dbgprintf(0, "Error: Ethernet Encapsulation Function given packet of wrong size!\n");
85                         return 0;
86                 }
87
88                 /*Copy Ethernet header over*/
89                 memcpy(new->data, old->data, sizeof(struct ether_header));
90
91                 /*Cast Pointer*/
92                 ethh=(struct ether_header*)(new->data);
93
94                 /*Adjust pointers and lengths*/
95                 nold.data= old->data+ sizeof(struct ether_header);
96                 nnew.data= new->data + sizeof(struct ether_header);
97                 nold.length= old->length - sizeof(struct ether_header);
98                 nnew.length= new->length - sizeof(struct ether_header);
99                 nnew.h=new->h;
100                 nold.h=old->h;
101
102                 /*Select Next Protocol*/
103                 switch(ntohs(ethh->ether_type)){
104                         case ETHERTYPE_IP:
105                                         if(!ipv4_encap(&nnew, &nold)){
106                                                         return 0;
107                                         }
108                                         break;
109                         case ETHERTYPE_IPV6:
110                                         if(!ipv6_encap(&nnew, &nold)){
111                                                         return 0;
112                                         }
113                                         break;
114                         default:
115                                         dbgprintf(1, "Unknown Next Protocol at Ethernet\n");
116                                         return 0;
117                                         break;
118                 }
119
120                 /*Adjust length*/
121                 new->length=nnew.length + sizeof(struct ether_header);
122 return 1;
123 }
124
125 /*IPv6 Encapsulation*/
126 int ipv6_encap(struct packet *new, const struct const_packet *old)
127 {
128                 struct ip6_hdr          *iph;
129                 struct packet           nnew;
130                 struct const_packet     nold;
131
132                 /*Safety checks*/
133                 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
134                         dbgprintf(0,"Error: IPv6 Encapsulation Function given bad data!\n");
135                         return 0;
136                 }
137                 if(old->length < sizeof(struct ip6_hdr) || new->length < sizeof(struct ip6_hdr)){
138                         dbgprintf(0, "Error: IPv6 Encapsulation Function given packet of wrong size!\n");
139                         return 0;
140                 }
141
142                 /*Copy IPv6 header over*/
143                 memcpy(new->data, old->data, sizeof(struct ip6_hdr));
144
145                 /*Cast Pointer*/
146                 iph=(struct ip6_hdr*)(new->data);
147
148                 /*Adjust pointers and lengths*/
149                 nold.data= old->data + sizeof(struct ip6_hdr);
150                 nnew.data= new->data +sizeof(struct ip6_hdr);
151                 nold.length= old->length - sizeof(struct ip6_hdr);
152                 nnew.length= new->length - sizeof(struct ip6_hdr);
153                 nnew.h=new->h;
154                 nold.h=old->h;
155
156                 /*Confirm that this is IPv6*/
157                 if((ntohl(iph->ip6_ctlun.ip6_un1.ip6_un1_flow) & (0xF0000000)) == (60000000)){
158                         dbgprintf(1, "Note: Packet is not IPv6\n");
159                         return 0;
160                 }
161
162                 /*Select Next Protocol*/
163                 switch(iph->ip6_ctlun.ip6_un1.ip6_un1_nxt){
164                         case 33:
165                                         /*DCCP*/
166                                         nnew.id_len=16;
167                                         nnew.src_id=malloc(nnew.id_len);
168                                         nnew.dest_id=malloc(nnew.id_len);
169                                         if(nnew.src_id==NULL||nnew.dest_id==NULL){
170                                                 dbgprintf(0,"Error: Couldn't allocate Memory\n");
171                                                 exit(1);
172                                         }
173                                         memcpy(nnew.src_id,&iph->ip6_src,nnew.id_len);
174                                         memcpy(nnew.dest_id,&iph->ip6_dst,nnew.id_len);
175                                         if(!convert_packet(&nnew, &nold)){
176                                                 return 0;
177                                         }
178                                         break;
179                         default:
180                                         dbgprintf(1, "Unknown Next Protocol at IPv6\n");
181                                         return 0;
182                                         break;
183                 }
184
185                 /*set ip to indicate that TCP is next protocol*/
186                 iph->ip6_ctlun.ip6_un1.ip6_un1_nxt=6;
187
188                 /*Determine if computed length is reasonable*/
189                 if(nnew.length > 0xFFFF){
190                                 dbgprintf(1, "Error: Given TCP data length is too large for an IPv6 packet!\n");
191                                 return 0;
192                 }
193
194                 /*Adjust IPv6 header to account for packet's total length*/
195                 iph->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(new->length);
196
197                 /*Adjust length*/
198                 new->length=nnew.length + sizeof(struct ip6_hdr);
199
200                 /*Cleanup*/
201                 free(nnew.dest_id);
202                 free(nnew.src_id);
203 return 1;
204 }
205
206 /*IPv4 Encapsulation*/
207 int ipv4_encap(struct packet *new, const struct const_packet *old)
208 {
209                 struct iphdr            *iph;
210                 struct packet           nnew;
211                 struct const_packet     nold;
212
213                 /*Safety checks*/
214                 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
215                         dbgprintf(0,"Error: IPv4 Encapsulation Function given bad data!\n");
216                         return 0;
217                 }
218                 if(old->length < sizeof(struct iphdr) || new->length < sizeof(struct iphdr)){
219                         dbgprintf(0, "Error: IPv4 Encapsulation Function given packet of wrong size!\n");
220                         return 0;
221                 }
222
223                 /*Copy IPv4 header over*/
224                 memcpy(new->data, old->data, sizeof(struct iphdr));
225
226                 /*Cast Pointer*/
227                 iph=(struct iphdr*)(new->data);
228
229                 /*Adjust pointers and lengths*/
230                 nold.data= old->data +iph->ihl*4;
231                 nnew.data= new->data +iph->ihl*4;
232                 nold.length= old->length -iph->ihl*4;
233                 nnew.length= new->length -iph->ihl*4;
234                 nnew.h=new->h;
235                 nold.h=old->h;
236
237                 /*Confirm that this is IPv4*/
238                 if(iph->version!=4){
239                         dbgprintf(1, "Note: Packet is not IPv4\n");
240                         return 0;
241                 }
242
243                 /*Select Next Protocol*/
244                 switch(iph->protocol){
245                         case 33:
246                                         /*DCCP*/
247                                         nnew.id_len=4;
248                                         nnew.src_id=malloc(nnew.id_len);
249                                         nnew.dest_id=malloc(nnew.id_len);
250                                         if(nnew.src_id==NULL||nnew.dest_id==NULL){
251                                                 dbgprintf(0,"Error: Couldn't allocate Memory\n");
252                                                 exit(1);
253                                         }
254                                         memcpy(nnew.src_id,&iph->saddr,nnew.id_len);
255                                         memcpy(nnew.dest_id,&iph->daddr,nnew.id_len);
256                                         if(!convert_packet(&nnew, &nold)){
257                                                 return 0;
258                                         }
259                                         break;
260                         default:
261                                         dbgprintf(1, "Unknown Next Protocol at IPv4\n");
262                                         return 0;
263                                         break;
264                 }
265
266                 /*set ip to indicate that TCP is next protocol*/
267                 iph->protocol=6;
268                 iph->check=htonl(0);
269
270                 /*Adjust length*/
271                 new->length=nnew.length + iph->ihl*4;
272
273                 /*Determine if computed length is reasonable*/
274                 if(nnew.length > 0xFFFF){
275                                 dbgprintf(1, "Error: Given TCP header+data length is too large for an IPv4 packet!\n");
276                                 return 0;
277                 }
278
279                 /*Adjust IPv4 header to account for packet's total length*/
280                 iph->tot_len=htons(new->length);
281
282                 /*Compute IPv4 Checksum*/
283                 iph->check=0;
284                 iph->check=ipv4_chksum(new->data,iph->ihl*4);
285
286                 /*Cleanup*/
287                 free(nnew.src_id);
288                 free(nnew.dest_id);
289 return 1;
290 }
291
292 int linux_cooked_encap(struct packet *new, const struct const_packet *old)
293 {
294         struct sll_header               *slh;
295         struct packet                   nnew;
296         struct const_packet             nold;
297
298
299         /*Safety checks*/
300         if(!new|| !old || !new->data || !old->data || !new->h || !old->h){
301                 dbgprintf(0,"Error: SLL Encapsulation Function given bad data!\n");
302                 return 0;
303         }
304         if(old->length < sizeof(struct sll_header) || new->length < sizeof(struct sll_header)){
305                 dbgprintf(0, "Error: SLL Encapsulation Function given packet of wrong size!\n");
306                 return 0;
307         }
308
309         /*Copy SLL header over*/
310         memcpy(new->data, old->data, sizeof(struct sll_header));
311
312         /*Cast Pointer*/
313         slh=(struct sll_header*)(new->data);
314
315         /*Adjust pointers and lengths*/
316         nold.data= old->data + sizeof(struct sll_header);
317         nnew.data= new->data + sizeof(struct sll_header);
318         nold.length= old->length - sizeof(struct sll_header);
319         nnew.length= new->length- sizeof(struct sll_header);
320         nnew.h=new->h;
321         nold.h=old->h;
322
323         /*Confirm that this is SLL*/
324         if(ntohs(slh->sll_pkttype) > 4){
325                 dbgprintf(1, "Note: Packet is not SLL (Linux Cooked Capture)\n");
326                 return 0;
327         }
328
329         /*Select Next Protocol*/
330         switch(ntohs(slh->sll_protocol)){
331                 case ETHERTYPE_IP:
332                                 if(!ipv4_encap(&nnew, &nold)){
333                                                 return 0;
334                                 }
335                                 break;
336                 case ETHERTYPE_IPV6:
337                                 if(!ipv6_encap(&nnew, &nold)){
338                                                 return 0;
339                                 }
340                                 break;
341                 default:
342                                 dbgprintf(1, "Unknown Next Protocol at SLL\n");
343                                 return 0;
344                                 break;
345         }
346
347         /*Adjust length*/
348         new->length=nnew.length + sizeof(struct sll_header);
349 return 1;
350 }