Browse Source

re-wrote socks proxy on client side

cecylia 6 years ago
parent
commit
b8b23307bc
10 changed files with 983 additions and 730 deletions
  1. 4 4
      client/Makefile
  2. 64 31
      client/crypto.c
  3. 750 657
      client/socks5proxy.c
  4. 11 3
      client/socks5proxy.h
  5. 53 0
      client/util.c
  6. 38 0
      client/util.h
  7. 1 1
      relay_station/Makefile
  8. 4 1
      relay_station/crypto.c
  9. 7 3
      relay_station/flow.c
  10. 51 30
      relay_station/relay.c

+ 4 - 4
client/Makefile

@@ -1,13 +1,13 @@
-CFLAGS=-g -Wall
+CFLAGS=-g -Wall -ggdb
 
 TARGETS= socks
 
 all: $(TARGETS)
 
-socks5proxy.o crypto.o tagging.o ptwist168.o:: socks5proxy.h crypto.h tagging.h ptwist.h
+socks5proxy.o crypto.o tagging.o ptwist168.o util.o:: socks5proxy.h crypto.h tagging.h ptwist.h util.h
 
-socks: socks5proxy.o crypto.o tagging.o ptwist168.o ptwist.h tagging.h crypto.h socks5proxy.h
-	gcc -o $@ $^ -lpthread -lssl -lcrypto
+socks: socks5proxy.o crypto.o tagging.o ptwist168.o util.o util.h ptwist.h tagging.h crypto.h socks5proxy.h
+	gcc -o $@ $^ -L/usr/local/lib -I/usr/local/include -lpthread -lssl -lcrypto
 
 clean:
 	-rm *.o

+ 64 - 31
client/crypto.c

@@ -26,6 +26,8 @@
  * work.
  */
 
+#include <string.h>
+
 #include <openssl/evp.h>
 #include <openssl/dh.h>
 #include <openssl/bn.h>
@@ -39,6 +41,7 @@
 #include "socks5proxy.h"
 #include "tagging.h"
 #include "ptwist.h"
+#include "util.h"
 
 static super_data *super;
 
@@ -50,7 +53,7 @@ int PRF(uint8_t *secret, int32_t secret_len,
 		uint8_t *seed4, int32_t seed4_len,
 		uint8_t *output, int32_t output_len){
 
-	EVP_MD_CTX ctx, ctx_tmp, ctx_init;
+	EVP_MD_CTX *ctx, *ctx_tmp, *ctx_init;
 	EVP_PKEY *mac_key;
 	const EVP_MD *md = EVP_sha256();
 
@@ -61,58 +64,68 @@ int PRF(uint8_t *secret, int32_t secret_len,
 
 	uint8_t *out = output;
 
-	EVP_MD_CTX_init(&ctx);
-	EVP_MD_CTX_init(&ctx_tmp);
-	EVP_MD_CTX_init(&ctx_init);
-	EVP_MD_CTX_set_flags(&ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#if OPENSSL_VERSION_NUMBER >= 0x1010000eL
+        ctx = EVP_MD_CTX_new();
+        ctx_tmp = EVP_MD_CTX_new();
+        ctx_init = EVP_MD_CTX_new();
+#else
+        ctx = ecalloc(1, sizeof(EVP_MD_CTX));
+	EVP_MD_CTX_init(ctx);
+        ctx_tmp = ecalloc(1, sizeof(EVP_MD_CTX));
+	EVP_MD_CTX_init(ctx_tmp);
+        ctx_init = ecalloc(1, sizeof(EVP_MD_CTX));
+	EVP_MD_CTX_init(ctx_init);
+#endif
+
+	EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
 
 	mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret, secret_len);
 
 	/* Calculate first A value */
-	EVP_DigestSignInit(&ctx_init, NULL, md, NULL, mac_key);
-	EVP_MD_CTX_copy_ex(&ctx, &ctx_init);
+	EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key);
+	EVP_MD_CTX_copy_ex(ctx, ctx_init);
 	if(seed1 != NULL && seed1_len > 0){
-		EVP_DigestSignUpdate(&ctx, seed1, seed1_len);
+		EVP_DigestSignUpdate(ctx, seed1, seed1_len);
 	}
 	if(seed2 != NULL && seed2_len > 0){
-		EVP_DigestSignUpdate(&ctx, seed2, seed2_len);
+		EVP_DigestSignUpdate(ctx, seed2, seed2_len);
 	}
 	if(seed3 != NULL && seed3_len > 0){
-		EVP_DigestSignUpdate(&ctx, seed3, seed3_len);
+		EVP_DigestSignUpdate(ctx, seed3, seed3_len);
 	}
 	if(seed4 != NULL && seed4_len > 0){
-		EVP_DigestSignUpdate(&ctx, seed4, seed4_len);
+		EVP_DigestSignUpdate(ctx, seed4, seed4_len);
 	}
-	EVP_DigestSignFinal(&ctx, A, &A_len);
+	EVP_DigestSignFinal(ctx, A, &A_len);
 
 	//iterate until desired length is achieved
 	while(remaining > 0){
 		/* Now compute SHA384(secret, A+seed) */
-		EVP_MD_CTX_copy_ex(&ctx, &ctx_init);
-		EVP_DigestSignUpdate(&ctx, A, A_len);
-		EVP_MD_CTX_copy_ex(&ctx_tmp, &ctx);
+		EVP_MD_CTX_copy_ex(ctx, ctx_init);
+		EVP_DigestSignUpdate(ctx, A, A_len);
+		EVP_MD_CTX_copy_ex(ctx_tmp, ctx);
 		if(seed1 != NULL && seed1_len > 0){
-			EVP_DigestSignUpdate(&ctx, seed1, seed1_len);
+			EVP_DigestSignUpdate(ctx, seed1, seed1_len);
 		}
 		if(seed2 != NULL && seed2_len > 0){
-			EVP_DigestSignUpdate(&ctx, seed2, seed2_len);
+			EVP_DigestSignUpdate(ctx, seed2, seed2_len);
 		}
 		if(seed3 != NULL && seed3_len > 0){
-			EVP_DigestSignUpdate(&ctx, seed3, seed3_len);
+			EVP_DigestSignUpdate(ctx, seed3, seed3_len);
 		}
 		if(seed4 != NULL && seed4_len > 0){
-			EVP_DigestSignUpdate(&ctx, seed4, seed4_len);
+			EVP_DigestSignUpdate(ctx, seed4, seed4_len);
 		}
 		
 		if(remaining > chunk){
-			EVP_DigestSignFinal(&ctx, out, &len);
+			EVP_DigestSignFinal(ctx, out, &len);
 			out += len;
 			remaining -= len;
 
 			/* Next A value */
-			EVP_DigestSignFinal(&ctx_tmp, A, &A_len);
+			EVP_DigestSignFinal(ctx_tmp, A, &A_len);
 		} else {
-			EVP_DigestSignFinal(&ctx, A, &A_len);
+			EVP_DigestSignFinal(ctx, A, &A_len);
 			memcpy(out, A, remaining);
 			remaining -= remaining;
 		}
@@ -120,9 +133,19 @@ int PRF(uint8_t *secret, int32_t secret_len,
 
 	EVP_PKEY_free(mac_key);
 
-	EVP_MD_CTX_cleanup(&ctx);
-	EVP_MD_CTX_cleanup(&ctx_tmp);
-	EVP_MD_CTX_cleanup(&ctx_init);
+#if OPENSSL_VERSION_NUMBER >= 0x1010000eL
+        EVP_MD_CTX_free(ctx);
+        EVP_MD_CTX_free(ctx_tmp);
+        EVP_MD_CTX_free(ctx_init);
+#else
+	EVP_MD_CTX_cleanup(ctx);
+	EVP_MD_CTX_cleanup(ctx_tmp);
+	EVP_MD_CTX_cleanup(ctx_init);
+        free(ctx);
+        free(ctx_tmp);
+        free(ctx_init);
+#endif
+
 	return 1;
 }
 
@@ -311,15 +334,25 @@ int super_decrypt(uint8_t *data){
 	p+=16;
 
 	//compute mac
-	EVP_MD_CTX mac_ctx;
-	EVP_MD_CTX_init(&mac_ctx);
-	EVP_MD_CTX_copy_ex(&mac_ctx, super->body_mac_ctx);
+	EVP_MD_CTX *mac_ctx;
+#if OPENSSL_VERSION_NUMBER >= 0x1010000eL
+        mac_ctx = EVP_MD_CTX_new();
+#else
+        mac_ctx = ecalloc(1, sizeof(EVP_MD_CTX));
+	EVP_MD_CTX_init(mac_ctx);
+#endif
+	EVP_MD_CTX_copy_ex(mac_ctx, super->body_mac_ctx);
 
-	EVP_DigestSignUpdate(&mac_ctx, p, len);
+	EVP_DigestSignUpdate(mac_ctx, p, len);
 
-    EVP_DigestSignFinal(&mac_ctx, output, &mac_len);
+        EVP_DigestSignFinal(mac_ctx, output, &mac_len);
 
-	EVP_MD_CTX_cleanup(&mac_ctx);
+#if OPENSSL_VERSION_NUMBER >= 0x1010000eL
+        EVP_MD_CTX_free(mac_ctx);
+#else
+	EVP_MD_CTX_cleanup(mac_ctx);
+        free(mac_ctx);
+#endif
 
 #ifdef DEBUG_PARSE
 	printf("Received mac:\n");

+ 750 - 657
client/socks5proxy.c

@@ -49,740 +49,833 @@
 #include "socks5proxy.h"
 #include "crypto.h"
 #include "tagging.h"
+#include "util.h"
+
+#define DEBUG
 
 static connection_table *connections;
 
-int main(void){
-	int listen_socket;
-	
-	struct sockaddr_in address;
-	struct sockaddr_in remote_addr;
-	socklen_t addr_size;
-
-	mkfifo("OUS_out", 0666);
-
-	//generate Slitheen ID using Telex tagging method
-	uint8_t slitheen_id[SLITHEEN_ID_LEN];
-	uint8_t shared_secret[16];
-
-	generate_slitheen_id(slitheen_id, shared_secret);
-
-	//RAND_bytes(slitheen_id, SLITHEEN_ID_LEN);
-	printf("Randomly generated slitheen id: ");
-	int i;
-	for(i=0; i< SLITHEEN_ID_LEN; i++){
-		printf("%02x ", slitheen_id[i]);
-	}
-	printf("\n");
-
-	// Calculate super encryption keys
-	generate_super_keys(shared_secret);
-
-	//b64 encode slitheen ID
-	char *encoded_bytes;
-	BUF_MEM *buffer_ptr;
-	BIO *bio, *b64;
-	b64 = BIO_new(BIO_f_base64());
-	bio = BIO_new(BIO_s_mem());
-	bio = BIO_push(b64, bio);
-
-	BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
-	BIO_write(bio, slitheen_id, SLITHEEN_ID_LEN);
-	BIO_flush(bio);
-	BIO_get_mem_ptr(bio, &buffer_ptr);
-	BIO_set_close(bio, BIO_NOCLOSE);
-	BIO_free_all(bio);
-	encoded_bytes = (*buffer_ptr).data;
-	encoded_bytes[(*buffer_ptr).length] = '\0';
-
-	//give encoded slitheen ID to ous
-	struct sockaddr_in ous_addr;
-	ous_addr.sin_family = AF_INET;
-	inet_pton(AF_INET, "127.0.0.1", &(ous_addr.sin_addr));
-	ous_addr.sin_port = htons(57173);
-
-	int32_t ous_in = socket(AF_INET, SOCK_STREAM, 0);
-	if(ous_in < 0){
-		printf("Failed to make ous_in socket\n");
-		return 1;
-	}
-
-	int32_t error = connect(ous_in, (struct sockaddr *) &ous_addr, sizeof (struct sockaddr));
-	if(error < 0){
-		printf("Error connecting\n");
-		return 1;
-	}
-        uint16_t len = htons(strlen(encoded_bytes));
-	int32_t bytes_sent = send(ous_in, (unsigned char *) &len, sizeof(uint16_t), 0);
-	bytes_sent += send(ous_in, encoded_bytes, ntohs(len), 0);
-	printf("Wrote %d bytes to OUS_in: %x\n %s\n", bytes_sent, len, encoded_bytes);
-
-	/* Spawn process to listen for incoming data from OUS 
-	int32_t demux_pipe[2];
-	if(pipe(demux_pipe) < 0){
-		printf("Failed to create pipe for new thread\n");
-		return 1;
-	}*/
-	connections = calloc(1, sizeof(connection_table));
-	connections->first = NULL;
-	
-	pthread_t *demux_thread = calloc(1, sizeof(pthread_t));
-	pthread_create(demux_thread, NULL, demultiplex_data, NULL);
-
-	if (!(listen_socket = socket(AF_INET, SOCK_STREAM, 0))){
-		printf("Error creating socket\n");
-		fflush(stdout);
-		return 1;
-	}
-
-
-	address.sin_family = AF_INET;
-	address.sin_addr.s_addr = INADDR_ANY;
-	address.sin_port = htons(1080);
-
-	int enable = 1;
-	if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) <0 ){
-		printf("Error setting sockopt\n");
-		return 1;
-	}
-
-	if(bind(listen_socket, (struct sockaddr *) &address, sizeof(address))){
-		printf("Error binding socket\n");
-		fflush(stdout);
-		return 1;
-	}
-
-	if(listen(listen_socket, 10) < 0){
-		printf("Error listening\n");
-		fflush(stdout);
-		close(listen_socket);
-		exit(1);
-	}
-	uint8_t last_id = 1;
-
-	printf("Ready for listening\n");
-
-	for(;;){
-		addr_size = sizeof(remote_addr);
-		int new_socket;
-		new_socket = accept(listen_socket, (struct sockaddr *) &remote_addr,
-						&addr_size);
-		if(new_socket < 0){
-			perror("accept");
-			exit(1);
-		}
-		printf("New connection\n");
-
-		//assign a new stream_id and create a pipe for the session
-		connection *new_conn = calloc(1, sizeof(connection));
-		new_conn->stream_id = last_id++;
-		
-		int32_t pipefd[2];
-		if(pipe(pipefd) < 0){
-			printf("Failed to create pipe\n");
-			continue;
-		}
-
-		new_conn->pipe_fd = pipefd[1];
-		new_conn->next = NULL;
-		
-		if(connections->first == NULL){
-			connections->first = new_conn;
-			printf("Added first connection with id: %d\n", new_conn->stream_id);
-			fflush(stdout);
-		} else {
-			connection *last = connections->first;
-			while(last->next != NULL){
-				last = last->next;
-			}
-			last->next = new_conn;
-			printf("Added connection with id: %d at %p\n", new_conn->stream_id, last->next);
-			fflush(stdout);
-		}
-
-		int pid = fork();
-		if(pid == 0){ //child
-
-			close(listen_socket);
-			proxy_data(new_socket, new_conn->stream_id, pipefd[0], ous_in);
-			exit(0);
-		}
-
-		close(new_socket);
-		
-	}
+typedef struct {
+    int32_t in;
+    int32_t out;
+} ous_pipes;
 
-	return 0;
+int main(void){
+    int listen_socket;
+    
+    struct sockaddr_in address;
+    struct sockaddr_in remote_addr;
+    socklen_t addr_size;
+
+    connections = calloc(1, sizeof(connection_table));
+    connections->first = NULL;
+    
+    int32_t ous_in[2];
+    if(pipe(ous_in) < 0){
+        printf("Failed to create pipe\n");
+        return 1;
+    }
+    int32_t ous_out[2];
+    if(pipe(ous_out) < 0){
+        printf("Failed to create pipe\n");
+        return 1;
+    }
+
+    ous_pipes pipes;
+    pipes.in = ous_in[0];
+    pipes.out = ous_out[1];
+
+    /* Spawn a thread to communicate with OUS */
+    pthread_t *ous_thread = calloc(1, sizeof(pthread_t));
+    pthread_create(ous_thread, NULL, ous_IO, (void *) &pipes);
+
+    ous_pipes mux_pipes;
+    mux_pipes.in = ous_in[1];
+    mux_pipes.out = ous_out[0];
+
+    /* Spawn a thread for multiplexing and demultiplexing */
+    pthread_t *demux_thread = calloc(1, sizeof(pthread_t));
+    pthread_create(demux_thread, NULL, demultiplex_data, (void *) &mux_pipes);
+
+    pthread_t *mux_thread = calloc(1, sizeof(pthread_t));
+    pthread_create(mux_thread, NULL, multiplex_data, (void *) &mux_pipes);
+
+    if (!(listen_socket = socket(AF_INET, SOCK_STREAM, 0))){
+        printf("Error creating socket\n");
+        fflush(stdout);
+        return 1;
+    }
+
+
+    address.sin_family = AF_INET;
+    address.sin_addr.s_addr = INADDR_ANY;
+    address.sin_port = htons(1080);
+
+    int enable = 1;
+    if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) <0 ){
+        printf("Error setting sockopt\n");
+        return 1;
+    }
+
+    if(bind(listen_socket, (struct sockaddr *) &address, sizeof(address))){
+        printf("Error binding socket\n");
+        fflush(stdout);
+        return 1;
+    }
+
+    if(listen(listen_socket, 10) < 0){
+        printf("Error listening\n");
+        fflush(stdout);
+        close(listen_socket);
+        exit(1);
+    }
+    uint8_t last_id = 1;
+
+    printf("Ready for listening\n");
+
+    for(;;){
+        addr_size = sizeof(remote_addr);
+        int new_socket;
+        new_socket = accept(listen_socket, (struct sockaddr *) &remote_addr,
+                                        &addr_size);
+        if(new_socket < 0){
+            perror("accept");
+            exit(1);
+        }
+        printf("New connection\n");
+
+        //assign a new stream_id and create a pipe for the session
+        connection *new_conn = calloc(1, sizeof(connection));
+        new_conn->stream_id = last_id++;
+        
+        new_conn->socket = new_socket;
+        new_conn->state = NEW_STREAM;
+        new_conn->next = NULL;
+        
+        if(connections->first == NULL){
+            connections->first = new_conn;
+            printf("Added first connection with id: %d\n", new_conn->stream_id);
+            fflush(stdout);
+        } else {
+            connection *last = connections->first;
+            while(last->next != NULL){
+                last = last->next;
+            }
+            last->next = new_conn;
+            printf("Added connection with id: %d at %p\n", new_conn->stream_id, last->next);
+            fflush(stdout);
+        }
+
+    }
+
+    return 0;
 }
 
-//continuously read from the socket and look for a CONNECT message
-int proxy_data(int sockfd, uint16_t stream_id, int32_t ous_out, int32_t ous_in){
-	uint8_t *buffer = calloc(1, BUFSIZ);
-	uint8_t *response = calloc(1, BUFSIZ);
+/*
+ * Responsible for communicating with the OUS. Upstream data is read from the pipes of individual
+ * streams and sent to the OUS. Downstream data is read from the OUS, demultiplexed according t
+ * stream ID, and sent to the corresponding stream.
+ */
+void *ous_IO(void *args){
 
-	int32_t i;
-	
-	int bytes_read = recv(sockfd, buffer, BUFSIZ-1, 0);
-	if (bytes_read < 0){
-		printf("Error reading from socket (fd = %d)\n", sockfd);
-		fflush(stdout);
-		goto err;
-	}
+    ous_pipes *pipes = (ous_pipes *) args;
 
-#ifdef DEBUG
-	printf("Received %d bytes (id %d):\n", bytes_read, stream_id);
-	for(i=0; i< bytes_read; i++){
-		printf("%02x ", buffer[i]);
-	}
-	printf("\n");
-	fflush(stdout);
-#endif
+    int32_t ous_in = pipes->in;
+    int32_t ous_out = pipes->out;
+
+    //generate Slitheen ID
+    uint8_t slitheen_id[SLITHEEN_ID_LEN];
+    uint8_t shared_secret[16];
 
-	//Respond to methods negotiation
-	struct socks_method_req *clnt_meth = (struct socks_method_req *) buffer;
-	uint8_t *p = buffer + 2;
-
-	if(clnt_meth->version != 0x05){
-		printf("Client supplied invalid version: %02x\n", clnt_meth->version);
-		fflush(stdout);
-		goto err;
-	}
-
-	int responded = 0;
-	int bytes_sent;
-	for(i=0; i< clnt_meth->num_methods; i++){
-		if(p[0] == 0x00){//send response with METH= 0x00
-			response[0] = 0x05;
-			response[1] = 0x00;
-			send(sockfd, response, 2, 0);
-			responded = 1;
-		}
-		p++;
-	}
-	if(!responded){//respond with METH= 0xFF
-		response[0] = 0x05;
-		response[1] = 0xFF;
-		send(sockfd, response, 2, 0);
-		goto err;
-	}
-
-	//Now wait for a connect request
-	bytes_read = recv(sockfd, buffer, BUFSIZ-1, 0);
-	if (bytes_read < 0){
-		printf("Error reading from socket\n");
-		fflush(stdout);
-		goto err;
-	}
+    generate_slitheen_id(slitheen_id, shared_secret);
 
 #ifdef DEBUG
-	printf("Received %d bytes (id %d):\n", bytes_read, stream_id);
-	for(i=0; i< bytes_read; i++){
-		printf("%02x ", buffer[i]);
-	}
-	printf("\n");
-	fflush(stdout);
+    printf("Randomly generated slitheen id: ");
+    int i;
+    for(i=0; i< SLITHEEN_ID_LEN; i++){
+        printf("%02x ", slitheen_id[i]);
+    }
+    printf("\n");
 #endif
 
-	//Now respond
-	response[0] = 0x05;
-	response[1] = 0x00;
-	response[2] = 0x00;
-	response[3] = 0x01;
+    // Calculate super encryption keys
+    generate_super_keys(shared_secret);
 
-	*((uint32_t *) (response + 4)) = 0;
-	*((uint16_t *) (response + 8)) = 0;
+    printf("Generated super encrypt keys\n");
 
-	send(sockfd, response, 10, 0);
+    char *encoded_bytes;
+    base64_encode(slitheen_id, SLITHEEN_ID_LEN, &encoded_bytes);
 
-	//wait for first upstream bytes
-	bytes_read += recv(sockfd, buffer+bytes_read, BUFSIZ-bytes_read-3, 0);
-	if (bytes_read < 0){
-		printf("Error reading from socket\n");
-		fflush(stdout);
-		goto err;
-	}
+    printf("Encoded ID\n");
+    //give encoded slitheen ID to ous
+    struct sockaddr_in ous_addr;
+    ous_addr.sin_family = AF_INET;
+    inet_pton(AF_INET, "127.0.0.1", &(ous_addr.sin_addr));
+    ous_addr.sin_port = htons(57173);
 
-#ifdef DEBUG_UPSTREAM
-	printf("Received %d bytes (id %d):\n", bytes_read, stream_id);
-	for(i=0; i< bytes_read; i++){
-		printf("%02x ", buffer[i]);
-	}
-	printf("\n");
-	fflush(stdout);
-#endif
+    int32_t ous = socket(AF_INET, SOCK_STREAM, 0);
+    if(ous < 0){
+        printf("Failed to make socket\n");
+        pthread_exit(NULL);
+    }
 
-	//pre-pend stream_id and length
-	memmove(buffer+sizeof(struct slitheen_up_hdr), buffer, bytes_read+1);
+    int32_t error = connect(ous, (struct sockaddr *) &ous_addr, sizeof (struct sockaddr));
+    if(error < 0){
+        printf("Error connecting to OUS\n");
+        pthread_exit(NULL);
+    }
+    printf("Connected to OUS\n");
 
-	struct slitheen_up_hdr *up_hdr = (struct slitheen_up_hdr *) buffer;
-	up_hdr->stream_id = stream_id;
-	up_hdr->len = htons(bytes_read);
+    uint16_t len = htons(strlen(encoded_bytes));
+    int32_t bytes_sent = send(ous, (unsigned char *) &len, sizeof(uint16_t), 0);
+    bytes_sent += send(ous, encoded_bytes, ntohs(len), 0);
+    printf("Wrote %d bytes to OUS_in: %x\n %s\n", bytes_sent, len, encoded_bytes);
 
-	bytes_read+= sizeof(struct slitheen_up_hdr);
+    uint8_t *buffer = emalloc(BUFSIZ);
+    int32_t buffer_len = BUFSIZ;
 
-	//encode bytes for safe transport (b64)
-	const char *encoded_bytes;
-	BUF_MEM *buffer_ptr;
-	BIO *bio, *b64;
-	b64 = BIO_new(BIO_f_base64());
-	bio = BIO_new(BIO_s_mem());
-	bio = BIO_push(b64, bio);
+    int32_t bytes_read;
 
-	BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
-	BIO_write(bio, buffer, bytes_read);
-	BIO_flush(bio);
-	BIO_get_mem_ptr(bio, &buffer_ptr);
-	BIO_set_close(bio, BIO_NOCLOSE);
-	BIO_free_all(bio);
-	encoded_bytes = (*buffer_ptr).data;
+    /* Select on proxy pipes, demux thread, and ous to send and receive data*/
+    for(;;){
+        fd_set read_fds;
+        fd_set write_fds;
 
-        uint16_t len = htons(strlen(encoded_bytes));
-	bytes_sent = send(ous_in, (unsigned char *) &len, sizeof(uint16_t), 0);
-	bytes_sent += send(ous_in, encoded_bytes, strlen(encoded_bytes), 0);
+        int32_t nfds = ous;
+        if(ous_in > nfds)
+            nfds = ous_in;
+        if(ous_out > nfds)
+            nfds = ous_out;
 
-#ifdef DEBUG_UPSTREAM
-	printf("Wrote %d bytes to OUS_in: %x %s\n", bytes_sent, len, encoded_bytes);
+
+        FD_ZERO(&read_fds);
+        FD_ZERO(&write_fds);
+
+        FD_SET(ous_in, &read_fds);
+        FD_SET(ous, &read_fds);
+        FD_SET(ous_out, &write_fds);
+        FD_SET(ous, &write_fds);
+
+        if(select(nfds+1, &read_fds, &write_fds, NULL, NULL) < 0){
+            fprintf(stderr, "Select error\n");
+            break;
+        }
+
+        if(FD_ISSET(ous_in, &read_fds) && FD_ISSET(ous, &write_fds)){
+
+            bytes_read = read(ous_in, buffer, buffer_len);
+
+#ifdef DEBUG
+            printf("Received %d bytes from multiplexer\n", bytes_read);
+            for(int i=0; i< bytes_read; i++){
+                printf("%02x ", buffer[i]);
+            }
+            printf("\n");
+            fflush(stdout);
 #endif
 
-	if(bytes_sent < 0){
-		printf("Error writing to websocket\n");
-		fflush(stdout);
-		goto err;
-	}
+            if(bytes_read > 0){
+                bytes_sent = send(ous, buffer, bytes_read, 0);
+#ifdef DEBUG
+                printf("Sent %d bytes to OUS\n", bytes_sent);
+                for(int i=0; i< bytes_sent; i++){
+                    printf("%02x ", buffer[i]);
+                }
+                printf("\n");
+                fflush(stdout);
+#endif
 
-	p = buffer+sizeof(struct slitheen_up_hdr);
+                if(bytes_sent <= 0){
+                    fprintf(stderr, "Connection to OUS closed\n");
+                    break;
+                }
 
-#ifdef DEBUG_UPSTREAM
-	for(i=0; i< bytes_read; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
-	fflush(stdout);
+            } else if (bytes_read == 0) {
+
+                fprintf(stderr, "Connection to multiplexer closed\n");
+                break;
+
+            } else {
+                fprintf(stderr, "Error reading from multiplexer\n");
+                break;
+            }
+        }
+
+        if(FD_ISSET(ous, &read_fds) && FD_ISSET(ous_out, &write_fds)){
+
+            bytes_read = recv(ous, buffer, 4, 0);
+#ifdef DEBUG
+            printf("Received %d bytes from OUS\n", bytes_read);
+            for(int i=0; i< bytes_read; i++){
+                printf("%02x ", buffer[i]);
+            }
+            printf("\n");
+            fflush(stdout);
 #endif
+            if (bytes_read <= 0) {
 
-	struct socks_req *clnt_req = (struct socks_req *) p;
-	p += 4;
-
-	//see if it's a connect request
-	if(clnt_req->cmd != 0x01){
-		printf("Error: issued a non-connect command\n");
-		fflush(stdout);
-		goto err;
-	}
-
-	//now select on pipe (for downstream data) and the socket (for upstream data)
-	for(;;){
-
-		fd_set readfds;
-		fd_set writefds;
-
-		int32_t nfds = (sockfd > ous_out) ? sockfd +1 : ous_out + 1;
-
-		FD_ZERO(&readfds);
-		FD_ZERO(&writefds);
-
-		FD_SET(sockfd, &readfds);
-		FD_SET(ous_out, &readfds);
-		FD_SET(sockfd, &writefds);
-
-		if(select(nfds, &readfds, &writefds, NULL, NULL) <0){
-			printf("Select error\n");
-			fflush(stdout);
-			continue;
-		}
-
-		if(FD_ISSET(sockfd, &readfds)){// && FD_ISSET(ous_in, &writefds)){
-
-			bytes_read = recv(sockfd, buffer, BUFSIZ-1, 0);
-			if (bytes_read < 0){
-				printf("Error reading from socket (in for loop)\n");
-				fflush(stdout);
-				goto err;
-			}
-			if(bytes_read == 0){
-				//socket is closed
-				printf("Closing connection for stream %d sockfd.\n", stream_id);
-				fflush(stdout);
-
-				//Send close message to slitheen proxy
-				up_hdr = (struct slitheen_up_hdr *) buffer;
-				up_hdr->stream_id = stream_id;
-				up_hdr->len = 0;
-				bio = BIO_new(BIO_s_mem());
-				b64 = BIO_new(BIO_f_base64());
-				bio = BIO_push(b64, bio);
-
-				BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
-				BIO_write(bio, buffer, 20);
-				BIO_flush(bio);
-				BIO_get_mem_ptr(bio, &buffer_ptr);
-				encoded_bytes = (*buffer_ptr).data;
-				BIO_set_close(bio, BIO_NOCLOSE);
-				BIO_free_all(bio);
-
-				uint8_t *ebytes = calloc(1, (*buffer_ptr).length+1);
-				memcpy(ebytes, (*buffer_ptr).data, (*buffer_ptr).length);
-				ebytes[(*buffer_ptr).length] = '\0';
-
-                                len = htons((*buffer_ptr).length);
-                                bytes_sent = send(ous_in, (unsigned char *) &len, sizeof(uint16_t), 0);
-                                bytes_sent += send(ous_in, ebytes, ntohs(len), 0);
-				printf("Closing message: %s\n", ebytes);
-
-				goto err;
-				
-			}
+                fprintf(stderr, "Connection to OUS closed\n");
+                break;
+            }
 
-			if(bytes_read > 0){
+            uint32_t *chunk_len = (uint32_t*) buffer;
+            
+            fprintf(stderr, "Length of this chunk: %u\n", *chunk_len);
 
-#ifdef DEBUG_UPSTREAM
-				printf("Received %d data bytes from sockfd (id %d):\n", bytes_read, stream_id);
-				for(i=0; i< bytes_read; i++){
-					printf("%02x ", buffer[i]);
-				}
-				printf("\n");
-				printf("%s\n", buffer);
-				fflush(stdout);
+            
+            bytes_read = recv(ous, buffer, *chunk_len, 0);
+#ifdef DEBUG
+            printf("Received %d bytes from OUS\n", bytes_read);
+            for(int i=0; i< bytes_read; i++){
+                printf("%02x ", buffer[i]);
+            }
+            printf("\n");
+            fflush(stdout);
 #endif
 
-				memmove(buffer+sizeof(struct slitheen_up_hdr), buffer, bytes_read);
+            if(bytes_read > 0){
+                bytes_sent = write(ous_out, buffer, bytes_read);
+#ifdef DEBUG
+                printf("Sent %d bytes to demultiplexer\n", bytes_sent);
+                for(int i=0; i< bytes_sent; i++){
+                    printf("%02x ", buffer[i]);
+                }
+                printf("\n");
+                fflush(stdout);
+#endif
 
-				up_hdr = (struct slitheen_up_hdr *) buffer;
-				up_hdr->stream_id = stream_id;
-				up_hdr->len = htons(bytes_read);
+                if(bytes_sent <= 0){
+                    fprintf(stderr, "Connection to demultiplexer closed\n");
+                    break;
+                }
 
-				bytes_read+= sizeof(struct slitheen_up_hdr);
+            } else if (bytes_read == 0) {
 
-				bio = BIO_new(BIO_s_mem());
-				b64 = BIO_new(BIO_f_base64());
-				bio = BIO_push(b64, bio);
+                fprintf(stderr, "Connection to OUS closed\n");
+                break;
 
-				BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
-				BIO_write(bio, buffer, bytes_read);
-				BIO_flush(bio);
-				BIO_get_mem_ptr(bio, &buffer_ptr);
-				BIO_set_close(bio, BIO_NOCLOSE);
-				BIO_free_all(bio);
-				encoded_bytes = (*buffer_ptr).data;
-				
-                                len = htons(strlen(encoded_bytes));
-                                bytes_sent = send(ous_in, (unsigned char *) &len, sizeof(uint16_t), 0);
-                                bytes_sent += send(ous_in, encoded_bytes, ntohs(len), 0);
+            } else {
+                fprintf(stderr, "Error reading from OUS\n");
+                break;
+            }
+        }
 
-#ifdef DEBUG_UPSTREAM
-				printf("Sent to OUS (%d bytes): %x %s\n",bytes_sent, len, message);
-#endif
+    }
+
+    fprintf(stderr, "Closing OUS\n");
+    close(ous);
+    close(ous_in);
+    close(ous_out);
+    free(buffer);
+    pthread_exit(NULL);
+
+}
+
+
+/*
+ * Continuously read from all stream sockets and pass data to ous
+ */
+void *multiplex_data(void *args){
+    ous_pipes *pipes = (ous_pipes *) args;
+
+    int32_t buffer_len = BUFSIZ;
+    uint8_t *buffer = ecalloc(1, buffer_len);
+
+    int32_t bytes_read;
+
+    uint8_t *response = ecalloc(1, BUFSIZ);
+    /* Select on stream sockets and ous_in pipe to send and receive data*/
+    for(;;){
+        fd_set read_fds;
+        fd_set write_fds;
+
+        int32_t nfds = 0;
 
+        FD_ZERO(&read_fds);
+        FD_ZERO(&write_fds);
 
-			}
-		} else if(FD_ISSET(ous_out, &readfds) && FD_ISSET(sockfd, &writefds)){
 
-			bytes_read = read(ous_out, buffer, BUFSIZ-1);
-			if (bytes_read <= 0){
-				printf("Error reading from ous_out (in for loop)\n");
-				fflush(stdout);
-				goto err;
-			}
+        //add all stream sockets to read_fds
+        connection *conn = connections->first;
+        while(conn != NULL){
+            if(conn->socket > nfds)
+                nfds = conn->socket;
+            FD_SET(conn->socket, &read_fds);
+            conn = conn->next;
+        }
 
-			if(bytes_read > 0){
+        FD_SET(pipes->in, &write_fds);
 
-#ifdef DEBUG_DOWNSTREAM
-				printf("Stream id %d received %d bytes from ous_out:\n", stream_id, bytes_read);
-				for(i=0; i< bytes_read; i++){
-					printf("%02x ", buffer[i]);
-				}
-				printf("\n");
-				printf("%s\n", buffer);
-				fflush(stdout);
+        if(pipes->in > nfds)
+            nfds = pipes->in;
+
+
+        struct timeval tv;
+        tv.tv_sec = 3;
+        tv.tv_usec = 0;
+        if(select(nfds+1, &read_fds, &write_fds, NULL, &tv) < 0){
+            fprintf(stderr, "Select error\n");
+            break;
+        }
+
+
+        struct slitheen_up_hdr *up_hdr;
+        uint16_t len;
+        char *encoded_bytes;
+
+        conn = connections->first;
+        while(conn != NULL){
+            uint8_t stream_id = conn->stream_id;
+            if(FD_ISSET(conn->socket, &read_fds) && FD_ISSET(pipes->in, &write_fds)){
+                printf("Reading from stream %d\n", conn->stream_id);
+                bytes_read = recv(conn->socket, buffer, buffer_len, 0);
+
+                if(bytes_read < 0){
+                    close(conn->socket);
+                    conn = conn->next;
+                    remove_connection(stream_id);
+                    continue;
+                } else if(bytes_read == 0){
+                    //socket is closed
+                    printf("Closing connection for stream %d sockfd.\n", conn->stream_id);
+                    fflush(stdout);
+
+                    if(conn->state == CONNECTED){
+                        //Send close message to slitheen proxy
+                        up_hdr = (struct slitheen_up_hdr *) buffer;
+                        up_hdr->stream_id = conn->stream_id;
+                        up_hdr->len = 0;
+
+                        base64_encode(buffer, 20, &encoded_bytes);
+
+                        len = htons(strlen(encoded_bytes));
+                        int32_t bytes_sent = write(pipes->in, (unsigned char *) &len, sizeof(uint16_t));
+                        bytes_sent += write(pipes->in, encoded_bytes, ntohs(len));
+
+                        printf("Wrote %d bytes to ous\n", bytes_sent);
+                        printf("Closing message: %s\n", encoded_bytes);
+                    }
+
+                    close(conn->socket);
+                    conn = conn->next;
+                    remove_connection(stream_id);
+                    continue;
+                }
+
+
+                switch(conn->state){
+                    case NEW_STREAM:
+                        printf("Received new stream data from stream %d\n", conn->stream_id);
+#ifdef DEBUG
+                        printf("Received %d bytes (id %d):\n", bytes_read, conn->stream_id);
+                        for(int i=0; i< bytes_read; i++){
+                            printf("%02x ", buffer[i]);
+                        }
+                        printf("\n");
+                        fflush(stdout);
 #endif
 
-				bytes_sent = send(sockfd, buffer, bytes_read, 0);
-				if(bytes_sent <= 0){
-					printf("Error sending bytes to browser for stream id %d\n", stream_id);
-				}
-				
-#ifdef DEBUG_DOWNSTREAM
-				printf("Sent to browser (%d bytes from stream id %d):\n", bytes_sent, stream_id);
-				for(i=0; i< bytes_sent; i++){
-					printf("%02x ", buffer[i]);
-				}
-				printf("\n");
-				fflush(stdout);
+                        //Respond to methods negotiation
+                        struct socks_method_req *clnt_meth = (struct socks_method_req *) buffer;
+                        uint8_t *p = buffer + 2;
+
+                        if(clnt_meth->version != 0x05){
+                            close(conn->socket);
+                            printf("Client supplied invalid version: %02x\n", clnt_meth->version);
+                            fflush(stdout);
+                            conn = conn->next;
+                            remove_connection(stream_id);
+                            continue;
+                        }
+
+                        int responded = 0;
+                        int bytes_sent;
+                        for(int i=0; i< clnt_meth->num_methods; i++){
+                            if(p[0] == 0x00){//send response with METH= 0x00
+                                response[0] = 0x05;
+                                response[1] = 0x00;
+                                send(conn->socket, response, 2, 0);
+                                responded = 1;
+                            }
+                            p++;
+                        }
+                        if(!responded){//respond with METH= 0xFF
+                            response[0] = 0x05;
+                            response[1] = 0xFF;
+                            send(conn->socket, response, 2, 0);
+                            close(conn->socket);
+                            conn = conn->next;
+                            remove_connection(stream_id);
+                            continue;
+                        }
+                        conn->state = NEGOTIATED;
+                        break;
+                    case NEGOTIATED:
+                        printf("Received negotiation data from stream %d\n", conn->stream_id);
+#ifdef DEBUG
+                        printf("Received %d bytes (id %d):\n", bytes_read, conn->stream_id);
+                        for(int i=0; i< bytes_read; i++){
+                            printf("%02x ", buffer[i]);
+                        }
+                        printf("\n");
+                        fflush(stdout);
 #endif
-			}
-		}
-	}
+                        //Respond to say connection was accepted
+                        response[0] = 0x05;
+                        response[1] = 0x00;
+                        response[2] = 0x00;
+                        response[3] = 0x01;
 
+                        *((uint32_t *) (response + 4)) = 0;
+                        *((uint16_t *) (response + 8)) = 0;
 
-err:
-		//should also remove stream from table
-	close(sockfd);
-	close(ous_in);
-	free(buffer);
-	free(response);
-	exit(0);
+                        send(conn->socket, response, 10, 0); //TODO: add check for send
+
+                        memmove(buffer+sizeof(struct slitheen_up_hdr), buffer, bytes_read);
+
+                        up_hdr = (struct slitheen_up_hdr *) buffer;
+                        up_hdr->stream_id = conn->stream_id;
+                        up_hdr->len = htons(bytes_read);
+
+                        bytes_read+= sizeof(struct slitheen_up_hdr);
+
+                        base64_encode(buffer, bytes_read, &encoded_bytes);
+
+                        len = htons(strlen(encoded_bytes));
+                        bytes_sent = write(pipes->in, (unsigned char *) &len, sizeof(uint16_t));
+                        bytes_sent += write(pipes->in, encoded_bytes, ntohs(len));
+                        printf("Wrote %d bytes to ous\n", bytes_sent);
+
+                        conn->state = CONNECTED;
+
+                        break;
+                    case CONNECTED:
+                        printf("Received application data from stream %d\n", conn->stream_id);
+#ifdef DEBUG_UPSTREAM
+                        printf("Received %d data bytes from sockfd (id %d):\n", bytes_read, conn->stream_id);
+                        for(i=0; i< bytes_read; i++){
+                                printf("%02x ", buffer[i]);
+                        }
+                        printf("\n");
+                        printf("%s\n", buffer);
+                        fflush(stdout);
+#endif
+
+                        memmove(buffer+sizeof(struct slitheen_up_hdr), buffer, bytes_read);
+
+                        up_hdr = (struct slitheen_up_hdr *) buffer;
+                        up_hdr->stream_id = conn->stream_id;
+                        up_hdr->len = htons(bytes_read);
+
+                        bytes_read+= sizeof(struct slitheen_up_hdr);
+
+                        base64_encode(buffer, bytes_read, &encoded_bytes);
+
+                        len = htons(strlen(encoded_bytes));
+                        bytes_sent = write(pipes->in, (unsigned char *) &len, sizeof(uint16_t));
+                        bytes_sent += write(pipes->in, encoded_bytes, ntohs(len));
+                        printf("Wrote %d bytes to ous\n", bytes_sent);
+
+#ifdef DEBUG_UPSTREAM
+                        printf("Sent to OUS (%d bytes): %x %s\n",bytes_sent, len, message);
+#endif
+                        break;
+                    default:
+                        fprintf(stderr, "Wrong connection state\n");
+                        close(conn->socket);
+                        conn = conn->next;
+                        remove_connection(stream_id);
+                        break;
+                }
+
+            }
+
+            conn = conn->next;
+        }
+    }
+    free(response);
+    pthread_exit(NULL);
 }
 
-/* Read blocks of covert data from OUS_out. Determine the stream id and the length of
+
+/* Read blocks of covert data from the OUS. Determine the stream id and the length of
  * the block and then write the data to the correct thread to be passed to the browser
  */
-void *demultiplex_data(){
-
-	int32_t buffer_len = BUFSIZ;
-	uint8_t *buffer = calloc(1, buffer_len);
-	uint8_t *p;
-
-	printf("Opening OUS_out... ");
-	int32_t ous_fd = open("OUS_out", O_RDONLY);
-	printf("done.\n");
-	uint8_t *partial_block = NULL;
-	uint32_t partial_block_len = 0;
-	uint32_t resource_remaining = 0;
-	uint64_t expected_next_count = 1;
-	data_block *saved_data = NULL;
-
-	for(;;){
-		int32_t bytes_read = read(ous_fd, buffer, buffer_len-partial_block_len);
+void *demultiplex_data(void *args){
+    ous_pipes *pipes = (ous_pipes *) args;
+
+    int32_t buffer_len = BUFSIZ;
+    uint8_t *buffer = calloc(1, buffer_len);
+    uint8_t *p;
+
+    uint8_t *partial_block = NULL;
+    uint32_t partial_block_len = 0;
+    uint32_t resource_remaining = 0;
+    uint64_t expected_next_count = 1;
+    data_block *saved_data = NULL;
+
+    for(;;){
+        printf("Demux thread waiting to read\n");
+        int32_t bytes_read = read(pipes->out, buffer, buffer_len-partial_block_len);
 		
-		if(bytes_read > 0){
-			int32_t bytes_remaining = bytes_read;
-			p = buffer;
-
-			//didn't read a full slitheen block last time
-			if(partial_block_len > 0){
-				//process first part of slitheen info
-				memmove(buffer+partial_block_len, buffer, bytes_read);
-				memcpy(buffer, partial_block, partial_block_len);
-				bytes_remaining += partial_block_len;
-				free(partial_block);
-				partial_block = NULL;
-				partial_block_len = 0;
-			}
-
-			while(bytes_remaining > 0){
-				if(resource_remaining <= 0){//we're at a new resource
-					//the first value for a new resource will be the resource length,
-					//followed by a newline
-					uint8_t *end_ptr;
-					resource_remaining = strtol((const char *) p, (char **) &end_ptr, 10);
+        if(bytes_read > 0){
+            int32_t bytes_remaining = bytes_read;
+            p = buffer;
+
+            //didn't read a full slitheen block last time
+            if(partial_block_len > 0){
+                //process first part of slitheen info
+                memmove(buffer+partial_block_len, buffer, bytes_read);
+                memcpy(buffer, partial_block, partial_block_len);
+                bytes_remaining += partial_block_len;
+                free(partial_block);
+                partial_block = NULL;
+                partial_block_len = 0;
+            }
+
+            while(bytes_remaining > 0){
+                if(resource_remaining <= 0){//we're at a new resource
+                    //the first value for a new resource will be the resource length,
+                    //followed by a newline
+                    uint8_t *end_ptr;
+                    resource_remaining = strtol((const char *) p, (char **) &end_ptr, 10);
 #ifdef DEBUG_PARSE
-					printf("Starting new resource of len %d bytes\n", resource_remaining);
-					printf("Resource len bytes:\n");
-					int i;
-					for(i=0; i< (end_ptr - p) + 1; i++){
-						printf("%02x ", ((const char *) p)[i]);
-					}
-					printf("\n");
+                    printf("Starting new resource of len %d bytes\n", resource_remaining);
+                    printf("Resource len bytes:\n");
+                    int i;
+                    for(i=0; i< (end_ptr - p) + 1; i++){
+                        printf("%02x ", ((const char *) p)[i]);
+                    }
+                    printf("\n");
 #endif
-					if(resource_remaining == 0){
-						bytes_remaining -= (end_ptr - p) + 1;
-						p += (end_ptr - p) + 1;
-					} else {
-						bytes_remaining -= (end_ptr - p) + 1;
-						p += (end_ptr - p) + 1;
+                    if(resource_remaining == 0){
+                        bytes_remaining -= (end_ptr - p) + 1;
+                        p += (end_ptr - p) + 1;
+                    } else {
+                        bytes_remaining -= (end_ptr - p) + 1;
+                        p += (end_ptr - p) + 1;
 
-					}
-					continue;
+                    }
+                    continue;
 
-				}
+                }
 
 
-				if(resource_remaining < SLITHEEN_HEADER_LEN){
-					printf("ERROR: Resource remaining doesn't fit header len.\n");
-					resource_remaining = 0;
-					bytes_remaining = 0;
-					break;
-				}
+                if(resource_remaining < SLITHEEN_HEADER_LEN){
+                    printf("ERROR: Resource remaining doesn't fit header len.\n");
+                    resource_remaining = 0;
+                    bytes_remaining = 0;
+                    break;
+                }
 
-				if(bytes_remaining < SLITHEEN_HEADER_LEN){
+                if(bytes_remaining < SLITHEEN_HEADER_LEN){
 
 #ifdef DEBUG_PARSE
-					printf("Partial header: ");
-					int i;
-					for(i = 0; i< bytes_remaining; i++){
-						printf("%02x ", p[i]);
-					}
-					printf("\n");
+                    printf("Partial header: ");
+                    int i;
+                    for(i = 0; i< bytes_remaining; i++){
+                        printf("%02x ", p[i]);
+                    }
+                    printf("\n");
 #endif
 
-					if(partial_block != NULL) printf("UH OH (PB)\n");
-					partial_block = calloc(1, bytes_remaining);
-					memcpy(partial_block, p, bytes_remaining);
-					partial_block_len = bytes_remaining;
-					bytes_remaining = 0;
-					break;
-				}
-
-				//decrypt header to see if we have entire block
-				uint8_t *tmp_header = malloc(SLITHEEN_HEADER_LEN);
-				memcpy(tmp_header, p, SLITHEEN_HEADER_LEN);
-				peek_header(tmp_header);
-
-				struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) tmp_header;
-				//first see if sl_hdr corresponds to a valid stream. If not, ignore rest of read bytes
+                    if(partial_block != NULL) printf("UH OH (PB)\n");
+                    partial_block = calloc(1, bytes_remaining);
+                    memcpy(partial_block, p, bytes_remaining);
+                    partial_block_len = bytes_remaining;
+                    bytes_remaining = 0;
+                    break;
+                }
+
+                //decrypt header to see if we have entire block
+                uint8_t *tmp_header = malloc(SLITHEEN_HEADER_LEN);
+                memcpy(tmp_header, p, SLITHEEN_HEADER_LEN);
+                peek_header(tmp_header);
+
+                struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) tmp_header;
+                //first see if sl_hdr corresponds to a valid stream. If not, ignore rest of read bytes
 #ifdef DEBUG_PARSE
-				printf("Slitheen header:\n");
-				int i;
-				for(i = 0; i< SLITHEEN_HEADER_LEN; i++){
-					printf("%02x ", tmp_header[i]);
-				}
-				printf("\n");
+                printf("Slitheen header:\n");
+                int i;
+                for(i = 0; i< SLITHEEN_HEADER_LEN; i++){
+                    printf("%02x ", tmp_header[i]);
+                }
+                printf("\n");
 #endif
-				if(ntohs(sl_hdr->len) > resource_remaining){
-					printf("ERROR: slitheen block doesn't fit in resource remaining!\n");
-					resource_remaining = 0;
-					bytes_remaining = 0;
-					break;
-				}
-
-				if(ntohs(sl_hdr->len) > bytes_remaining){
-					if(partial_block != NULL) printf("UH OH (PB)\n");
-					partial_block = calloc(1, ntohs(sl_hdr->len));
-					memcpy(partial_block, p, bytes_remaining);
-					partial_block_len = bytes_remaining;
-					bytes_remaining = 0;
-					free(tmp_header);
-					break;
-				}
-
-				super_decrypt(p);
-
-				sl_hdr = (struct slitheen_hdr *) p;
-				free(tmp_header);
-
-				p += SLITHEEN_HEADER_LEN;
-				bytes_remaining -= SLITHEEN_HEADER_LEN;
-				resource_remaining -= SLITHEEN_HEADER_LEN;
-
-				if((!sl_hdr->len) && (sl_hdr->garbage)){
+                if(ntohs(sl_hdr->len) > resource_remaining){
+                    printf("ERROR: slitheen block doesn't fit in resource remaining!\n");
+                    resource_remaining = 0;
+                    bytes_remaining = 0;
+                    break;
+                }
+
+                if(ntohs(sl_hdr->len) > bytes_remaining){
+                    if(partial_block != NULL) printf("UH OH (PB)\n");
+                    partial_block = calloc(1, ntohs(sl_hdr->len));
+                    memcpy(partial_block, p, bytes_remaining);
+                    partial_block_len = bytes_remaining;
+                    bytes_remaining = 0;
+                    free(tmp_header);
+                    break;
+                }
+
+                super_decrypt(p);
+
+                sl_hdr = (struct slitheen_hdr *) p;
+                free(tmp_header);
+
+                p += SLITHEEN_HEADER_LEN;
+                bytes_remaining -= SLITHEEN_HEADER_LEN;
+                resource_remaining -= SLITHEEN_HEADER_LEN;
+
+                if((!sl_hdr->len) && (sl_hdr->garbage)){
 
 #ifdef DEBUG_PARSE
-					printf("%d Garbage bytes\n", ntohs(sl_hdr->garbage));
+                    printf("%d Garbage bytes\n", ntohs(sl_hdr->garbage));
 #endif
-					p += ntohs(sl_hdr->garbage);
-					bytes_remaining -= ntohs(sl_hdr->garbage);
-					resource_remaining -= ntohs(sl_hdr->garbage);
-					continue;
-				}
-
-				int32_t pipe_fd =-1;
-				if(connections->first == NULL){
-					printf("Error: there are no connections\n");
-				} else {
-					connection *last = connections->first;
-					if (last->stream_id == sl_hdr->stream_id){
-						pipe_fd = last->pipe_fd;
-					}
-					while(last->next != NULL){
-						last = last->next;
-						if (last->stream_id == sl_hdr->stream_id){
-							pipe_fd = last->pipe_fd;
-						}
-					}
-				}
+                    p += ntohs(sl_hdr->garbage);
+                    bytes_remaining -= ntohs(sl_hdr->garbage);
+                    resource_remaining -= ntohs(sl_hdr->garbage);
+                    continue;
+                }
+
+                int32_t sock =-1;
+                if(connections->first == NULL){
+                    printf("Error: there are no connections\n");
+                } else {
+                    connection *last = connections->first;
+                    if (last->stream_id == sl_hdr->stream_id){
+                        sock = last->socket;
+                    }
+                    while(last->next != NULL){
+                        last = last->next;
+                        if (last->stream_id == sl_hdr->stream_id){
+                            sock = last->socket;
+                        }
+                    }
+                }
 				
-				if(pipe_fd == -1){
-					printf("No stream id exists. Possibly invalid header\n");
-					break;
-				}
+                if(sock == -1){
+                    printf("No stream id exists. Possibly invalid header\n");
+                    break;
+                }
 				
 #ifdef DEBUG_PARSE
-				printf("Received information for stream id: %d of length: %u\n", sl_hdr->stream_id, ntohs(sl_hdr->len));
+                printf("Received information for stream id: %d of length: %u\n", sl_hdr->stream_id, ntohs(sl_hdr->len));
 #endif
 
-				//figure out how much to skip
-				int32_t padding = 0;
-				if(ntohs(sl_hdr->len) %16){
-					padding = 16 - ntohs(sl_hdr->len)%16;
-				}
-				p += 16; //IV
-
-				//check counter to see if we are missing data
-				if(sl_hdr->counter > expected_next_count){
-					//save any future data
-					printf("Received header with count %lu. Expected count %lu.\n",
-							sl_hdr->counter, expected_next_count);
-					if((saved_data == NULL) || (saved_data->count > sl_hdr->counter)){
-						data_block *new_block = malloc(sizeof(data_block));
-						new_block->count = sl_hdr->counter;
+                //figure out how much to skip
+                int32_t padding = 0;
+                if(ntohs(sl_hdr->len) %16){
+                    padding = 16 - ntohs(sl_hdr->len)%16;
+                }
+                p += 16; //IV
+
+                //check counter to see if we are missing data
+                if(sl_hdr->counter > expected_next_count){
+                    //save any future data
+                    printf("Received header with count %lu. Expected count %lu.\n",
+                                        sl_hdr->counter, expected_next_count);
+                    if((saved_data == NULL) || (saved_data->count > sl_hdr->counter)){
+                        data_block *new_block = malloc(sizeof(data_block));
+                        new_block->count = sl_hdr->counter;
+                        new_block->len = ntohs(sl_hdr->len);
+                        new_block->data = malloc(ntohs(sl_hdr->len));
+
+                        memcpy(new_block->data, p, ntohs(sl_hdr->len));
+
+                        new_block->socket = sock;
+                        new_block->next = saved_data;
+
+                        saved_data = new_block;
+
+                    } else {
+                        data_block *last = saved_data;
+                        while((last->next != NULL) && (last->next->count < sl_hdr->counter)){
+                            last = last->next;
+                        }
+                        data_block *new_block = malloc(sizeof(data_block));
+                        new_block->count = sl_hdr->counter;
                         new_block->len = ntohs(sl_hdr->len);
-						new_block->data = malloc(ntohs(sl_hdr->len));
-
-						memcpy(new_block->data, p, ntohs(sl_hdr->len));
-                        
-						new_block->pipe_fd = pipe_fd;
-						new_block->next = saved_data;
-
-						saved_data = new_block;
-
-					} else {
-						data_block *last = saved_data;
-						while((last->next != NULL) && (last->next->count < sl_hdr->counter)){
-							last = last->next;
-						}
-						data_block *new_block = malloc(sizeof(data_block));
-						new_block->count = sl_hdr->counter;
-                                                new_block->len = ntohs(sl_hdr->len);
-						new_block->data = malloc(ntohs(sl_hdr->len));
-						memcpy(new_block->data, p, ntohs(sl_hdr->len));
-                                                new_block->pipe_fd = pipe_fd;
-						new_block->next = last->next;
-
-						last->next = new_block;
-					}
-				} else {
-					int32_t bytes_sent = write(pipe_fd, p, ntohs(sl_hdr->len));
-					if(bytes_sent <= 0){
-						printf("Error reading to pipe for stream id %d\n",
-								sl_hdr->stream_id);
-					}
-
-					//increment expected counter
-					expected_next_count++;
-				}
-
-				//now check to see if there is saved data to write out
-				if(saved_data != NULL){
-					data_block *current_block = saved_data;
-					while((current_block != NULL) &&
-							(expected_next_count == current_block->count)){
-						int32_t bytes_sent = write(current_block->pipe_fd,
-                                                    current_block->data, current_block->len);
-						if(bytes_sent <= 0){
-							printf("Error reading to pipe for stream id %d\n",
-									sl_hdr->stream_id);
-						}
-						expected_next_count++;
-						saved_data = current_block->next;
-						free(current_block->data);
-						free(current_block);
-						current_block = saved_data;
-					}
-				}
-
-				p += ntohs(sl_hdr->len); //encrypted data
-				p += 16; //mac
-				p += padding;
-				p += ntohs(sl_hdr->garbage);
-
-				bytes_remaining -= 
-					ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
-				resource_remaining -= 
-					ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
-
-			}
-
-		} else {
-			printf("Error: read %d bytes from OUS_out\n", bytes_read);
-			printf("Re-opening OUS_out... ");
-			close(ous_fd);
-			ous_fd = open("OUS_out", O_RDONLY);
-			printf("done.\n");
-		}
+                        new_block->data = malloc(ntohs(sl_hdr->len));
+                        memcpy(new_block->data, p, ntohs(sl_hdr->len));
+                        new_block->socket = sock;
+                        new_block->next = last->next;
+
+                        last->next = new_block;
+                    }
+                } else {
+                    int32_t bytes_sent = send(sock, p, ntohs(sl_hdr->len), 0);
+                    if(bytes_sent <= 0){
+                        printf("Error writing to socket for stream id %d\n", sl_hdr->stream_id);
+                    }
+
+                    //increment expected counter
+                    expected_next_count++;
+                }
+
+                //now check to see if there is saved data to write out
+                if(saved_data != NULL){
+                    data_block *current_block = saved_data;
+                    while((current_block != NULL) && (expected_next_count == current_block->count)){
+                        int32_t bytes_sent = send(current_block->socket, current_block->data, 
+                                current_block->len, 0);
+                        if(bytes_sent <= 0){
+                            printf("Error writing to socket for stream id %d\n", sl_hdr->stream_id);
+                        }
+                        expected_next_count++;
+                        saved_data = current_block->next;
+                        free(current_block->data);
+                        free(current_block);
+                        current_block = saved_data;
+                    }
+                }
+
+                p += ntohs(sl_hdr->len); //encrypted data
+                p += 16; //mac
+                p += padding;
+                p += ntohs(sl_hdr->garbage);
+
+                bytes_remaining -= ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
+                resource_remaining -= ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
+
+            }
+
+        } else {
+            printf("Error: read %d bytes from OUS_out\n", bytes_read);
+            goto err;
+        }
 		
-	}
-	free(buffer);
-	close(ous_fd);
+    }
+err:
+    free(buffer);
+    close(pipes->out);
+    pthread_exit(NULL);
+
+}
+
+
+int remove_connection(uint16_t stream_id){
 
+    connection *last = connections->first;
+    connection *prev = last;
+    while(last != NULL){
+        if(last->stream_id == stream_id){
+            if(last == connections->first){
+                connections->first = last->next;
+            } else {
+                prev->next = last->next;
+            }
+            free(last);
+            printf("Removed stream id %d from connections table\n", stream_id);
+            break;
+        }
+
+        prev = last;
+        last = last->next;
+    }
+
+    return 1;
 }
 
+

+ 11 - 3
client/socks5proxy.h

@@ -34,8 +34,10 @@
 #define SLITHEEN_SUPER_CONST "SLITHEEN_SUPER_ENCRYPT"
 #define SLITHEEN_SUPER_CONST_SIZE 22
 
-int proxy_data(int sockfd, uint16_t stream_id, int32_t pipefd, int32_t ous_in);
 void *demultiplex_data();
+void *multiplex_data();
+void *ous_IO();
+int remove_connection(uint16_t stream_id);
 
 struct __attribute__ ((__packed__)) slitheen_hdr {
 	uint64_t counter;
@@ -52,9 +54,15 @@ struct __attribute__ ((__packed__)) slitheen_up_hdr{
 	uint16_t len;
 };
 
+#define NEW_STREAM 0
+#define NEGOTIATED 1
+#define CONNECTED 2
+
+
 typedef struct connection_st{
-	int32_t pipe_fd;
 	uint16_t stream_id;
+        int32_t socket;
+        uint8_t state;
 	struct connection_st *next;
 } connection;
 
@@ -66,7 +74,7 @@ typedef struct data_block_st {
 	uint64_t count;
 	uint8_t *data;
         uint16_t len;
-        int32_t pipe_fd;
+        int32_t socket;
 	struct data_block_st *next;
 } data_block;
 

+ 53 - 0
client/util.c

@@ -0,0 +1,53 @@
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
+#include <openssl/evp.h>
+
+#include "util.h"
+
+/*
+ * Base64 encodes input bytes and stores them in out
+ */
+int base64_encode(uint8_t *in, size_t len, char **out){
+
+    //b64 encode slitheen ID
+    BUF_MEM *buffer_ptr;
+    BIO *bio, *b64;
+    b64 = BIO_new(BIO_f_base64());
+    bio = BIO_new(BIO_s_mem());
+    bio = BIO_push(b64, bio);
+
+    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+    BIO_write(bio, in, len);
+    BIO_flush(bio);
+    BIO_get_mem_ptr(bio, &buffer_ptr);
+    BIO_set_close(bio, BIO_NOCLOSE);
+    BIO_free_all(bio);
+    *out = (*buffer_ptr).data;
+    //*out[(*buffer_ptr).length] = '\0';
+
+    return 1;
+}
+
+//malloc macro that exits on error
+void *emalloc(size_t size){
+    void *ptr = malloc(size);
+    if (ptr == NULL){
+        fprintf(stderr, "Memory failure. Exiting...\n");
+	exit(1);
+    }
+
+    return ptr;
+}
+
+//calloc macro that exits on error
+void *ecalloc(size_t nmemb, size_t size){
+    void *ptr = calloc(nmemb, size);
+    if(ptr == NULL){
+        fprintf(stderr, "Memory failure. Exiting...\n");
+        exit(1);
+    }
+
+    return ptr;
+}

+ 38 - 0
client/util.h

@@ -0,0 +1,38 @@
+/*
+ * Slitheen - a decoy routing system for censorship resistance
+ * Copyright (C) 2017 Cecylia Bocovich (cbocovic@uwaterloo.ca)
+ *
+ * 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, version 3.
+ *
+ * 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/>.
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ * 
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with the OpenSSL library (or a modified version of that library), 
+ * containing parts covered by the terms of [name of library's license],
+ * the licensors of this Program grant you additional permission to convey
+ * the resulting work. {Corresponding Source for a non-source form of such
+ * a combination shall include the source code for the parts of the OpenSSL
+ * library used as well as that of the covered work.}
+ */
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+int base64_encode(uint8_t *in, size_t len, char **out);
+void *emalloc(size_t size);
+void *ecalloc(size_t nmemb, size_t size);
+
+#endif
+

+ 1 - 1
relay_station/Makefile

@@ -1,4 +1,4 @@
-CFLAGS=-g -ggdb -Wall -std=gnu99 -DDEBUG_HS
+CFLAGS=-g -ggdb -Wall -std=gnu99 -DDEBUG_DOWN -DDEBUG_PROXY -DRESOURCE_DEBUG
 
 TARGETS=slitheen-proxy
 

+ 4 - 1
relay_station/crypto.c

@@ -340,7 +340,9 @@ int extract_parameters(flow *f, uint8_t *hs){
 
 		//int curve_id = (p[1] << 8) + p[2];
 		int curve_id = *(p+2);
+#ifdef DEBUG_HS
                 printf("Using curve number %d\n", curve_id);
+#endif
 		if((curve_id < 0) || ((unsigned int)curve_id >
 						            sizeof(nid_list) / sizeof(nid_list[0]))){
 			goto err;
@@ -1006,9 +1008,11 @@ int extract_server_random(flow *f, uint8_t *hs){
 		f->message_digest = EVP_sha384();
 
 	} else {
+#ifdef DEBUG_HS
 		printf("%x %x = %x\n", p[0], p[1], ((p[0] <<8) + p[1]));
 		printf("Error: unsupported cipher\n");
 		fflush(stdout);
+#endif
 		return 1;
 	}
 
@@ -1620,7 +1624,6 @@ void check_handshake(struct packet_info *info){
 #endif
 
 				flow_ptr->ref_ctr--;
-                                printf("Flow added. %p ref_ctr %d\n", flow_ptr, flow_ptr->ref_ctr);
 
 			} else { /* else update saved flow with new key and random nonce */
 				for(int i=0; i<16; i++){

+ 7 - 3
relay_station/flow.c

@@ -81,7 +81,6 @@ flow *add_flow(struct packet_info *info) {
 	new_flow->dst_port = info->tcp_hdr->dst_port;
 
 	new_flow->ref_ctr = 1;
-        printf("Adding new flow (%p ref ctr %d)\n", new_flow, 1);
 	new_flow->removed = 0;
 
 	new_flow->upstream_app_data = emalloc(sizeof(app_data_queue));
@@ -308,15 +307,17 @@ int update_flow(flow *f, uint8_t *record, uint8_t incoming) {
 				case TLS_CERT:
 #ifdef DEBUG_HS
 					printf("Received cert\n");
+#endif
 					if(update_handshake_hash(f, p)){
 						fprintf(stderr, "Error updating finish has with CLNT_HELLO msg\n");
 						remove_flow(f);
 						goto err;
 					}
-#endif
 					break;
                                 case TLS_CERT_STATUS:
+#ifdef DEBUG_HS
                                         printf("Received certificate status\n");
+#endif
 					if(update_handshake_hash(f, p)){
 						fprintf(stderr, "Error updating finish has with CLNT_HELLO msg\n");
 						remove_flow(f);
@@ -985,9 +986,12 @@ int verify_extensions(flow *f, uint8_t *hs, uint32_t len){
     //Check to make sure both client and server included extension
     if(!f->extended_master_secret || !extended_master_secret){
         f->extended_master_secret = 0;
-    } else {
+    }
+#ifdef DEBUG_HS
+    else {
         printf("Extended master secret extension\n");
     }
+#endif
 
     return 0;
 

+ 51 - 30
relay_station/relay.c

@@ -250,7 +250,7 @@ int read_header(flow *f, struct packet_info *info){
 		//TODO: re-encrypt and return
 	}
 
-#ifdef DEBUG
+#ifdef DEBUG_US
 	printf("Upstream data: (%x:%d > %x:%d )\n",info->ip_hdr->src.s_addr,ntohs(info->tcp_hdr->src_port), info->ip_hdr->dst.s_addr, ntohs(info->tcp_hdr->dst_port));
 	printf("%s\n", decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN);
 #endif
@@ -267,7 +267,7 @@ int read_header(flow *f, struct packet_info *info){
 		return 0;
 	}
 
-#ifdef DEBUG
+#ifdef DEBUG_US
 	printf("UPSTREAM: Found x-slitheen header\n");
 	fflush(stdout);
 	fprintf(stdout,"UPSTREAM Flow: %x:%d > %x:%d (%s)\n", info->ip_hdr->src.s_addr,ntohs(info->tcp_hdr->src_port), info->ip_hdr->dst.s_addr, ntohs(info->tcp_hdr->dst_port) ,(info->ip_hdr->src.s_addr != f->src_ip.s_addr)? "incoming":"outgoing");
@@ -277,7 +277,7 @@ int read_header(flow *f, struct packet_info *info){
 	header_ptr += strlen("X-Slitheen: ");
 	
 	if(*header_ptr == '\r' || *header_ptr == '\0'){
-#ifdef DEBUG
+#ifdef DEBUG_US
 		printf("No messages\n");
 #endif
 		free(decrypted_data);
@@ -298,11 +298,11 @@ int read_header(flow *f, struct packet_info *info){
 	}
 	c++;
 	*c = '\0';
-#ifdef DEBUG
+#ifdef DEBUG_US
 	printf("UPSTREAM: Found %d messages\n", num_messages);
 #endif
 
-	for(int i=0; i< num_messages-1; i++){
+	for(int i=0; i< num_messages; i++){
 		char *message = messages[i];
 
 		//b64 decode the data
@@ -327,7 +327,7 @@ int read_header(flow *f, struct packet_info *info){
 
 		BIO_free_all(bio);
 
-#ifdef DEBUG
+#ifdef DEBUG_US
 		printf("Decoded to get %d bytes:\n", output_len);
 		for(int j=0; j< output_len; j++){
 			printf("%02x ", upstream_data[j]);
@@ -339,7 +339,7 @@ int read_header(flow *f, struct packet_info *info){
 
 		if(i== 0){
 			//this is the Slitheen ID
-#ifdef DEBUG
+#ifdef DEBUG_US
 			printf("Slitheen ID:");
 			for(int j=0; j< output_len; j++){
 				printf("%02x ", p[j]);
@@ -356,7 +356,7 @@ int read_header(flow *f, struct packet_info *info){
 					f->downstream_queue = last->downstream_queue;
 					f->client_ptr = last; 
 					break;
-#ifdef DEBUG
+#ifdef DEBUG_US
 				} else {
 					for(int j=0; j< output_len; j++){
 						printf("%02x ", last->slitheen_id[j]);
@@ -448,7 +448,7 @@ int read_header(flow *f, struct packet_info *info){
 					close(stream_pipe);
 					break;
 				}
-#ifdef DEBUG
+#ifdef DEBUG_US
 				printf("Found stream id %d\n", last->stream_id);
 				printf("Writing %d bytes to pipe\n", stream_len);
 #endif
@@ -512,8 +512,6 @@ int read_header(flow *f, struct packet_info *info){
 	}
 
 	//save a reference to the proxy threads in a global table
-	
-
 	free(decrypted_data);
 	if(record_ptr != NULL)
 		free(record_ptr);
@@ -603,23 +601,27 @@ void *proxy_covert_site(void *data){
 
     handle = socket(AF_INET, SOCK_STREAM, 0);
     if(handle < 0){
-		goto err;
+        goto err;
     }
 
-	struct sockaddr_in my_addr;
-	socklen_t my_addr_len = sizeof(my_addr);
+    struct sockaddr_in my_addr;
+    socklen_t my_addr_len = sizeof(my_addr);
 
     int32_t error = connect (handle, (struct sockaddr *) &dest, sizeof (struct sockaddr));
 
+#ifdef DEBUG_PROXY
+    printf("Connected to covert site for stream %d\n", stream_id);
+#endif
+
     if(error <0){
-		goto err;
+        goto err;
     }
 
 	getsockname(handle, (struct sockaddr *) &my_addr, &my_addr_len);
 
 	//see if there were extra upstream bytes
 	if(data_len > 0){
-#ifdef DEBUG
+#ifdef DEBUG_PROXY
 		printf("Data len is %d\n", data_len);
 		printf("Upstream bytes: ");
 		for(int i=0; i< data_len; i++){
@@ -662,7 +664,7 @@ void *proxy_covert_site(void *data){
 			int32_t bytes_read = read(thread_data->pipefd, buffer, buffer_len);
 
 			if(bytes_read > 0){
-#ifdef DEBUG
+#ifdef DEBUG_PROXY
 				printf("PROXY (id %d): read %d bytes from pipe\n", stream_id, bytes_read);
 				for(int i=0; i< bytes_read; i++){
 					printf("%02x ", buffer[i]);
@@ -673,8 +675,10 @@ void *proxy_covert_site(void *data){
 				bytes_sent = send(handle, buffer,
 						bytes_read, 0);
 				if( bytes_sent <= 0){
+                                    printf("Error sending bytes to covert site (stream %d)\n", stream_id);
 					break;
 				} else if (bytes_sent < bytes_read){
+                                    printf("Sent less bytes than read to covert site (stream %d)\n", stream_id);
 					break;
 				}
 			} else {
@@ -724,7 +728,7 @@ void *proxy_covert_site(void *data){
 			if(bytes_read > 0){
 				uint8_t *new_data = emalloc(bytes_read);
 				memcpy(new_data, buffer, bytes_read);
-#ifdef DEBUG
+#ifdef DEBUG_PROXY
 				printf("PROXY (id %d): read %d bytes from censored site\n",stream_id, bytes_read);
 				for(int i=0; i< bytes_read; i++){
 					printf("%02x ", buffer[i]);
@@ -768,7 +772,6 @@ void *proxy_covert_site(void *data){
 	if(streams->first != NULL){
 		if(last->stream_id == stream_id){
 			streams->first = last->next;
-			printf("Freeing (2) %p\n", last);
 			free(last);
 		} else {
 			while(last->next != NULL){
@@ -776,7 +779,6 @@ void *proxy_covert_site(void *data){
 				last = last->next;
 				if(last->stream_id == stream_id){
 					prev->next = last->next;
-					printf("Freeing (2) %p\n", last);
 					free(last);
 					break;
 				}
@@ -930,6 +932,9 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 
 
 			if(f->httpstate == PARSE_HEADER || f->httpstate == BEGIN_CHUNK || f->httpstate == END_CHUNK){
+#ifdef RESOURCE_DEBUG
+                            printf("record exceeds packet length, FORFEIT\n");
+#endif
 				f->httpstate = FORFEIT_REST;
 			} else if( f->httpstate == MID_CONTENT || f->httpstate == MID_CHUNK){
 				f->remaining_response_len -= record_len - 24; //len of IV and padding
@@ -972,6 +977,9 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 				}
 				if(f->remaining_response_len < 0){
 					f->remaining_response_len = 0;
+#ifdef RESOURCE_DEBUG
+                            printf("Resource is mid-content and super long record exceeds remaining resource len, FORFEIT\n");
+#endif
 					f->httpstate = FORFEIT_REST;
 				}
 			}
@@ -1005,12 +1013,12 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 		changed = 1;
 
 #ifdef DEBUG_DOWN
-		printf("Decryption succeeded\n");
-		printf("Bytes:\n");
-		for(int i=0; i< n; i++){
-			printf("%02x ", record_ptr[EVP_GCM_TLS_EXPLICIT_IV_LEN+i]);
-		}
-		printf("\n");
+		printf("Decrypted new record\n");
+		//printf("Bytes:\n");
+		//for(int i=0; i< n; i++){
+		//	printf("%02x ", record_ptr[EVP_GCM_TLS_EXPLICIT_IV_LEN+i]);
+		//}
+		//printf("\n");
 		printf("Text:\n");
 		printf("%s\n", record_ptr+EVP_GCM_TLS_EXPLICIT_IV_LEN);
 		fflush(stdout);
@@ -1023,6 +1031,10 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 
 		while(remaining_record_len > 0){
 
+#ifdef RESOURCE_DEBUG
+                    printf("Current state: %d\n", f->httpstate);
+#endif
+
 			switch(f->httpstate){
 
 				case PARSE_HEADER:
@@ -1037,6 +1049,9 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 							c[0] = ' ';
 							c++;
 						}
+#ifdef RESOURCE_DEBUG
+                                                printf("Found and replaced leaf header\n");
+#endif
 					} else {
 						f->replace_response = 0;
 					}
@@ -1146,6 +1161,9 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 						p = (uint8_t *) needle + 2;
 					} else {
 						remaining_record_len = 0;
+#ifdef RESOURCE_DEBUG
+                            printf("Error parsing in BEGIN_CHUNK, FORFEIT\n");
+#endif
 						f->httpstate = FORFEIT_REST;
 					}
 					}
@@ -1195,7 +1213,7 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 						remaining_record_len -= 2;
 					} else {
 						remaining_record_len = 0;
-						//printf("Couldn't find end of chunk, sending to FORFEIT_REST\n");
+						printf("Couldn't find end of chunk, sending to FORFEIT_REST\n");
 						f->httpstate = FORFEIT_REST;
 					}
 					break;
@@ -1208,7 +1226,7 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 						remaining_record_len -= 2;
 					} else {
 						remaining_record_len = 0;
-						//printf("Couldn't find end of body, sending to FORFEIT_REST\n");
+						printf("Couldn't find end of body, sending to FORFEIT_REST\n");
 						f->httpstate = FORFEIT_REST;
 					}
 					break;
@@ -1225,7 +1243,7 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 			}
 		}
 #ifdef DEBUG_DOWN
-		if(changed){
+		if(changed && f->replace_response){
 			printf("Resource is now\n");
 			printf("Bytes:\n");
 			for(int i=0; i< n; i++){
@@ -1283,7 +1301,10 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 	data_queue *downstream_queue = f->downstream_queue;
 	client *client_ptr = f->client_ptr;
 
-	if(client_ptr == NULL) return 1;
+	if(client_ptr == NULL){
+            printf("ERROR: no client\n");
+            return 1;
+        }
 
 
 	//Fill as much as we can from the censored_queue