Explorar el Código

made connection table and switched from processes to threads

cbocovic hace 9 años
padre
commit
d63fe78cc9
Se han modificado 5 ficheros con 405 adiciones y 133 borrados
  1. 4 4
      server/Makefile
  2. 132 0
      server/flow.c
  3. 46 0
      server/flow.h
  4. 0 54
      server/rserv.c
  5. 223 75
      server/slitheen-proxy.c

+ 4 - 4
server/Makefile

@@ -1,16 +1,16 @@
-CFLAGS=-g
+CFLAGS=-g -Wall
 
 TARGETS=slitheen-proxy
 
 all: $(TARGETS)
 
-slitheen-proxy.o rserv.o ptwist168.o:: ptwist.h rserv.h
+slitheen-proxy.o flow.o rserv.o ptwist168.o:: ptwist.h rserv.h flow.h
 
 rserv: rserv.o ptwist168.o
 	gcc -g -o $@ $^ -lssl -lcrypto
 
-slitheen-proxy: slitheen-proxy.o rserv.o ptwist168.o ptwist.h rserv.h
-	gcc -g -o $@ $^ -lssl -lcrypto -lpcap
+slitheen-proxy: slitheen-proxy.o flow.o rserv.o ptwist168.o ptwist.h rserv.h flow.h
+	gcc -g -o $@ $^ -lssl -lcrypto -lpcap -lpthread
 
 clean:
 	-rm *.o

+ 132 - 0
server/flow.c

@@ -0,0 +1,132 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "flow.h"
+
+static flow_table *table;
+
+/* Initialize the table of tagged flows */
+int init_flow_table(void) {
+
+	table = malloc(sizeof(flow_table));
+	
+	table->table = (flow *) malloc(sizeof(flow)*MAX_FLOWS);
+	if( table->table == NULL){
+		fprintf(stderr, "malloc failed.\n");
+		return 1;
+	}
+	table->len = 0;
+	table->max_len = MAX_FLOWS;
+
+	return 0;
+}
+
+
+/* Add a new flow to the tagged flow table */
+int add_flow(flow newFlow) {
+	flow *ptr;
+
+	if(table->len == table->max_len){
+		//grow_table();
+		return(1);
+	}
+	printf("there are %d flows in the table\n", table->len);
+
+	ptr = table->table + table->len;
+	newFlow.tls_state = 1;
+	newFlow.encrypted = 0;
+	*ptr = newFlow;
+
+	table->len ++;
+
+	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; 
+				break;
+		case 2: state = state | TLS_SERV_HELLO; 
+				break;
+		case 4: state = state | TLS_NEW_SESS; 
+				break;
+		case 16: state = state | TLS_KEY_EXCHG; 
+				break;
+		case 20: state = state | TLS_FINISHED; 
+				break;
+	}
+	f->tls_state = state;
+	return 0;
+}
+
+int remove_flow(int index) {
+	int i;
+	flow *ptr;
+
+	if(index){
+		ptr = table->table + index -1;
+		for(i=0; i< table->len - index; i++){
+			ptr += i;
+			*ptr = *(ptr + 1);
+		}
+		table->len --;
+	} else {
+		return 1;
+	}
+
+	printf("flow removed!\n");
+	return 0;
+}
+
+int grow_table() {
+	return 0;
+}
+
+int check_flow(flow observed){
+	/* Loop through flows in table and see if it exists */
+	int i;
+	flow *candidate = table->table;
+
+	/* Check first in this direction */
+	for(i=0; i<table->len; i++){
+		candidate += i;
+		if(candidate->src_ip.s_addr == observed.src_ip.s_addr){
+			if(candidate->dst_ip.s_addr == observed.dst_ip.s_addr){
+				if(candidate->src_port == observed.src_port){
+					if(candidate->dst_port == observed.dst_port){
+						return i+1;
+					}
+				}
+			}
+		}
+	}
+
+
+	candidate = table->table;
+	/* Then in the other direction */
+	for(i=0; i<table->len; i++){
+		candidate += i;
+		if(candidate->src_ip.s_addr == observed.dst_ip.s_addr){
+			if(candidate->dst_ip.s_addr == observed.src_ip.s_addr){
+				if(candidate->src_port == observed.dst_port){
+					if(candidate->dst_port == observed.src_port){
+						return i+1;
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+flow *get_flow(int index){
+	if(index < table->len){
+		return table->table+index;
+	} else {
+		return NULL;
+	}
+}
+

+ 46 - 0
server/flow.h

@@ -0,0 +1,46 @@
+#ifndef __RELAY_H__
+#define __RELAY_H__
+
+#include <netinet/in.h>
+#include "ptwist.h"
+
+#define MAX_FLOWS 10
+
+#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;
+
+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 */
+
+	u_int seq_num;		/* sequence number */
+
+	byte key[16];		/* negotiated key */
+	int tls_state;		/* TLS handshake state */
+	int encrypted;		/* indicates whether flow is encrypted */
+
+} flow;
+
+typedef struct flow_table_st {
+	flow *table;
+	int len;
+	int max_len;
+} flow_table;
+
+
+int init_flow_table (void);
+int add_flow(flow newFlow);
+int update_flow(int index, int code);
+int remove_flow(int index);
+int check_flow(flow observed);
+flow *get_flow(int index);
+
+#endif /* __RELAY_H__ */

+ 0 - 54
server/rserv.c

@@ -80,57 +80,3 @@ int check_tag(byte key[16], const byte privkey[PTWIST_BYTES],
     return ret;
 }
 
-/*
-int main(int argc, char **argv)
-{
-    FILE *fp;
-    int res;
-    byte privkey[PTWIST_BYTES];
-    byte tag[PTWIST_TAG_BYTES];
-    int tottagged = 0;
-    int totuntagged = 0;
-    const char *tagsfile = argc > 1 ? argv[1] : "tags";
-
-    /* Load the private key 
-    fp = fopen("privkey", "rb");
-    if (fp == NULL) {
-	perror("fopen");
-	exit(1);
-    }
-    res = fread(privkey, PTWIST_BYTES, 1, fp);
-    if (res < 1) {
-	perror("fread");
-	exit(1);
-    }
-    fclose(fp);
-
-    /* Validate the tags in the tags file 
-    fp = fopen(tagsfile, "rb");
-    if (fp == NULL) {
-	perror("fopen");
-	exit(1);
-    }
-    while (fread(tag, PTWIST_TAG_BYTES, 1, fp) == 1) {
-	byte key[16];
-	int res = check_tag(key, privkey, tag, (const byte *)"context", 7);
-	tottagged += (!res);
-	totuntagged += (!(!res));
-#if 0
-	if (res) {
-	    printf("Untagged\n");
-	} else {
-	    int j;
-	    for(j=0;j<16;++j) {
-		printf("%02x", key[j]);
-	    }
-	    printf("\n");
-	}
-#endif
-    }
-    fclose(fp);
-
-    printf("%d tagged, %d untagged\n", tottagged, totuntagged);
-
-    return 0;
-}
-*/

+ 223 - 75
server/slitheen-proxy.c

@@ -1,103 +1,240 @@
 #include <pcap.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
 #include "ptwist.h"
 #include "rserv.h"
+#include "flow.h"
 
 #define macaddr "08:00:27:e8:9d:d4"
 
-//Definitions for parsing packet data
-#define ETHER_ADDR_LEN 6
-#define ETHER_HDR_LEN  2*ETHER_ADDR_LEN + 2
-#define RECORD_HDR 5
-#define CLIENT_HELLO_HDR 4
-#define CLIENT_HELLO_RAND 32
+/* 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;
+};
 
 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 *sniff_packets(void *);
+
+void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *ptr){
 
-//TODO: look for slitheen tag. The ClientHello message starts at offset 0x4d of packet after TCP 3-way handshake and has flag [P.].
-//For now, write *all* clientHello msgs to a file
-void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){
-	pcap_t *handle;
-	char errbuf[BUFSIZ];
-	char *writedev = args;
-	int i, res;
-	const unsigned char *p;
 	FILE *fp;
+	int res, i, code;
+	unsigned char *p;
 
     byte privkey[PTWIST_BYTES];
 	byte key[16];
 
-	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 = packet;
-	p += ETHER_HDR_LEN; //skip ethernet header
-	p += (p[0] & 0x0f)*4;	//skip IP header
-	p += 12; //skip first part of TCP header
-	p += (p[0] >> 4)*4 - 12; //skip rest of TCP header
-	//check for handshake message
-	if (p[0] == 0x16){
-		p += RECORD_HDR;
-		if (p[0] == 0x01){
-			p += CLIENT_HELLO_HDR;
-			p += 2; //dunno what these are
-			//now pointing to hello random :D
-			p += 4; //skipping time bytes
-			/* Load the private key */
-			fp = fopen("privkey", "rb");
+	p = ptr;
+	code = p[0];
+
+	printf("handshake code: %d\n", code);
+
+	if (code == 0x01){
+		p += CLIENT_HELLO_HEADER_LEN;
+		//now pointing to hello random :D
+		p += 4; //skipping time bytes
+		/* Load the private key */
+		fp = fopen("privkey", "rb");
+		if (fp == NULL) {
+			perror("fopen");
+			exit(1);
+		}
+		res = fread(privkey, PTWIST_BYTES, 1, fp);
+		if (res < 1) {
+			perror("fread");
+			exit(1);
+		}
+		fclose(fp);
+
+		/* check tag*/ 
+		res = check_tag(key, privkey, p, (const byte *)"context", 7);
+		if (res) {
+			printf("Untagged\n");
+		} else {
+			fp = fopen("tags", "wb");
 			if (fp == NULL) {
 				perror("fopen");
 				exit(1);
 			}
-			res = fread(privkey, PTWIST_BYTES, 1, fp);
-			if (res < 1) {
-				perror("fread");
-				exit(1);
+			//Write tag to file
+			for(i=0; i< 28; i++){
+				fprintf(fp, "%02x ", p[i]);
 			}
 			fclose(fp);
+			strncpy((char *) f.key, (char *) key, 16);
+
+			/* Save flow in table */
+			printf("saving flow..\n");
+			add_flow(f);
+			printf("saved\n");
 
-			/* check tag*/ 
-			res = check_tag(key, privkey, p, (const byte *)"context", 7);
-			if (res) {
-				printf("Untagged\n");
-			} else {
-				fp = fopen("tags", "wb");
-				if (fp == NULL) {
-					perror("fopen");
-					exit(1);
-				}
-				//Write tag to file
-				for(i=0; i< 28; i++){
-					fprintf(fp, "%02x ", p[i]);
-				}
-				fclose(fp);
+		}
+	} else {
+		int index = check_flow(f);
+		update_flow(index, code);
+	}
+
+}
+
+void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){
+	pcap_t *handle;
+	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);
+		}
+	}
+
+	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);
 			}
+
+		}
+
+		/* 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);
 
-	if((pcap_inject(handle, packet, header->len)) < 0 ){
-		fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
+	} else {
+
+		if((pcap_inject(handle, packet, header->len)) < 0 ){
+			fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
+		}
 	}
 
 	pcap_close(handle);
 
 }
 
-int usage(void){
+void usage(void){
 	printf("Usage: slitheen-proxy [internal network interface] [NAT interface]\n");
 }
 
 int main(int argc, char *argv[]){
-	pid_t pid;
+	pthread_t t1, t2;
 	char filter1[33] = "ether src host 08:00:27:e8:9d:d4";
 	char filter2[33] = "ether src host 08:00:27:e8:9d:d4";
 
 	char *dev1 = NULL; /* Device that leads to the internal network */
 	char *dev2 = NULL; /* Device that leads out to the world */
 
+	struct sniff_args outbound;
+	struct sniff_args inbound;
+
 	if (argc != 3) { 
 		usage();
 		return(2);
@@ -108,30 +245,40 @@ int main(int argc, char *argv[]){
 	snprintf(filter1, 33, "ether src host %s", macaddr);
 	snprintf(filter2, 33, "ether dst host %s", macaddr);
 
-	pid = fork();
-	if (pid < 0) {
-		fprintf(stderr, "Fork call failed.\n");
-		return(2);
-	}
-	if (pid == 0) {
-		sniff_packets(dev1, dev2, filter1);		
-	} else {
-		sniff_packets(dev2, dev1, filter2);
-	}
+	init_flow_table();
+
+	/* Create threads */
+	outbound.readdev = dev1;
+	outbound.writedev = dev2;
+	outbound.filter = filter1;
+	inbound.readdev = dev2;
+	inbound.writedev = dev1;
+	inbound.filter = filter2;
+	pthread_create(&t1, NULL, sniff_packets, (void *) &outbound);
+	pthread_create(&t2, NULL, sniff_packets, (void *) &inbound);
+
+	pthread_join(t1, NULL);
+	pthread_join(t2, NULL);
 	
 	return(0);
 }
 
-int sniff_packets(char *readdev, char *writedev, char *filter){
+void *sniff_packets(void *args){
 	pcap_t *handle;
 	char errbuf[BUFSIZ];
 	struct bpf_program fp;
 	bpf_u_int32 mask;
 	bpf_u_int32 net;
 
+	char *readdev, *writedev, *filter;
+	struct sniff_args *arg_st = (struct sniff_args *) args;
+	readdev = arg_st->readdev;
+	writedev = arg_st->writedev;
+	filter = arg_st->filter;
+
 	if (pcap_lookupnet(readdev, &net, &mask, errbuf) == -1){
 		fprintf(stderr, "Can't get netmask for device %s\n", readdev);
-		return(2);
+		exit(2);
 	}
 
 	handle = pcap_open_live(readdev, BUFSIZ, 1, 1000, errbuf);
@@ -141,23 +288,24 @@ int sniff_packets(char *readdev, char *writedev, char *filter){
 
 	if(pcap_datalink(handle) != DLT_EN10MB) {
 		fprintf(stderr, "Device %s does not provide Ethernet headers - not supported\n", readdev);
-		return(2);
+		exit(2);
 	}
 
 	if(pcap_compile(handle, &fp, filter, 0 , net) == -1){
 		fprintf(stderr, "Couldn't parse filter %s: %s\n", filter, pcap_geterr(handle));
-		return(2);
+		exit(2);
 	}
 
 	if (pcap_setfilter(handle, &fp) == -1) {
 		fprintf(stderr, "Couldn't install filter %s: %s\n", filter, pcap_geterr(handle));
-		return(2);
+		exit(2);
 	}
 
 	/*callback function*/
-	pcap_loop(handle, -1, got_packet, writedev);
+	pcap_loop(handle, -1, got_packet, (unsigned char *) writedev);
 
 	/*Sniff a packet*/
 	pcap_close(handle);
-	return(0);
+
+	return NULL;
 }