/******************************************************************************
-Author: Samuel Jero
+Utility to convert a DCCP flow to a TCP flow for DCCP analysis via
+ tcptrace.
-Date: 7/2011
+Copyright (C) 2012 Samuel Jero <sj323707@ohio.edu>
-Description: Program to convert a DCCP flow to a TCP flow for DCCP analysis via
- tcptrace.
+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
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Author: Samuel Jero <sj323707@ohio.edu>
+Date: 11/2012
Notes:
1)CCID2 ONLY
2)DCCP MUST use 48 bit sequence numbers
3)Checksums are not computed (they are zeroed)
- 4)Only implements those packet types normally used in a session
+ 4)DCCP DATA packets are not implemented (Linux doesn't use them)
5)DCCP Ack packets show up as TCP packets containing one byte
- 6)Very little error checking of packet headers
******************************************************************************/
#include "dccp2tcp.h"
-void PcapSavePacket(struct pcap_pkthdr *h, u_char *data);
-void process_packets();
void handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
int convert_packet(struct packet *new, const struct const_packet* old);
unsigned int interp_ack_vect(u_char* hdr);
-u_int32_t initialize_seq(struct host *seq, __be16 source, __be32 initial);
+u_int32_t initialize_seq(struct host *seq, __be32 initial);
u_int32_t add_new_seq(struct host *seq, __be32 num, int size, enum dccp_pkt_type type);
u_int32_t convert_ack(struct host *seq, __be32 num);
int acked_packet_size(struct host *seq, __be32 num);
/*loop through commandline options*/
for(int i=1; i < argc; i++){
- if(argv[i][0]!='-'){
- if(dfile==NULL){ /*assign first non-dash argument to the dccp file*/
+ if(argv[i][0]!='-' || (argv[i][0]=='-' && strlen(argv[i])==1)){
+ if(dfile==NULL || argv[i][0]=='-'){
+ /*assign first non-dash (or only dash) argument to the dccp file*/
dfile=argv[i];
}else{
if(tfile==NULL){
}
/*process packets*/
+ chead=NULL;
u_char *user=(u_char*)out;
pcap_loop(in, -1, handle_packet, user);
/*close files*/
pcap_close(in);
pcap_dump_close(out);
+
+ /*Delete all connections*/
+ cleanup_connections();
return 0;
}
old.h=h;
old.length=h->caplen;
old.data=bytes;
+ old.dest_id=NULL;
+ old.src_id=NULL;
new.h=&nh;
new.length=MAX_PACKET;
+ new.dest_id=NULL;
+ new.src_id=NULL;
/*create buffer for new packet*/
new.data=ndata=malloc(MAX_PACKET);
/*Safety checks*/
if(!new || !old || !new->data || !old->data || !new->h || !old->h){
dbgprintf(0,"Error: Convert Packet Function given bad data!\n");
+ exit(1);
return 0;
}
- if(old->length < sizeof(struct dccp_hdr) || new->length < sizeof(struct dccp_hdr)){
- dbgprintf(0, "Error: Convert Packet Function given packet of wrong size!\n");
+ 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;
}
/*cast header pointers*/
tcph=(struct tcphdr*)new->data;
- tcpopt=new->data + sizeof(struct tcphdr);
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));
- dbgprintf(2,"Sequence Number: %llu\n", (unsigned long long)(((unsigned long)ntohs(dccph->dccph_seq)<<32) + ntohl(dccphex->dccph_seq_low)));
+ dbgprintf(2,"Sequence Number: %llu\n", (unsigned long long)
+ (((unsigned long)ntohs(dccph->dccph_seq)<<32) + ntohl(dccphex->dccph_seq_low)));
/*Get Hosts*/
- if(get_host(new->src_id, new->dest_id, dccph->dccph_sport, dccph->dccph_dport, h1, h2)){
+ if(get_host(new->src_id, new->dest_id, new->id_len,
+ dccph->dccph_sport, dccph->dccph_dport, &h1, &h2)){
dbgprintf(0,"Error: Can't Get Hosts!\n");
return 0;
}
- if(!h1 || !h2){
+ if(h1==NULL || h2==NULL){
dbgprintf(0, "Error: Can't Get Hosts!\n");
return 0;
}
+ /*Ensure packet is at least as large as DCCP header*/
+ if(old->length < dccph->dccph_doff*4){
+ dbgprintf(0, "Error: DCCP Header truncated\n");
+ return 0;
+ }
+ if(dccph->dccph_type!=DCCP_PKT_DATA &&
+ old->length < (sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) +
+ sizeof(struct dccp_hdr_ack_bits))){
+ dbgprintf(0, "Error: DCCP Packet Too short!\n");
+ }
+
/*determine data length*/
datalength=old->length - dccph->dccph_doff*4;
pd=old->data + dccph->dccph_doff*4;
tcph->window=htons(0);
}
tcph->ack_seq=htonl(0);
- tcph->seq=htonl(initialize_seq(h1, dccph->dccph_sport, ntohl(dccphex->dccph_seq_low)));
+ tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
tcph->syn=1;
tcph->ack=0;
tcph->fin=0;
/* add Sack-permitted option, if relevant*/
if(sack){
+ tcpopt=(u_char*)(new->data + tcph->doff*4);
*tcpopt=4;
tcpopt++;
*tcpopt=2;
if(yellow){
tcph->window=htons(0);
}
- tcph->seq=htonl(initialize_seq(h1, dccph->dccph_sport, ntohl(dccphex->dccph_seq_low)));
+ tcph->seq=htonl(initialize_seq(h1, ntohl(dccphex->dccph_seq_low)));
tcph->syn=1;
tcph->ack=1;
tcph->fin=0;
/* add Sack-permitted option, if relevant*/
if(sack){
+ tcpopt=(u_char*)(new->data + tcph->doff*4);
*tcpopt=4;
*(tcpopt+1)=2;
tcph->doff++;
}
if(sack){
if(sack!=2 || interp_ack_vect((u_char*)dccph)){
- ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
+ ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
}
}
}
if(sack){
if(sack!=2 || interp_ack_vect((u_char*)dccph)){
- ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
+ ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
}
}
}
if(sack){
if(sack!=2 || interp_ack_vect((u_char*)dccph)){
- ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
+ ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
}
}
}
if(sack){
if(sack!=2 || interp_ack_vect((u_char*)dccph)){
- ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
+ ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
}
}
}
if(sack){
if(sack!=2 || interp_ack_vect((u_char*)dccph)){
- ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
+ ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low) );
}
}
}
if(sack){
if(sack!=2 || interp_ack_vect((u_char*)dccph)){
- ack_vect2sack(h2, tcph, tcpopt, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
+ ack_vect2sack(h2, tcph, (u_char*)tcph + tcph->doff*4, (u_char*)dccph, ntohl(dccphack->dccph_ack_nr_low));
}
}
/*parse options*/
while(optlen > 0){
- len=*(opt+1);
/*One byte options (no length)*/
if(*opt< 32){
continue;
}
+ /*Check option length*/
+ len=*(opt+1);
+ if(len > optlen){
+ dbgprintf(0, "Warning: Option would extend into packet data\n");
+ return additional;
+ }
+
/*Ack Vector Option*/
if(*opt==38 || *opt==39){
tmp=len-2;
bp+= (*cur & 0x3F)+1;
}
- if(((*cur& 0xF0)!= 0xC0) && ((*cur& 0xF0)!= 0x00) && ((*cur& 0xF0)!= 0x40)){
+ if(((*cur& 0xC0)!= 0xC0) && ((*cur& 0xC0)!= 0x00) && ((*cur& 0xC0)!= 0x40)){
dbgprintf(1, "Warning: Invalid Ack Vector!! (Linux will handle poorly!)\n");
}
tmp--;
/* Setup Sequence Number Structure*/
-u_int32_t initialize_seq(struct host *seq, __be16 source, __be32 initial)
+u_int32_t initialize_seq(struct host *seq, __be32 initial)
{
/*set default values*/
seq->cur=0;
exit(1);
}
+ if(seq->table==NULL){
+ dbgprintf(1, "Warning: Connection uninitialized\n");
+ return initialize_seq(seq, num);
+ }
+
/*account for missing packets*/
+ if(num - seq->table[seq->cur].old +1 >=100){
+ dbgprintf(1,"Missing more than 100 packets!\n");
+ }
while(seq->table[seq->cur].old +1 < num && seq->table[seq->cur].old +1 > 0){
prev=seq->cur;
- dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
+ if(num - seq->table[seq->cur].old +1 <100){
+ dbgprintf(1,"Missing Packet: %X\n",seq->table[prev].new+1);
+ }
seq->cur=(seq->cur+1)%(seq->size);/*find next available table slot*/
seq->table[seq->cur].old=seq->table[prev].old+1;
seq->table[seq->cur].new=seq->table[prev].new + seq->table[prev].size;
exit(1);
}
+ if(seq->table==NULL){
+ dbgprintf(1, "Warning: Connection uninitialized\n");
+ initialize_seq(seq, num);
+ }
+
/*loop through table looking for the DCCP ack number*/
for(int i=0; i < seq->size; i++){
if(seq->table[i].old==num){
exit(1);
}
+ if(seq->table==NULL){
+ dbgprintf(1, "Warning: Connection uninitialized\n");
+ initialize_seq(seq, num);
+ }
+
/*loop through table looking for the DCCP ack number*/
for(int i=0; i < seq->size; i++){
if(seq->table[i].old==num){
/*parse options*/
while(optlen > 0){
- len=*(opt+1);
/*One byte options (no length)*/
if(*opt< 32){
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;