Browse Source

finished packet and record reassembly code

cbocovic 9 years ago
parent
commit
10057195c2
7 changed files with 633 additions and 159 deletions
  1. 10 4
      server/Makefile
  2. 185 12
      server/flow.c
  3. 26 12
      server/flow.h
  4. 146 131
      server/slitheen-proxy.c
  5. 84 0
      server/slitheen.h
  6. 153 0
      server/util.c
  7. 29 0
      server/util.h

+ 10 - 4
server/Makefile

@@ -1,19 +1,25 @@
-CFLAGS=-g -Wall
+CFLAGS=-g -Wall -std=gnu99
 
 TARGETS=slitheen-proxy
 
 all: $(TARGETS)
 
-slitheen-proxy.o flow.o rserv.o ptwist168.o:: ptwist.h rserv.h flow.h
+slitheen-proxy.o flow.o rserv.o ptwist168.o util.o:: ptwist.h rserv.h flow.h slitheen.h util.h
 
 rserv: rserv.o ptwist168.o
 	gcc -g -o $@ $^ -lssl -lcrypto
 
-slitheen-proxy: slitheen-proxy.o flow.o rserv.o ptwist168.o ptwist.h rserv.h flow.h
-	gcc -g -o $@ $^ -lssl -lcrypto -lpcap -lpthread
+slitheen-proxy: slitheen-proxy.o flow.o rserv.o ptwist168.o util.o util.h ptwist.h rserv.h flow.h slitheen.h
+	gcc -g -o $@ $^ -I/home/slitheen/Documents/include/openssl libssl.a libcrypto.a -lpcap -lpthread
 
 clean:
 	-rm *.o
 
 veryclean: clean
 	-rm $(TARGETS)
+
+#DEPS=ptwist.h rserv.h flow.h slitheen.h util.h
+#
+#%.o: %.c $(DEPS)
+#	gcc -g -Wall -std=c99 -c -o $@ $<
+

+ 185 - 12
server/flow.c

@@ -1,6 +1,8 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include "flow.h"
+#include "slitheen.h"
 
 static flow_table *table;
 
@@ -32,8 +34,9 @@ int add_flow(flow newFlow) {
 	printf("there are %d flows in the table\n", table->len);
 
 	ptr = table->table + table->len;
-	newFlow.tls_state = 1;
+	newFlow.state = TLS_CLNT_HELLO;
 	newFlow.encrypted = 0;
+	newFlow.packet_chain = NULL;
 	*ptr = newFlow;
 
 	table->len ++;
@@ -41,23 +44,133 @@ int add_flow(flow newFlow) {
 	return(0);
 }
 
-int update_flow(int index, int code) {
-	flow *f;
-	f = get_flow(index-1);
-	int state = 0;
-	switch(code){
-		case 1: state = state | TLS_CLNT_HELLO; 
+/* Updates the flow state */
+int update_flow(flow *f) {
+	uint8_t *record;
+	const struct record_header *record_hdr;
+	const struct handshake_header *handshake_hdr;
+
+	uint8_t *p = f->packet_chain->data;
+
+	record_hdr = (struct record_header*) p;
+	int record_len;
+	int data_len;
+
+	if (record_hdr->type != HS){
+		if(record_hdr->type == APP){
+			printf("Received application data!\n");
+		}
+		//TODO: later figure this out, for now delete
+		f->packet_chain = f->packet_chain->next;
+		if( f->packet_chain != NULL){
+			update_flow(f);
+		}
+		return 0;
+	}
+	/* This is a TLS handshake */
+	//printf("record version(major): %d.\n", (record_hdr->version&0xFF00)>>8);
+	//printf("record version(minor): %d.\n", record_hdr->version&0xFF);
+	//printf("record length: %d.\n", RECORD_LEN(record_hdr));
+
+	record_len = RECORD_LEN(record_hdr);
+	data_len = f->packet_chain->data_len;
+	packet *current = f->packet_chain;
+	record = calloc(1, record_len);
+	for(int i=0; (i<data_len) && (i<record_len); i++){
+		record[i] = p[i];
+	}
+	//printf("record len: %d, data_len: %d\n", record_len, data_len);
+	while(record_len > data_len) {
+		if(current->next == NULL){
+			//printf("Don't have enought to reconstruct record\n");
+			free(record);
+			return 0;
+		}
+		if(current->next->seq_num != current->seq_num + current->len){
+			printf("Missing packet: seq_num= %d, datalen= %d, nextseq= %d\n", current->seq_num, current->len, current->next->seq_num);
+			free(record);
+			return 0;
+		}
+
+		current = current->next;
+		p = current->data;
+		int i;
+		for(i=0; (i<current->data_len) && (i+data_len < record_len); i++){
+
+			record[data_len] = p[i];
+		}
+		//printf("Filled %d\n", i);
+		data_len += current->data_len;
+	}
+
+	p = record;
+	p += RECORD_HEADER_LEN;
+	handshake_hdr = (struct handshake_header*) p;
+
+	int size_hs = HANDSHAKE_MESSAGE_LEN(handshake_hdr);
+	printf("Handshake Message:\n");
+	f->state = handshake_hdr->type;
+
+#define TLS_CERT 0x0b
+#define TLS_SRVR_KEYEX 0x0c
+#define TLS_CERT_REQ 0x0d
+#define TLS_SRVR_HELLO_DONE 0x0e
+#define TLS_CERT_VERIFY 0x0f
+#define TLS_CLNT_KEYEX 0x10
+#define TLS_FINISHED 0x14
+
+	/* Now see if there's anything extra to do */
+	switch(f->state){
+	/* Checks to see if this is a possibly tagged hello msg */
+		case TLS_CLNT_HELLO: 
+			/* Expecting server hello msg */
+			printf("Received client hello!\n");
+				break;
+		case TLS_SERV_HELLO:
+			printf("Received server hello!\n");
+				break;
+		case TLS_NEW_SESS:
+			printf("Received new session!\n");
+				break;
+		case TLS_CERT:
+			printf("Received certificate!\n");
+			/* Need to extract server params */
+				break;
+		case TLS_SRVR_KEYEX:
+			printf("Received server key exchange!\n");
 				break;
-		case 2: state = state | TLS_SERV_HELLO; 
+		case TLS_CERT_REQ:
+			printf("Received certificate request!\n");
 				break;
-		case 4: state = state | TLS_NEW_SESS; 
+		case TLS_SRVR_HELLO_DONE:
+			printf("Received server hello done!\n");
 				break;
-		case 16: state = state | TLS_KEY_EXCHG; 
+		case TLS_CERT_VERIFY:
+			printf("Received certificate verify!\n");
 				break;
-		case 20: state = state | TLS_FINISHED; 
+		case TLS_CLNT_KEYEX:
+			printf("Received client key exchange!\n");
 				break;
+		case TLS_FINISHED:
+			printf("Received finished message!\n");
+				break;
+	}
+	record_len += RECORD_HEADER_LEN;
+
+	if(record_len == data_len){
+		/* record ended on packet boundary */
+		//printf("record consumed packet\n");
+		f->packet_chain = current->next;
+	} else {
+		/* need to update data */
+		f->packet_chain = current; //TODO: make current
+		current->data = current->data + (current->data_len - (data_len - record_len));
+		current->data_len = data_len - record_len;
+		//printf("more records? extra: %d\n", current->data_len);
+		update_flow(f);
 	}
-	f->tls_state = state;
+
+	free(record);
 	return 0;
 }
 
@@ -84,6 +197,9 @@ int grow_table() {
 	return 0;
 }
 
+/** Returns the index of a flow in the flow table if
+ *  it exists, returns 0 if it is not present.
+ */
 int check_flow(flow observed){
 	/* Loop through flows in table and see if it exists */
 	int i;
@@ -130,3 +246,60 @@ flow *get_flow(int index){
 	}
 }
 
+/* Adds a packet the flow's packet chain */
+int add_packet(flow *f, uint8_t *p){
+	const struct ip_header *ip_hdr;
+	const struct tcp_header *tcp_hdr;
+
+	packet *new_packet = malloc(sizeof(packet));
+
+	p += ETHER_HEADER_LEN; //skip ethernet header
+	ip_hdr = (struct ip_header*) p;
+	int size_ip = IP_HEADER_LEN(ip_hdr);
+
+	if (ip_hdr->proto != IPPROTO_TCP){
+		return 0;
+	}
+
+	p += size_ip;	//skip IP header
+
+	tcp_hdr = (struct tcp_header*) p;
+	int size_tcp = TCP_HEADER_LEN(tcp_hdr);
+	p += size_tcp;
+
+	new_packet->seq_num = htonl(tcp_hdr->sequence_num);
+	new_packet->len = htons(ip_hdr->len) - (size_ip + size_tcp);
+	new_packet->data = p;
+	new_packet->data_len = htons(ip_hdr->len) - (size_ip + size_tcp);
+	new_packet->next = NULL;
+
+	/* Find appropriate place in chain */
+	if(new_packet->data_len > 0){
+		packet *previous = NULL;
+		packet *next = f->packet_chain;
+		while(next != NULL && (next->seq_num <= new_packet->seq_num)){
+			//printf("next: %u <= new: %u\n", next->seq_num, new_packet->seq_num);
+			previous = next;
+			next = next->next;
+		}
+
+		//place packet after current
+		if(previous == NULL){
+			//goes at the beginning of chain
+			new_packet->next = f->packet_chain;
+			f->packet_chain = new_packet;
+		} else {
+			new_packet->next = next;
+			previous->next = new_packet;
+		}
+		printf("Flow: %d > %d\n", ip_hdr->src.s_addr, ip_hdr->dst.s_addr);
+		printf("ID number: %u\n", htonl(ip_hdr->id));
+		printf("Sequence number: %u\n", htonl(tcp_hdr->sequence_num));
+		printf("Acknowledgement number: %u\n", htonl(tcp_hdr->ack_num));
+		printf("Length: %d\n", new_packet->data_len);
+
+	}
+	
+	return 0;
+
+}

+ 26 - 12
server/flow.h

@@ -6,26 +6,38 @@
 
 #define MAX_FLOWS 10
 
+#define TLS_HELLO_REQ 0x00
 #define TLS_CLNT_HELLO 0x01
 #define TLS_SERV_HELLO 0x02
-#define TLS_KEY_EXCHG 0x04
-#define TLS_NEW_SESS 0x08
-#define TLS_FINISHED 0x10
-
-typedef struct tcp_state_st {
-	int sequence_number;
-
-} TCP_state;
+#define TLS_NEW_SESS 0x04
+#define TLS_CERT 0x0b
+#define TLS_SRVR_KEYEX 0x0c
+#define TLS_CERT_REQ 0x0d
+#define TLS_SRVR_HELLO_DONE 0x0e
+#define TLS_CERT_VERIFY 0x0f
+#define TLS_CLNT_KEYEX 0x10
+#define TLS_FINISHED 0x14
+
+struct packet_st{
+	uint32_t seq_num;
+	uint16_t len;
+	uint16_t data_len;
+	uint8_t *data;
+	struct packet_st *next;
+};
+
+typedef struct packet_st packet;
 
 typedef struct flow_st {
 	struct in_addr src_ip, dst_ip; /* Source and Destination addresses */
-	u_short src_port, dst_port;	/* Source and Destination ports */
+	uint16_t src_port, dst_port;	/* Source and Destination ports */
 
-	u_int seq_num;		/* sequence number */
+	uint32_t seq_num;		/* sequence number */
 
 	byte key[16];		/* negotiated key */
-	int tls_state;		/* TLS handshake state */
+	int state;		/* TLS handshake state */
 	int encrypted;		/* indicates whether flow is encrypted */
+	packet *packet_chain; /* currently held data */
 
 } flow;
 
@@ -38,9 +50,11 @@ typedef struct flow_table_st {
 
 int init_flow_table (void);
 int add_flow(flow newFlow);
-int update_flow(int index, int code);
+int update_flow(flow *f);
 int remove_flow(int index);
 int check_flow(flow observed);
 flow *get_flow(int index);
 
+int add_packet(flow *f, uint8_t *data);
+
 #endif /* __RELAY_H__ */

+ 146 - 131
server/slitheen-proxy.c

@@ -7,84 +7,36 @@
 #include "ptwist.h"
 #include "rserv.h"
 #include "flow.h"
-
-#define macaddr "08:00:27:e8:9d:d4"
-
-/* Ethernet addresses are 6 bytes */
-#define ETHER_ADDR_LEN	6
-#define ETHER_HEADER_LEN  2*ETHER_ADDR_LEN + 2
-
-/* Definitions for parsing packet data */
-struct ip_header {
-	u_char versionihl;		/* Version >> 4 | IHL & 0x0f */
-	u_char dscpecn;		/* DSCP >> 2 | ECN  & 0x03 */
-	u_short len;		/* Total Length */
-	u_short id;		/* Identification */
-	u_short flagsoff;		/* Flags >> 13 | Fragment Offset & 0x1fff */
-#define RF 0x8000		/* Reserved; must be zero */
-#define DF 0x4000		/* Dont Fragment */
-#define MF 0x2000		/* More Fragments */
-	u_char ttl;		/* Time To Live */
-	u_char proto;		/* Protocol */
-	u_short chksum;		/* Header Checksum */
-	struct in_addr src, dst; /* Source and Destination addresses */
-};
-#define IP_HEADER_LEN(ip)		(((ip)->versionihl) & 0x0f)*4
-
-struct tcp_header {
-	u_short src_port;	/* source port */
-	u_short dst_port;	/* destination port */
-	u_int sequence_num;		/* sequence number */
-	u_int ack_num;		/* acknowledgement number */
-	u_char offset_res_ns;	/*Data offset >> 4 |  res >> 1 | NS 0x01 */
-	u_char flags;			/* Flags */
-#define FIN 0x01
-#define RST 0x04
-	u_short win_size;		/* Window size*/
-	u_short chksum;		/* Checksum */
-	u_short urg;		/* Urgent pointer */
-};
-#define TCP_HEADER_LEN(tcp)		(((tcp)->offset_res_ns) >> 4)*4
-
-struct tls_header {
-	u_char type; /* Content Type */
-#define CCS 0x14
-#define A   0x15
-#define HS  0x16
-#define APP 0x17
-#define HB  0x18
-	u_short version; /* Version */
-	u_short len; /* Length */
-	u_char msg; /* Message Type */
-#define CLIENT_HELLO 0x01
-#define FINISHED 0x14
-};
-#define RECORD_HEADER_LEN 5
-#define CLIENT_HELLO_HEADER_LEN 6
-
-struct sniff_args {
-	char *readdev;
-	char *writedev;
-	char *filter;
-};
+#include "slitheen.h"
+#include "util.h"
 
 void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
-void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *p);
+void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *p, u_short length);
 void *sniff_packets(void *);
+void process_packet(const u_char *packet);
 
-void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *ptr){
+/** Checks a handshake message to see if it is tagged or a
+ *  recognized flow.
+ *  Inputs: The tcp header for the message, its associated flow,
+ *  a pointer to the handshake header, and the length of
+ *  the record.
+ */
+void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *ptr, u_short length){
 
 	FILE *fp;
 	int res, i, code;
+	u_int size_hs;
 	unsigned char *p;
+	const struct handshake_header *handshake_hdr;
 
     byte privkey[PTWIST_BYTES];
 	byte key[16];
 
 	p = ptr;
-	code = p[0];
+	handshake_hdr = (struct handshake_header*) p;
 
-	printf("handshake code: %d\n", code);
+	code = handshake_hdr->type;
+	size_hs = HANDSHAKE_MESSAGE_LEN(handshake_hdr);
 
 	if (code == 0x01){
 		p += CLIENT_HELLO_HEADER_LEN;
@@ -118,6 +70,7 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 				fprintf(fp, "%02x ", p[i]);
 			}
 			fclose(fp);
+			//TODO: this might not be okay...
 			strncpy((char *) f.key, (char *) key, 16);
 
 			//Write key to file
@@ -132,14 +85,10 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 			fclose(fp);
 
 			/* Save flow in table */
-			printf("saving flow..\n");
 			add_flow(f);
-			printf("saved\n");
+			printf("Saved new flow\n");
 
 		}
-	} else {
-		int index = check_flow(f);
-		update_flow(index, code);
 	}
 
 }
@@ -149,82 +98,55 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
 	char errbuf[BUFSIZ];
 	char *writedev = (char *) args;
 	unsigned char *p;
-	int index;
 
 	const struct ip_header *ip_hdr;
 	const struct tcp_header *tcp_hdr;
 
-	u_int size_ip;
-	u_int size_tcp;
-
-	flow newFlow;
-
 	handle = pcap_open_live(writedev, BUFSIZ, 1, 1000, errbuf);
 	if (handle == NULL){
 		fprintf(stderr, "Couldn't open device %s: %s\n", writedev, errbuf);
 	}
-	/* check for clientHello */
+
 	p = (unsigned char *) packet;
 	p += ETHER_HEADER_LEN; //skip ethernet header
 	ip_hdr = (struct ip_header*) p;
-	size_ip = IP_HEADER_LEN(ip_hdr);
-
-	if (ip_hdr->proto == IPPROTO_TCP){
-		p += size_ip;	//skip IP header
-
-		tcp_hdr = (struct tcp_header*) p;
-		size_tcp = TCP_HEADER_LEN(tcp_hdr);
-		p += size_tcp;
-
-		newFlow.src_ip = ip_hdr->src;
-		newFlow.dst_ip = ip_hdr->dst;
-		newFlow.src_port = tcp_hdr->src_port;
-		newFlow.dst_port = tcp_hdr->dst_port;
-
-		newFlow.seq_num = tcp_hdr->sequence_num;
-
-		if (p[0] == 0x16){ /* This is a TLS handshake */
-			p += RECORD_HEADER_LEN;
-			check_handshake(tcp_hdr, newFlow, p);
+	p += IP_HEADER_LEN(ip_hdr);//TODO: remove
+	tcp_hdr = (struct tcp_header*) p;//TODO: remove
+
+	/* Check to make sure it is an IP packet */
+	if( (ip_hdr->versionihl >>4) != 4)
+		goto end;
+
+	/* Packet may be split over multiple frames. In this case,
+	 * reconstruct the packet before trying to read TLS records
+	 */
+	if((htons(ip_hdr->flagsoff)&MF) || (htons(ip_hdr->flagsoff) &0x1fff) ){ /* this is a fragment */
+		printf("MF: %d, OFF: %d.\n", htons(ip_hdr->flagsoff)&MF, htons(ip_hdr->flagsoff)&0x1fff);
+		printf("Received packet fragment.\n");
+		printf("%d packet bytes: \n", IP_HEADER_LEN(ip_hdr));
+		for(int i=0; i< IP_HEADER_LEN(ip_hdr); i++){
+			printf("%02x ", p[i]);
 		}
-	}
-
-	if((index = check_flow(newFlow))){
-		flow *observed = get_flow(index-1);
-
-		/* Update TCP state */
-		if(tcp_hdr->flags & (FIN | RST) ){
-			/* Remove flow from table, connection ended */
-			remove_flow(index);
-		}
-
-		/* Check to see if TLS finished message has passed */
-		if(observed->tls_state & TLS_FINISHED){
-			//decrypt packet?
-			printf("TLS finished received.\n");
-		} else {
-			//check to see if tls_finished message
-			if((observed->tls_state & TLS_NEW_SESS) && !observed->encrypted){
-				//packet should be encrypted
-				observed->encrypted = 1;
-			} else if(observed->encrypted){ /* decrypt tls finished message */
-				printf("need to decrypt this finished message\n");
-				update_flow(index, 20);
-			}
-
+		printf("\n");
+		u_char *complete_packet;
+		//save packet fragment
+		complete_packet = malloc(65535);
+
+		int success = report_fragment(p, complete_packet, header->len);
+		if(success){
+			process_packet(complete_packet);
 		}
+		/* TODO: handle errors */
+		
+	} else { /*not a fragment, add to packet chain */
+		process_packet(packet);
+	}
+	
+end:
 
-		/* Hand packet to relay module */
-		if((pcap_inject(handle, packet, header->len)) < 0 ){
-			fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
-		}
-		//handle_flow(handle, packet, header->len);
-
-	} else {
-
-		if((pcap_inject(handle, packet, header->len)) < 0 ){
-			fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
-		}
+	/* Hand packet to relay module */
+	if((pcap_inject(handle, packet, header->len)) < 0 ){
+		fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
 	}
 
 	pcap_close(handle);
@@ -257,6 +179,7 @@ int main(int argc, char *argv[]){
 	snprintf(filter2, 33, "ether dst host %s", macaddr);
 
 	init_flow_table();
+	init_fragment_table();
 
 	/* Create threads */
 	outbound.readdev = dev1;
@@ -320,3 +243,95 @@ void *sniff_packets(void *args){
 
 	return NULL;
 }
+
+/* This function receives a full ip packet and then:
+ * 	1) identifies the flow
+ * 	2) adds the packet to the flow's data chain
+ * 	3) updates the packet's state
+ */
+void process_packet(const u_char *packet){
+	unsigned char *p;
+	int index, i;
+
+	const struct ip_header *ip_hdr;
+	const struct tcp_header *tcp_hdr;
+	const struct record_header *record_hdr;
+
+	u_int size_ip;
+	u_int size_tcp;
+
+	flow newFlow;
+
+	p = (unsigned char *) packet;
+	p += ETHER_HEADER_LEN; //skip ethernet header
+	ip_hdr = (struct ip_header*) p;
+	size_ip = IP_HEADER_LEN(ip_hdr);
+
+	if (ip_hdr->proto == IPPROTO_TCP){
+		p += size_ip;	//skip IP header
+
+		tcp_hdr = (struct tcp_header*) p;
+		size_tcp = TCP_HEADER_LEN(tcp_hdr);
+		p += size_tcp;
+
+		newFlow.src_ip = ip_hdr->src;
+		newFlow.dst_ip = ip_hdr->dst;
+		newFlow.src_port = tcp_hdr->src_port;
+		newFlow.dst_port = tcp_hdr->dst_port;
+
+		newFlow.seq_num = tcp_hdr->sequence_num;
+		record_hdr = (struct record_header*) p;
+
+		/* Checks to see if this is a possibly tagged hello msg */
+		if (record_hdr->type == HS){ /* This is a TLS handshake */
+			//printf("record type: %d.\n", record_hdr->type);
+			//printf("record version(major): %d.\n", (record_hdr->version&0xFF00)>>8);
+			//printf("record version(minor): %d.\n", record_hdr->version&0xFF);
+			//printf("record length: %d.\n", RECORD_LEN(record_hdr));
+			//printf("record header bytes:\n");
+			//for(i=0; i<RECORD_HEADER_LEN; i++){
+			//	printf("%02x ", p[i]);
+			//}
+			//printf("\n");
+			p += RECORD_HEADER_LEN;
+			check_handshake(tcp_hdr, newFlow, p, RECORD_LEN(record_hdr));
+			//printf("Length of packet: %d.\n", htons(ip_hdr->len));
+		}
+	}
+
+	/* Now if flow is in table, update state */
+	if((index = check_flow(newFlow))){
+		flow *observed = get_flow(index-1);
+
+
+		/* Pass data to packet chain */
+		add_packet(observed, packet);
+
+		/* Update flow state */
+		if(observed->packet_chain != NULL){
+			update_flow(observed);
+		}
+
+		/* Update TCP state */
+		if(tcp_hdr->flags & (FIN | RST) ){
+			/* Remove flow from table, connection ended */
+			remove_flow(index);
+		}
+
+		/* Check to see if TLS finished message has passed */
+		if(observed->state == TLS_FINISHED){
+			//decrypt packet?
+			printf("TLS finished received.\n");
+		} else {
+			//check to see if tls_finished message
+			if((observed->state == TLS_NEW_SESS) && !observed->encrypted){
+				//packet should be encrypted
+				observed->encrypted = 1;
+			} else if(observed->encrypted){ /* decrypt tls finished message */
+				printf("need to decrypt this finished message\n");
+			}
+
+		}
+	}
+
+}

+ 84 - 0
server/slitheen.h

@@ -0,0 +1,84 @@
+#ifndef _SLITHEEN_H_
+#define _SLITHEEN_H_
+#include <stdlib.h>
+#include <netinet/in.h>
+
+#define macaddr "08:00:27:e8:9d:d4"
+
+/* Ethernet addresses are 6 bytes */
+#define ETHER_ADDR_LEN	6
+#define ETHER_HEADER_LEN  2*ETHER_ADDR_LEN + 2
+
+/* Definitions for parsing packet data */
+struct ip_header {
+	u_char versionihl;		/* Version >> 4 | IHL & 0x0f */
+	u_char dscpecn;		/* DSCP >> 2 | ECN  & 0x03 */
+	u_short len;		/* Total Length */
+	u_short id;		/* Identification */
+	u_short flagsoff;		/* Flags >> 13 | Fragment Offset & 0x1fff */
+#define RF 0x8000		/* Reserved; must be zero */
+#define DF 0x4000		/* Dont Fragment */
+#define MF 0x2000		/* More Fragments */
+	u_char ttl;		/* Time To Live */
+	u_char proto;		/* Protocol */
+	u_short chksum;		/* Header Checksum */
+	struct in_addr src, dst; /* Source and Destination addresses */
+};
+#define IP_HEADER_LEN(ip)		(((ip)->versionihl) & 0x0f)*4
+
+struct tcp_header {
+	u_short src_port;	/* source port */
+	u_short dst_port;	/* destination port */
+	u_int sequence_num;		/* sequence number */
+	u_int ack_num;		/* acknowledgement number */
+	u_char offset_res_ns;	/*Data offset >> 4 |  res >> 1 | NS 0x01 */
+	u_char flags;			/* Flags */
+#define FIN 0x01
+#define RST 0x04
+	u_short win_size;		/* Window size*/
+	u_short chksum;		/* Checksum */
+	u_short urg;		/* Urgent pointer */
+};
+#define TCP_HEADER_LEN(tcp)		(((tcp)->offset_res_ns) >> 4)*4
+
+struct tls_header {
+	u_char type; /* Content Type */
+#define CCS 0x14
+#define A   0x15
+#define HS  0x16
+#define APP 0x17
+#define HB  0x18
+	u_short version; /* Version */
+	u_short len; /* Length */
+	u_char msg; /* Message Type */
+#define CLIENT_HELLO 0x01
+#define FINISHED 0x14
+};
+#define RECORD_HEADER_LEN 5
+#define CLIENT_HELLO_HEADER_LEN 6
+
+struct __attribute__((__packed__)) record_header {
+	u_char type;
+#define HS 0x16
+	u_short version;
+	u_char len1;
+	u_char len2;
+};
+#define RECORD_LEN(rec)		(((rec)->len1) << 8)+((rec)->len2)
+
+struct __attribute__((__packed__)) handshake_header {
+	u_char type; /*Handshake message type */
+	u_char len1;
+	u_char len2;
+	u_char len3;
+};
+#define HANDSHAKE_MESSAGE_LEN(hs)		(((hs)->len1) << 16)+(((hs)->len2) << 8)+ ((hs)->len3)
+#define HANDSHAKE_HEADER_LEN 4
+
+struct sniff_args {
+	char *readdev;
+	char *writedev;
+	char *filter;
+};
+
+#endif /* _SLITHEEN_H_ */

+ 153 - 0
server/util.c

@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "util.h"
+#include "slitheen.h"
+
+static fragment_table *frag_table;
+
+/**
+ * This function takes as argument a packet fragment. It checks
+ * to see if there are other pending packets. If so, it
+ * looks for matching identification numbers and attempts
+ * to reconstruct a packet. If the packet reconstruction was
+ * complete, returns a 1 and the input packet will point to
+ * the completely reassembled ip packet. If the reconstruction
+ * requires more fragments, it returns a 0. Returns -1 on error
+ */
+int report_fragment(const u_char *data, u_char *packet, u_int length){
+	int i, ret;
+	unsigned char *partial_packet;
+	const struct ip_header *ip_hdr;
+
+	ip_hdr = (struct ip_header*) data;
+	printf("fragment reported.\n");
+	/* First check to see if this belongs to a partial packet */
+	for (i=0; i<frag_table->len; i++){
+		printf("checking fragments.\n");
+		fragment *candidate = frag_table->table+i;
+		if (candidate->id == ip_hdr->id){
+			/*update fragment in table with new data */
+			printf("Matches existing packet.\n");
+			ret = update_fragment(i, data, length);
+			if(ret == 1){
+				/* Complete, copy into packet ptr */
+				printf("Successfully reconstructed packet!\n");
+				for(i=0; i<ip_hdr->len; i++){
+					packet[i] = candidate->data[i];
+				}
+			}
+			return ret;
+		}
+	}
+
+	printf("Creating new partial packet.\n");
+	/* New packet, create a new table entry */
+	fragment new_fragment;
+	new_fragment.id = ip_hdr->id;
+	new_fragment.ip_len = ip_hdr->len;
+	partial_packet = malloc(65535);
+	new_fragment.data = partial_packet;
+	if(add_fragment(new_fragment))
+		return -1;
+
+	/* Now add data into fragment */
+	printf("New partial packet created.\n");
+	return update_fragment(frag_table->len -1, data, length);
+
+}
+
+/**
+ * Initializes the table of all partialy reconstructed
+ * packets. Sets the maximum length to defined MAX_FRAGMENTS
+ */
+int init_fragment_table(void) {
+
+	frag_table = malloc(sizeof(fragment_table));
+	
+	frag_table->table = (fragment *) malloc(sizeof(fragment)*MAX_FRAGMENTS);
+	if( frag_table->table == NULL){
+		fprintf(stderr, "malloc failed.\n");
+		return 1;
+	}
+	frag_table->len = 0;
+	frag_table->max_len = MAX_FRAGMENTS;
+
+	return 0;
+}
+
+/**
+ * Adds a new fragment to the table of partial packets.
+ */
+int add_fragment(fragment new_fragment){
+	fragment *ptr;
+
+	if(frag_table->len == frag_table->max_len){
+		//grow_table();
+		return(1);
+	}
+
+	ptr = frag_table->table + frag_table->len;
+	*ptr = new_fragment;
+
+	frag_table->len ++;
+
+	return 0;
+}
+
+/**
+ * Updates an existing partial packet by copying data into
+ * packet. returns a 1 if reconstruction is complete, 0 if not,
+ * and -1 on error.
+ */
+int update_fragment(int index, const u_char *data, u_int length){
+	int i, data_length;
+	unsigned char *src, *dest;
+	const struct ip_header *ip_hdr;
+	u_short offset;
+	fragment *ptr;
+	u_int size_ip_hdr;
+
+	ip_hdr = (struct ip_header*) data;
+	offset = ip_hdr->flagsoff & 0x1fff;
+	size_ip_hdr = IP_HEADER_LEN(ip_hdr);
+
+	ptr = (fragment *) frag_table->table+index;
+	dest = ptr->data + offset;
+	src = (unsigned char *) data + size_ip_hdr;
+
+	/* Copy all but the last 4 bytes to partial packet
+	 * these belong to the ethernet footer */
+	data_length = length - size_ip_hdr - 4;
+
+	for(i=0; i< data_length; i++){
+		dest[i] = src[i];
+	}
+
+	if(i== ip_hdr->len){
+		/* return a 1! */
+		printf("Filled fragment %d from %d to %d.\n", ip_hdr->id, offset, offset + data_length);
+		return 1;
+	}
+
+	printf("Filled fragment %d from %d to %d.\n", ip_hdr->id, offset, offset+data_length);
+	printf("Still need %d to %d.\n", offset + data_length, ip_hdr->len);
+
+	return 0;
+}
+
+void remove_fragment(int index){
+	/* free ptr to data */
+
+	/* remove reference in table to fragment */
+	int i;
+	fragment *ptr;
+
+	ptr = frag_table->table + index;
+	
+	for(i=0; i< frag_table->len - index-1; i++){
+		*ptr = *(ptr + 1);
+		ptr += i;
+	}
+	frag_table->len --;
+
+}

+ 29 - 0
server/util.h

@@ -0,0 +1,29 @@
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <stdlib.h>
+
+#define MAX_FRAGMENTS 10
+
+/* Depreciated */
+
+typedef struct fragment_st {
+	u_char *data;
+	u_short ip_len; /* Length of complete packet */
+	u_short id; /* Length of the IPv4 ID number*/
+
+} fragment;
+
+typedef struct fragment_table_st {
+	fragment *table;
+	int len;
+	int max_len;
+} fragment_table;
+
+int report_fragment(const u_char *fragment, u_char *packet, u_int length);
+int init_fragment_table(void);
+int add_fragment(fragment new_fragment);
+void remove_fragment(int index);
+int update_fragment(int index, const u_char *data, u_int length);
+
+#endif /* _UTIL_H_ */