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 ******************************************************************************/
33 int debug=0; /*set to 1 to turn on debugging information*/
34 int yellow=0; /*tcptrace yellow line as currently acked packet*/
35 int green=0; /*tcptrace green line as currently acked packet*/
36 int sack=0; /*add TCP SACKS*/
38 pcap_t* in; /*libpcap input file discriptor*/
39 pcap_dumper_t *out; /*libpcap output file discriptor*/
40 struct connection *chead; /*connection list*/
44 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
45 int convert_packet(struct packet *new, const struct const_packet* old);
46 unsigned int interp_ack_vect(u_char* hdr);
47 u_int32_t initialize_seq(struct host *seq, __be32 initial);
48 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type);
49 u_int32_t convert_ack(struct host *seq, __be32 num);
50 int acked_packet_size(struct host *seq, __be32 num);
51 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack);
54 /*Parse commandline options and open files*/
55 int main(int argc, char *argv[])
62 /*parse commandline options*/
63 if(argc<3 || argc > 9){
64 dbgprintf(0, "Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
68 /*loop through commandline options*/
69 for(int i=1; i < argc; i++){
70 if(argv[i][0]!='-' || (argv[i][0]=='-' && strlen(argv[i])==1)){
71 if(dfile==NULL || argv[i][0]=='-'){
72 /*assign first non-dash (or only dash) argument to the dccp file*/
76 tfile=argv[i]; /*assign second non-dash argument to the dccp file*/
78 dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
83 if(argv[i][1]=='d' && strlen(argv[i])==2){ /*debug option*/
86 if(argv[i][1]=='y' && strlen(argv[i])==2){ /*yellow option*/
89 if(argv[i][1]=='g' && strlen(argv[i])==2){ /*green option*/
92 if(argv[i][1]=='s' && strlen(argv[i])==2){ /*sack option*/
98 if(dfile==NULL || tfile==NULL){
99 dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
103 /*all options validated*/
106 dbgprintf(1,"Debug On\n");
108 dbgprintf(1,"Tcptrace green line at highest acknowledgment\n");
110 dbgprintf(1,"Tcptrace green line at highest acknowledged acknowledgment\n");
113 dbgprintf(1,"Tcptrace yellow line at highest acknowledgment\n");
115 dbgprintf(1,"Tcptrace yellow line window value (a made up number)\n");
118 dbgprintf(1,"Adding TCP SACKS\n");
120 dbgprintf(1,"Input file: %s\n", dfile);
121 dbgprintf(1,"Output file: %s\n", tfile);
124 /*attempt to open input file*/
125 in=pcap_open_offline(dfile, erbuffer);
127 dbgprintf(0,"Error opening input file\n");
131 /*attempt to open output file*/
132 out=pcap_dump_open(in,tfile);
134 dbgprintf(0,"Error opening output file\n");
140 u_char *user=(u_char*)out;
141 pcap_loop(in, -1, handle_packet, user);
145 pcap_dump_close(out);
147 /*Delete all connections*/
148 cleanup_connections();
153 /*call back function for pcap_loop--do basic packet handling*/
154 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
157 struct pcap_pkthdr nh;
160 struct const_packet old;
162 /*Determine the link type for this packet*/
163 link_type=pcap_datalink(in);
165 /*create new libpcap header*/
166 memcpy(&nh, h, sizeof(struct pcap_pkthdr));
168 /*Setup packet structs*/
170 old.length=h->caplen;
175 new.length=MAX_PACKET;
179 /*create buffer for new packet*/
180 new.data=ndata=malloc(MAX_PACKET);
182 dbgprintf(0,"Error: Couldn't allocate Memory\n");
186 /*make sure the packet is all zero*/
187 memset(new.data, 0, MAX_PACKET);
189 /*do all the fancy conversions*/
190 if(!do_encap(link_type, &new, &old)){
196 pcap_dump(user,&nh, ndata);
203 /*do all the dccp to tcp conversions*/
204 int convert_packet(struct packet *new, const struct const_packet* old)
207 struct dccp_hdr *dccph;
208 struct dccp_hdr_ext *dccphex;
209 struct dccp_hdr_ack_bits *dccphack;
210 struct host *h1=NULL;
211 struct host *h2=NULL;
219 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
220 dbgprintf(0,"Error: Convert Packet Function given bad data!\n");
224 if(old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)) || new->length < sizeof(struct dccp_hdr)){
225 dbgprintf(0, "Error: DCCP Packet Too short!\n");
229 /*cast header pointers*/
230 tcph=(struct tcphdr*)new->data;
231 dccph=(struct dccp_hdr*)old->data;
232 dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr));
233 dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
235 dbgprintf(2,"Sequence Number: %llu\n", (unsigned long long)
236 (((unsigned long)ntohs(dccph->dccph_seq)<<32) + ntohl(dccphex->dccph_seq_low)));
239 if(get_host(new->src_id, new->dest_id, new->id_len,
240 dccph->dccph_sport, dccph->dccph_dport, &h1, &h2)){
241 dbgprintf(0,"Error: Can't Get Hosts!\n");
244 if(h1==NULL || h2==NULL){
245 dbgprintf(0, "Error: Can't Get Hosts!\n");
249 /*Ensure packet is at least as large as DCCP header*/
250 if(old->length < dccph->dccph_doff*4){
251 dbgprintf(0, "Error: DCCP Header truncated\n");
254 if(dccph->dccph_type!=DCCP_PKT_DATA &&
255 old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) +
256 sizeof(struct dccp_hdr_ack_bits))){
257 dbgprintf(0, "Error: DCCP Packet Too short!\n");
260 /*determine data length*/
261 datalength=old->length - dccph->dccph_doff*4;
262 pd=old->data + dccph->dccph_doff*4;
264 /*set TCP standard features*/
265 tcph->source=dccph->dccph_sport;
266 tcph->dest=dccph->dccph_dport;
268 tcph->check=htonl(0);
271 /*Adjust TCP advertised window size*/
273 tcph->window=htons(30000);
276 /*make changes by packet type*/
277 if(dccph->dccph_type==DCCP_PKT_REQUEST){//DCCP REQUEST -->TCP SYN
278 dbgprintf(2,"Packet Type: Request\n");
281 tcph->window=htons(0);
283 tcph->ack_seq=htonl(0);
284 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
290 /* add Sack-permitted option, if relevant*/
292 tcpopt=(u_char*)(new->data + tcph->doff*4);
304 if(dccph->dccph_type==DCCP_PKT_RESPONSE){//DCCP RESPONSE-->TCP SYN,ACK
305 dbgprintf(2,"Packet Type: Response\n");
306 if(h2->state==OPEN && h1->state==INIT){
307 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
309 tcph->window=htons(0);
311 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
317 /* add Sack-permitted option, if relevant*/
319 tcpopt=(u_char*)(new->data + tcph->doff*4);
330 if(dccph->dccph_type==DCCP_PKT_DATA){//DCCP DATA----Never seen in packet capture
331 dbgprintf(0,"DCCP Data packet not yet implemented\n");
335 if(dccph->dccph_type==DCCP_PKT_DATAACK){//DCCP DATAACK-->TCP ACK with data
336 dbgprintf(2,"Packet Type: DataAck\n");
338 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
340 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
342 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type));
344 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
347 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
348 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
358 npd=new->data + tcph->doff*4;
359 memcpy(npd, pd, datalength);
362 len= tcph->doff*4 + datalength;
365 if(dccph->dccph_type==DCCP_PKT_ACK){ //DCCP ACK -->TCP ACK with no data
366 dbgprintf(2,"Packet Type: Ack\n");
368 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
370 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
372 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
374 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*1400);
375 if(-interp_ack_vect((u_char*)dccph)*1400 > 65535){
376 printf("Note: TCP Window Overflow @ %d.%d\n", (int)old->h->ts.tv_sec, (int)old->h->ts.tv_usec);
380 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
381 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
391 len=tcph->doff*4 + 1;
394 if(dccph->dccph_type==DCCP_PKT_CLOSEREQ){//DCCP CLOSEREQ----Never seen in packet capture
395 dbgprintf(0,"DCCP CloseReq not yet implemented\n");
399 if(dccph->dccph_type==DCCP_PKT_CLOSE){//DCCP CLOSE-->TCP FIN,ACK
400 dbgprintf(2,"Packet Type: Close\n");
401 update_state(h1,CLOSE);
403 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
405 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
407 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
409 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
412 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
413 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
426 if(dccph->dccph_type==DCCP_PKT_RESET){//DCCP RESET-->TCP FIN,ACK (only seen at end of connection as CLOSE ACK)
427 if(h2->state==CLOSE){
428 update_state(h1,CLOSE);
430 dbgprintf(2,"Packet Type: Reset\n");
432 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
434 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
436 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
438 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
441 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
442 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
455 if(dccph->dccph_type==DCCP_PKT_SYNC){//DCCP SYNC
456 dbgprintf(2,"Packet Type: Sync\n");
458 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
460 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
462 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
464 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
466 tcph->window=htons(0);
469 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
470 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
483 if(dccph->dccph_type==DCCP_PKT_SYNCACK){//DCCP SYNACK
484 dbgprintf(2,"Packet Type: SyncAck\n");
486 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
488 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
490 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
492 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
494 tcph->window=htons(0);
497 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
498 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
511 if(dccph->dccph_type==DCCP_PKT_INVALID){//DCCP INVALID----Never seen in packet capture
512 dbgprintf(0,"Invalid DCCP Packet!!\n");
521 /*Parse Ack Vector Options
522 * Returns the Number of packets since last recorded loss*/
523 unsigned int interp_ack_vect(u_char* hdr)
525 int hdrlen=((struct dccp_hdr*)hdr)->dccph_doff*4;
526 //struct dccp_hdr_ext* e=(struct dccp_hdr_ext*)hdr + sizeof(struct dccp_hdr);
535 /*setup pointer to DCCP options and determine how long the options are*/
536 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
537 opt=hdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
542 /*One byte options (no length)*/
549 /*Check option length*/
552 dbgprintf(0, "Warning: Option would extend into packet data\n");
556 /*Ack Vector Option*/
557 if(*opt==38 || *opt==39){
560 /*loop through Vector*/
562 /*ack vector works BACKWARDS through time*/
564 /*keep track of total packets recieved and if
565 a packet is lost, subtract all packets received
567 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
572 if((*cur & 0xC0)==0x00){ //received packet
573 bp+= (*cur & 0x3F)+1;
576 if(((*cur& 0xC0)!= 0xC0) && ((*cur& 0xC0)!= 0x00) && ((*cur& 0xC0)!= 0x40)){
577 dbgprintf(1, "Warning: Invalid Ack Vector!! (Linux will handle poorly!)\n");
588 dbgprintf(2,"Ack vector adding: %i\n", additional);
593 /* Setup Sequence Number Structure*/
594 u_int32_t initialize_seq(struct host *seq, __be32 initial)
596 /*set default values*/
601 seq->table=(struct tbl*)malloc(sizeof(struct tbl)*TBL_SZ);
602 if(seq->table==NULL){
603 dbgprintf(0,"Can't Allocate Memory!\n");
607 /*add first sequence number*/
608 seq->table[0].old=initial;
609 seq->table[0].new=initial;
610 seq->table[0].type=DCCP_PKT_REQUEST;
611 seq->table[0].size=0;
612 update_state(seq,OPEN);
617 /*Convert Sequence Numbers*/
618 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type)
622 dbgprintf(0,"ERROR NULL POINTER!\n");
626 if(seq->table==NULL){
627 dbgprintf(1, "Warning: Connection uninitialized\n");
628 return initialize_seq(seq, num);
631 /*account for missing packets*/
632 if(num - seq->table[seq->cur].old +1 >=100){
633 dbgprintf(1,"Missing more than 100 packets!\n");
635 while(seq->table[seq->cur].old +1 < num && seq->table[seq->cur].old +1 > 0){
637 if(num - seq->table[seq->cur].old +1 <100){
638 dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
640 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
641 seq->table[seq->cur].old=seq->table[prev].old+1;
642 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
643 seq->table[seq->cur].size=size;
644 seq->table[seq->cur].type=type;
648 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
649 seq->table[seq->cur].old=num;
650 seq->table[seq->cur].size=size;
651 seq->table[seq->cur].type=type;
652 if(seq->table[prev].type==DCCP_PKT_REQUEST || seq->table[prev].type==DCCP_PKT_RESPONSE){
653 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
654 seq->table[seq->cur].size=1;
655 return seq->table[prev].new + seq->table[prev].size+1;
657 if(type==DCCP_PKT_DATA || type==DCCP_PKT_DATAACK || type==DCCP_PKT_ACK){
658 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
659 return seq->table[seq->cur].new+1;
661 if(type==DCCP_PKT_SYNC || type==DCCP_PKT_SYNCACK){
662 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
663 return seq->table[seq->cur].new;
665 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
666 return seq->table[seq->cur].new +1;
670 /*Convert Ack Numbers*/
671 u_int32_t convert_ack(struct host *seq, __be32 num)
674 dbgprintf(0,"ERROR NULL POINTER!\n");
678 if(seq->table==NULL){
679 dbgprintf(1, "Warning: Connection uninitialized\n");
680 initialize_seq(seq, num);
683 /*loop through table looking for the DCCP ack number*/
684 for(int i=0; i < seq->size; i++){
685 if(seq->table[i].old==num){
686 return seq->table[i].new + seq->table[i].size + 1; /*TCP acks the sequence number plus 1*/
690 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
695 /* Get size of packet being acked*/
696 int acked_packet_size(struct host *seq, __be32 num)
699 dbgprintf(0,"ERROR NULL POINTER!\n");
703 if(seq->table==NULL){
704 dbgprintf(1, "Warning: Connection uninitialized\n");
705 initialize_seq(seq, num);
708 /*loop through table looking for the DCCP ack number*/
709 for(int i=0; i < seq->size; i++){
710 if(seq->table[i].old==num){
711 return seq->table[i].size;
715 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
720 /*Ack Vector to SACK Option*/
721 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack)
723 int hdrlen=((struct dccp_hdr*)dccphdr)->dccph_doff*4;
740 /*setup pointer to DCCP options and determine how long the options are*/
741 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
742 opt=dccphdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
744 /*setup tcp pointers*/
753 /*setup tcp control variables*/
762 /*One byte options (no length)*/
771 dbgprintf(0, "Warning: Option would extend into packet data\n");
775 /*Ack Vector Option*/
776 if(*opt==38 || *opt==39){
779 /*loop through Vector*/
781 /*ack vector works BACKWARDS through time*/
783 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
784 if(cont){ /*end a SACK run, if one is started*/
785 bR=convert_ack(seq, bp);
795 bp= bp - (*cur & 0x3F)- 1;
798 if((*cur & 0xC0)==0x00){ //received packet
799 if(!cont){ /*if no SACK run and we can start another one, do so*/
801 bL=convert_ack(seq, bp);
807 bp = bp -(*cur & 0x3F)- 1;
818 /*if we are in the middle of a SACK run, close it*/
820 bR=convert_ack(seq, bp);
828 /*adjust length if the option is actually added*/
836 void dbgprintf(int level, const char *fmt, ...)
841 vfprintf(stderr, fmt, args);