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)Only implements those packet types normally used in a session
14 5)DCCP Ack packets show up as TCP packets containing one byte
15 6)Very little error checking of packet headers
16 ******************************************************************************/
20 int debug=0; /*set to 1 to turn on debugging information*/
21 int yellow=0; /*tcptrace yellow line as currently acked packet*/
22 int green=0; /*tcptrace green line as currently acked packet*/
23 int sack=0; /*add TCP SACKS*/
25 pcap_t* in; /*libpcap input file discriptor*/
26 pcap_dumper_t *out; /*libpcap output file discriptor*/
27 struct connection *chead; /*connection list*/
31 void PcapSavePacket(struct pcap_pkthdr *h, u_char *data);
32 void process_packets();
33 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
34 int convert_packet(struct packet *new, const struct const_packet* old);
35 unsigned int interp_ack_vect(u_char* hdr);
36 u_int32_t initialize_seq(struct host *seq, __be16 source, __be32 initial);
37 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type);
38 u_int32_t convert_ack(struct host *seq, __be32 num);
39 int acked_packet_size(struct host *seq, __be32 num);
40 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack);
43 /*Parse commandline options and open files*/
44 int main(int argc, char *argv[])
51 /*parse commandline options*/
52 if(argc<3 || argc > 9){
53 dbgprintf(0, "Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
57 /*loop through commandline options*/
58 for(int i=1; i < argc; i++){
60 if(dfile==NULL){ /*assign first non-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);
138 /*call back function for pcap_loop--do basic packet handling*/
139 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
142 struct pcap_pkthdr nh;
145 struct const_packet old;
147 /*Determine the link type for this packet*/
148 link_type=pcap_datalink(in);
150 /*create new libpcap header*/
151 memcpy(&nh, h, sizeof(struct pcap_pkthdr));
153 /*Setup packet structs*/
155 old.length=h->caplen;
158 new.length=MAX_PACKET;
160 /*create buffer for new packet*/
161 new.data=ndata=malloc(MAX_PACKET);
163 dbgprintf(0,"Error: Couldn't allocate Memory\n");
167 /*make sure the packet is all zero*/
168 memset(new.data, 0, MAX_PACKET);
170 /*do all the fancy conversions*/
171 if(!do_encap(link_type, &new, &old)){
177 pcap_dump(user,&nh, ndata);
184 /*do all the dccp to tcp conversions*/
185 int convert_packet(struct packet *new, const struct const_packet* old)
188 struct dccp_hdr *dccph;
189 struct dccp_hdr_ext *dccphex;
190 struct dccp_hdr_ack_bits *dccphack;
191 struct host *h1=NULL;
192 struct host *h2=NULL;
200 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
201 dbgprintf(0,"Error: Convert Packet Function given bad data!\n");
205 if(old->length < sizeof(struct dccp_hdr) || new->length < sizeof(struct dccp_hdr)){
206 dbgprintf(0, "Error: Convert Packet Function given packet of wrong size!\n");
210 /*cast header pointers*/
211 tcph=(struct tcphdr*)new->data;
212 tcpopt=new->data + sizeof(struct tcphdr);
213 dccph=(struct dccp_hdr*)old->data;
214 dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr));
215 dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
217 dbgprintf(2,"Sequence Number: %llu\n", (unsigned long long)(((unsigned long)ntohs(dccph->dccph_seq)<<32) + ntohl(dccphex->dccph_seq_low)));
220 if(get_host(new->src_id, new->dest_id, dccph->dccph_sport, dccph->dccph_dport, &h1, &h2)){
221 dbgprintf(0,"Error: Can't Get Hosts!\n");
224 if(h1==NULL || h2==NULL){
225 dbgprintf(0, "Error: Can't Get Hosts!\n");
229 /*determine data length*/
230 datalength=old->length - dccph->dccph_doff*4;
231 pd=old->data + dccph->dccph_doff*4;
233 /*set TCP standard features*/
234 tcph->source=dccph->dccph_sport;
235 tcph->dest=dccph->dccph_dport;
237 tcph->check=htonl(0);
240 /*Adjust TCP advertised window size*/
242 tcph->window=htons(30000);
245 /*make changes by packet type*/
246 if(dccph->dccph_type==DCCP_PKT_REQUEST){//DCCP REQUEST -->TCP SYN
247 dbgprintf(2,"Packet Type: Request\n");
250 tcph->window=htons(0);
252 tcph->ack_seq=htonl(0);
253 tcph->seq=htonl(initialize_seq(h1, dccph->dccph_sport, ntohl(dccphex->dccph_seq_low)));
259 /* add Sack-permitted option, if relevant*/
272 if(dccph->dccph_type==DCCP_PKT_RESPONSE){//DCCP RESPONSE-->TCP SYN,ACK
273 dbgprintf(2,"Packet Type: Response\n");
274 if(h2->state==OPEN && h1->state==INIT){
275 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
277 tcph->window=htons(0);
279 tcph->seq=htonl(initialize_seq(h1, dccph->dccph_sport, ntohl(dccphex->dccph_seq_low)));
285 /* add Sack-permitted option, if relevant*/
297 if(dccph->dccph_type==DCCP_PKT_DATA){//DCCP DATA----Never seen in packet capture
298 dbgprintf(0,"DCCP Data packet not yet implemented\n");
302 if(dccph->dccph_type==DCCP_PKT_DATAACK){//DCCP DATAACK-->TCP ACK with data
303 dbgprintf(2,"Packet Type: DataAck\n");
305 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
307 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
309 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type));
311 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
314 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
315 ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
325 npd=new->data + tcph->doff*4;
326 memcpy(npd, pd, datalength);
329 len= tcph->doff*4 + datalength;
332 if(dccph->dccph_type==DCCP_PKT_ACK){ //DCCP ACK -->TCP ACK with no data
333 dbgprintf(2,"Packet Type: Ack\n");
335 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
337 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
339 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
341 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*1400);
342 if(-interp_ack_vect((u_char*)dccph)*1400 > 65535){
343 printf("Note: TCP Window Overflow @ %d.%d\n", (int)old->h->ts.tv_sec, (int)old->h->ts.tv_usec);
347 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
348 ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
358 len=tcph->doff*4 + 1;
361 if(dccph->dccph_type==DCCP_PKT_CLOSEREQ){//DCCP CLOSEREQ----Never seen in packet capture
362 dbgprintf(0,"DCCP CloseReq not yet implemented\n");
366 if(dccph->dccph_type==DCCP_PKT_CLOSE){//DCCP CLOSE-->TCP FIN,ACK
367 dbgprintf(2,"Packet Type: Close\n");
368 update_state(h1,CLOSE);
370 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
372 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
374 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
376 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
379 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
380 ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
393 if(dccph->dccph_type==DCCP_PKT_RESET){//DCCP RESET-->TCP FIN,ACK (only seen at end of connection as CLOSE ACK)
394 if(h2->state==CLOSE){
395 update_state(h1,CLOSE);
397 dbgprintf(2,"Packet Type: Reset\n");
399 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
401 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
403 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
405 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
408 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
409 ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
422 if(dccph->dccph_type==DCCP_PKT_SYNC){//DCCP SYNC
423 dbgprintf(2,"Packet Type: Sync\n");
425 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
427 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
429 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
431 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
433 tcph->window=htons(0);
436 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
437 ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
450 if(dccph->dccph_type==DCCP_PKT_SYNCACK){//DCCP SYNACK
451 dbgprintf(2,"Packet Type: SyncAck\n");
453 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
455 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
457 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
459 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
461 tcph->window=htons(0);
464 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
465 ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
478 if(dccph->dccph_type==DCCP_PKT_INVALID){//DCCP INVALID----Never seen in packet capture
479 dbgprintf(0,"Invalid DCCP Packet!!\n");
488 /*Parse Ack Vector Options
489 * Returns the Number of packets since last recorded loss*/
490 unsigned int interp_ack_vect(u_char* hdr)
492 int hdrlen=((struct dccp_hdr*)hdr)->dccph_doff*4;
493 //struct dccp_hdr_ext* e=(struct dccp_hdr_ext*)hdr + sizeof(struct dccp_hdr);
502 /*setup pointer to DCCP options and determine how long the options are*/
503 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
504 opt=hdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
510 /*One byte options (no length)*/
517 /*Ack Vector Option*/
518 if(*opt==38 || *opt==39){
521 /*loop through Vector*/
523 /*ack vector works BACKWARDS through time*/
525 /*keep track of total packets recieved and if
526 a packet is lost, subtract all packets received
528 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
533 if((*cur & 0xC0)==0x00){ //received packet
534 bp+= (*cur & 0x3F)+1;
537 if(((*cur& 0xF0)!= 0xC0) && ((*cur& 0xF0)!= 0x00) && ((*cur& 0xF0)!= 0x40)){
538 dbgprintf(1, "Warning: Invalid Ack Vector!! (Linux will handle poorly!)\n");
549 dbgprintf(2,"Ack vector adding: %i\n", additional);
554 /* Setup Sequence Number Structure*/
555 u_int32_t initialize_seq(struct host *seq, __be16 source, __be32 initial)
557 /*set default values*/
562 seq->table=(struct tbl*)malloc(sizeof(struct tbl)*TBL_SZ);
563 if(seq->table==NULL){
564 dbgprintf(0,"Can't Allocate Memory!\n");
568 /*add first sequence number*/
569 seq->table[0].old=initial;
570 seq->table[0].new=initial;
571 seq->table[0].type=DCCP_PKT_REQUEST;
572 seq->table[0].size=0;
573 update_state(seq,OPEN);
578 /*Convert Sequence Numbers*/
579 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type)
583 dbgprintf(0,"ERROR NULL POINTER!\n");
587 if(seq->table==NULL){
588 dbgprintf(1, "Warning: Connection uninitialized\n");
589 return initialize_seq(seq, 0, num);
592 /*account for missing packets*/
593 while(seq->table[seq->cur].old +1 < num && seq->table[seq->cur].old +1 > 0){
595 dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
596 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
597 seq->table[seq->cur].old=seq->table[prev].old+1;
598 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
599 seq->table[seq->cur].size=size;
600 seq->table[seq->cur].type=type;
604 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
605 seq->table[seq->cur].old=num;
606 seq->table[seq->cur].size=size;
607 seq->table[seq->cur].type=type;
608 if(seq->table[prev].type==DCCP_PKT_REQUEST || seq->table[prev].type==DCCP_PKT_RESPONSE){
609 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
610 seq->table[seq->cur].size=1;
611 return seq->table[prev].new + seq->table[prev].size+1;
613 if(type==DCCP_PKT_DATA || type==DCCP_PKT_DATAACK || type==DCCP_PKT_ACK){
614 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
615 return seq->table[seq->cur].new+1;
617 if(type==DCCP_PKT_SYNC || type==DCCP_PKT_SYNCACK){
618 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
619 return seq->table[seq->cur].new;
621 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
622 return seq->table[seq->cur].new +1;
626 /*Convert Ack Numbers*/
627 u_int32_t convert_ack(struct host *seq, __be32 num)
630 dbgprintf(0,"ERROR NULL POINTER!\n");
634 if(seq->table==NULL){
635 dbgprintf(1, "Warning: Connection uninitialized\n");
636 initialize_seq(seq, 0, num);
639 /*loop through table looking for the DCCP ack number*/
640 for(int i=0; i < seq->size; i++){
641 if(seq->table[i].old==num){
642 return seq->table[i].new + seq->table[i].size + 1; /*TCP acks the sequence number plus 1*/
646 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
651 /* Get size of packet being acked*/
652 int acked_packet_size(struct host *seq, __be32 num)
655 dbgprintf(0,"ERROR NULL POINTER!\n");
659 if(seq->table==NULL){
660 dbgprintf(1, "Warning: Connection uninitialized\n");
661 initialize_seq(seq, 0, num);
664 /*loop through table looking for the DCCP ack number*/
665 for(int i=0; i < seq->size; i++){
666 if(seq->table[i].old==num){
667 return seq->table[i].size;
671 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
676 /*Ack Vector to SACK Option*/
677 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack)
679 int hdrlen=((struct dccp_hdr*)dccphdr)->dccph_doff*4;
696 /*setup pointer to DCCP options and determine how long the options are*/
697 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
698 opt=dccphdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
700 /*setup tcp pointers*/
709 /*setup tcp control variables*/
719 /*One byte options (no length)*/
726 /*Ack Vector Option*/
727 if(*opt==38 || *opt==39){
730 /*loop through Vector*/
732 /*ack vector works BACKWARDS through time*/
734 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
735 if(cont){ /*end a SACK run, if one is started*/
736 bR=convert_ack(seq, bp);
746 bp= bp - (*cur & 0x3F)- 1;
749 if((*cur & 0xC0)==0x00){ //received packet
750 if(!cont){ /*if no SACK run and we can start another one, do so*/
752 bL=convert_ack(seq, bp);
758 bp = bp -(*cur & 0x3F)- 1;
769 /*if we are in the middle of a SACK run, close it*/
771 bR=convert_ack(seq, bp);
779 /*adjust length if the option is actually added*/
787 void dbgprintf(int level, const char *fmt, ...)
792 vfprintf(stderr, fmt, args);