1 /******************************************************************************
6 Description: Program to convert a DCCP flow to a TCP flow for DCCP analysis via
11 2)DCCP MUST use 48 bit sequence numbers
12 3)Checksums are not computed (they are zeroed)
13 4)DCCP DATA packets are not implemented (Linux doesn't use them)
14 5)DCCP Ack packets show up as TCP packets containing one byte
15 ******************************************************************************/
19 int debug=0; /*set to 1 to turn on debugging information*/
20 int yellow=0; /*tcptrace yellow line as currently acked packet*/
21 int green=0; /*tcptrace green line as currently acked packet*/
22 int sack=0; /*add TCP SACKS*/
24 pcap_t* in; /*libpcap input file discriptor*/
25 pcap_dumper_t *out; /*libpcap output file discriptor*/
26 struct connection *chead; /*connection list*/
30 void PcapSavePacket(struct pcap_pkthdr *h, u_char *data);
31 void process_packets();
32 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
33 int convert_packet(struct packet *new, const struct const_packet* old);
34 unsigned int interp_ack_vect(u_char* hdr);
35 u_int32_t initialize_seq(struct host *seq, __be32 initial);
36 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type);
37 u_int32_t convert_ack(struct host *seq, __be32 num);
38 int acked_packet_size(struct host *seq, __be32 num);
39 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack);
42 /*Parse commandline options and open files*/
43 int main(int argc, char *argv[])
50 /*parse commandline options*/
51 if(argc<3 || argc > 9){
52 dbgprintf(0, "Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
56 /*loop through commandline options*/
57 for(int i=1; i < argc; i++){
58 if(argv[i][0]!='-' || (argv[i][0]=='-' && strlen(argv[i])==1)){
59 if(dfile==NULL || argv[i][0]=='-'){
60 /*assign first non-dash (or only dash) argument to the dccp file*/
64 tfile=argv[i]; /*assign second non-dash argument to the dccp file*/
66 dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
71 if(argv[i][1]=='d' && strlen(argv[i])==2){ /*debug option*/
74 if(argv[i][1]=='y' && strlen(argv[i])==2){ /*yellow option*/
77 if(argv[i][1]=='g' && strlen(argv[i])==2){ /*green option*/
80 if(argv[i][1]=='s' && strlen(argv[i])==2){ /*sack option*/
86 if(dfile==NULL || tfile==NULL){
87 dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
91 /*all options validated*/
94 dbgprintf(1,"Debug On\n");
96 dbgprintf(1,"Tcptrace green line at highest acknowledgment\n");
98 dbgprintf(1,"Tcptrace green line at highest acknowledged acknowledgment\n");
101 dbgprintf(1,"Tcptrace yellow line at highest acknowledgment\n");
103 dbgprintf(1,"Tcptrace yellow line window value (a made up number)\n");
106 dbgprintf(1,"Adding TCP SACKS\n");
108 dbgprintf(1,"Input file: %s\n", dfile);
109 dbgprintf(1,"Output file: %s\n", tfile);
112 /*attempt to open input file*/
113 in=pcap_open_offline(dfile, erbuffer);
115 dbgprintf(0,"Error opening input file\n");
119 /*attempt to open output file*/
120 out=pcap_dump_open(in,tfile);
122 dbgprintf(0,"Error opening output file\n");
128 u_char *user=(u_char*)out;
129 pcap_loop(in, -1, handle_packet, user);
133 pcap_dump_close(out);
135 /*Delete all connections*/
136 cleanup_connections();
141 /*call back function for pcap_loop--do basic packet handling*/
142 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
145 struct pcap_pkthdr nh;
148 struct const_packet old;
150 /*Determine the link type for this packet*/
151 link_type=pcap_datalink(in);
153 /*create new libpcap header*/
154 memcpy(&nh, h, sizeof(struct pcap_pkthdr));
156 /*Setup packet structs*/
158 old.length=h->caplen;
161 new.length=MAX_PACKET;
163 /*create buffer for new packet*/
164 new.data=ndata=malloc(MAX_PACKET);
166 dbgprintf(0,"Error: Couldn't allocate Memory\n");
170 /*make sure the packet is all zero*/
171 memset(new.data, 0, MAX_PACKET);
173 /*do all the fancy conversions*/
174 if(!do_encap(link_type, &new, &old)){
180 pcap_dump(user,&nh, ndata);
187 /*do all the dccp to tcp conversions*/
188 int convert_packet(struct packet *new, const struct const_packet* old)
191 struct dccp_hdr *dccph;
192 struct dccp_hdr_ext *dccphex;
193 struct dccp_hdr_ack_bits *dccphack;
194 struct host *h1=NULL;
195 struct host *h2=NULL;
203 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
204 dbgprintf(0,"Error: Convert Packet Function given bad data!\n");
208 if(old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)) || new->length < sizeof(struct dccp_hdr)){
209 dbgprintf(0, "Error: DCCP Packet Too short!\n");
213 /*cast header pointers*/
214 tcph=(struct tcphdr*)new->data;
215 dccph=(struct dccp_hdr*)old->data;
216 dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr));
217 dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
219 dbgprintf(2,"Sequence Number: %llu\n", (unsigned long long)(((unsigned long)ntohs(dccph->dccph_seq)<<32) + ntohl(dccphex->dccph_seq_low)));
222 if(get_host(new->src_id, new->dest_id, dccph->dccph_sport, dccph->dccph_dport, &h1, &h2)){
223 dbgprintf(0,"Error: Can't Get Hosts!\n");
226 if(h1==NULL || h2==NULL){
227 dbgprintf(0, "Error: Can't Get Hosts!\n");
231 /*Ensure packet is at least as large as DCCP header*/
232 if(old->length < dccph->dccph_doff*4){
233 dbgprintf(0, "Error: DCCP Header truncated\n");
236 if(dccph->dccph_type!=DCCP_PKT_DATA &&
237 old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) +
238 sizeof(struct dccp_hdr_ack_bits))){
239 dbgprintf(0, "Error: DCCP Packet Too short!\n");
242 /*determine data length*/
243 datalength=old->length - dccph->dccph_doff*4;
244 pd=old->data + dccph->dccph_doff*4;
246 /*set TCP standard features*/
247 tcph->source=dccph->dccph_sport;
248 tcph->dest=dccph->dccph_dport;
250 tcph->check=htonl(0);
253 /*Adjust TCP advertised window size*/
255 tcph->window=htons(30000);
258 /*make changes by packet type*/
259 if(dccph->dccph_type==DCCP_PKT_REQUEST){//DCCP REQUEST -->TCP SYN
260 dbgprintf(2,"Packet Type: Request\n");
263 tcph->window=htons(0);
265 tcph->ack_seq=htonl(0);
266 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
272 /* add Sack-permitted option, if relevant*/
274 tcpopt=(u_char*)(new->data + tcph->doff*4);
286 if(dccph->dccph_type==DCCP_PKT_RESPONSE){//DCCP RESPONSE-->TCP SYN,ACK
287 dbgprintf(2,"Packet Type: Response\n");
288 if(h2->state==OPEN && h1->state==INIT){
289 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
291 tcph->window=htons(0);
293 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
299 /* add Sack-permitted option, if relevant*/
301 tcpopt=(u_char*)(new->data + tcph->doff*4);
312 if(dccph->dccph_type==DCCP_PKT_DATA){//DCCP DATA----Never seen in packet capture
313 dbgprintf(0,"DCCP Data packet not yet implemented\n");
317 if(dccph->dccph_type==DCCP_PKT_DATAACK){//DCCP DATAACK-->TCP ACK with data
318 dbgprintf(2,"Packet Type: DataAck\n");
320 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
322 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
324 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type));
326 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
329 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
330 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
340 npd=new->data + tcph->doff*4;
341 memcpy(npd, pd, datalength);
344 len= tcph->doff*4 + datalength;
347 if(dccph->dccph_type==DCCP_PKT_ACK){ //DCCP ACK -->TCP ACK with no data
348 dbgprintf(2,"Packet Type: Ack\n");
350 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
352 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
354 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
356 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*1400);
357 if(-interp_ack_vect((u_char*)dccph)*1400 > 65535){
358 printf("Note: TCP Window Overflow @ %d.%d\n", (int)old->h->ts.tv_sec, (int)old->h->ts.tv_usec);
362 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
363 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
373 len=tcph->doff*4 + 1;
376 if(dccph->dccph_type==DCCP_PKT_CLOSEREQ){//DCCP CLOSEREQ----Never seen in packet capture
377 dbgprintf(0,"DCCP CloseReq not yet implemented\n");
381 if(dccph->dccph_type==DCCP_PKT_CLOSE){//DCCP CLOSE-->TCP FIN,ACK
382 dbgprintf(2,"Packet Type: Close\n");
383 update_state(h1,CLOSE);
385 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
387 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
389 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
391 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
394 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
395 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
408 if(dccph->dccph_type==DCCP_PKT_RESET){//DCCP RESET-->TCP FIN,ACK (only seen at end of connection as CLOSE ACK)
409 if(h2->state==CLOSE){
410 update_state(h1,CLOSE);
412 dbgprintf(2,"Packet Type: Reset\n");
414 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
416 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
418 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
420 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
423 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
424 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
437 if(dccph->dccph_type==DCCP_PKT_SYNC){//DCCP SYNC
438 dbgprintf(2,"Packet Type: Sync\n");
440 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
442 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
444 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
446 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
448 tcph->window=htons(0);
451 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
452 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
465 if(dccph->dccph_type==DCCP_PKT_SYNCACK){//DCCP SYNACK
466 dbgprintf(2,"Packet Type: SyncAck\n");
468 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
470 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
472 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
474 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
476 tcph->window=htons(0);
479 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
480 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
493 if(dccph->dccph_type==DCCP_PKT_INVALID){//DCCP INVALID----Never seen in packet capture
494 dbgprintf(0,"Invalid DCCP Packet!!\n");
503 /*Parse Ack Vector Options
504 * Returns the Number of packets since last recorded loss*/
505 unsigned int interp_ack_vect(u_char* hdr)
507 int hdrlen=((struct dccp_hdr*)hdr)->dccph_doff*4;
508 //struct dccp_hdr_ext* e=(struct dccp_hdr_ext*)hdr + sizeof(struct dccp_hdr);
517 /*setup pointer to DCCP options and determine how long the options are*/
518 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
519 opt=hdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
524 /*One byte options (no length)*/
531 /*Check option length*/
534 dbgprintf(0, "Warning: Option would extend into packet data\n");
538 /*Ack Vector Option*/
539 if(*opt==38 || *opt==39){
542 /*loop through Vector*/
544 /*ack vector works BACKWARDS through time*/
546 /*keep track of total packets recieved and if
547 a packet is lost, subtract all packets received
549 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
554 if((*cur & 0xC0)==0x00){ //received packet
555 bp+= (*cur & 0x3F)+1;
558 if(((*cur& 0xC0)!= 0xC0) && ((*cur& 0xC0)!= 0x00) && ((*cur& 0xC0)!= 0x40)){
559 dbgprintf(1, "Warning: Invalid Ack Vector!! (Linux will handle poorly!)\n");
570 dbgprintf(2,"Ack vector adding: %i\n", additional);
575 /* Setup Sequence Number Structure*/
576 u_int32_t initialize_seq(struct host *seq, __be32 initial)
578 /*set default values*/
583 seq->table=(struct tbl*)malloc(sizeof(struct tbl)*TBL_SZ);
584 if(seq->table==NULL){
585 dbgprintf(0,"Can't Allocate Memory!\n");
589 /*add first sequence number*/
590 seq->table[0].old=initial;
591 seq->table[0].new=initial;
592 seq->table[0].type=DCCP_PKT_REQUEST;
593 seq->table[0].size=0;
594 update_state(seq,OPEN);
599 /*Convert Sequence Numbers*/
600 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type)
604 dbgprintf(0,"ERROR NULL POINTER!\n");
608 if(seq->table==NULL){
609 dbgprintf(1, "Warning: Connection uninitialized\n");
610 return initialize_seq(seq, num);
613 /*account for missing packets*/
614 if(num - seq->table[seq->cur].old +1 >=100){
615 dbgprintf(1,"Missing more than 100 packets!\n");
617 while(seq->table[seq->cur].old +1 < num && seq->table[seq->cur].old +1 > 0){
619 if(num - seq->table[seq->cur].old +1 <100){
620 dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
622 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
623 seq->table[seq->cur].old=seq->table[prev].old+1;
624 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
625 seq->table[seq->cur].size=size;
626 seq->table[seq->cur].type=type;
630 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
631 seq->table[seq->cur].old=num;
632 seq->table[seq->cur].size=size;
633 seq->table[seq->cur].type=type;
634 if(seq->table[prev].type==DCCP_PKT_REQUEST || seq->table[prev].type==DCCP_PKT_RESPONSE){
635 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
636 seq->table[seq->cur].size=1;
637 return seq->table[prev].new + seq->table[prev].size+1;
639 if(type==DCCP_PKT_DATA || type==DCCP_PKT_DATAACK || type==DCCP_PKT_ACK){
640 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
641 return seq->table[seq->cur].new+1;
643 if(type==DCCP_PKT_SYNC || type==DCCP_PKT_SYNCACK){
644 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
645 return seq->table[seq->cur].new;
647 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
648 return seq->table[seq->cur].new +1;
652 /*Convert Ack Numbers*/
653 u_int32_t convert_ack(struct host *seq, __be32 num)
656 dbgprintf(0,"ERROR NULL POINTER!\n");
660 if(seq->table==NULL){
661 dbgprintf(1, "Warning: Connection uninitialized\n");
662 initialize_seq(seq, num);
665 /*loop through table looking for the DCCP ack number*/
666 for(int i=0; i < seq->size; i++){
667 if(seq->table[i].old==num){
668 return seq->table[i].new + seq->table[i].size + 1; /*TCP acks the sequence number plus 1*/
672 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
677 /* Get size of packet being acked*/
678 int acked_packet_size(struct host *seq, __be32 num)
681 dbgprintf(0,"ERROR NULL POINTER!\n");
685 if(seq->table==NULL){
686 dbgprintf(1, "Warning: Connection uninitialized\n");
687 initialize_seq(seq, num);
690 /*loop through table looking for the DCCP ack number*/
691 for(int i=0; i < seq->size; i++){
692 if(seq->table[i].old==num){
693 return seq->table[i].size;
697 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
702 /*Ack Vector to SACK Option*/
703 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack)
705 int hdrlen=((struct dccp_hdr*)dccphdr)->dccph_doff*4;
722 /*setup pointer to DCCP options and determine how long the options are*/
723 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
724 opt=dccphdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
726 /*setup tcp pointers*/
735 /*setup tcp control variables*/
744 /*One byte options (no length)*/
753 dbgprintf(0, "Warning: Option would extend into packet data\n");
757 /*Ack Vector Option*/
758 if(*opt==38 || *opt==39){
761 /*loop through Vector*/
763 /*ack vector works BACKWARDS through time*/
765 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
766 if(cont){ /*end a SACK run, if one is started*/
767 bR=convert_ack(seq, bp);
777 bp= bp - (*cur & 0x3F)- 1;
780 if((*cur & 0xC0)==0x00){ //received packet
781 if(!cont){ /*if no SACK run and we can start another one, do so*/
783 bL=convert_ack(seq, bp);
789 bp = bp -(*cur & 0x3F)- 1;
800 /*if we are in the middle of a SACK run, close it*/
802 bR=convert_ack(seq, bp);
810 /*adjust length if the option is actually added*/
818 void dbgprintf(int level, const char *fmt, ...)
823 vfprintf(stderr, fmt, args);