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, __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++){
59 if(argv[i][0]!='-' || (argv[i][0]=='-' && strlen(argv[i])==1)){
60 if(dfile==NULL || argv[i][0]=='-'){
61 /*assign first non-dash (or only dash) argument to the dccp file*/
65 tfile=argv[i]; /*assign second non-dash argument to the dccp file*/
67 dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
72 if(argv[i][1]=='d' && strlen(argv[i])==2){ /*debug option*/
75 if(argv[i][1]=='y' && strlen(argv[i])==2){ /*yellow option*/
78 if(argv[i][1]=='g' && strlen(argv[i])==2){ /*green option*/
81 if(argv[i][1]=='s' && strlen(argv[i])==2){ /*sack option*/
87 if(dfile==NULL || tfile==NULL){
88 dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-y] [-g] [-s]\n");
92 /*all options validated*/
95 dbgprintf(1,"Debug On\n");
97 dbgprintf(1,"Tcptrace green line at highest acknowledgment\n");
99 dbgprintf(1,"Tcptrace green line at highest acknowledged acknowledgment\n");
102 dbgprintf(1,"Tcptrace yellow line at highest acknowledgment\n");
104 dbgprintf(1,"Tcptrace yellow line window value (a made up number)\n");
107 dbgprintf(1,"Adding TCP SACKS\n");
109 dbgprintf(1,"Input file: %s\n", dfile);
110 dbgprintf(1,"Output file: %s\n", tfile);
113 /*attempt to open input file*/
114 in=pcap_open_offline(dfile, erbuffer);
116 dbgprintf(0,"Error opening input file\n");
120 /*attempt to open output file*/
121 out=pcap_dump_open(in,tfile);
123 dbgprintf(0,"Error opening output file\n");
129 u_char *user=(u_char*)out;
130 pcap_loop(in, -1, handle_packet, user);
134 pcap_dump_close(out);
136 /*Delete all connections*/
137 cleanup_connections();
142 /*call back function for pcap_loop--do basic packet handling*/
143 void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
146 struct pcap_pkthdr nh;
149 struct const_packet old;
151 /*Determine the link type for this packet*/
152 link_type=pcap_datalink(in);
154 /*create new libpcap header*/
155 memcpy(&nh, h, sizeof(struct pcap_pkthdr));
157 /*Setup packet structs*/
159 old.length=h->caplen;
162 new.length=MAX_PACKET;
164 /*create buffer for new packet*/
165 new.data=ndata=malloc(MAX_PACKET);
167 dbgprintf(0,"Error: Couldn't allocate Memory\n");
171 /*make sure the packet is all zero*/
172 memset(new.data, 0, MAX_PACKET);
174 /*do all the fancy conversions*/
175 if(!do_encap(link_type, &new, &old)){
181 pcap_dump(user,&nh, ndata);
188 /*do all the dccp to tcp conversions*/
189 int convert_packet(struct packet *new, const struct const_packet* old)
192 struct dccp_hdr *dccph;
193 struct dccp_hdr_ext *dccphex;
194 struct dccp_hdr_ack_bits *dccphack;
195 struct host *h1=NULL;
196 struct host *h2=NULL;
204 if(!new || !old || !new->data || !old->data || !new->h || !old->h){
205 dbgprintf(0,"Error: Convert Packet Function given bad data!\n");
209 if(old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)) || new->length < sizeof(struct dccp_hdr)){
210 dbgprintf(0, "Error: DCCP Packet Too short!\n");
214 /*cast header pointers*/
215 tcph=(struct tcphdr*)new->data;
216 dccph=(struct dccp_hdr*)old->data;
217 dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr));
218 dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
220 dbgprintf(2,"Sequence Number: %llu\n", (unsigned long long)(((unsigned long)ntohs(dccph->dccph_seq)<<32) + ntohl(dccphex->dccph_seq_low)));
223 if(get_host(new->src_id, new->dest_id, dccph->dccph_sport, dccph->dccph_dport, &h1, &h2)){
224 dbgprintf(0,"Error: Can't Get Hosts!\n");
227 if(h1==NULL || h2==NULL){
228 dbgprintf(0, "Error: Can't Get Hosts!\n");
232 /*Ensure packet is at least as large as DCCP header*/
233 if(old->length < dccph->dccph_doff*4){
234 dbgprintf(0, "Error: DCCP Header truncated\n");
237 if(dccph->dccph_type!=DCCP_PKT_DATA &&
238 old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) +
239 sizeof(struct dccp_hdr_ack_bits))){
240 dbgprintf(0, "Error: DCCP Packet Too short!\n");
243 /*determine data length*/
244 datalength=old->length - dccph->dccph_doff*4;
245 pd=old->data + dccph->dccph_doff*4;
247 /*set TCP standard features*/
248 tcph->source=dccph->dccph_sport;
249 tcph->dest=dccph->dccph_dport;
251 tcph->check=htonl(0);
254 /*Adjust TCP advertised window size*/
256 tcph->window=htons(30000);
259 /*make changes by packet type*/
260 if(dccph->dccph_type==DCCP_PKT_REQUEST){//DCCP REQUEST -->TCP SYN
261 dbgprintf(2,"Packet Type: Request\n");
264 tcph->window=htons(0);
266 tcph->ack_seq=htonl(0);
267 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
273 /* add Sack-permitted option, if relevant*/
275 tcpopt=(u_char*)(new->data + tcph->doff*4);
287 if(dccph->dccph_type==DCCP_PKT_RESPONSE){//DCCP RESPONSE-->TCP SYN,ACK
288 dbgprintf(2,"Packet Type: Response\n");
289 if(h2->state==OPEN && h1->state==INIT){
290 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
292 tcph->window=htons(0);
294 tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
300 /* add Sack-permitted option, if relevant*/
302 tcpopt=(u_char*)(new->data + tcph->doff*4);
313 if(dccph->dccph_type==DCCP_PKT_DATA){//DCCP DATA----Never seen in packet capture
314 dbgprintf(0,"DCCP Data packet not yet implemented\n");
318 if(dccph->dccph_type==DCCP_PKT_DATAACK){//DCCP DATAACK-->TCP ACK with data
319 dbgprintf(2,"Packet Type: DataAck\n");
321 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
323 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
325 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type));
327 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
330 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
331 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
341 npd=new->data + tcph->doff*4;
342 memcpy(npd, pd, datalength);
345 len= tcph->doff*4 + datalength;
348 if(dccph->dccph_type==DCCP_PKT_ACK){ //DCCP ACK -->TCP ACK with no data
349 dbgprintf(2,"Packet Type: Ack\n");
351 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
353 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
355 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
357 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*1400);
358 if(-interp_ack_vect((u_char*)dccph)*1400 > 65535){
359 printf("Note: TCP Window Overflow @ %d.%d\n", (int)old->h->ts.tv_sec, (int)old->h->ts.tv_usec);
363 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
364 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
374 len=tcph->doff*4 + 1;
377 if(dccph->dccph_type==DCCP_PKT_CLOSEREQ){//DCCP CLOSEREQ----Never seen in packet capture
378 dbgprintf(0,"DCCP CloseReq not yet implemented\n");
382 if(dccph->dccph_type==DCCP_PKT_CLOSE){//DCCP CLOSE-->TCP FIN,ACK
383 dbgprintf(2,"Packet Type: Close\n");
384 update_state(h1,CLOSE);
386 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
388 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
390 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
392 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
395 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
396 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
409 if(dccph->dccph_type==DCCP_PKT_RESET){//DCCP RESET-->TCP FIN,ACK (only seen at end of connection as CLOSE ACK)
410 if(h2->state==CLOSE){
411 update_state(h1,CLOSE);
413 dbgprintf(2,"Packet Type: Reset\n");
415 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
417 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
419 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type));
421 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
424 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
425 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
438 if(dccph->dccph_type==DCCP_PKT_SYNC){//DCCP SYNC
439 dbgprintf(2,"Packet Type: Sync\n");
441 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
443 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
445 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
447 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
449 tcph->window=htons(0);
452 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
453 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
466 if(dccph->dccph_type==DCCP_PKT_SYNCACK){//DCCP SYNACK
467 dbgprintf(2,"Packet Type: SyncAck\n");
469 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)));
471 tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph)));
473 tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type));
475 tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low)));
477 tcph->window=htons(0);
480 if(sack!=2 || interp_ack_vect((u_char*)dccph)){
481 ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
494 if(dccph->dccph_type==DCCP_PKT_INVALID){//DCCP INVALID----Never seen in packet capture
495 dbgprintf(0,"Invalid DCCP Packet!!\n");
504 /*Parse Ack Vector Options
505 * Returns the Number of packets since last recorded loss*/
506 unsigned int interp_ack_vect(u_char* hdr)
508 int hdrlen=((struct dccp_hdr*)hdr)->dccph_doff*4;
509 //struct dccp_hdr_ext* e=(struct dccp_hdr_ext*)hdr + sizeof(struct dccp_hdr);
518 /*setup pointer to DCCP options and determine how long the options are*/
519 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
520 opt=hdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
525 /*One byte options (no length)*/
532 /*Check option length*/
535 dbgprintf(0, "Warning: Option would extend into packet data\n");
539 /*Ack Vector Option*/
540 if(*opt==38 || *opt==39){
543 /*loop through Vector*/
545 /*ack vector works BACKWARDS through time*/
547 /*keep track of total packets recieved and if
548 a packet is lost, subtract all packets received
550 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
555 if((*cur & 0xC0)==0x00){ //received packet
556 bp+= (*cur & 0x3F)+1;
559 if(((*cur& 0xC0)!= 0xC0) && ((*cur& 0xC0)!= 0x00) && ((*cur& 0xC0)!= 0x40)){
560 dbgprintf(1, "Warning: Invalid Ack Vector!! (Linux will handle poorly!)\n");
571 dbgprintf(2,"Ack vector adding: %i\n", additional);
576 /* Setup Sequence Number Structure*/
577 u_int32_t initialize_seq(struct host *seq, __be32 initial)
579 /*set default values*/
584 seq->table=(struct tbl*)malloc(sizeof(struct tbl)*TBL_SZ);
585 if(seq->table==NULL){
586 dbgprintf(0,"Can't Allocate Memory!\n");
590 /*add first sequence number*/
591 seq->table[0].old=initial;
592 seq->table[0].new=initial;
593 seq->table[0].type=DCCP_PKT_REQUEST;
594 seq->table[0].size=0;
595 update_state(seq,OPEN);
600 /*Convert Sequence Numbers*/
601 u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type)
605 dbgprintf(0,"ERROR NULL POINTER!\n");
609 if(seq->table==NULL){
610 dbgprintf(1, "Warning: Connection uninitialized\n");
611 return initialize_seq(seq, num);
614 /*account for missing packets*/
615 if(num - seq->table[seq->cur].old +1 >=100){
616 dbgprintf(1,"Missing more than 100 packets!\n");
618 while(seq->table[seq->cur].old +1 < num && seq->table[seq->cur].old +1 > 0){
620 if(num - seq->table[seq->cur].old +1 <100){
621 dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
623 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
624 seq->table[seq->cur].old=seq->table[prev].old+1;
625 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
626 seq->table[seq->cur].size=size;
627 seq->table[seq->cur].type=type;
631 seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
632 seq->table[seq->cur].old=num;
633 seq->table[seq->cur].size=size;
634 seq->table[seq->cur].type=type;
635 if(seq->table[prev].type==DCCP_PKT_REQUEST || seq->table[prev].type==DCCP_PKT_RESPONSE){
636 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
637 seq->table[seq->cur].size=1;
638 return seq->table[prev].new + seq->table[prev].size+1;
640 if(type==DCCP_PKT_DATA || type==DCCP_PKT_DATAACK || type==DCCP_PKT_ACK){
641 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
642 return seq->table[seq->cur].new+1;
644 if(type==DCCP_PKT_SYNC || type==DCCP_PKT_SYNCACK){
645 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
646 return seq->table[seq->cur].new;
648 seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
649 return seq->table[seq->cur].new +1;
653 /*Convert Ack Numbers*/
654 u_int32_t convert_ack(struct host *seq, __be32 num)
657 dbgprintf(0,"ERROR NULL POINTER!\n");
661 if(seq->table==NULL){
662 dbgprintf(1, "Warning: Connection uninitialized\n");
663 initialize_seq(seq, num);
666 /*loop through table looking for the DCCP ack number*/
667 for(int i=0; i < seq->size; i++){
668 if(seq->table[i].old==num){
669 return seq->table[i].new + seq->table[i].size + 1; /*TCP acks the sequence number plus 1*/
673 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
678 /* Get size of packet being acked*/
679 int acked_packet_size(struct host *seq, __be32 num)
682 dbgprintf(0,"ERROR NULL POINTER!\n");
686 if(seq->table==NULL){
687 dbgprintf(1, "Warning: Connection uninitialized\n");
688 initialize_seq(seq, num);
691 /*loop through table looking for the DCCP ack number*/
692 for(int i=0; i < seq->size; i++){
693 if(seq->table[i].old==num){
694 return seq->table[i].size;
698 dbgprintf(1, "Error: Address Not Found! looking for: %X\n", num);
703 /*Ack Vector to SACK Option*/
704 void ack_vect2sack(struct host *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, __be32 dccpack)
706 int hdrlen=((struct dccp_hdr*)dccphdr)->dccph_doff*4;
723 /*setup pointer to DCCP options and determine how long the options are*/
724 optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits);
725 opt=dccphdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits);
727 /*setup tcp pointers*/
736 /*setup tcp control variables*/
745 /*One byte options (no length)*/
754 dbgprintf(0, "Warning: Option would extend into packet data\n");
758 /*Ack Vector Option*/
759 if(*opt==38 || *opt==39){
762 /*loop through Vector*/
764 /*ack vector works BACKWARDS through time*/
766 if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet
767 if(cont){ /*end a SACK run, if one is started*/
768 bR=convert_ack(seq, bp);
778 bp= bp - (*cur & 0x3F)- 1;
781 if((*cur & 0xC0)==0x00){ //received packet
782 if(!cont){ /*if no SACK run and we can start another one, do so*/
784 bL=convert_ack(seq, bp);
790 bp = bp -(*cur & 0x3F)- 1;
801 /*if we are in the middle of a SACK run, close it*/
803 bR=convert_ack(seq, bp);
811 /*adjust length if the option is actually added*/
819 void dbgprintf(int level, const char *fmt, ...)
824 vfprintf(stderr, fmt, args);