1 /******************************************************************************
2 Utility to convert a DCCP flow to a TCP flow for DCCP analysis via
5 Copyright (C) 2012 Samuel Jero <sj323707@ohio.edu>
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.
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.
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/>.
20 Author: Samuel Jero <sj323707@ohio.edu>
25 2)DCCP MUST use 48 bit sequence numbers
26 3)Checksums are not computed (they are zeroed)
27 4)DCCP DATA packets are not implemented (Linux doesn't use them)
28 5)DCCP Ack packets show up as TCP packets containing one byte
29 ******************************************************************************/
32 unsigned int interp_ack_vect(u_char* hdr);
33 u_int32_t initialize_seq(struct host *seq, __be32 initial);
34 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type);
35 u_int32_t convert_ack(struct host *seq, __be32 num);
36 int acked_packet_size(struct host *seq, __be32 num);
37 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack);
39 /*do all the dccp to tcp conversions*/
40 int ccid2_convert_packet(struct packet *new, const struct const_packet* old)
43 struct dccp_hdr *dccph;
44 struct dccp_hdr_ext *dccphex;
45 struct dccp_hdr_ack_bits *dccphack;
54 /*cast header pointers*/
55 tcph=(struct tcphdr*)new->data;
56 dccph=(struct dccp_hdr*)old->data;
57 dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr));
58 dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
61 if(get_host(new->src_id, new->dest_id, new->id_len,
62 dccph->dccph_sport, dccph->dccph_dport, &h1, &h2)){
63 dbgprintf(0,"Error: Can't Get Hosts!\n");
66 if(h1==NULL || h2==NULL){
67 dbgprintf(0, "Error: Can't Get Hosts!\n");
71 /*Ensure packet is at least as large as DCCP header*/
72 if(dccph->dccph_type!=DCCP_PKT_DATA &&
73 old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) +
74 sizeof(struct dccp_hdr_ack_bits))){
75 dbgprintf(0, "Error: DCCP Packet Too short!\n");
78 /*determine data length*/
79 datalength=old->length - dccph->dccph_doff*4;
80 pd=old->data + dccph->dccph_doff*4;
82 /*set TCP standard features*/
83 tcph->source=dccph->dccph_sport;
84 tcph->dest=dccph->dccph_dport;
89 /*Adjust TCP advertised window size*/
91 tcph->window=htons(30000);
94 /*make changes by packet type*/
95 if(dccph->dccph_type==DCCP_PKT_REQUEST){//DCCP REQUEST -->TCP SYN
96 dbgprintf(2,"Packet Type: Request\n");
99 tcph->window=htons(0);
101 tcph->ack_seq=htonl(0);
102 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
108 /* add Sack-permitted option, if relevant*/
110 tcpopt=(u_char*)(new->data + tcph->doff*4);
122 if(dccph->dccph_type==DCCP_PKT_RESPONSE){//DCCP RESPONSE-->TCP SYN,ACK
123 dbgprintf(2,"Packet Type: Response\n");
124 if(h2->state==OPEN && h1->state==INIT){
125 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
127 tcph->window=htons(0);
129 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
135 /* add Sack-permitted option, if relevant*/
137 tcpopt=(u_char*)(new->data + tcph->doff*4);
148 if(dccph->dccph_type==DCCP_PKT_DATA){//DCCP DATA----Never seen in packet capture
149 dbgprintf(0,"DCCP Data packet not yet implemented\n");
153 if(dccph->dccph_type==DCCP_PKT_DATAACK){//DCCP DATAACK-->TCP ACK with data
154 dbgprintf(2,"Packet Type: DataAck\n");
156 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
158 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
160 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type));
162 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
165 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
166 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
176 npd=new->data + tcph->doff*4;
177 memcpy(npd, pd, datalength);
180 len= tcph->doff*4 + datalength;
183 if(dccph->dccph_type==DCCP_PKT_ACK){ //DCCP ACK -->TCP ACK with no data
184 dbgprintf(2,"Packet Type: Ack\n");
186 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
188 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
190 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
192 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*1400);
193 if(-interp_ack_vect((u_char*)dccph)*1400 > 65535){
194 printf("Note: TCP Window Overflow @ %d.%d\n", (int)old->h->ts.tv_sec, (int)old->h->ts.tv_usec);
198 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
199 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
209 len=tcph->doff*4 + 1;
212 if(dccph->dccph_type==DCCP_PKT_CLOSEREQ){//DCCP CLOSEREQ----Never seen in packet capture
213 dbgprintf(0,"DCCP CloseReq not yet implemented\n");
217 if(dccph->dccph_type==DCCP_PKT_CLOSE){//DCCP CLOSE-->TCP FIN,ACK
218 dbgprintf(2,"Packet Type: Close\n");
219 update_state(h1,CLOSE);
221 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
223 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
225 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
227 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
230 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
231 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
244 if(dccph->dccph_type==DCCP_PKT_RESET){//DCCP RESET-->TCP FIN,ACK (only seen at end of connection as CLOSE ACK)
245 if(h2->state==CLOSE){
246 update_state(h1,CLOSE);
248 dbgprintf(2,"Packet Type: Reset\n");
250 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
252 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
254 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
256 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
259 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
260 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
273 if(dccph->dccph_type==DCCP_PKT_SYNC){//DCCP SYNC
274 dbgprintf(2,"Packet Type: Sync\n");
276 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
278 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
280 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
282 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
284 tcph->window=htons(0);
287 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
288 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
301 if(dccph->dccph_type==DCCP_PKT_SYNCACK){//DCCP SYNACK
302 dbgprintf(2,"Packet Type: SyncAck\n");
304 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
306 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
308 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
310 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
312 tcph->window=htons(0);
315 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
316 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
329 if(dccph->dccph_type==DCCP_PKT_INVALID){//DCCP INVALID----Never seen in packet capture
330 dbgprintf(0,"Invalid DCCP Packet!!\n");
339 /*Parse Ack Vector Options
340 * Returns the Number of packets since last recorded loss*/
341 unsigned int interp_ack_vect(u_char* hdr)
343 int hdrlen=((struct dccp_hdr*)hdr)->dccph_doff*4;
344 //struct dccp_hdr_ext* e=(struct dccp_hdr_ext*)hdr + sizeof(struct dccp_hdr);
353 /*setup pointer to DCCP options and determine how long the options are*/
354 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
355 opt=hdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
360 /*One byte options (no length)*/
367 /*Check option length*/
370 dbgprintf(0, "Warning: Option would extend into packet data\n");
374 /*Ack Vector Option*/
375 if(*opt==38 || *opt==39){
378 /*loop through Vector*/
380 /*ack vector works BACKWARDS through time*/
382 /*keep track of total packets recieved and if
383 a packet is lost, subtract all packets received
385 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
390 if((*cur & 0xC0)==0x00){ //received packet
391 bp+= (*cur & 0x3F)+1;
394 if(((*cur& 0xC0)!= 0xC0) && ((*cur& 0xC0)!= 0x00) && ((*cur& 0xC0)!= 0x40)){
395 dbgprintf(1, "Warning: Invalid Ack Vector!! (Linux will handle poorly!)\n");
406 dbgprintf(2,"Ack vector adding: %i\n", additional);
411 /* Setup Sequence Number Structure*/
412 u_int32_t initialize_seq(struct host *seq, __be32 initial)
414 /*set default values*/
419 seq->table=(struct tbl*)malloc(sizeof(struct tbl)*TBL_SZ);
420 if(seq->table==NULL){
421 dbgprintf(0,"Can't Allocate Memory!\n");
425 /*add first sequence number*/
426 seq->table[0].old=initial;
427 seq->table[0].new=initial;
428 seq->table[0].type=DCCP_PKT_REQUEST;
429 seq->table[0].size=0;
430 update_state(seq,OPEN);
435 /*Convert Sequence Numbers*/
436 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type)
440 dbgprintf(0,"ERROR NULL POINTER!\n");
444 if(seq->table==NULL){
445 dbgprintf(1, "Warning: Connection uninitialized\n");
446 return initialize_seq(seq, num);
449 /*account for missing packets*/
450 if(num - seq->table[seq->cur].old +1 >=100){
451 dbgprintf(1,"Missing more than 100 packets!\n");
453 while(seq->table[seq->cur].old +1 < num && seq->table[seq->cur].old +1 > 0){
455 if(num - seq->table[seq->cur].old +1 <100){
456 dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
458 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
459 seq->table[seq->cur].old=seq->table[prev].old+1;
460 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
461 seq->table[seq->cur].size=size;
462 seq->table[seq->cur].type=type;
466 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
467 seq->table[seq->cur].old=num;
468 seq->table[seq->cur].size=size;
469 seq->table[seq->cur].type=type;
470 if(seq->table[prev].type==DCCP_PKT_REQUEST || seq->table[prev].type==DCCP_PKT_RESPONSE){
471 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
472 seq->table[seq->cur].size=1;
473 return seq->table[prev].new + seq->table[prev].size+1;
475 if(type==DCCP_PKT_DATA || type==DCCP_PKT_DATAACK || type==DCCP_PKT_ACK){
476 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
477 return seq->table[seq->cur].new+1;
479 if(type==DCCP_PKT_SYNC || type==DCCP_PKT_SYNCACK){
480 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
481 return seq->table[seq->cur].new;
483 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
484 return seq->table[seq->cur].new +1;
488 /*Convert Ack Numbers*/
489 u_int32_t convert_ack(struct host *seq, __be32 num)
492 dbgprintf(0,"ERROR NULL POINTER!\n");
496 if(seq->table==NULL){
497 dbgprintf(1, "Warning: Connection uninitialized\n");
498 initialize_seq(seq, num);
501 /*loop through table looking for the DCCP ack number*/
502 for(int i=0; i < seq->size; i++){
503 if(seq->table[i].old==num){
504 return seq->table[i].new + seq->table[i].size + 1; /*TCP acks the sequence number plus 1*/
508 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
513 /* Get size of packet being acked*/
514 int acked_packet_size(struct host *seq, __be32 num)
517 dbgprintf(0,"ERROR NULL POINTER!\n");
521 if(seq->table==NULL){
522 dbgprintf(1, "Warning: Connection uninitialized\n");
523 initialize_seq(seq, num);
526 /*loop through table looking for the DCCP ack number*/
527 for(int i=0; i < seq->size; i++){
528 if(seq->table[i].old==num){
529 return seq->table[i].size;
533 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
538 /*Ack Vector to SACK Option*/
539 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack)
541 int hdrlen=((struct dccp_hdr*)dccphdr)->dccph_doff*4;
558 /*setup pointer to DCCP options and determine how long the options are*/
559 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
560 opt=dccphdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
562 /*setup tcp pointers*/
571 /*setup tcp control variables*/
580 /*One byte options (no length)*/
589 dbgprintf(0, "Warning: Option would extend into packet data\n");
593 /*Ack Vector Option*/
594 if(*opt==38 || *opt==39){
597 /*loop through Vector*/
599 /*ack vector works BACKWARDS through time*/
601 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
602 if(cont){ /*end a SACK run, if one is started*/
603 bR=convert_ack(seq, bp);
613 bp= bp - (*cur & 0x3F)- 1;
616 if((*cur & 0xC0)==0x00){ //received packet
617 if(!cont){ /*if no SACK run and we can start another one, do so*/
619 bL=convert_ack(seq, bp);
625 bp = bp -(*cur & 0x3F)- 1;
636 /*if we are in the middle of a SACK run, close it*/
638 bR=convert_ack(seq, bp);
646 /*adjust length if the option is actually added*/