X-Git-Url: http://sjero.net/git/?p=dccp2tcp;a=blobdiff_plain;f=dccp2tcp.c;h=db9ca53181241d0e9a4461778ee8ed2edacef554;hp=fb648cf2f8e4508f56eb71264a8295d6a4c41ce6;hb=20f1a0d4c106ab4927e9b1c1ad097fbb9179eae7;hpb=f1192c520b51dd718d81d268b98c82e4688f13f4 diff --git a/dccp2tcp.c b/dccp2tcp.c index fb648cf..db9ca53 100644 --- a/dccp2tcp.c +++ b/dccp2tcp.c @@ -2,7 +2,7 @@ Utility to convert a DCCP flow to a TCP flow for DCCP analysis via tcptrace. -Copyright (C) 2012 Samuel Jero +Copyright (C) 2013 Samuel Jero This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,13 +18,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . Author: Samuel Jero -Date: 11/2012 +Date: 02/2013 Notes: - 1)CCID2 ONLY - 2)DCCP MUST use 48 bit sequence numbers - 3)DCCP DATA packets are not implemented (Linux doesn't use them) - 4)DCCP Ack packets show up as TCP packets containing one byte + 1)DCCP MUST use 48 bit sequence numbers + 2)DCCP Ack packets show up as TCP packets containing one byte ******************************************************************************/ #include "dccp2tcp.h" @@ -45,6 +43,20 @@ struct connection *chead; /*connection list*/ void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes); +int handle_request(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_response(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_dataack(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_ack(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_closereq(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_close(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_reset(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_sync(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_syncack(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int handle_data(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2); +int parse_options(const u_char* opt_start, int len, struct hcon* A, struct hcon* B); +int process_feature(const u_char* feat, int len, int confirm, int L, struct hcon* A, struct hcon* B); +void ack_vect2sack(struct hcon *seq, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, + __be32 dccpack, struct hcon* o_hcn); void version(); void usage(); @@ -206,8 +218,8 @@ int convert_packet(struct packet *new, const struct const_packet* old) struct tcphdr *tcph; struct dccp_hdr *dccph; struct dccp_hdr_ext *dccphex; - struct host *h1=NULL; - struct host *h2=NULL; + struct hcon *h1=NULL; + struct hcon *h2=NULL; /*Safety checks*/ if(!new || !old || !new->data || !old->data || !new->h || !old->h){ @@ -215,7 +227,8 @@ int convert_packet(struct packet *new, const struct const_packet* old) exit(1); return 0; } - if(old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)) || new->length < sizeof(struct dccp_hdr)){ + if(old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)) + || new->length < sizeof(struct dccp_hdr)){ dbgprintf(0, "Error: DCCP Packet Too short!\n"); return 0; } @@ -245,17 +258,83 @@ int convert_packet(struct packet *new, const struct const_packet* old) return 0; } - /*TODO: Add CCID detection*/ - if(h1->type==CCID2 && h2->type==CCID2){ - if(ccid2_convert_packet(new,old)==0){ - return 0; - } - } - if(h1->type==CCID3 && h2->type==CCID3){ - //ccid3_convert_packet(new,old); + /*set TCP standard features*/ + tcph->source=dccph->dccph_sport; + tcph->dest=dccph->dccph_dport; + tcph->doff=5; + tcph->check=htonl(0); + tcph->urg_ptr=0; + + /*Adjust TCP advertised window size*/ + if(!yellow){ + tcph->window=htons(30000); } - if(ccid2_convert_packet(new,old)==0){ - return 0; + + /*Process DCCP Packet Types*/ + switch(dccph->dccph_type){ + case DCCP_PKT_REQUEST: + dbgprintf(2,"Packet Type: Request\n"); + if(!handle_request(new, old, h1, h2)){ + return 0; + } + break; + case DCCP_PKT_RESPONSE: + dbgprintf(2,"Packet Type: Response\n"); + if(!handle_response(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_DATA: + if(!handle_data(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_DATAACK: + dbgprintf(2,"Packet Type: DataAck\n"); + if(!handle_dataack(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_ACK: + dbgprintf(2,"Packet Type: Ack\n"); + if(!handle_ack(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_CLOSEREQ: + dbgprintf(2,"Packet Type: CloseReq\n"); + if(!handle_closereq(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_CLOSE: + dbgprintf(2,"Packet Type: Close\n"); + if(!handle_close(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_RESET: + dbgprintf(2,"Packet Type: Reset\n"); + if(!handle_reset(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_SYNC: + dbgprintf(2,"Packet Type: Sync\n"); + if(!handle_sync(new,old,h1,h2)){ + return 0; + } + break; + case DCCP_PKT_SYNCACK: + dbgprintf(2,"Packet Type: SyncAck\n"); + if(!handle_syncack(new,old,h1,h2)){ + return 0; + } + break; + default: + dbgprintf(0,"Invalid DCCP Packet!!\n"); + return 0; + break; } /*Compute TCP checksums*/ @@ -269,13 +348,815 @@ int convert_packet(struct packet *new, const struct const_packet* old) new->length, new->dest_id, new->src_id, 6); }else{ tcph->check=0; - dbgprintf(2,"Unknown ID Length, can't do checksums"); + dbgprintf(2,"Unknown ID Length, can't do checksums\n"); + } + + return 1; +} + +int handle_request(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + int datalength; + int optlen; + u_char* tcpopt; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + + /*determine data length*/ + datalength=old->length - dccph->dccph_doff*4; + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr)-sizeof(struct dccp_hdr_ext)-sizeof(struct dccp_hdr_request); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do conversion*/ + if(yellow){ + tcph->window=htons(0); + } + tcph->ack_seq=htonl(0); + if(h1->state==INIT){ + tcph->seq=htonl(initialize_hcon(h1, ntohl(dccphex->dccph_seq_low))); + }else{ + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type)); + } + tcph->syn=1; + tcph->ack=0; + tcph->fin=0; + tcph->rst=0; + + /* add Sack-permitted option, if relevant*/ + if(sack){ + tcpopt=(u_char*)(new->data + tcph->doff*4); + *tcpopt=4; + tcpopt++; + *tcpopt=2; + tcph->doff++; + } + + /*calculate length*/ + new->length=tcph->doff*4; + return 1; +} + +int handle_response(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + u_char* tcpopt; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + + sizeof(struct dccp_hdr_ack_bits)+sizeof(struct dccp_hdr_request)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + + sizeof(struct dccp_hdr_ack_bits) + sizeof(struct dccp_hdr_request); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) + - sizeof(struct dccp_hdr_ack_bits) - sizeof(struct dccp_hdr_request); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do conversion*/ + if(h2->state!=OPEN){ + dbgprintf(0,"Warning: DCCP Response without a Request!!\n"); + } + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + h1->high_ack=ntohl(tcph->ack_seq); + if(yellow){ + tcph->window=htons(0); + } + if(h1->state==INIT){ + tcph->seq=htonl(initialize_hcon(h1, ntohl(dccphex->dccph_seq_low))); } + tcph->syn=1; + tcph->ack=1; + tcph->fin=0; + tcph->rst=0; + /* add Sack-permitted option, if relevant*/ + if(sack){ + tcpopt=(u_char*)(new->data + tcph->doff*4); + *tcpopt=4; + *(tcpopt+1)=2; + tcph->doff++; + } + + /*calculate length*/ + new->length=tcph->doff*4; return 1; } -void version(){ +int handle_dataack(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int datalength; + int optlen; + const u_char* pd; + u_char* npd; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*determine data length*/ + datalength=old->length - dccph->dccph_doff*4; + pd=old->data + dccph->dccph_doff*4; + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low))); + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + tcph->syn=0; + tcph->ack=1; + tcph->fin=0; + tcph->rst=0; + + /*copy data*/ + npd=new->data + tcph->doff*4; + memcpy(npd, pd, datalength); + + /*calculate length*/ + new->length=tcph->doff*4 + datalength; + return 1; +} + +int handle_ack(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*1400); + if(-interp_ack_vect((u_char*)dccph)*1400 > 65535){ + dbgprintf(0,"Note: TCP Window Overflow @ %d.%d\n", (int)old->h->ts.tv_sec, (int)old->h->ts.tv_usec); + } + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + + tcph->syn=0; + tcph->ack=1; + tcph->fin=0; + tcph->rst=0; + + /*calculate length*/ + new->length=tcph->doff*4 + 1; + return 1; +} + +int handle_closereq(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low))); + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + + tcph->syn=0; + tcph->ack=1; + tcph->fin=1; + tcph->rst=0; + + /*calculate length*/ + new->length=tcph->doff*4; + return 1; +} + +int handle_close(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + update_state(h1,CLOSE); + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low))); + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + + tcph->syn=0; + tcph->ack=1; + tcph->fin=1; + tcph->rst=0; + + /*calculate length*/ + new->length=tcph->doff*4; + return 1; +} + +int handle_reset(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + if(h2->state==CLOSE){ + update_state(h1,CLOSE); + } + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),1,dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low))); + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + + tcph->syn=0; + tcph->ack=1; + tcph->fin=1; + tcph->rst=0; + + /*calculate length*/ + new->length=tcph->doff*4; + return 1; +} + +int handle_sync(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low))); + }else{ + tcph->window=htons(0); + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + + tcph->syn=0; + tcph->ack=1; + tcph->fin=0; + tcph->rst=0; + + /*calculate length*/ + new->length=tcph->doff*4; + return 1; +} + +int handle_syncack(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + struct dccp_hdr_ack_bits *dccphack; + int optlen; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + dccphack=(struct dccp_hdr_ack_bits*)(old->data+ sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)); + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do Conversion*/ + if(green){ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low),h1)); + }else{ + tcph->ack_seq=htonl(convert_ack(h2,ntohl(dccphack->dccph_ack_nr_low)+interp_ack_vect((u_char*)dccph),h1)); + } + h1->high_ack=ntohl(tcph->ack_seq); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),0,dccph->dccph_type)); + if(yellow){ + tcph->window=htons(-interp_ack_vect((u_char*)dccph)*acked_packet_size(h2, ntohl(dccphack->dccph_ack_nr_low))); + }else{ + tcph->window=htons(0); + } + if(sack){ + if(sack!=2 || interp_ack_vect((u_char*)dccph)){ + ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low),h1); + } + } + + tcph->syn=0; + tcph->ack=1; + tcph->fin=0; + tcph->rst=0; + + /*calculate length*/ + new->length=tcph->doff*4; + return 1; +} + +int handle_data(struct packet* new, const struct const_packet* old, struct hcon* h1, struct hcon* h2) +{ + struct tcphdr *tcph; + struct dccp_hdr *dccph; + struct dccp_hdr_ext *dccphex; + int datalength; + int optlen; + const u_char* pd; + u_char* npd; + const u_char* dccpopt; + + /*length check*/ + if(new->length < sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext)){ + return 0; + } + + /*cast header pointers*/ + tcph=(struct tcphdr*)new->data; + dccph=(struct dccp_hdr*)old->data; + dccphex=(struct dccp_hdr_ext*)(old->data+sizeof(struct dccp_hdr)); + + /*determine data length*/ + datalength=old->length - dccph->dccph_doff*4; + pd=old->data + dccph->dccph_doff*4; + + /*Process DCCP Options*/ + dccpopt=old->data + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext); + optlen=dccph->dccph_doff*4 - sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext); + if(!parse_options(dccpopt,optlen,h1,h2)){ + return 0; + } + + /*Do conversion*/ + tcph->ack_seq=htonl(h1->high_ack); + tcph->seq=htonl(add_new_seq(h1, ntohl(dccphex->dccph_seq_low),datalength, dccph->dccph_type)); + tcph->syn=0; + tcph->ack=1; + tcph->fin=0; + tcph->rst=0; + + /*copy data*/ + npd=new->data + tcph->doff*4; + memcpy(npd, pd, datalength); + + /*calculate length*/ + new->length=tcph->doff*4 + datalength; + return 1; +} + +int parse_options(const u_char* opt_start, int len, struct hcon* A, struct hcon* B) +{ + int optlen; + int length; + const u_char* opt; + + /*setup pointer to DCCP options and determine how long the options are*/ + optlen=len; + opt=opt_start; + + /*parse options*/ + while(optlen > 0){ + /*One byte options (no length)*/ + if(*opt< 32){ + optlen--; + opt++; + continue; + } + + /*Check option length*/ + length=*(opt+1); + if(length > optlen){ + dbgprintf(0, "Warning: Option would extend into packet data\n"); + return 0; + } + if(length < 2){ + dbgprintf(0, "Warning: Bad Option!\n"); + return 0; + } + + /*Ack Vector Option*/ + if(*opt==38 || *opt==39){ + + } + + /*NDP Count Option*/ + if(*opt==37){ + + } + + /*Feature negotation*/ + if(*opt==32){ + /*Change L*/ + if(!process_feature(opt+2,length-2,FALSE,TRUE,A,B)){ + return 0; + } + } + if(*opt==33){ + /*Confirm L*/ + if(!process_feature(opt+2,length-2,TRUE,TRUE,A,B)){ + return 0; + } + } + if(*opt==34){ + /*Change R*/ + if(!process_feature(opt+2,length-2,FALSE,FALSE,A,B)){ + return 0; + } + } + if(*opt==35){ + /*Confirm R*/ + if(!process_feature(opt+2,length-2,TRUE,FALSE,A,B)){ + return 0; + } + } + + optlen-=length; + opt+=length; + } + + return 1; +} + +int process_feature(const u_char* feat, int len, int confirm, int L, struct hcon* A, struct hcon* B) +{ + const u_char* val; + int ccid; + + val=feat+1; + + switch(*feat){ + case 1: + /*CCID*/ + if(confirm==FALSE){ + switch(*val){ + case 2: + ccid=CCID2; + break; + case 3: + ccid=CCID3; + break; + default: + ccid=UNKNOWN; + break; + } + if(L==TRUE){ + B->type=ccid; + }else{ + A->type=ccid; + } + } + break; + case 2: + /*Short sequence nums*/ + if(confirm==FALSE && *val==1){ + dbgprintf(0,"Error! DCCP is trying to turn on short sequence numbers! We do not support this!!\n"); + exit(1); + } + break; + } + return 1; +} + +/*Ack Vector to SACK Option*/ +void ack_vect2sack(struct hcon *hcn, struct tcphdr *tcph, u_char* tcpopts, u_char* dccphdr, + __be32 dccpack, struct hcon* o_hcn) +{ + int hdrlen=((struct dccp_hdr*)dccphdr)->dccph_doff*4; + int optlen; + int len; + int tmp; + __be32 bp; + u_char* temp; + u_char* opt; + u_char* cur; + u_char* tlen; + u_int32_t bL=0; + u_int32_t bR; + u_int32_t* pL; + u_int32_t* pR; + int num_blocks; + int cont; + int isopt; + + /*setup pointer to DCCP options and determine how long the options are*/ + optlen=hdrlen-sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext) - sizeof(struct dccp_hdr_ack_bits); + opt=dccphdr + sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_ack_bits); + + if(optlen<=0){ + return; + } + + /*setup tcp pointers*/ + num_blocks=4; + *tcpopts=5; + tlen=tcpopts+1; + temp=tlen; + temp++; + pL=(u_int32_t*)temp; + pR=pL+1; + + /*setup tcp control variables*/ + bp=dccpack; + cont=0; + *tlen=2; + isopt=0; + + /*parse options*/ + while(optlen > 0){ + + /*One byte options (no length)*/ + if(*opt< 32){ + optlen--; + opt++; + continue; + } + + len=*(opt+1); + if(len > optlen){ + dbgprintf(0, "Warning: Option would extend into packet data\n"); + break; + } + + /*Ack Vector Option*/ + if(*opt==38 || *opt==39){ + tmp=len-2; + cur=opt+2; + /*loop through Vector*/ + while(tmp > 0){ + /*ack vector works BACKWARDS through time*/ + + if((*cur & 0xC0)==0xC0 || (*cur & 0xC0)==0x40){ //lost packet + if(cont){ /*end a SACK run, if one is started*/ + bR=convert_ack(hcn, bp,o_hcn); + cont=0; + num_blocks--; + *pR=htonl(bR); + *pL=htonl(bL); + tcph->doff+=2; + *tlen+=8; + pL=pR+1; + pR=pL+1; + } + bp= bp - (*cur & 0x3F)- 1; + } + + if((*cur & 0xC0)==0x00){ //received packet + if(!cont){ /*if no SACK run and we can start another one, do so*/ + if(num_blocks>0){ + bL=convert_ack(hcn, bp, o_hcn); + isopt=1; + cont=1; + + } + } + bp = bp -(*cur & 0x3F)- 1; + } + tmp--; + cur++; + } + } + + optlen-=len; + opt+=len; + } + + /*if we are in the middle of a SACK run, close it*/ + if(cont){ + bR=convert_ack(hcn, bp,o_hcn); + *pR=htonl(bR); + *pL=htonl(bL); + tcph->doff+=2; + *tlen+=8; + cont=0; + } + + /*adjust length if the option is actually added*/ + if(isopt){ + tcph->doff+=1; + } +return; +} + +void version() +{ dbgprintf(0, "dccp2tcp version %.1f\nCopyright (C) %i Samuel Jero \n", DCCP2TCP_VERSION,COPYRIGHT_YEAR); dbgprintf(0, "This program comes with ABSOLUTELY NO WARRANTY.\n"); dbgprintf(0, "This is free software, and you are welcome to\nredistribute it under certain conditions.\n"); @@ -285,7 +1166,7 @@ void version(){ /*Usage information for program*/ void usage() { - dbgprintf(0,"Usage: dccp2tcp dccp_file tcp_file [-d] [-h] [-V] [-y] [-g] [-s]\n"); + dbgprintf(0,"Usage: dccp2tcp [-d] [-h] [-V] [-y] [-g] [-s] dccp_file tcp_file\n"); dbgprintf(0, " -d Debug. May be repeated for aditional verbosity.\n"); dbgprintf(0, " -V Version information\n"); dbgprintf(0, " -h Help\n");