Browse Source

fixed bugs in replacement code

cbocovic 9 years ago
parent
commit
76103ca00b
8 changed files with 489 additions and 61 deletions
  1. 105 22
      server/crypto.c
  2. 1 1
      server/crypto.h
  3. 18 3
      server/flow.c
  4. 10 2
      server/flow.h
  5. 319 8
      server/relay.c
  6. 2 0
      server/relay.h
  7. 27 25
      server/slitheen-proxy.c
  8. 7 0
      server/slitheen.h

+ 105 - 22
server/crypto.c

@@ -59,18 +59,47 @@ int extract_parameters(flow *f, uint8_t *hs){
 	return 0;
 }
 
-/* Decrypt the TLS FINISHED message
- * Verify that the data is:
- * 	PRF(master_secret, finished_label, Hash(handshake_messages))*/
-int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type){
+/** MAC a message
+ * TODO: look at tls1_mac in t1_enc.c
+ * For now, only goes one way (macs message to be written)
+ */
+int32_t mac(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc){
+	uint8_t *seq;
+	uint8_t header[13];
+	int32_t md_size;
+
+	//TODO: update this is I need more than two
+	seq = (incoming) ? f->read_seq : f->write_seq;
+
+    header[8] = type;
+    header[9] = 0x03;//TODO: update for different versions
+    header[10] = 0x03;
+    header[11] = (len) >> 8;
+    header[12] = (len) & 0xff;
+
+	EVP_DigestSignUpdate(f->read_mac_ctx, header, sizeof(header));
+	EVP_DigestSignUpdate(f->read_mac_ctx, input, len);
+	int32_t t = EVP_DigestSignFinal(f->read_mac_ctx, output, &md_size);
+
+	return md_size;
+
+}
+
+/* Encrypt/decrypt message
+ *
+ */
+int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc){
 	uint8_t *p = input;
 	
-	EVP_CIPHER_CTX *ds = (incoming) ? f->read_ctx : f->write_ctx;
+	EVP_CIPHER_CTX *ds = (incoming) ? ((enc) ? f->srvr_write_ctx : f->clnt_read_ctx) : ((enc) ? f->clnt_write_ctx : f->srvr_read_ctx) ;
 	if(ds == NULL){
 		printf("FAIL\n");
 		return 1;
 	}
-	uint8_t *seq = (incoming) ? f->read_seq : f->write_seq;
+
+	//TODO: wrap my mind around this, might need 2 more
+	uint8_t *seq;
+	seq = (incoming) ? f->read_seq : f->write_seq;
 
 	if(f->application && (ds->iv[EVP_GCM_TLS_FIXED_IV_LEN] == 0)){
 		//fill in rest of iv
@@ -86,26 +115,32 @@ int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incom
 //	printf("\n");
 
 	int32_t bs = EVP_CIPHER_block_size(ds->cipher);
+	printf("bs = %d\n", bs);
 	//padding stuff? TODO: understand this
 	uint8_t buf[13];
 	memcpy(buf, seq, 8);
+
 	for(int i=7; i>=0; i--){
 		++seq[i];
 		if(seq[i] != 0)
 			break;
 	}
+	
 	buf[8] = type;
 	buf[9] = 0x03;
 	buf[10] = 0x03;
 	buf[11] = len >> 8; //len >> 8;
 	buf[12] = len & 0xff;//len *0xff;
 	int32_t pad = EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_AEAD_TLS1_AAD,
-			13, buf);
-	//printf("buf: ");
-	//for(int i=0; i<13; i++){
-//		printf("%02x ", buf[i]);
-//	}
-//	printf("\n");
+			13, buf); // = int32_t pad?
+	printf("buf (%s): ", incoming ? "read" : "write");
+	for(int i=0; i<13; i++){
+		printf("%02x ", buf[i]);
+	}
+	printf("\n");
+
+	if(enc)
+		len += pad;
 
 /*	printf("Decrypting: ");
 	for(int i=0; i<len; i++){
@@ -114,15 +149,23 @@ int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incom
 	printf("\n");*/
 	int32_t n = EVP_Cipher(ds, p, p, len); //decrypt in place
 	if(n<0) return 0;
+	printf("%s %d bytes\n", (enc) ? "Encrypted" : "Decrypted", n);
+	printf("seq after (%s): ", incoming ? "read" : "write");
+	for(int i=0; i<8; i++){
+		printf("%02x ", seq[i]);
+	}
+	printf("\n");
 /*	printf("Decrypted: ");
 	for(int i=0; i<n; i++){
 		printf("%02x ", p[i]);
 	}
 	printf("\n");
 	printf("decrypted %d/%d bytes.\n", n, len);*/
-	p[EVP_GCM_TLS_EXPLICIT_IV_LEN+n] = '\0';
+	if(!enc)
+		p[EVP_GCM_TLS_EXPLICIT_IV_LEN+n] = '\0';
 
-	return 1;
+
+	return n;
 }
 
 int verify_finish_hash(flow *f, uint8_t *p, int32_t incoming){
@@ -323,8 +366,15 @@ int init_ciphers(flow *f){
 
 	EVP_CIPHER_CTX *r_ctx;
 	EVP_CIPHER_CTX *w_ctx;
+	EVP_CIPHER_CTX *w_ctx_srvr;
+	EVP_CIPHER_CTX *r_ctx_srvr;
 	const EVP_CIPHER *c = EVP_aes_256_gcm();
 
+	EVP_MD_CTX *read_mac_ctx;
+	EVP_MD_CTX *write_mac_ctx;
+	EVP_PKEY *read_mac_key;
+	EVP_PKEY *write_mac_key;
+
 	/* Generate Keys */
 	uint8_t *write_mac, *write_key, *write_iv;
 	uint8_t *read_mac, *read_key, *read_iv;
@@ -332,7 +382,7 @@ int init_ciphers(flow *f){
 
 	key_len = EVP_CIPHER_key_length(c);
 	iv_len = EVP_CIPHER_iv_length(c); //EVP_GCM_TLS_FIXED_IV_LEN;
-	mac_len = EVP_MD_size(EVP_get_digestbyname(SN_sha384));
+	mac_len = EVP_MD_size(EVP_sha384());
 	int32_t total_len = key_len + iv_len + mac_len;
 	total_len *= 2;
 	uint8_t *key_block = calloc(1, total_len);
@@ -359,13 +409,38 @@ int init_ciphers(flow *f){
 	write_mac = key_block + 2*key_len + 2*iv_len;
 	read_mac = key_block + 2*key_len + 2*iv_len + mac_len;
 
+	/*
+	printf("read_mac: \n");
+	for(int i=0; i< mac_len; i++){
+		printf("%02x ", read_mac[i]);
+	}
+	printf("write_mac: \n");
+	for(int i=0; i< mac_len; i++){
+		printf("%02x ", write_mac[i]);
+	}*/
+
 	/* Initialize Cipher Contexts */
 	r_ctx = EVP_CIPHER_CTX_new();
 	w_ctx = EVP_CIPHER_CTX_new();
 	EVP_CIPHER_CTX_init(r_ctx);
 	EVP_CIPHER_CTX_init(w_ctx);
-
-/*#ifdef KSSL_DEBUG
+	w_ctx_srvr = EVP_CIPHER_CTX_new();
+	r_ctx_srvr = EVP_CIPHER_CTX_new();
+	EVP_CIPHER_CTX_init(w_ctx_srvr);
+	EVP_CIPHER_CTX_init(r_ctx_srvr);
+
+	/* Initialize MACs */
+	read_mac_ctx = EVP_MD_CTX_create();
+	write_mac_ctx = EVP_MD_CTX_create();
+	/*read_mac_key =EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, read_mac, mac_len);
+	write_mac_key =EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, write_mac, mac_len);
+	EVP_DigestSignInit(read_mac_ctx, NULL, EVP_sha384(), NULL, read_mac_key);
+	EVP_DigestSignInit(write_mac_ctx, NULL, EVP_sha384(), NULL, write_mac_key);
+	EVP_PKEY_free(read_mac_key);
+	EVP_PKEY_free(write_mac_key);*/
+
+
+#ifdef KSSL_DEBUG
     {
         int i;
         fprintf(stderr, "EVP_CipherInit_ex(r_ctx,c,key=,iv=,which)\n");
@@ -378,7 +453,7 @@ int init_ciphers(flow *f){
             fprintf(stderr, "%02x", read_iv[i]);
         fprintf(stderr, "\n");
     }
-//#endif                           KSSL_DEBUG_
+#endif                           KSSL_DEBUG_
     {
         int i;
         fprintf(stderr, "EVP_CipherInit_ex(w_ctx,c,key=,iv=,which)\n");
@@ -395,12 +470,20 @@ int init_ciphers(flow *f){
 
 
 	EVP_CipherInit_ex(r_ctx, c, NULL, read_key, NULL, 0);
-	EVP_CipherInit_ex(w_ctx, c, NULL, write_key, NULL, 0);
+	EVP_CipherInit_ex(w_ctx, c, NULL, write_key, NULL, 1);
+	EVP_CipherInit_ex(w_ctx_srvr, c, NULL, read_key, NULL, 1);
+	EVP_CipherInit_ex(r_ctx_srvr, c, NULL, write_key, NULL, 0);
 	EVP_CIPHER_CTX_ctrl(r_ctx, EVP_CTRL_GCM_SET_IV_FIXED, EVP_GCM_TLS_FIXED_IV_LEN, read_iv);
 	EVP_CIPHER_CTX_ctrl(w_ctx, EVP_CTRL_GCM_SET_IV_FIXED, EVP_GCM_TLS_FIXED_IV_LEN, write_iv);
-
-	f->read_ctx = r_ctx;
-	f->write_ctx = w_ctx;
+	EVP_CIPHER_CTX_ctrl(w_ctx_srvr, EVP_CTRL_GCM_SET_IV_FIXED, EVP_GCM_TLS_FIXED_IV_LEN, read_iv);
+	EVP_CIPHER_CTX_ctrl(r_ctx_srvr, EVP_CTRL_GCM_SET_IV_FIXED, EVP_GCM_TLS_FIXED_IV_LEN, write_iv);
+
+	f->clnt_read_ctx = r_ctx;
+	f->clnt_write_ctx = w_ctx;
+	f->srvr_read_ctx = r_ctx_srvr;
+	f->srvr_write_ctx = w_ctx_srvr;
+	f->read_mac_ctx = read_mac_ctx;
+	f->write_mac_ctx = write_mac_ctx;
 
 	return 0;
 }

+ 1 - 1
server/crypto.h

@@ -6,7 +6,7 @@
 							(((unsigned int)(c[1]))    )),c+=2)
 
 int extract_parameters(flow *f, uint8_t *hs);
-int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type);
+int encrypt(flow *f, uint8_t *input, uint8_t *output, int32_t len, int32_t incoming, int32_t type, int32_t enc);
 void extract_server_random(flow *f, uint8_t *hs);
 int compute_master_secret(flow *f);
 

+ 18 - 3
server/flow.c

@@ -43,6 +43,9 @@ flow *add_flow(flow newFlow) {
 	newFlow.application = 0;
 	newFlow.packet_chain = NULL;
 	newFlow.censored_queue = calloc(1,2048);
+	newFlow.censored_length = 0;
+	newFlow.outbox_len = 0;
+
 	newFlow.finish_md_ctx = EVP_MD_CTX_create();
 	const EVP_MD *md = EVP_sha384();
 	EVP_DigestInit_ex(newFlow.finish_md_ctx, md, NULL);
@@ -113,7 +116,7 @@ int update_flow(flow *f) {
 			printf("Handshake Message:\n");
 
 			if((incoming && f->in_encrypted) || (!incoming && f->out_encrypted)){
-				encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16);
+				encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16, 0);
 				p += EVP_GCM_TLS_EXPLICIT_IV_LEN;
 				if(incoming) f->in_encrypted = 2;
 				else f->out_encrypted = 2;
@@ -178,6 +181,16 @@ int update_flow(flow *f) {
 					if((f->in_encrypted == 2) && (f->out_encrypted == 2)){
 						printf("Handshake complete!\n");
 						f->application = 1;
+						if(current->incoming)
+							f->seq_num = current->seq_num + current->len;
+						printf("current sequence number: %d = %d, plus length %d\n", f->seq_num, current->seq_num, current->len);
+						//update sequence number to reflect latest incoming packet
+						while(current->next != NULL){
+							current = current->next;
+							if(current->incoming)
+								f->seq_num = current->seq_num+ current->len;
+							printf("current sequence number: %d, plus length %d\n", current->seq_num, current->len);
+						}
 					}
 					break;
 				default:
@@ -203,7 +216,7 @@ int update_flow(flow *f) {
 			p = record;
 			p += RECORD_HEADER_LEN;
 
-			encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16);
+			encrypt(f, p, p, record_len - RECORD_HEADER_LEN, incoming, 0x16, 0);
 			p += EVP_GCM_TLS_EXPLICIT_IV_LEN;
 			printf("Alert: %02x %02x\n", p[0], p[1]);
 			break;
@@ -220,7 +233,8 @@ int update_flow(flow *f) {
 			}
 			return 0;
 	}
-
+	//TODO: clean this up
+	if(!f->application){
 	f->seq_num = current->seq_num;
 
 	if(record_len == data_len){
@@ -233,6 +247,7 @@ int update_flow(flow *f) {
 		current->data_len = data_len - record_len;
 		update_flow(f);
 	}
+	}
 
 	free(record);
 	return 0;

+ 10 - 2
server/flow.h

@@ -44,12 +44,17 @@ typedef struct flow_st {
 	int application; /* indicates handshake is complete */
 	packet *packet_chain; /* currently held data */
 	uint8_t *censored_queue;
+	uint32_t censored_length;
 	DH *dh;
 
 	uint8_t handshake_hash[EVP_MAX_MD_SIZE];
 	EVP_MD_CTX *finish_md_ctx;
-	EVP_CIPHER_CTX *read_ctx;
-	EVP_CIPHER_CTX *write_ctx;
+	EVP_CIPHER_CTX *clnt_read_ctx;
+	EVP_CIPHER_CTX *clnt_write_ctx;
+	EVP_CIPHER_CTX *srvr_read_ctx;
+	EVP_CIPHER_CTX *srvr_write_ctx;
+	EVP_MD_CTX *read_mac_ctx;
+	EVP_MD_CTX *write_mac_ctx;
 
 	uint8_t client_random[SSL3_RANDOM_SIZE];
 	uint8_t server_random[SSL3_RANDOM_SIZE];
@@ -58,6 +63,9 @@ typedef struct flow_st {
 	uint8_t read_seq[8];
 	uint8_t write_seq[8];
 
+	uint8_t *outbox;
+	int32_t outbox_len;
+
 } flow;
 
 typedef struct flow_table_st {

+ 319 - 8
server/relay.c

@@ -31,13 +31,13 @@ int replace_packet(flow *f, uint8_t *packet){
 
 	tcp_hdr = (struct tcp_header*) p;
 	int size_tcp = TCP_HEADER_LEN(tcp_hdr);
-	p += size_tcp;
 
 	/*fprintf(stderr,"Flow: %d > %d (%s)\n", ip_hdr->src.s_addr, ip_hdr->dst.s_addr, (ip_hdr->src.s_addr != f->src_ip.s_addr)? "incoming":"outgoing");
 	fprintf(stderr,"ID number: %u\n", htonl(ip_hdr->id));
 	fprintf(stderr,"Sequence number: %u\n", htonl(tcp_hdr->sequence_num));
 	fprintf(stderr,"Acknowledgement number: %u\n", htonl(tcp_hdr->ack_num));*/
-	int app_data_len = htons(ip_hdr->len) - (size_ip + size_tcp);
+	int32_t app_data_len = htons(ip_hdr->len) - (size_ip + size_tcp);
+	printf("app_data length: %u\n", app_data_len);
 	if(app_data_len <= 0){
 		return 0;
 	}
@@ -46,6 +46,27 @@ int replace_packet(flow *f, uint8_t *packet){
 	if(ip_hdr->src.s_addr == f->src_ip.s_addr){
 		read_header(f, packet);
 		return 0;
+	} else {
+		printf("Current sequence number: %d\n", f->seq_num);
+		printf("Received sequence number: %d\n", htonl(tcp_hdr->sequence_num));
+		uint32_t offset = htonl(tcp_hdr->sequence_num) - f->seq_num;
+		if(offset == 0)
+			f->seq_num += app_data_len;
+		/* if incoming, replace with data from queue */
+		//if(htonl(tcp_hdr->sequence_num) >= f->seq_num){
+			replace_contents(f, p, app_data_len, offset, ip_hdr->src, ip_hdr->dst);
+		//}//TODO: need to do something about replaying packets (maybe store previously sent data??
+
+		p = packet + ETHER_HEADER_LEN;
+#ifdef DEBUG
+		fprintf(stdout, "ip hdr length: %d\n", htons(ip_hdr->len));
+		fprintf(stdout, "Injecting the following packet:\n");
+		for(int i=0; i< htons(ip_hdr->len); i++){
+			fprintf(stdout, "%02x ", p[i]);
+		}
+		fprintf(stdout, "\n");
+		fflush(stdout);
+#endif
 	}
 	return 0;
 
@@ -85,14 +106,24 @@ int read_header(flow *f, uint8_t *packet){
 
 	memcpy(decrypted_data, p, record_length);
 
-	if(!encrypt(f, decrypted_data, decrypted_data, record_length, 0, 0x17)){
-		fprintf(stderr,"decryption failed\n");
+	if(!encrypt(f, decrypted_data, decrypted_data, record_length, 0, record_hdr->type, 0)){
+		fprintf(stdout,"decryption failed\n");
 		return 0;
 	} else {
-		fprintf(stderr, "decryption succeeded!\n");
-		decrypted_data+= EVP_GCM_TLS_EXPLICIT_IV_LEN;
-		fprintf(stderr, "request:");
-		fprintf(stderr,"%s\n ", decrypted_data);
+		fprintf(stdout, "decryption succeeded!\n");
+		if(record_hdr->type == 0x17){
+			decrypted_data+= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+			fprintf(stdout, "request:");
+			fprintf(stdout,"%s\n ", decrypted_data);
+		}
+		
+	}
+	if(record_hdr->type == 0x15){
+		printf("received alert\n");
+		for(int i=0; i<record_length; i++){
+			printf("%02x ", decrypted_data[i]);
+		}
+		fflush(stdout);
 	}
 
 	/* search through decrypted data for x-ignore */
@@ -196,6 +227,7 @@ int read_header(flow *f, uint8_t *packet){
 	for(int i=0; i< bytes_read; i++){
 		f->censored_queue[i] = buf[i];
 	}
+	f->censored_length = bytes_read;
 
 	//for now, just close socket
 	close(handle);
@@ -203,3 +235,282 @@ int read_header(flow *f, uint8_t *packet){
 	return 0;
 
 }
+
+int replace_contents(flow *f, uint8_t *data, int32_t data_len, int32_t offset, struct in_addr src, struct in_addr dst){
+
+	printf("Replacing contents...\n");
+	uint8_t *p = data;
+
+	struct tcp_header *tcp_hdr = (struct tcp_header*) p;
+	int size_tcp = TCP_HEADER_LEN(tcp_hdr);
+	p += size_tcp;
+
+	int32_t tmp_len = data_len;
+
+	//step 1: replace record contents
+	//note: encrypted message will be original message size + EVP_GCM_TLS_EXPLICIT_IV_LEN + 16 byte pad
+	//first check to see if there's anything in the outbox
+	if(f->outbox_len > 0){
+		printf("Printing from outbox\n");
+		if(f->outbox_len < data_len){
+			printf("Next record:\n");
+			for(int i=0; i< RECORD_HEADER_LEN; i++){
+				printf("%02x ", p[f->outbox_len+i]);
+			}
+			printf("\n");
+		} else {
+			printf("Outbox takes up entire packet\n");
+		}
+
+		if(tmp_len >= f->outbox_len){
+			memcpy(p, f->outbox, f->outbox_len);
+
+			p += f->outbox_len;
+			tmp_len -= f->outbox_len;
+			f->outbox_len = 0;
+			free(f->outbox);
+			printf("outbox now empty\n");
+		} else {
+			printf("Outbox has %d - %d bytes\n", f->outbox_len, tmp_len);
+			memcpy(p, f->outbox, tmp_len);
+			uint8_t *tmp = calloc(1, f->outbox_len - tmp_len);
+			f->outbox_len -= tmp_len;
+			memcpy(tmp, f->outbox + tmp_len, f->outbox_len);
+			free(f->outbox);
+			f->outbox = tmp;
+			printf(" = %d bytes left in outbox\n", f->outbox_len);
+			tmp_len -= tmp_len;
+		}
+	}
+
+	while(tmp_len > 0){
+
+		struct record_header *record_hdr = (struct record_header*) p;
+		uint32_t record_length = RECORD_LEN(record_hdr);
+		fprintf(stdout, "Record:\n");
+		for(int i=0; i< RECORD_HEADER_LEN; i++){
+			printf("%02x ", p[i]);
+		}
+		printf("\n");
+
+		p += RECORD_HEADER_LEN;
+		if(record_hdr->type != 0x17){
+			//TODO: might need to decrypt and re-encrypt
+			printf("received non-application data\n");
+			tmp_len -= (record_length+ RECORD_HEADER_LEN);
+			p += record_length;
+			continue;
+		}
+
+		uint8_t *new_record = calloc(1, record_length);
+		memcpy(new_record, p, record_length);
+		uint8_t *tmp_p = new_record;
+
+
+		/*// BEGIN TEST CODE //
+
+		//Print original record
+		printf("Original record (%d bytes):\n", record_length);
+		for(int i=0; i< record_length; i++){
+			printf("%02x ", p[i]);
+		}
+		printf("\n");
+
+		//print few bytes of next record (if present)
+		if(data_len > record_length + RECORD_HEADER_LEN){
+			printf("Next record:\n");
+			for(int i=0; i< RECORD_HEADER_LEN; i++){
+				printf("%02x ", p[record_length+i]);
+			}
+			printf("\n");
+		} else {
+			printf("No extra record: %d = %d + %d\n", data_len, record_length, RECORD_HEADER_LEN);
+		}
+
+
+		//Decrypt record
+		printf("Decrypting record... ");
+		int n;
+		if(!(n = encrypt(f, p, p, record_length, 1, 0x17, 0))){
+			fprintf(stderr,"failed\n");
+			return 0;
+		} else {
+			fprintf(stderr, "succeeded!\n");
+			printf("Decrypted record:\n");
+			for(int i=0; i< record_length; i++){
+				printf("%02x ", p[i]);
+			}
+			printf("\n");
+			printf("%s\n", p+ EVP_GCM_TLS_EXPLICIT_IV_LEN);
+		}
+
+		//return seq to what it was
+		for(int i=7; i>=0; i--){
+			--f->read_seq[i];
+			if(f->read_seq[i] >= 0)
+				break;
+			else
+				f->read_seq[i] = 0;
+		}
+		printf("seq reverted (%s): ", "read");
+		for(int i=0; i<8; i++){
+			printf("%02x ", f->read_seq[i]);
+		}
+		printf("\n");
+
+		//Now reposition it to be fed into encrypt function
+		//memcpy(p, p+ EVP_GCM_TLS_EXPLICIT_IV_LEN, n);
+
+		// END TEST CODE */
+
+		//step 2: figure out what happens if we don't have data
+		tmp_p += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+		
+		struct slitheen_header *sl_hdr = (struct slitheen_header *) tmp_p;
+		sl_hdr->marker = 0x01;
+		sl_hdr->version = 0x01;
+		int32_t remaining = record_length - (SLITHEEN_HEADER_LEN
+				+ EVP_GCM_TLS_EXPLICIT_IV_LEN + 16);
+		fprintf(stdout, "filling with censored queue data (%d out of %d) at offset %d\n", remaining, f->censored_length-offset, offset);
+		if(remaining > 0){
+			if(remaining+offset <= f->censored_length){
+				fprintf(stdout, "We have enough data to fill the record\n");
+				for(int i = 0; i< remaining; i++){
+					tmp_p[SLITHEEN_HEADER_LEN+i] = f->censored_queue[i + offset];
+				}
+				//TODO: when I restructure this for more data, figure out freeing these pointers
+				f->censored_queue += remaining;
+				f->censored_length -= remaining;
+				sl_hdr->len = htons(remaining);
+				fprintf(stdout, "copied %d data\n", ntohs(sl_hdr->len));
+
+			} else {
+				int32_t dummy_offset = f->censored_length - offset;
+				if(dummy_offset < 0) dummy_offset = 0;
+				fprintf(stdout, "Not enough data (%d bytes)\n", dummy_offset);
+				for(int i = 0; i< dummy_offset; i++){
+					tmp_p[SLITHEEN_HEADER_LEN+i] = f->censored_queue[i + offset];
+				}
+				//TODO: note, we may also be receiving misordered packets. Take Ian's suggestion into account here
+				f->censored_queue += dummy_offset;
+				f->censored_length -= dummy_offset;
+				sl_hdr->len = htons(dummy_offset);
+				//TODO: should i < record_length or remaining??
+				for(int i = dummy_offset; i< remaining; i++){
+					tmp_p[SLITHEEN_HEADER_LEN+i] = 'A';
+				}
+				fprintf(stdout, "copied %d data and %d garbage bytes\n", ntohs(sl_hdr->len), remaining - dummy_offset);
+			}
+			printf("Slitheen header\n");
+			for(int i=0; i<4; i++)
+				printf("%02x ", tmp_p[i]);
+			printf("\n");
+		}
+		tmp_p -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+		//step 3: encrypt new record
+		//fprintf(stderr, "computing mac\n");
+		//int32_t mac_size = mac(f, p, p+(record_length - (EVP_GCM_TLS_EXPLICIT_IV_LEN + 16)), record_length - (EVP_GCM_TLS_EXPLICIT_IV_LEN + 16), 1, 0x17, 1); 
+		//printf(stderr, "mac size: %d\n", mac_size);
+		//fprintf(stderr, "encrypting\n");
+		int32_t success;
+		if((success = encrypt(f, tmp_p, tmp_p, record_length-16, 1, 0x17, 1))< 0){
+			fprintf(stdout,"encryption failed\n");
+			return 0;
+		} else {
+			fprintf(stdout, "encryption succeeded!\n");
+			//printf("Encrypted data:\n");
+			//for(int i=0; i< success; i++){
+			//	printf("%02x ", tmp_p[i]);
+			//}
+			//printf("\n");
+		}
+		//copy new record into packet
+		if(record_length +RECORD_HEADER_LEN > tmp_len){
+			//We have a partial record
+			printf("Warning: partial record\n");
+			memcpy(p, new_record, tmp_len - RECORD_HEADER_LEN);
+			f->outbox_len = record_length - (tmp_len - RECORD_HEADER_LEN);
+			//save left-overs in outbox
+			f->outbox = calloc(1, f->outbox_len);
+			memcpy(f->outbox, new_record + (tmp_len - RECORD_HEADER_LEN),
+					f->outbox_len);
+			free(new_record);
+			printf("Outbox has %d = %d - %d bytes\n", f->outbox_len, record_length+RECORD_HEADER_LEN, tmp_len);
+		} else {
+			memcpy(p, new_record, record_length);
+			free(new_record);
+		}
+
+
+		//check to see if next record still exists
+		if(data_len > record_length + RECORD_HEADER_LEN){
+			printf("Next record:\n");
+			for(int i=0; i< RECORD_HEADER_LEN; i++){
+				printf("%02x ", p[record_length+i]);
+			}
+			printf("\n");
+		} else {
+			printf("No extra record: %d <= %d + %d\n", data_len, record_length, RECORD_HEADER_LEN);
+		}
+		tmp_len -= record_length+ RECORD_HEADER_LEN;
+		p += record_length;
+
+	}
+	//step 4: recompute TCP checksum
+	p = data;
+	p[16] = 0; p[17] = 0;//zero out checksum
+	uint16_t chksm = tcp_checksum(p, data_len, src, dst);
+	p[17] = chksm & 0xFF;
+	p[16] = chksm >> 8;
+	fprintf(stdout, "Checksum: 0x%0x%0x\n", p[16], p[17]);
+	fflush(stdout);
+
+	return 0;
+}
+
+/** Computes the TCP checksum of the data according to RFC 793
+ *  sum all 16-bit words in the segment, padd the last word if
+ *  needed
+ *
+ *  there is a pseudo-header prefixed to the segment and
+ *  included in the checksum:
+ *
+ *         +--------+--------+--------+--------+
+ *         |           Source Address          |
+ *         +--------+--------+--------+--------+
+ *         |         Destination Address       |
+ *         +--------+--------+--------+--------+
+ *         |  zero  |  PTCL  |    TCP Length   |
+ *         +--------+--------+--------+--------+
+ */
+uint16_t tcp_checksum(uint8_t *data, int32_t data_len, struct in_addr src, struct in_addr dst){
+
+	uint8_t *p = data;
+
+	struct tcp_header *tcp_hdr = (struct tcp_header*) p;
+	int size_tcp = TCP_HEADER_LEN(tcp_hdr);
+	//Construct pseudo-header
+	uint16_t tcp_length = data_len + size_tcp;
+	uint8_t proto = IPPROTO_TCP;
+	fprintf(stdout, "summing pseudoheader\n");
+	uint32_t sum = (ntohl(src.s_addr)) >> 16;
+	sum += (ntohl(src.s_addr)) &0xFFFF;
+	sum += (ntohl(dst.s_addr)) >> 16;
+	sum += (ntohl(dst.s_addr)) & 0xFFFF;
+	sum += proto;
+	sum += tcp_length;
+
+	//now sum the text
+	for(int i=0; i< tcp_length-1; i+=2){
+		sum += (uint16_t) ((p[i] << 8) + p[i+1]);
+
+	}
+	if(tcp_length %2 != 0){
+		sum += (uint16_t) (p[tcp_length - 1]) << 8;
+	}
+	//now add most significant to last significant bits
+	sum = (sum >> 16) + (sum & 0xFFFF);
+	//now subtract from 0xFF
+	sum = 0xFFFF - sum;
+	return (uint16_t) sum;
+}

+ 2 - 0
server/relay.h

@@ -5,6 +5,8 @@
 #include <stdint.h>
 
 int replace_packet(flow *f, uint8_t *packet);
+int replace_contents(flow *f, uint8_t *data, int32_t data_len, int32_t offset, struct in_addr src, struct in_addr dst);
 int read_header(flow *f, uint8_t *packet);
+uint16_t tcp_checksum(uint8_t *data, int32_t data_len, struct in_addr src, struct in_addr dst);
 
 #endif /* _RELAY_H_ */

+ 27 - 25
server/slitheen-proxy.c

@@ -106,18 +106,11 @@ void check_handshake(const struct tcp_header *tcp_hdr, flow f, unsigned char *pt
 }
 
 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;
+	pcap_t *handle = (pcap_t *) args;
 	unsigned char *p;
 
 	const struct ip_header *ip_hdr;
 	//const struct tcp_header *tcp_hdr;
-
-	handle = pcap_open_live(writedev, BUFSIZ, 1, 1000, errbuf);
-	if (handle == NULL){
-		fprintf(stderr, "Couldn't open device %s: %s\n", writedev, errbuf);
-	}
 	p = (unsigned char *) packet;
 	p += ETHER_HEADER_LEN; //skip ethernet header
 	ip_hdr = (struct ip_header*) p;
@@ -152,14 +145,17 @@ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *pa
 	} else { /*not a fragment, add to packet chain */
 		process_packet(packet);
 	}
-	
 end:
 	if((pcap_inject(handle, packet, header->len)) < 0 ){
 		fprintf(stderr, "Error: %s\n", pcap_geterr(handle));
 	}
-
-	pcap_close(handle);
-
+#ifdef DEBUG
+	fprintf(stderr, "injected the following packet:\n");
+	for(int i=0; i< header->len; i++){
+		fprintf(stderr, "%02x ", packet[i]);
+	}
+	fprintf(stderr, "\n");
+#endif
 }
 
 void usage(void){
@@ -207,8 +203,10 @@ int main(int argc, char *argv[]){
 }
 
 void *sniff_packets(void *args){
-	pcap_t *handle;
-	char errbuf[BUFSIZ];
+	pcap_t *rd_handle;
+	pcap_t *wr_handle;
+	char rd_errbuf[BUFSIZ];
+	char wr_errbuf[BUFSIZ];
 	struct bpf_program fp;
 	bpf_u_int32 mask;
 	bpf_u_int32 net;
@@ -219,36 +217,40 @@ void *sniff_packets(void *args){
 	writedev = arg_st->writedev;
 	filter = arg_st->filter;
 
-	if (pcap_lookupnet(readdev, &net, &mask, errbuf) == -1){
+	if (pcap_lookupnet(readdev, &net, &mask, rd_errbuf) == -1){
 		fprintf(stderr, "Can't get netmask for device %s\n", readdev);
 		exit(2);
 	}
 
-	handle = pcap_open_live(readdev, BUFSIZ, 1, 1000, errbuf);
-	if (handle == NULL){
-		fprintf(stderr, "Couldn't open device %s: %s\n", readdev, errbuf);
+	rd_handle = pcap_open_live(readdev, BUFSIZ, 1, 0, rd_errbuf);
+	if (rd_handle == NULL){
+		fprintf(stderr, "Couldn't open device %s: %s\n", readdev, rd_errbuf);
 	}
 
-	if(pcap_datalink(handle) != DLT_EN10MB) {
+	if(pcap_datalink(rd_handle) != DLT_EN10MB) {
 		fprintf(stderr, "Device %s does not provide Ethernet headers - not supported\n", readdev);
 		exit(2);
 	}
 
-	if(pcap_compile(handle, &fp, filter, 0 , net) == -1){
-		fprintf(stderr, "Couldn't parse filter %s: %s\n", filter, pcap_geterr(handle));
+	if(pcap_compile(rd_handle, &fp, filter, 0 , net) == -1){
+		fprintf(stderr, "Couldn't parse filter %s: %s\n", filter, pcap_geterr(rd_handle));
 		exit(2);
 	}
 
-	if (pcap_setfilter(handle, &fp) == -1) {
-		fprintf(stderr, "Couldn't install filter %s: %s\n", filter, pcap_geterr(handle));
+	if (pcap_setfilter(rd_handle, &fp) == -1) {
+		fprintf(stderr, "Couldn't install filter %s: %s\n", filter, pcap_geterr(rd_handle));
 		exit(2);
 	}
 
+	wr_handle = pcap_open_live(writedev, BUFSIZ, 1, 0, wr_errbuf);
+	if (wr_handle == NULL){
+		fprintf(stderr, "Couldn't open device %s: %s\n", writedev, wr_errbuf);
+	}
 	/*callback function*/
-	pcap_loop(handle, -1, got_packet, (unsigned char *) writedev);
+	pcap_loop(rd_handle, -1, got_packet, (unsigned char *) wr_handle);
 
 	/*Sniff a packet*/
-	pcap_close(handle);
+	pcap_close(rd_handle);
 
 	return NULL;
 }

+ 7 - 0
server/slitheen.h

@@ -57,6 +57,13 @@ struct tls_header {
 #define RECORD_HEADER_LEN 5
 #define CLIENT_HELLO_HEADER_LEN 6
 
+struct slitheen_header {
+	u_char marker; /* 0x01 means censored data, 0x02 means dummy data */
+	u_char version; /* For now 0x01 */
+	u_short len;
+};
+#define SLITHEEN_HEADER_LEN 4
+
 struct __attribute__((__packed__)) record_header {
 	u_char type;
 #define HS 0x16