Browse Source

added webm state machine to relay station + unit tests

cecylia 6 years ago
parent
commit
1e9f684215

+ 2 - 2
relay_station/Makefile

@@ -4,9 +4,9 @@ TARGETS=slitheen
 
 all: $(TARGETS)
 
-packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o:: ptwist.h flow.h packet.h crypto.h relay.h cryptothread.h util.h
+webm.o packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o:: ptwist.h flow.h packet.h crypto.h relay.h cryptothread.h util.h webm.h
 
-slitheen: slitheen.c packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o relay.h crypto.h ptwist.h flow.h packet.h cryptothread.h util.h
+slitheen: slitheen.c packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o webm.o webm.h relay.h crypto.h ptwist.h flow.h packet.h cryptothread.h util.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -lpcap -lpthread -ldl
 
 clean:

+ 2 - 0
relay_station/flow.c

@@ -184,6 +184,8 @@ flow *add_flow(struct packet_info *info) {
     new_flow->remaining_record_len = 0;
     new_flow->remaining_response_len = 0;
     new_flow->httpstate = PARSE_HEADER;
+    new_flow->webmstate = 0;
+    new_flow->remaining_element = 0;
     new_flow->replace_response = 0;
 
     new_flow->ecdh = NULL;

+ 2 - 0
relay_station/flow.h

@@ -164,6 +164,8 @@ typedef struct flow_st {
     //for downstream processing
     uint32_t remaining_record_len;
     uint8_t httpstate;
+    uint8_t webmstate;
+    uint64_t remaining_element;
     uint32_t remaining_response_len;
     uint8_t replace_response;
 

+ 4 - 1
relay_station/tests/Makefile

@@ -1,7 +1,7 @@
 CC=gcc
 CFLAGS=-g -ggdb -Wall -std=gnu99
 
-TARGETS=check_tagged check_handshake
+TARGETS=check_tagged check_handshake test_webm
 
 all: $(TARGETS)
 
@@ -13,6 +13,9 @@ check_tagged: check_tagged.c test_util.o ../flow.c ../crypto.o ../relay.o ../cry
 check_handshake: check_handshake.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 
+test_webm: test_webm.c test_util.o ../flow.o ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
+	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
+
 clean:
 	-rm $(TARGETS)
 

BIN
relay_station/tests/data/webm_0x7fd590016250


+ 25 - 0
relay_station/tests/test_util.c

@@ -58,3 +58,28 @@ int32_t read_file(const char *path, uint8_t **target){
 
     return result;
 }
+
+int32_t read_file_len(const char *path, uint8_t **target, int32_t *len){
+
+    FILE *fp;
+    int32_t fsize;
+
+    fp = fopen(path, "rb");
+    if (fp == NULL) {
+        perror("fopen");
+        return 0;
+    }
+
+    fseek(fp, 0, SEEK_END);
+    fsize = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+    *target = smalloc(fsize);
+
+    int32_t result = fread(*target, fsize, 1, fp);
+
+    *len = fsize;
+
+    fclose(fp);
+
+    return result;
+}

+ 1 - 0
relay_station/tests/test_util.h

@@ -28,6 +28,7 @@
 #define TEST_UTIL_H
 
 int32_t read_file(const char *path, uint8_t **target);
+int32_t read_file_len(const char *path, uint8_t **target, int32_t *len);
 
 #endif /* TEST_UTIL_H */
 

+ 168 - 0
relay_station/tests/test_webm.c

@@ -0,0 +1,168 @@
+/** test_webm.c
+ *
+ * Unit tests for the relay station webm parser
+ */
+
+#include <check.h>
+#include "../flow.h"
+#include "test_util.h"
+#include "../webm.h"
+#include "../webm.c"
+
+START_TEST(variable_header_parser) {
+    //set up common webm length field
+    uint8_t *p = malloc(4);
+
+    p[0] = 0x1a;
+    p[1] = 0x45;
+    p[2] = 0xdf;
+    p[3] = 0xa3;
+
+    uint8_t header_len;
+    uint32_t header = variable_header(p, &header_len);
+
+    ck_assert_int_eq(header_len, 4);
+    ck_assert_int_eq(header, 0x1a45dfa3);
+}
+END_TEST
+
+START_TEST(variable_length_parser) {
+
+    uint8_t *p = malloc(8);
+
+    p[0] = 0x9f;
+    p[1] = 0x00;
+    p[2] = 0x00;
+    p[3] = 0x00;
+
+    uint8_t int_len;
+    uint32_t len = variable_length(p, &int_len);
+
+    ck_assert_int_eq(int_len, 1);
+    ck_assert_int_eq(len, 0x1f);
+
+    p[0] = 0x21;
+    p[1] = 0x0d;
+    p[2] = 0x8c;
+    p[3] = 0x00;
+
+    len = variable_length(p, &int_len);
+
+    ck_assert_int_eq(int_len, 3);
+    ck_assert_int_eq(len, 0x10d8c);
+}
+END_TEST
+
+START_TEST(webm_parser) {
+
+    //need to create a flow for this
+    flow *f = smalloc(sizeof(flow));
+
+    //we only need to set the webmstate and remaining_element fields of the flow
+    f->webmstate = BEGIN_ELEMENT;
+    f->remaining_element = 0;
+
+    uint8_t *data;
+    int32_t file_len;
+
+    /* Read in webm data */
+    if(!read_file_len("data/webm_0x7fd590016250", &data, &file_len)){
+        ck_abort();
+    }
+
+    uint8_t *p = data;
+    parse_webm(f, p, 8);
+
+    //The remaining element length should be the element length (31) - the extra
+    //three bytes we parsed (28)
+    ck_assert_int_eq(f->remaining_element, 28);
+
+    ck_assert_int_eq(f->webmstate, MID_ELEMENT);
+
+    p += 8;
+    file_len -= 8;
+
+    //Parse the rest of the header
+    parse_webm(f, p, 28);
+    
+    ck_assert_int_eq(f->remaining_element, 0);
+
+    ck_assert_int_eq(f->webmstate, BEGIN_ELEMENT);
+
+    p+= 28;
+    file_len -= 28;
+
+    //Now parse segment header
+    parse_webm(f, p, 16);
+
+    ck_assert_int_eq(f->webmstate, MID_ELEMENT);
+
+    p+= 16;
+    file_len -= 16;
+
+    parse_webm(f, p, 185);
+    ck_assert_int_eq(f->webmstate, BEGIN_ELEMENT);
+
+    //Detect cluster element ID
+    p += 185;
+    file_len -= 185;
+
+    ck_assert_int_eq(p[0], 0x1f);
+    ck_assert_int_eq(p[1], 0x43);
+    ck_assert_int_eq(p[2], 0xb6);
+    ck_assert_int_eq(p[3], 0x75);
+
+    //Parse into media element
+    parse_webm(f, p, 8);
+
+    //make sure it was changed to slitheen ID
+    ck_assert_int_eq(p[0], 0x16);
+    ck_assert_int_eq(p[1], 0x73);
+    ck_assert_int_eq(p[2], 0x6c);
+    ck_assert_int_eq(p[3], 0x69);
+
+    ck_assert_int_eq(f->webmstate, MEDIA);
+
+    //parse to end of file
+    p += 8;
+    file_len -= 8;
+
+    parse_webm(f, p, file_len);
+
+    free(data);
+
+}
+END_TEST
+
+Suite *webm_suite(void) {
+    Suite *s;
+    TCase *tc_core;
+
+    s = suite_create("WebM Parser");
+
+    tc_core = tcase_create("Core");
+    tcase_add_test(tc_core, variable_header_parser);
+    tcase_add_test(tc_core, variable_length_parser);
+    tcase_add_test(tc_core, webm_parser);
+    suite_add_tcase(s, tc_core);
+
+    return s;
+}
+
+int main(void){
+
+    int number_failed;
+    Suite *s;
+    SRunner *sr;
+
+    s = webm_suite();
+    sr = srunner_create(s);
+
+    srunner_set_fork_status(sr, CK_NOFORK);
+
+    srunner_run_all(sr, CK_NORMAL);
+    number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

+ 215 - 0
relay_station/webm.c

@@ -0,0 +1,215 @@
+/* Name: webm.c
+ *
+ * This file contains functions for manipulating tagged flows. 
+ *
+ * Slitheen - a decoy routing system for censorship resistance
+ * Copyright (C) 2018 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 the OpenSSL Licence and the
+ * SSLeay 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "webm.h"
+#include "flow.h"
+
+static uint64_t variable_length(uint8_t *p, uint8_t *int_length);
+static uint32_t variable_header(uint8_t *p, uint8_t *int_length);
+
+/**
+ * Parses the webm content type
+ *
+ * Returns 0 on success 1 on failure
+ */
+int32_t parse_webm(flow *f, uint8_t *ptr, uint32_t len) {
+
+    if(!f->webmstate){
+        //make sure this is a webm resource
+        return 1;
+    }
+
+    uint8_t *p = ptr;
+    uint32_t remaining_len = len;
+
+    while (remaining_len){
+        switch (f->webmstate){
+            case BEGIN_ELEMENT: 
+                if(remaining_len < 8){
+                    //this will be difficult to parse
+                    //TODO: make this easier to deal with
+                    printf("PARSE FAIL: too little len remaining\n");
+                    return 1;
+                }
+
+                //The only elements we care about are:
+                //  the segment header (0x18538067), and
+                //  the cluster header (0x1f43b675).
+
+                //Parse header:
+                uint8_t header_len;
+                uint32_t header = variable_header(p, &header_len);
+
+                printf("Received header: %x\n", header);
+
+                if (header == 0x18538067) {
+                    // do nothing. Move on to parsing sub-element
+                    
+                } else if (header == 0x1f43b675) {
+                    f->webmstate = MEDIA;
+
+                    //replace with slitheen header
+                    p[0] = 0x16; //'SYN'
+                    p[1] = 0x73; //'s'
+                    p[2] = 0x6c; //'l'
+                    p[3] = 0x69; //'i'
+
+                } else {
+                    //we want to skip this element
+                    f->webmstate = MID_ELEMENT;
+                }
+
+                p += header_len;
+                remaining_len -= header_len;
+
+                //parse length of header
+                uint8_t int_len;
+                uint64_t element_len = variable_length(p, &int_len);
+
+                p += int_len;
+                remaining_len -= int_len;
+
+                printf("element length: %lu\n", element_len);
+
+                f->remaining_element = element_len;
+
+                break;
+            case MID_ELEMENT:
+                //The initial sequence of bytes contains everything up to the media
+                //segments
+                
+                if(f->remaining_element <= remaining_len){
+                    //we have the entire element in this packet
+                    
+                    p += f->remaining_element;
+                    remaining_len -= f->remaining_element;
+
+                    f->remaining_element = 0;
+                    f->webmstate = BEGIN_ELEMENT;
+                } else {
+                    //still have more of this element to process
+
+                    p += remaining_len;
+                    f->remaining_element -= remaining_len;
+                    remaining_len = 0;
+                }
+
+                break;
+            case MEDIA:
+                //We're replacing all of this element
+
+                if(f->remaining_element <= remaining_len){
+                    //we have the entire element in this packet
+                    
+                    p += f->remaining_element;
+                    remaining_len -= f->remaining_element;
+
+                    f->remaining_element = 0;
+                    f->webmstate = BEGIN_ELEMENT;
+                } else {
+                    //still have more of this element to process
+
+                    p += remaining_len;
+                    f->remaining_element -= remaining_len;
+                    remaining_len = 0;
+                }
+
+                break;
+        }
+    }
+
+    printf("Remaining element: %lu\n", f->remaining_element);
+
+    return 0;
+}
+
+static uint64_t variable_length(uint8_t *p, uint8_t *int_length){
+
+    //first check for length of int
+    uint8_t count = 1;
+    uint32_t mask = 1 << 7;
+
+    uint64_t len;
+
+    while (count < 8) {
+        if ((p[0] & mask) != 0) {
+            break;
+        }
+
+        mask >>= 1;
+        count += 1;
+    }
+
+    *int_length = count;
+
+    //now calculate the integer
+    len = p[0] & ~mask;
+
+    for(int i=1; i< count; i++){
+        len <<= 8;
+        len |= p[i];
+    }
+
+    return len;
+}
+
+static uint32_t variable_header(uint8_t *p, uint8_t *int_length){
+
+    //first check for length of int
+    uint8_t count = 1;
+    uint32_t mask = 1 << 7;
+
+    uint32_t len;
+
+    while (count < 4) {
+        if ((p[0] & mask) != 0) {
+            break;
+        }
+
+        mask >>= 1;
+        count += 1;
+    }
+
+    *int_length = count;
+
+    //now calculate the integer
+    len = p[0];
+
+    for(int i=1; i< count; i++){
+        len <<= 8;
+        len |= p[i];
+    }
+
+    return len;
+}

+ 41 - 0
relay_station/webm.h

@@ -0,0 +1,41 @@
+/* Slitheen - a decoy routing system for censorship resistance
+ * Copyright (C) 2018 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 the OpenSSL Licence and the
+ * SSLeay 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 WEBM_H
+#define WEBM_H
+
+#include "flow.h"
+
+int32_t parse_webm(flow *f, uint8_t *ptr, uint32_t len);
+
+/* WebM states */
+
+#define BEGIN_ELEMENT 0x01
+#define MID_ELEMENT 0x02
+#define MEDIA 0x03
+
+#endif /* WEBM_H */
+