|
@@ -3,6 +3,8 @@
|
|
|
#include <stdint.h>
|
|
|
#include <pthread.h>
|
|
|
#include <errno.h>
|
|
|
+#include <semaphore.h>
|
|
|
+
|
|
|
#include "flow.h"
|
|
|
#include "crypto.h"
|
|
|
#include "slitheen.h"
|
|
@@ -13,6 +15,8 @@ static session_cache *sessions;
|
|
|
data_queue *downstream_queue;
|
|
|
stream_table *streams;
|
|
|
|
|
|
+sem_t flow_table_lock;
|
|
|
+
|
|
|
/* Initialize the table of tagged flows */
|
|
|
int init_tables(void) {
|
|
|
|
|
@@ -20,6 +24,8 @@ int init_tables(void) {
|
|
|
table->first_entry = NULL;
|
|
|
table->len = 0;
|
|
|
|
|
|
+ sem_init(&flow_table_lock, 0, 1);
|
|
|
+
|
|
|
downstream_queue = calloc(1, sizeof(data_queue));
|
|
|
downstream_queue->first_block = NULL;
|
|
|
|
|
@@ -40,6 +46,7 @@ flow *add_flow(flow newFlow) {
|
|
|
|
|
|
printf("there are %d flows in the table\n", table->len);
|
|
|
|
|
|
+ sem_init(&(newFlow.flow_lock), 0, 1);
|
|
|
newFlow.state = TLS_CLNT_HELLO;
|
|
|
newFlow.in_encrypted = 0;
|
|
|
newFlow.out_encrypted = 0;
|
|
@@ -47,7 +54,7 @@ flow *add_flow(flow newFlow) {
|
|
|
newFlow.resume_session = 0;
|
|
|
newFlow.current_session = NULL;
|
|
|
newFlow.packet_chain = NULL;
|
|
|
- newFlow.censored_queue = NULL;
|
|
|
+ sem_init(&(newFlow.packet_chain_lock), 0, 1);
|
|
|
newFlow.upstream_queue = NULL;
|
|
|
newFlow.upstream_remaining = 0;
|
|
|
newFlow.outbox = NULL;
|
|
@@ -63,11 +70,17 @@ flow *add_flow(flow newFlow) {
|
|
|
const EVP_MD *md = EVP_sha384();
|
|
|
EVP_DigestInit_ex(newFlow.finish_md_ctx, md, NULL);
|
|
|
|
|
|
+ newFlow.clnt_read_ctx = NULL;
|
|
|
+ newFlow.clnt_write_ctx = NULL;
|
|
|
+ newFlow.srvr_read_ctx = NULL;
|
|
|
+ newFlow.srvr_write_ctx = NULL;
|
|
|
+
|
|
|
memset(newFlow.read_seq, 0, 8);
|
|
|
memset(newFlow.write_seq, 0, 8);
|
|
|
|
|
|
*ptr = newFlow;
|
|
|
|
|
|
+ sem_wait(&flow_table_lock);
|
|
|
flow_entry *last = table->first_entry;
|
|
|
if(last == NULL){
|
|
|
table->first_entry = entry;
|
|
@@ -78,6 +91,7 @@ flow *add_flow(flow newFlow) {
|
|
|
last->next = entry;
|
|
|
}
|
|
|
table->len ++;
|
|
|
+ sem_post(&flow_table_lock);
|
|
|
|
|
|
return ptr;
|
|
|
}
|
|
@@ -96,17 +110,20 @@ int update_flow(flow *f) {
|
|
|
const struct record_header *record_hdr;
|
|
|
const struct handshake_header *handshake_hdr;
|
|
|
|
|
|
- uint8_t *p = f->packet_chain->data;
|
|
|
+ sem_wait(&(f->packet_chain_lock));
|
|
|
|
|
|
+ if(f->packet_chain == NULL){
|
|
|
+ sem_post(&(f->packet_chain_lock));
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ uint8_t *p = f->packet_chain->data;
|
|
|
record_hdr = (struct record_header*) p;
|
|
|
int record_len;
|
|
|
int data_len;
|
|
|
|
|
|
record_len = RECORD_LEN(record_hdr)+RECORD_HEADER_LEN;
|
|
|
data_len = f->packet_chain->data_len;
|
|
|
- if(f->packet_chain == NULL){
|
|
|
- return 0;
|
|
|
- }
|
|
|
+
|
|
|
packet *current = f->packet_chain;
|
|
|
int incoming = current->incoming;
|
|
|
record = calloc(1, record_len);
|
|
@@ -117,13 +134,11 @@ int update_flow(flow *f) {
|
|
|
|
|
|
while(record_len > data_len) {
|
|
|
if(current->next == NULL){
|
|
|
- free(record);
|
|
|
- return 0;
|
|
|
+ goto err;
|
|
|
}
|
|
|
if(current->next->seq_num != current->seq_num + current->len){
|
|
|
printf("Missing packet: seq_num= %d, datalen= %d, nextseq= %d\n", current->seq_num, current->len, current->next->seq_num);
|
|
|
- free(record);
|
|
|
- return 0;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
current = current->next;
|
|
@@ -266,29 +281,53 @@ int update_flow(flow *f) {
|
|
|
printf("Error: Not a Record (%x:%d -> %x:%d)\n", f->src_ip.s_addr, f->src_port, f->dst_ip.s_addr, f->dst_port);
|
|
|
fflush(stdout);
|
|
|
//TODO: later figure this out, for now delete
|
|
|
+ packet *tmp = f->packet_chain;
|
|
|
f->packet_chain = f->packet_chain->next;
|
|
|
-
|
|
|
+ free(tmp->data);
|
|
|
+ free(tmp);
|
|
|
+
|
|
|
if( f->packet_chain != NULL){
|
|
|
+ sem_post(&(f->packet_chain_lock));
|
|
|
+ free(record);
|
|
|
update_flow(f);
|
|
|
+ return 0;
|
|
|
}
|
|
|
- return 0;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
- if(!f->application){
|
|
|
- f->seq_num = current->seq_num;
|
|
|
-
|
|
|
- if(record_len == data_len){
|
|
|
- /* record ended on packet boundary */
|
|
|
- f->packet_chain = current->next;
|
|
|
- } else {
|
|
|
- /* need to update data */
|
|
|
- f->packet_chain = current;
|
|
|
- current->data = current->data + (current->data_len - (data_len - record_len));
|
|
|
- current->data_len = data_len - record_len;
|
|
|
- update_flow(f);
|
|
|
- }
|
|
|
- }
|
|
|
+ //if(!f->application){
|
|
|
+ f->seq_num = current->seq_num;
|
|
|
+
|
|
|
+ if(record_len == data_len){
|
|
|
+ /* record ended on packet boundary */
|
|
|
+ current = current->next;
|
|
|
+ packet *tmp = f->packet_chain;
|
|
|
+ while(tmp != current){
|
|
|
+ f->packet_chain = tmp->next;
|
|
|
+ free(tmp->data);
|
|
|
+ free(tmp);
|
|
|
+ tmp = f->packet_chain;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* need to update data */
|
|
|
+ packet *tmp = f->packet_chain;
|
|
|
+ while(tmp != current){
|
|
|
+ f->packet_chain = tmp->next;
|
|
|
+ free(tmp->data);
|
|
|
+ free(tmp);
|
|
|
+ tmp = f->packet_chain;
|
|
|
+ }
|
|
|
+ memmove(current->data, current->data + (current->data_len - (data_len - record_len)), data_len - record_len);
|
|
|
+ current->data_len = data_len - record_len;
|
|
|
+ sem_post(&(f->packet_chain_lock));
|
|
|
+ free(record);
|
|
|
+ update_flow(f);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ //}
|
|
|
|
|
|
+err:
|
|
|
+ sem_post(&(f->packet_chain_lock));
|
|
|
free(record);
|
|
|
return 0;
|
|
|
}
|
|
@@ -304,6 +343,22 @@ int update_flow(flow *f) {
|
|
|
*/
|
|
|
int remove_flow(flow *f) {
|
|
|
|
|
|
+ EVP_MD_CTX_destroy(f->finish_md_ctx);
|
|
|
+ //Clean up cipher ctxs
|
|
|
+ if(f->clnt_read_ctx != NULL){
|
|
|
+ EVP_CIPHER_CTX_free(f->clnt_read_ctx);
|
|
|
+ }
|
|
|
+ if(f->clnt_write_ctx != NULL){
|
|
|
+ EVP_CIPHER_CTX_free(f->clnt_write_ctx);
|
|
|
+ }
|
|
|
+ if(f->srvr_read_ctx != NULL){
|
|
|
+ EVP_CIPHER_CTX_free(f->srvr_read_ctx);
|
|
|
+ }
|
|
|
+ if(f->srvr_write_ctx != NULL){
|
|
|
+ EVP_CIPHER_CTX_free(f->srvr_write_ctx);
|
|
|
+ }
|
|
|
+
|
|
|
+ sem_wait(&flow_table_lock);
|
|
|
flow_entry *entry = table->first_entry;
|
|
|
if(entry->f == f){
|
|
|
table->first_entry = entry->next;
|
|
@@ -312,31 +367,31 @@ int remove_flow(flow *f) {
|
|
|
printf("flow removed!\n");
|
|
|
fflush(stdout);
|
|
|
table->len --;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ } else {
|
|
|
|
|
|
- flow_entry *next;
|
|
|
- for(int i=0; i< table->len; i++){
|
|
|
- if(entry->next != NULL){
|
|
|
- next = entry->next;
|
|
|
- } else {
|
|
|
- printf("Flow not in table\n");
|
|
|
- return 1;
|
|
|
- }
|
|
|
+ flow_entry *next;
|
|
|
+ for(int i=0; i< table->len; i++){
|
|
|
+ if(entry->next != NULL){
|
|
|
+ next = entry->next;
|
|
|
+ } else {
|
|
|
+ printf("Flow not in table\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- if(next->f == f){
|
|
|
- entry->next = next->next;
|
|
|
- free(next->f);
|
|
|
- free(next);
|
|
|
- printf("flow removed!\n");
|
|
|
- table->len --;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if(next->f == f){
|
|
|
+ entry->next = next->next;
|
|
|
+ free(next->f);
|
|
|
+ free(next);
|
|
|
+ printf("flow removed!\n");
|
|
|
+ table->len --;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- entry = next;
|
|
|
+ entry = next;
|
|
|
+ }
|
|
|
}
|
|
|
+ sem_post(&flow_table_lock);
|
|
|
|
|
|
- printf("Should not get here!\n");
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -361,9 +416,11 @@ flow *check_flow(flow observed){
|
|
|
int i;
|
|
|
flow_entry *entry = table->first_entry;
|
|
|
flow *candidate;
|
|
|
+ flow *found = NULL;
|
|
|
if(entry == NULL)
|
|
|
return NULL;
|
|
|
|
|
|
+ sem_wait(&flow_table_lock);
|
|
|
/* Check first in this direction */
|
|
|
for(i=0; i<table->len; i++){
|
|
|
if(entry == NULL){
|
|
@@ -375,7 +432,7 @@ flow *check_flow(flow observed){
|
|
|
if(candidate->dst_ip.s_addr == observed.dst_ip.s_addr){
|
|
|
if(candidate->src_port == observed.src_port){
|
|
|
if(candidate->dst_port == observed.dst_port){
|
|
|
- return candidate;
|
|
|
+ found = candidate;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -396,32 +453,17 @@ flow *check_flow(flow observed){
|
|
|
if(candidate->dst_ip.s_addr == observed.src_ip.s_addr){
|
|
|
if(candidate->src_port == observed.dst_port){
|
|
|
if(candidate->dst_port == observed.src_port){
|
|
|
- return candidate;
|
|
|
+ found = candidate;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
entry = entry->next;
|
|
|
}
|
|
|
+ sem_post(&flow_table_lock);
|
|
|
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/** Returns the flow in the flow table at a specified index
|
|
|
- *
|
|
|
- * Input:
|
|
|
- * index: the desired index of the flow table
|
|
|
- *
|
|
|
- * Output:
|
|
|
- * the flow at the specified index
|
|
|
-flow *get_flow(int index){
|
|
|
- if(index < table->len){
|
|
|
- return table->table+index;
|
|
|
- } else {
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ return found;
|
|
|
}
|
|
|
- */
|
|
|
|
|
|
int init_session_cache(void){
|
|
|
sessions = malloc(sizeof(session_cache));
|
|
@@ -692,15 +734,18 @@ int save_session_ticket(flow *f, uint8_t *hs, uint32_t len){
|
|
|
|
|
|
/* Adds a packet the flow's packet chain */
|
|
|
int add_packet(flow *f, struct packet_info *info){
|
|
|
- packet *new_packet = malloc(sizeof(packet));
|
|
|
-
|
|
|
if (info->tcp_hdr == NULL){
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ packet *new_packet = calloc(1, sizeof(packet));
|
|
|
new_packet->seq_num = htonl(info->tcp_hdr->sequence_num);
|
|
|
new_packet->len = info->app_data_len;
|
|
|
- new_packet->data = info->app_data;
|
|
|
+
|
|
|
+ uint8_t *packet_data = calloc(1, new_packet->len);
|
|
|
+ memcpy(packet_data, info->app_data, new_packet->len);
|
|
|
+
|
|
|
+ new_packet->data = packet_data;
|
|
|
new_packet->data_len = new_packet->len;
|
|
|
new_packet->next = NULL;
|
|
|
new_packet->incoming =
|