[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stegotorus/master] Renames after the merge; drop the old x_http.
commit 0382170797b7ddadfd91b292d35da0a08627e57e
Author: Zack Weinberg <zackw@xxxxxxx>
Date: Thu Dec 1 23:30:00 2011 +0000
Renames after the merge; drop the old x_http.
---
Makefile.am | 17 +-
run-autogen.csh | 3 -
src/steg/cookies.c | 234 -------
src/steg/cookies.cc | 234 +++++++
src/steg/crc32.c | 82 ---
src/steg/crc32.cc | 82 +++
src/steg/http.cc | 857 +++++++++++++++++++++++++
src/steg/jsSteg.c | 1163 ---------------------------------
src/steg/jsSteg.cc | 1163 +++++++++++++++++++++++++++++++++
src/steg/payloads.c | 1669 ------------------------------------------------
src/steg/payloads.cc | 1669 ++++++++++++++++++++++++++++++++++++++++++++++++
src/steg/pdfSteg.c | 630 ------------------
src/steg/pdfSteg.cc | 630 ++++++++++++++++++
src/steg/swfSteg.c | 282 --------
src/steg/swfSteg.c.old | 264 --------
src/steg/swfSteg.cc | 282 ++++++++
src/steg/x_http.c.old | 337 ----------
src/steg/x_http.cc | 360 -----------
src/steg/x_http2.c | 857 -------------------------
src/steg/zpack.c | 408 ------------
src/steg/zpack.cc | 408 ++++++++++++
21 files changed, 5333 insertions(+), 6298 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index ebf44d9..bbd89a6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,15 +19,14 @@ PROTOCOLS = \
src/protocol/x_null.cc
STEGANOGRAPHERS = \
- src/steg/x_http.cc \
- src/steg/x_http2.c \
- src/steg/payloads.c \
- src/steg/cookies.c \
- src/steg/jsSteg.c \
- src/steg/swfSteg.c \
- src/steg/zpack.c \
- src/steg/crc32.c \
- src/steg/pdfSteg.c
+ src/steg/http.cc \
+ src/steg/payloads.cc \
+ src/steg/cookies.cc \
+ src/steg/jsSteg.cc \
+ src/steg/swfSteg.cc \
+ src/steg/zpack.cc \
+ src/steg/crc32.cc \
+ src/steg/pdfSteg.cc
libstegotorus_a_SOURCES = \
src/connections.cc \
diff --git a/run-autogen.csh b/run-autogen.csh
deleted file mode 100644
index 9fe8c44..0000000
--- a/run-autogen.csh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/csh
-setenv PATH /usr/local/bin:`echo $PATH`
-./autogen.sh
diff --git a/src/steg/cookies.c b/src/steg/cookies.c
deleted file mode 100644
index c773386..0000000
--- a/src/steg/cookies.c
+++ /dev/null
@@ -1,234 +0,0 @@
-
-#include "cookies.h"
-
-int unwrap_cookie(unsigned char* inbuf, unsigned char* outbuf, int buflen) {
- int i,j;
- j = 0;
-
- for (i=0; i < buflen; i++) {
- char c = inbuf[i];
-
- if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
- outbuf[j++] = c;
- }
-
- return j;
-
-}
-
-
-
-
-
-
-/* valid cookie characters: anything between between 33 and 126, with the exception of "=" and ';'*/
-/* writes a line of the form XXXX=YYYYY of length cookielen to outbuf, outbuf length >= cookielen */
-/* returns data consumed if success. datalen assumed to be greater than cookielen*/
-
-
-int gen_one_cookie(unsigned char* outbuf, int cookielen, unsigned char* data, int datalen) {
- int sofar = 0;
- unsigned char c;
- int namelen, vlen;
- int data_consumed = 0;
-
- if (cookielen < 4)
- return -1;
-
-
-
- if (cookielen > 13)
- namelen = rand() % 10 + 1;
- else
- namelen = rand() % (cookielen - 3) + 1;
-
- vlen = cookielen - namelen;
-
-
-
- while (sofar < namelen) {
- c = rand() % (127 - 33) + 33;
- if (c == '=' || c == ';' || c == '`' || c == '\'' || c == '%' || c == '+' || c == '{' || c == '}' ||
- c == '<' || c == '>' || c == '?' || c == '#')
- continue;
-
- if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (rand () % 4 != 0)) {
- if (data_consumed < datalen)
- outbuf[sofar++] = data[data_consumed++];
- }
- else
- outbuf[sofar++] = c;
- }
-
-
- outbuf[sofar++] = '=';
-
-
- while (sofar < cookielen) {
- c = rand() % (127 - 33) + 33;
- if (c == '=' || c == ';' || c == '`' || c == '\'' || c == '%' || c == '+' || c == '{' || c == '}' ||
- c == '<' || c == '>' || c == '?' || c == '#')
- continue;
-
-
-
- if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (rand() % 4 != 0)) {
- if (data_consumed < datalen)
- outbuf[sofar++] = data[data_consumed++];
- }
- else
- outbuf[sofar++] = c;
- }
-
-
-
- return data_consumed;
-
-}
-
-
-
-
-/* dummy version for testing */
-int gen_one_cookie2(unsigned char* outbuf, int cookielen, unsigned char* data, int datalen) {
- int i;
-
- if (cookielen < 4)
- return -1;
-
- if (datalen >= cookielen) {
- memcpy(outbuf, data, cookielen);
- return cookielen;
- }
-
- memcpy(outbuf, data, datalen);
- for (i=datalen; i < cookielen; i++)
- outbuf[i] = '+';
-
- return datalen;
-
-}
-
-/* returns data consumed */
-int gen_cookie_field(unsigned char* outbuf, int total_cookie_len, unsigned char* data, int datalen) {
- int rem_cookie_len = total_cookie_len;
- int consumed = 0;
-
-
- if (total_cookie_len < 4) {
- fprintf(stderr, "error: cookie length too small\n");
- return -1;
- }
-
- while (rem_cookie_len > 4) {
- int cookielen = 4 + rand() % (rem_cookie_len - 3);
-
- int cnt = gen_one_cookie(outbuf, cookielen, data + consumed, datalen - consumed);
-
- if (cnt < 0) {
- fprintf(stderr, "error: couldn't create cookie %d\n", cnt);
- return cnt;
- }
-
-
-
- consumed += cnt;
- // fprintf(stderr, "cnt = %d %d %d; consumed = %d\n", cnt, rem_cookie_len, cookielen, consumed);
- rem_cookie_len = rem_cookie_len - cookielen;
- outbuf += cookielen;
-
-
-
- if (rem_cookie_len == 0) {
- break;
- }
- else if (rem_cookie_len <= 5) {
- int i = 0;
- if ((consumed < datalen) && (consumed % 2 == 1)) {
- outbuf[0] = data[consumed];
- consumed++;
- outbuf++;
- rem_cookie_len--;
- }
-
- for (i=0; i < rem_cookie_len; i++)
- outbuf[i] = "ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ"[rand() % 40];
-
- return consumed;
- }
-
-
- outbuf[0] = ';';
- outbuf++;
- rem_cookie_len--;
- }
-
-
- if (consumed % 2 == 1) {
- if ((outbuf[-1] >= '0' && outbuf[-1] <= '9') || (outbuf[-1] >= 'a' && outbuf[-1] <= 'f')) {
- outbuf[-1] = '*';
- consumed--;
- }
- else {
- outbuf[-1] = data[consumed];
- consumed++;
- }
- }
-
-
- return consumed;
-}
-
-
-/* dummy version for testing */
-int gen_cookie_field2(unsigned char* outbuf, int total_cookie_len, unsigned char* data, int datalen) {
- int i;
- if (datalen >= total_cookie_len) {
- memcpy(outbuf, data, total_cookie_len);
- return total_cookie_len;
- }
-
- memcpy(outbuf, data, datalen);
- for (i=datalen; i < total_cookie_len; i++)
- outbuf[i] = '*';
-
- return datalen;
-}
-
-
-
-
-/*
-
-int main () {
- char outbuf[200];
- char data[52] = "1a239023820389023802380389abc2322132321932847203aedf";
- char data2[200];
- // srand(time(NULL));
- srand (20);
-
-
-
- int i=0;
-
- for (i=0; i < 1000000; i++) {
- int cookielen = rand()%50 + 5;
- bzero(outbuf, sizeof(outbuf));
- int len = gen_cookie_field(outbuf, cookielen, data, sizeof(data));
- // printf("len = %d cookie = %s %d\n", len, outbuf, cookielen);
- bzero(data2, sizeof(data2));
- int len2 = unwrap_cookie(outbuf, data2, cookielen);
- // printf("unwrapped datalen = %d data = %s\n", len, data2);
-
- if (len != len2)
- printf("hello %d\n", i);
- }
-
-
-
-
-}
-
-*/
-
-
diff --git a/src/steg/cookies.cc b/src/steg/cookies.cc
new file mode 100644
index 0000000..c773386
--- /dev/null
+++ b/src/steg/cookies.cc
@@ -0,0 +1,234 @@
+
+#include "cookies.h"
+
+int unwrap_cookie(unsigned char* inbuf, unsigned char* outbuf, int buflen) {
+ int i,j;
+ j = 0;
+
+ for (i=0; i < buflen; i++) {
+ char c = inbuf[i];
+
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
+ outbuf[j++] = c;
+ }
+
+ return j;
+
+}
+
+
+
+
+
+
+/* valid cookie characters: anything between between 33 and 126, with the exception of "=" and ';'*/
+/* writes a line of the form XXXX=YYYYY of length cookielen to outbuf, outbuf length >= cookielen */
+/* returns data consumed if success. datalen assumed to be greater than cookielen*/
+
+
+int gen_one_cookie(unsigned char* outbuf, int cookielen, unsigned char* data, int datalen) {
+ int sofar = 0;
+ unsigned char c;
+ int namelen, vlen;
+ int data_consumed = 0;
+
+ if (cookielen < 4)
+ return -1;
+
+
+
+ if (cookielen > 13)
+ namelen = rand() % 10 + 1;
+ else
+ namelen = rand() % (cookielen - 3) + 1;
+
+ vlen = cookielen - namelen;
+
+
+
+ while (sofar < namelen) {
+ c = rand() % (127 - 33) + 33;
+ if (c == '=' || c == ';' || c == '`' || c == '\'' || c == '%' || c == '+' || c == '{' || c == '}' ||
+ c == '<' || c == '>' || c == '?' || c == '#')
+ continue;
+
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (rand () % 4 != 0)) {
+ if (data_consumed < datalen)
+ outbuf[sofar++] = data[data_consumed++];
+ }
+ else
+ outbuf[sofar++] = c;
+ }
+
+
+ outbuf[sofar++] = '=';
+
+
+ while (sofar < cookielen) {
+ c = rand() % (127 - 33) + 33;
+ if (c == '=' || c == ';' || c == '`' || c == '\'' || c == '%' || c == '+' || c == '{' || c == '}' ||
+ c == '<' || c == '>' || c == '?' || c == '#')
+ continue;
+
+
+
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (rand() % 4 != 0)) {
+ if (data_consumed < datalen)
+ outbuf[sofar++] = data[data_consumed++];
+ }
+ else
+ outbuf[sofar++] = c;
+ }
+
+
+
+ return data_consumed;
+
+}
+
+
+
+
+/* dummy version for testing */
+int gen_one_cookie2(unsigned char* outbuf, int cookielen, unsigned char* data, int datalen) {
+ int i;
+
+ if (cookielen < 4)
+ return -1;
+
+ if (datalen >= cookielen) {
+ memcpy(outbuf, data, cookielen);
+ return cookielen;
+ }
+
+ memcpy(outbuf, data, datalen);
+ for (i=datalen; i < cookielen; i++)
+ outbuf[i] = '+';
+
+ return datalen;
+
+}
+
+/* returns data consumed */
+int gen_cookie_field(unsigned char* outbuf, int total_cookie_len, unsigned char* data, int datalen) {
+ int rem_cookie_len = total_cookie_len;
+ int consumed = 0;
+
+
+ if (total_cookie_len < 4) {
+ fprintf(stderr, "error: cookie length too small\n");
+ return -1;
+ }
+
+ while (rem_cookie_len > 4) {
+ int cookielen = 4 + rand() % (rem_cookie_len - 3);
+
+ int cnt = gen_one_cookie(outbuf, cookielen, data + consumed, datalen - consumed);
+
+ if (cnt < 0) {
+ fprintf(stderr, "error: couldn't create cookie %d\n", cnt);
+ return cnt;
+ }
+
+
+
+ consumed += cnt;
+ // fprintf(stderr, "cnt = %d %d %d; consumed = %d\n", cnt, rem_cookie_len, cookielen, consumed);
+ rem_cookie_len = rem_cookie_len - cookielen;
+ outbuf += cookielen;
+
+
+
+ if (rem_cookie_len == 0) {
+ break;
+ }
+ else if (rem_cookie_len <= 5) {
+ int i = 0;
+ if ((consumed < datalen) && (consumed % 2 == 1)) {
+ outbuf[0] = data[consumed];
+ consumed++;
+ outbuf++;
+ rem_cookie_len--;
+ }
+
+ for (i=0; i < rem_cookie_len; i++)
+ outbuf[i] = "ghijklmnopqrstuvwxyzGHIJKLMNOPQRSTUVWXYZ"[rand() % 40];
+
+ return consumed;
+ }
+
+
+ outbuf[0] = ';';
+ outbuf++;
+ rem_cookie_len--;
+ }
+
+
+ if (consumed % 2 == 1) {
+ if ((outbuf[-1] >= '0' && outbuf[-1] <= '9') || (outbuf[-1] >= 'a' && outbuf[-1] <= 'f')) {
+ outbuf[-1] = '*';
+ consumed--;
+ }
+ else {
+ outbuf[-1] = data[consumed];
+ consumed++;
+ }
+ }
+
+
+ return consumed;
+}
+
+
+/* dummy version for testing */
+int gen_cookie_field2(unsigned char* outbuf, int total_cookie_len, unsigned char* data, int datalen) {
+ int i;
+ if (datalen >= total_cookie_len) {
+ memcpy(outbuf, data, total_cookie_len);
+ return total_cookie_len;
+ }
+
+ memcpy(outbuf, data, datalen);
+ for (i=datalen; i < total_cookie_len; i++)
+ outbuf[i] = '*';
+
+ return datalen;
+}
+
+
+
+
+/*
+
+int main () {
+ char outbuf[200];
+ char data[52] = "1a239023820389023802380389abc2322132321932847203aedf";
+ char data2[200];
+ // srand(time(NULL));
+ srand (20);
+
+
+
+ int i=0;
+
+ for (i=0; i < 1000000; i++) {
+ int cookielen = rand()%50 + 5;
+ bzero(outbuf, sizeof(outbuf));
+ int len = gen_cookie_field(outbuf, cookielen, data, sizeof(data));
+ // printf("len = %d cookie = %s %d\n", len, outbuf, cookielen);
+ bzero(data2, sizeof(data2));
+ int len2 = unwrap_cookie(outbuf, data2, cookielen);
+ // printf("unwrapped datalen = %d data = %s\n", len, data2);
+
+ if (len != len2)
+ printf("hello %d\n", i);
+ }
+
+
+
+
+}
+
+*/
+
+
diff --git a/src/steg/crc32.c b/src/steg/crc32.c
deleted file mode 100644
index 7fdc847..0000000
--- a/src/steg/crc32.c
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "crc32.h"
-
-#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
-
-static const unsigned int crc_c[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-
-unsigned int generate_crc32c(char *buffer, size_t length) {
- size_t i;
- unsigned int crc32 = ~0L;
-
- for (i = 0; i < length; i++){
- CRC32C(crc32, (unsigned char)buffer[i]);
- }
- return ~crc32;
-}
-
diff --git a/src/steg/crc32.cc b/src/steg/crc32.cc
new file mode 100644
index 0000000..7fdc847
--- /dev/null
+++ b/src/steg/crc32.cc
@@ -0,0 +1,82 @@
+#include "crc32.h"
+
+#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
+
+static const unsigned int crc_c[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+
+unsigned int generate_crc32c(char *buffer, size_t length) {
+ size_t i;
+ unsigned int crc32 = ~0L;
+
+ for (i = 0; i < length; i++){
+ CRC32C(crc32, (unsigned char)buffer[i]);
+ }
+ return ~crc32;
+}
+
diff --git a/src/steg/http.cc b/src/steg/http.cc
new file mode 100644
index 0000000..7377196
--- /dev/null
+++ b/src/steg/http.cc
@@ -0,0 +1,857 @@
+/* Copyright (c) 2011, SRI International
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Contributors: Zack Weinberg, Vinod Yegneswaran
+ See LICENSE for other credits and copying information
+*/
+
+
+
+#include "util.h"
+#include "connections.h"
+#include "steg.h"
+#include "payloads.h"
+#include "cookies.h"
+#include "swfSteg.h"
+#include "pdfSteg.h"
+#include "jsSteg.h"
+
+#include <event2/buffer.h>
+#include <stdio.h>
+
+
+
+
+
+
+#define MIN_COOKIE_SIZE 24
+#define MAX_COOKIE_SIZE 1024
+
+
+int
+x_http2_server_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source);
+
+int
+lookup_peer_name_from_ip(char* p_ip, char* p_name);
+
+
+static int has_peer_name = 0;
+static char peername[512];
+
+
+struct x_http2_steg_t
+{
+ steg_t super;
+
+ int have_transmitted;
+ int have_received;
+ int type;
+};
+
+
+STEG_DEFINE_MODULE(x_http2,
+ 1024, /* client-server max data rate - made up */
+ 10240, /* server-client max data rate - ditto */
+ 1, /* max concurrent connections per IP */
+ 1); /* max concurrent IPs */
+
+
+
+
+
+
+int x_http2_client_uri_transmit (steg_t *s, struct evbuffer *source, conn_t *conn);
+int x_http2_client_cookie_transmit (steg_t *s, struct evbuffer *source, conn_t *conn);
+
+void evbuffer_dump(struct evbuffer *buf, FILE *out);
+void buf_dump(unsigned char* buf, int len, FILE *out);
+int gen_uri_field(char* uri, unsigned int uri_sz, char* data, int datalen);
+
+
+void
+evbuffer_dump(struct evbuffer *buf, FILE *out)
+{
+ int nextent = evbuffer_peek(buf, SSIZE_MAX, 0, 0, 0);
+ struct evbuffer_iovec v[nextent];
+ int i;
+ const unsigned char *p, *limit;
+
+ if (evbuffer_peek(buf, -1, 0, v, nextent) != nextent)
+ abort();
+
+ for (i = 0; i < nextent; i++) {
+ p = v[i].iov_base;
+ limit = p + v[i].iov_len;
+
+ putc('|', out);
+ while (p < limit) {
+ if (*p < 0x20 || *p >= 0x7F || *p == '\\' || *p == '|')
+ fprintf(out, "\\x%02x", *p);
+ else
+ putc(*p, out);
+ p++;
+ }
+ }
+ putc('|', out);
+}
+
+
+
+
+
+void
+buf_dump(unsigned char* buf, int len, FILE *out)
+{
+ int i=0;
+ putc('|', out);
+ while (i < len) {
+ if (buf[i] < 0x20 || buf[i] >= 0x7F || buf[i] == '\\' || buf[i]== '|')
+ fprintf(out, "\\x%02x", buf[i]);
+ else
+ putc(buf[i], out);
+ i++;
+ }
+ putc('|', out);
+ putc('\n', out);
+}
+
+
+
+
+
+steg_t *
+x_http2_new(rng_t *rng, unsigned int is_clientside)
+{
+
+ STEG_NEW(x_http2, state, rng, is_clientside);
+
+ if (is_clientside)
+ load_payloads("traces/client.out");
+ else {
+ load_payloads("traces/server.out");
+ init_JS_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, JS_MIN_AVAIL_SIZE);
+ // init_JS_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, JS_MIN_AVAIL_SIZE, HTTP_CONTENT_HTML);
+ init_HTML_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, HTML_MIN_AVAIL_SIZE);
+ init_PDF_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, PDF_MIN_AVAIL_SIZE);
+ init_SWF_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, 0);
+ }
+
+
+ /* if there were extra stuff to fill in, you would do it here */
+ return upcast_steg(state);
+}
+
+void
+x_http2_del(steg_t *s)
+{
+ x_http2_steg_t *state = downcast_steg(s);
+
+ STEG_DEL(s);
+
+ /* if there were extra stuff to deallocate, you would do it here */
+ free(state);
+}
+
+
+// x_http2_detect determines if a packet should be processed by the http2 steg module
+unsigned int
+x_http2_detect(conn_t *conn)
+{
+ struct evbuffer *buf = conn_get_inbound(conn);
+ unsigned char *data;
+
+ //return 0;
+/*****
+ Here is a list of HTTP response codes extracted from the server-portals.out trace
+
+7369 HTTP/1.1 200 OK
+ 470 HTTP/1.1 302 Found
+ 350 HTTP/1.1 304 Not Modified
+ 212 HTTP/1.1 302 Moved Temporarily
+ 184 HTTP/1.1 204 No Content
+ 451 HTTP/1.0 200 OK
+ 36 HTTP/1.0 204 No Content
+ 21 HTTP/1.1 301 Moved Permanently
+ 19 HTTP/1.1 302 Object moved
+ 15 HTTP/1.1 404 Not Found
+
+ 7 HTTP/1.0 304 Not Modified
+ 6 HTTP/1.1 302 Redirect
+ 3 HTTP/1.0 200 Ok
+ 2 HTTP/1.1 303 Object Moved
+ 2 HTTP/1.0 301 Moved Permanently
+ 2 HTTP/1.0 302 Moved Temporarily
+ 2 HTTP/1.0 400 Bad request
+ 2 HTTP/1.0 403 Forbidden
+ 1 HTTP/1.0 404 Not Found
+ 1 HTTP/1.1 200
+ 1 HTTP/1.1 302 FOUND
+ 1 HTTP/1.1 304
+ 1 HTTP/1.1 400 Bad Request
+ 1 HTTP/1.1 403 Forbidden
+ 1 HTTP/1.1 503 Service Unavailable.
+ *****/
+
+ // The first part of a valid HTTP response should be of the form
+ // HTTP/1.x nnn
+
+ if (evbuffer_get_length(buf) >= 12) {
+ data = evbuffer_pullup(buf, 12);
+
+ if (data != NULL &&
+ ((!memcmp(data, "HTTP/1.1 200", 12)) ||
+ (!memcmp(data, "HTTP/1.1 302", 12)) ||
+ (!memcmp(data, "HTTP/1.1 304", 12)) ||
+ (!memcmp(data, "HTTP/1.1 204", 12)) ||
+ (!memcmp(data, "HTTP/1.0 200", 12)) ||
+ (!memcmp(data, "HTTP/1.0 204", 12)) ||
+ (!memcmp(data, "HTTP/1.1 301", 12)) ||
+ (!memcmp(data, "HTTP/1.1 302", 12)) ||
+ (!memcmp(data, "HTTP/1.1 404", 12)))) {
+ log_debug("x_http2_detect: valid response");
+ return 1;
+ }
+ }
+
+
+
+
+
+ // SC: if we are only interested in jsSteg, we may want to
+ // consider HTTP/1.1 and HTTP/1.0 responses whose code is 200 only
+
+ // check to see if this is a valid HTTP request
+ //
+ // the following is for HTTP requests used by the http2 steg module
+ // The client always transmits "GET /" followed by at least four
+ // characters that are either lowercase hex digits or equals
+ // signs, so we need nine bytes of incoming data.
+
+
+
+ if (evbuffer_get_length(buf) >= 9) {
+ data = evbuffer_pullup(buf, 9);
+ if (data != NULL && (!memcmp(data, "GET /", 5) || !memcmp(data, "POST /", 5) || !memcmp(data, "Cookie", 6))) {
+ log_debug("x_http2_detect: valid request");
+ return 1;
+ }
+ }
+
+ log_debug("x_http2_detect: didn't find either HTTP request or response");
+ /* Didn't find either the client or the server pattern. */
+ return 0;
+}
+
+size_t
+x_http2_transmit_room(steg_t *s, conn_t *conn)
+{
+ unsigned int mjc;
+
+ if (downcast_steg(s)->have_transmitted)
+ /* can't send any more on this connection */
+ return 0;
+
+
+ if (s->is_clientside) {
+ /* per http://www.boutell.com/newfaq/misc/urllength.html,
+ IE<9 can handle no more than 2048 characters in the path
+ component of a URL; we're not talking to IE, but this limit
+ means longer paths look fishy; we hex-encode the path, so
+ we have to cut the number in half. */
+ return (MIN_COOKIE_SIZE + rand() % (MAX_COOKIE_SIZE - MIN_COOKIE_SIZE)) / 4;
+ // return 1024;
+ }
+ else {
+
+ if (!downcast_steg(s)->have_received)
+ return 0;
+
+ switch(downcast_steg(s)->type) {
+
+ case HTTP_CONTENT_SWF:
+ return 1024;
+
+ case HTTP_CONTENT_JAVASCRIPT:
+ mjc = get_max_JS_capacity() / 2;
+ if (mjc > 1024) {
+ // it should be 1024 + ...., but seems like we need to be a little bit smaller (chopper bug?)
+ int rval = 512 + rand()%(mjc - 1024);
+ // fprintf(stderr, "returning rval %d, mjc %d\n", rval, mjc);
+ return rval;
+ }
+ log_warn("js capacity too small\n");
+ exit(-1);
+
+ case HTTP_CONTENT_HTML:
+ mjc = get_max_HTML_capacity() / 2;
+ if (mjc > 1024) {
+ // it should be 1024 + ...., but seems like we need to be a little bit smaller (chopper bug?)
+ int rval = 512 + rand()%(mjc - 1024);
+ // fprintf(stderr, "returning rval %d, mjc %d\n", rval, mjc);
+ return rval;
+ }
+ log_warn("js capacity too small\n");
+ exit(-1);
+
+ case HTTP_CONTENT_PDF:
+ // return 1024 + rand()%(get_max_PDF_capacity() - 1024)
+ return PDF_MIN_AVAIL_SIZE;
+ }
+
+ return SIZE_MAX;
+ }
+}
+
+
+
+
+
+
+int
+lookup_peer_name_from_ip(char* p_ip, char* p_name) {
+ struct addrinfo* ailist;
+ struct addrinfo* aip;
+ struct addrinfo hint;
+ char buf[128];
+
+ hint.ai_flags = AI_CANONNAME;
+ hint.ai_family = 0;
+ hint.ai_socktype = 0;
+ hint.ai_protocol = 0;
+ hint.ai_addrlen = 0;
+ hint.ai_canonname = NULL;
+ hint.ai_addr = NULL;
+ hint.ai_next = NULL;
+
+ strcpy(buf, p_ip);
+ buf[strchr(buf, ':') - buf] = 0;
+
+
+ if (getaddrinfo(buf, NULL, &hint, &ailist)) {
+ fprintf(stderr, "error: getaddrinfo() %s\n", p_ip);
+ exit(1);
+ }
+
+ for (aip = ailist; aip != NULL; aip = aip->ai_next) {
+ char buf[512];
+ if (getnameinfo(aip->ai_addr, sizeof(struct sockaddr), buf, 512, NULL, 0, 0) == 0) {
+ sprintf(p_name, "%s", buf);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+int
+x_http2_client_cookie_transmit (steg_t *s, struct evbuffer *source, conn_t *conn) {
+
+ /* On the client side, we have to embed the data in a GET query somehow;
+ the only plausible places to put it are the URL and cookies. This
+ presently uses the URL. And it can't be binary. */
+ // struct evbuffer *scratch;
+ struct evbuffer_iovec *iv;
+ int i, nv;
+ struct evbuffer *dest = conn_get_outbound(conn);
+ size_t sbuflen = evbuffer_get_length(source);
+ char buf[10000];
+ unsigned char data[(int) sbuflen*2];
+ // unsigned char outbuf[MAX_COOKIE_SIZE];
+
+ unsigned char outbuf[(int) sbuflen*8];
+ int datalen;
+
+
+ // size_t sofar = 0;
+ size_t cookie_len;
+
+
+ /* Convert all the data in 'source' to hexadecimal and write it to
+ 'scratch'. Data is padded to a multiple of four characters with
+ equals signs. */
+
+
+ unsigned int len = 0;
+ unsigned int cnt = 0;
+
+
+
+ datalen = 0;
+ cookie_len = 4 * sbuflen + rand() % 4;
+
+
+ nv = evbuffer_peek(source, sbuflen, NULL, NULL, 0);
+ iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
+
+ if (evbuffer_peek(source, sbuflen, NULL, iv, nv) != nv) {
+ free(iv);
+ return -1;
+ }
+
+ // retry up to 10 times
+ while (!len) {
+ len = find_client_payload(buf, sizeof(buf), TYPE_HTTP_REQUEST);
+ if (cnt++ == 10) return -1;
+ }
+
+
+ if (has_peer_name == 0 && lookup_peer_name_from_ip((char*) conn->peername, peername))
+ has_peer_name = 1;
+
+ // if (find_uri_type(buf) != HTTP_CONTENT_SWF) {
+ // fprintf(stderr, "%s\n", buf);
+ // exit(-1);
+ // }
+
+
+
+ cnt = 0;
+
+ for (i = 0; i < nv; i++) {
+ const unsigned char *p = iv[i].iov_base;
+ const unsigned char *limit = p + iv[i].iov_len;
+ char c;
+ while (p < limit && cnt < sbuflen) {
+ c = *p++;
+ data[datalen] = "0123456789abcdef"[(c & 0xF0) >> 4];
+ data[datalen+1] = "0123456789abcdef"[(c & 0x0F) >> 0];
+ datalen += 2;
+ cnt++;
+ }
+ }
+
+ free(iv);
+
+ if (cookie_len < 4) cookie_len = 4;
+
+ datalen = gen_cookie_field(outbuf, cookie_len, data, datalen);
+ log_debug("CLIENT: sending cookie of length = %d %d\n", datalen, (int) cookie_len);
+ // fprintf(stderr, "CLIENT: sending cookie of length = %d %d\n", datalen, (int) cookie_len);
+
+ if (datalen < 0) {
+ log_debug("cookie generation failed\n");
+ return -1;
+ }
+
+
+ if (evbuffer_add(dest, buf, strstr(buf, "\r\n") - buf + 2) || // add uri field
+ evbuffer_add(dest, "Host: ", 6) ||
+ evbuffer_add(dest, peername, strlen(peername)) ||
+ evbuffer_add(dest, strstr(buf, "\r\n"), len - (unsigned int) (strstr(buf, "\r\n") - buf)) || // add everything but first line
+ evbuffer_add(dest, "Cookie: ", 8) ||
+ evbuffer_add(dest, outbuf, cookie_len) ||
+ evbuffer_add(dest, "\r\n\r\n", 4)) {
+ log_debug("error ***********************");
+ return -1;
+ }
+
+ // debug
+ // log_warn("CLIENT HTTP request header:");
+ // buf_dump((unsigned char*)buf, len, stderr);
+
+ // sofar += datalen/2;
+ evbuffer_drain(source, datalen/2);
+
+ log_debug("CLIENT TRANSMITTED payload %d\n", (int) sbuflen);
+
+ conn_cease_transmission(conn);
+
+ downcast_steg(s)->type = find_uri_type(buf, sizeof(buf));
+ downcast_steg(s)->have_transmitted = 1;
+ return 0;
+}
+
+
+
+
+int gen_uri_field(char* uri, unsigned int uri_sz, char* data, int datalen) {
+ unsigned int so_far = 0;
+ uri[0] = 0;
+
+ strcat(uri, "GET /");
+ so_far = 5;
+
+ while (datalen > 0) {
+ unsigned int r = rand() % 4;
+
+ if (r == 1) {
+ r = rand() % 46;
+ if (r < 20)
+ uri[so_far++] = 'g' + r;
+ else
+ uri[so_far++] = 'A' + r - 20;
+ }
+ else {
+ uri[so_far++] = data[0];
+ data++;
+ datalen--;
+ }
+
+
+
+ r = rand() % 8;
+
+ if (r == 0 && datalen > 0)
+ uri[so_far++] = '/';
+
+ if (r == 2 && datalen > 0)
+ uri[so_far++] = '_';
+
+
+ if (so_far > uri_sz - 6) {
+ fprintf(stderr, "too small\n");
+ return 0;
+ }
+ }
+
+ switch(rand()%4){
+ case 1:
+ memcpy(uri+so_far, ".htm ", 6);
+ break;
+ case 2:
+ memcpy(uri+so_far, ".html ", 7);
+ break;
+ case 3:
+ memcpy(uri+so_far, ".js ", 5);
+ break;
+ case 0:
+ memcpy(uri+so_far, ".swf ", 6);
+ break;
+
+ }
+
+ return strlen(uri);
+
+}
+
+
+
+
+
+int
+x_http2_client_uri_transmit (steg_t *s, struct evbuffer *source, conn_t *conn) {
+
+
+ struct evbuffer *dest = conn_get_outbound(conn);
+
+
+ struct evbuffer_iovec *iv;
+ int i, nv;
+
+ /* Convert all the data in 'source' to hexadecimal and write it to
+ 'scratch'. Data is padded to a multiple of four characters with
+ equals signs. */
+ size_t slen = evbuffer_get_length(source);
+ size_t datalen = 0;
+ int cnt = 0;
+ char data[2*slen];
+
+ char outbuf[1024];
+ int len =0;
+ char buf[10000];
+
+
+ if (has_peer_name == 0 && lookup_peer_name_from_ip((char*) conn->peername, peername))
+ has_peer_name = 1;
+
+
+
+ nv = evbuffer_peek(source, slen, NULL, NULL, 0);
+ iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
+ if (evbuffer_peek(source, slen, NULL, iv, nv) != nv) {
+ free(iv);
+ return -1;
+ }
+
+ for (i = 0; i < nv; i++) {
+ const unsigned char *p = iv[i].iov_base;
+ const unsigned char *limit = p + iv[i].iov_len;
+ char c;
+ while (p < limit) {
+ c = *p++;
+ data[datalen++] = "0123456789abcdef"[(c & 0xF0) >> 4];
+ data[datalen++] = "0123456789abcdef"[(c & 0x0F) >> 0];
+ }
+ }
+ free(iv);
+
+
+
+ do {
+ datalen = gen_uri_field(outbuf, sizeof(outbuf), data, datalen);
+ } while (datalen == 0);
+
+
+
+
+ // retry up to 10 times
+ while (!len) {
+ len = find_client_payload(buf, sizeof(buf), TYPE_HTTP_REQUEST);
+ if (cnt++ == 10) return -1;
+ }
+
+
+ // fprintf(stderr, "outbuf = %s\n", outbuf);
+
+ if (evbuffer_add(dest, outbuf, datalen) || // add uri field
+ evbuffer_add(dest, "HTTP/1.1\r\nHost: ", 19) ||
+ evbuffer_add(dest, peername, strlen(peername)) ||
+ evbuffer_add(dest, strstr(buf, "\r\n"), len - (unsigned int) (strstr(buf, "\r\n") - buf)) || // add everything but first line
+ evbuffer_add(dest, "\r\n", 2)) {
+ log_debug("error ***********************");
+ return -1;
+ }
+
+
+
+ evbuffer_drain(source, slen);
+ conn_cease_transmission(conn);
+ downcast_steg(s)->type = find_uri_type(outbuf, sizeof(outbuf));
+ downcast_steg(s)->have_transmitted = 1;
+ return 0;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int
+x_http2_transmit(steg_t *s, struct evbuffer *source, conn_t *conn)
+{
+ // struct evbuffer *dest = conn_get_outbound(conn);
+
+ // fprintf(stderr, "in x_http2_ transmit %d\n", downcast_steg(s)->type);
+
+
+
+ if (s->is_clientside) {
+ /* On the client side, we have to embed the data in a GET query somehow;
+ the only plausible places to put it are the URL and cookies. This
+ presently uses the URL. And it can't be binary. */
+
+ if (evbuffer_get_length(source) < 72)
+ return x_http2_client_uri_transmit(s, source, conn); //@@
+ return x_http2_client_cookie_transmit(s, source, conn); //@@
+ }
+ else {
+ int rval = -1;
+ switch(downcast_steg(s)->type) {
+
+ case HTTP_CONTENT_SWF:
+ rval = x_http2_server_SWF_transmit(s, source, conn);
+ break;
+
+ case HTTP_CONTENT_JAVASCRIPT:
+ rval = x_http2_server_JS_transmit(s, source, conn, HTTP_CONTENT_JAVASCRIPT);
+ break;
+
+ case HTTP_CONTENT_HTML:
+ rval = x_http2_server_JS_transmit(s, source, conn, HTTP_CONTENT_HTML);
+ break;
+
+ case HTTP_CONTENT_PDF:
+ rval = x_http2_server_PDF_transmit(s, source, conn);
+ break;
+ }
+
+ if (rval == 0) downcast_steg(s)->have_transmitted = 1;
+ return rval;
+ }
+}
+
+
+
+
+
+
+int
+x_http2_server_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
+
+ int cnt = 0;
+ unsigned char* data;
+ int type;
+
+ do {
+ struct evbuffer_ptr s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
+ unsigned char *p;
+ unsigned char c, h, secondhalf;
+ char outbuf[MAX_COOKIE_SIZE];
+ int sofar = 0;
+ int cookie_mode = 0;
+
+
+ if (s2.pos == -1) {
+ log_debug("Did not find end of request %d", (int) evbuffer_get_length(source));
+ // evbuffer_dump(source, stderr);
+ return RECV_INCOMPLETE;
+ }
+
+ log_debug("SERVER received request header of length %d", (int)s2.pos);
+
+ data = evbuffer_pullup(source, s2.pos+4);
+
+ if (data == NULL) {
+ log_debug("SERVER evbuffer_pullup fails");
+ return RECV_BAD;
+ }
+
+
+ data[s2.pos+3] = 0;
+
+ type = find_uri_type((char *)data, s2.pos+4);
+
+ if (strstr((char*) data, "Cookie") != NULL) {
+ p = (unsigned char*) strstr((char*) data, "Cookie:") + sizeof "Cookie: "-1;
+ cookie_mode = 1;
+ }
+ else
+ p = data + sizeof "GET /" -1;
+
+
+ secondhalf = 0;
+ c = 0;
+
+
+ while (strncmp((char*) p, "\r\n", 2) != 0 && (cookie_mode != 0 || p[0] != '.')) {
+ if (!secondhalf)
+ c = 0;
+ if ('0' <= *p && *p <= '9')
+ h = *p - '0';
+ else if ('a' <= *p && *p <= 'f')
+ h = *p - 'a' + 10;
+ else {
+ p++;
+ continue;
+ }
+
+ c = (c << 4) + h;
+ if (secondhalf) {
+ outbuf[sofar++] = c;
+ cnt++;
+ }
+ secondhalf = !secondhalf;
+ p++;
+ }
+
+ outbuf[sofar] = 0;
+
+ if (secondhalf) {
+ fprintf(stderr, "incorrect cookie or uri recovery \n");
+ exit(-1);
+ }
+
+
+
+ if (evbuffer_add(dest, outbuf, sofar)) {
+ log_debug("Failed to transfer buffer");
+ return RECV_BAD;
+ }
+ evbuffer_drain(source, s2.pos + sizeof("\r\n\r\n") - 1);
+ } while (evbuffer_get_length(source));
+
+
+ downcast_steg(s)->have_received = 1;
+ downcast_steg(s)->type = type;
+ // fprintf(stderr, "SERVER RECEIVED payload %d %d\n", cnt, type);
+
+ conn_transmit_soon(conn, 100);
+ return RECV_GOOD;
+}
+
+
+
+
+
+
+
+
+
+
+
+static int
+x_http2_receive(steg_t *s, conn_t *conn, struct evbuffer *dest)
+{
+ struct evbuffer *source = conn_get_inbound(conn);
+ // unsigned int type;
+ int rval = RECV_BAD;
+
+
+ if (s->is_clientside) {
+
+ // fprintf(stderr, "client type = %d\n", downcast_steg(s)->type);
+
+ switch(downcast_steg(s)->type) {
+
+ case HTTP_CONTENT_SWF:
+ rval = x_http2_handle_client_SWF_receive(s, conn, dest, source);
+ break;
+
+ case HTTP_CONTENT_JAVASCRIPT:
+ case HTTP_CONTENT_HTML:
+ rval = x_http2_handle_client_JS_receive(s, conn, dest, source);
+ break;
+
+ case HTTP_CONTENT_PDF:
+ rval = x_http2_handle_client_PDF_receive(s, conn, dest, source);
+ break;
+ }
+
+ if (rval == RECV_GOOD) downcast_steg(s)->have_received = 1;
+ return rval;
+
+ } else {
+ return x_http2_server_receive(s, conn, dest, source);
+ }
+
+
+}
diff --git a/src/steg/jsSteg.c b/src/steg/jsSteg.c
deleted file mode 100644
index 1486255..0000000
--- a/src/steg/jsSteg.c
+++ /dev/null
@@ -1,1163 +0,0 @@
-#include "payloads.h"
-#include "jsSteg.h"
-#include "cookies.h"
-
-void buf_dump(unsigned char* buf, int len, FILE *out);
-
-
-/*
- * jsSteg: A Javascript-based steganography module
- *
- */
-
-
-/*
- * int isxString(char *str)
- *
- * description:
- * return 1 if all char in str are hexadecimal
- * return 0 otherwise
- *
- */
-int isxString(char *str) {
- unsigned int i;
- char *dp = str;
- for (i=0; i<strlen(str); i++) {
- if (! isxdigit(*dp) ) {
- return 0;
- }
- }
- return 1;
-}
-
-
-/*
- * isGzipContent(char *msg)
- *
- * If the HTTP header of msg specifies that the content is gzipped,
- * this function returns 1; otherwise, it returns 0
- *
- * Assumptions:
- * msg is null terminated
- *
- */
-int isGzipContent (char *msg) {
- char *ptr = msg, *end;
- int gzipFlag = 0;
-
- if (!strstr(msg, "\r\n\r\n"))
- return 0;
-
- while (1) {
- end = strstr(ptr, "\r\n");
- if (end == NULL) {
- break;
- }
-
- if (!strncmp(ptr, "Content-Encoding: gzip", 22)) {
- gzipFlag = 1;
- break;
- }
-
- if (!strncmp(end, "\r\n\r\n", 4)){
- break;
- }
- ptr = end+2;
- }
-
- return gzipFlag;
-}
-
-
-/*
- * findContentType(char *msg)
- *
- * If the HTTP header of msg specifies that the content type:
- * case (content type)
- * javascript: return HTTP_CONTENT_JAVASCRIPT
- * pdf: return HTTP_CONTENT_PDF
- * shockwave: return HTTP_CONTENT_SWF
- * html: return HTTP_CONTENT_HTML
- * otherwise: return 0
- *
- * Assumptions:
- * msg is null terminated
- *
- */
-int findContentType (char *msg) {
- char *ptr = msg, *end;
-
- if (!strstr(msg, "\r\n\r\n"))
- return 0;
-
- while (1) {
- end = strstr(ptr, "\r\n");
- if (end == NULL) {
- break;
- }
-
- if (!strncmp(ptr, "Content-Type:", 13)) {
-
- if (!strncmp(ptr+14, "text/javascript", 15) ||
- !strncmp(ptr+14, "application/javascript", 22) ||
- !strncmp(ptr+14, "application/x-javascript", 24)) {
- return HTTP_CONTENT_JAVASCRIPT;
- }
- if (!strncmp(ptr+14, "text/html", 9)) {
- return HTTP_CONTENT_HTML;
- }
- if (!strncmp(ptr+14, "application/pdf", 15) ||
- !strncmp(ptr+14, "application/x-pdf", 17)) {
- return HTTP_CONTENT_PDF;
- }
- if (!strncmp(ptr+14, "application/x-shockwave-flash", strlen("application/x-shockwave-flash"))) {
- return HTTP_CONTENT_SWF;
- }
- }
-
- if (!strncmp(end, "\r\n\r\n", 4)){
- break;
- }
- ptr = end+2;
- }
-
- return 0;
-}
-
-
-
-/*
- * int encode(char *data, char *jTemplate, char *jData,
- * unsigned int dlen, unsigned int jtlen, unsigned int jdlen)
- *
- * description:
- * embed hex-encoded data (data) in the input Javascript (jTemplate)
- * and put the result in jData
- * function returns the number of characters in data successfully
- * embedded in jData, or returns one of the error codes
- *
- * approach:
- * replaces characters in jTemplate that are hexadecimal (i.e., {0-9,a-f,A-F})
- * with those in data, and leave the non-hex char in place
- *
- * input:
- * - data[] : hex data to hide
- * - dlen : size of data
- * - jTemplate[] : Javascript
- * - jlen : size of jTemplate
- * - jdlen : size of jData, output buffer
- *
- * output:
- * - jData : result of encoding data in jTemplate
- *
- * assumptions:
- * - data is hex-encoded
- *
- * exceptions:
- * - if (jdlen < jtlen) return INVALID_BUF_SIZE
- * - if (data contains non-hex char) return INVALID_DATA_CHAR
- *
- * example:
- * data = "0123456789ABCDEF"
- * jTemplate = "dfp_ord=Math.random()*10000000000000000; dfp_tile = 1;"
- * encode() returns 16
- * jData = "01p_or2=M3th.r4n5om()*6789ABCDEF0000000; dfp_tile = 1;"
- *
- */
-int encode(char *data, char *jTemplate, char *jData,
- unsigned int dlen, unsigned int jtlen, unsigned int jdlen )
-{
- unsigned int encCnt = 0; /* num of data encoded in jData */
- char *dp, *jtp, *jdp; /* current pointers for data, jTemplate, and jData */
-
- unsigned int j;
-
- /*
- * insanity checks
- */
- if (jdlen < jtlen) { return INVALID_BUF_SIZE; }
-
- dp = data; jtp = jTemplate; jdp = jData;
-
- if (! isxString(dp) ) { return INVALID_DATA_CHAR; }
-
- /* handling boundary case: dlen == 0 */
- if (dlen < 1) { return 0; }
-
-
- for (j=0; j<jtlen; j++) {
- /* found a hex char in jTemplate that can be used for encoding data */
- if ( isxdigit(*jtp) ) {
- *jdp = *dp;
- dp++;
- encCnt++;
- if (encCnt == dlen) {
- jtp++; jdp++;
- break;
- }
- } else {
- *jdp = *jtp;
- }
- jtp++; jdp++;
- }
-
-
- /* copying the rest of jTemplate to jdata */
- while (jtp < (jTemplate+jtlen)) {
- *jdp++ = *jtp++;
- }
-
- return encCnt;
-}
-
-
-#define startScriptTypeJS "<script type=\"text/javascript\">"
-#define endScriptTypeJS "</script>"
-// #define JS_DELIMITER "?"
-// #define JS_DELIMITER_REPLACEMENT "."
-
-
-/*
- * similar to encode(), but uses offset2Hex to look for usable hex char
- * in JS for encoding. See offset2Hex for what hex char are considered
- * usable. encode() also converts JS_DELIMITER that appears in the
- * the JS to JS_DELIMITER_REPLACEMENT, before all the data is encoded.
- *
- * Output:
- * fin - signal the caller whether all data has been encoded and
- * a JS_DELIMITER has been added
- */
-int encode2(char *data, char *jTemplate, char *jData,
- unsigned int dlen, unsigned int jtlen,
- unsigned int jdlen, int *fin)
-{
- unsigned int encCnt = 0; /* num of data encoded in jData */
- char *dp, *jtp, *jdp; /* current pointers for data, jTemplate, and jData */
- int i,j;
-
- /*
- * insanity checks
- */
- if (jdlen < jtlen) { return INVALID_BUF_SIZE; }
-
- dp = data; jtp = jTemplate; jdp = jData;
-
- if (! isxString(dp) ) { return INVALID_DATA_CHAR; }
-
- /* handling boundary case: dlen == 0 */
- if (dlen < 1) { return 0; }
-
-
- i = offset2Hex(jtp, (jTemplate+jtlen)-jtp, 0);
- while (encCnt < dlen && i != -1) {
- // copy next i char from jtp to jdp,
- // except that if *jtp==JS_DELIMITER, copy
- // JS_DELIMITER_REPLACEMENT to jdp instead
- j = 0;
- while (j < i) {
- if (*jtp == JS_DELIMITER) {
- *jdp = JS_DELIMITER_REPLACEMENT;
- } else {
- *jdp = *jtp;
- }
- jtp = jtp + 1; jdp = jdp + 1; j++;
- }
-
- *jdp = *dp;
- encCnt++;
- dp = dp + 1; jtp = jtp + 1; jdp = jdp + 1;
-
- i = offset2Hex(jtp, (jTemplate+jtlen)-jtp, 1);
- }
-
-
-
- // copy the rest of jTemplate to jdata
- // if we've encoded all data, replace the first
- // char in jTemplate by JS_DELIMITER, if needed,
- // to signal the end of data encoding
-
-#ifdef DEBUG2
- printf("encode2: encCnt = %d; dlen = %d\n", encCnt, dlen);
-#endif
-
- *fin = 0;
- if (encCnt == dlen) {
- // replace the next char in jTemplate by JS_DELIMITER
- if (jtp < (jTemplate+jtlen)) {
- *jdp = JS_DELIMITER;
- }
- jdp = jdp+1; jtp = jtp+1;
- *fin = 1;
- }
-
- while (jtp < (jTemplate+jtlen)) {
- if (*jtp == JS_DELIMITER) {
- if (encCnt < dlen) {
- *jdp = JS_DELIMITER_REPLACEMENT;
- } else {
- *jdp = *jtp;
- }
- // else if (isxdigit(*jtp)) {
- // if (encCnt < dlen && *fin == 0) {
- // *jdp = JS_DELIMITER;
- // *fin = 1;
- // } else {
- // *jdp = *jtp;
- // }
- // }
- } else {
- *jdp = *jtp;
- }
- jdp = jdp+1; jtp = jtp+1;
- }
-
-#ifdef DEBUG2
- printf("encode2: encCnt = %d; dlen = %d\n", encCnt, dlen);
- printf("encode2: fin= %d\n", *fin);
-#endif
-
- return encCnt;
-
-}
-
-
-
-int encodeHTTPBody(char *data, char *jTemplate, char *jData,
- unsigned int dlen, unsigned int jtlen,
- unsigned int jdlen, int mode)
-{
- char *dp, *jtp, *jdp; // current pointers for data, jTemplate, and jData
- unsigned int encCnt = 0; // num of data encoded in jData
- int n; // tmp for updating encCnt
- char *jsStart, *jsEnd;
- int skip;
- int scriptLen;
- int fin;
- unsigned int dlen2 = dlen;
- dp = data;
- jtp = jTemplate;
- jdp = jData;
-
-
- if (mode == CONTENT_JAVASCRIPT) {
- // assumption: the javascript pertaining to jTemplate has enough capacity
- // to encode jData. thus, we only invoke encode() once here.
- encCnt = encode2(dp, jtp, jdp, dlen, jtlen, jdlen, &fin);
- // ensure that all dlen char from data have been encoded in jData
-#ifdef DEBUG
- if (encCnt != dlen || fin == 0) {
- printf("Problem encoding all data to the JS\n");
- }
-#endif
- return encCnt;
-
- }
-
- else if (mode == CONTENT_HTML_JAVASCRIPT) {
- while (encCnt < dlen2) {
- jsStart = strstr(jtp, startScriptTypeJS);
- if (jsStart == NULL) {
-#ifdef DEBUG
- printf("lack of usable JS; can't find startScriptType\n");
-#endif
- return encCnt;
- }
- skip = strlen(startScriptTypeJS)+jsStart-jtp;
-#ifdef DEBUG2
- printf("copying %d (skip) char from jtp to jdp\n", skip);
-#endif
- memcpy(jdp, jtp, skip);
- jtp = jtp+skip; jdp = jdp+skip;
- jsEnd = strstr(jtp, endScriptTypeJS);
- if (jsEnd == NULL) {
-#ifdef DEBUG
- printf("lack of usable JS; can't find endScriptType\n");
-#endif
- return encCnt;
- }
-
- // the JS for encoding data is between jsStart and jsEnd
- scriptLen = jsEnd - jtp;
- // n = encode2(dp, jtp, jdp, dlen, jtlen, jdlen, &fin);
- n = encode2(dp, jtp, jdp, dlen, scriptLen, jdlen, &fin);
- // update encCnt, dp, and dlen based on n
- if (n > 0) {
- encCnt = encCnt+n; dp = dp+n; dlen = dlen-n;
- }
- // update jtp, jdp, jdlen
- skip = jsEnd-jtp;
- jtp = jtp+skip; jdp = jdp+skip; jdlen = jdlen-skip;
- skip = strlen(endScriptTypeJS);
- memcpy(jdp, jtp, skip);
- jtp = jtp+skip; jdp = jdp+skip; jdlen = jdlen-skip;
- }
-
- // copy the rest of jTemplate to jdp
- skip = jTemplate+jtlen-jtp;
-
- // handling the boundary case in which JS_DELIMITER hasn't been
- // added by encode()
- if (fin == 0 && dlen == 0) {
- if (skip > 0) {
- *jtp = JS_DELIMITER;
- jtp = jtp+1; jdp = jdp+1;
- skip--;
- }
- }
- memcpy(jdp, jtp, skip);
- return encCnt;
-
- } else {
- log_warn("Unknown mode (%d) for encode2()", mode);
- return 0;
- }
-
-
-}
-
-/*
- * int decode(char *jData, char *dataBuf,
- * unsigned int jdlen, unsigned int dlen, unsigned int dataBufSize)
- *
- * description:
- * extract hex char from Javascript embedded with data (jData)
- * and put the result in dataBuf
- * function returns the number of hex char extracted from jData
- * to dataBuf, or returns one of the error codes
- *
- * input:
- * - jData[]: Javascript embedded with hex-encoded data
- * - jdlen : size of jData
- * - dlen : size of data to recover
- * - dataBufSize : size of output data buffer (dataBuf)
- *
- * output:
- * - dataBuf[] : output buffer for recovered data
- *
- * assumptions:
- * - data is hex-encoded
- *
- * exceptions:
- * - if (dlen > dataBufSize) return INVALID_BUF_SIZE
- *
- * example:
- * jData = "01p_or2=M3th.r4n5om()*6789ABCDEF0000000; dfp_tile = 1;"
- * jdlen = 54
- * dlen = 16
- * dataBufSize = 1000
- * decode() returns 16
- * dataBuf= "0123456789ABCDEF"
- *
- */
-int decode (char *jData, char *dataBuf, unsigned int jdlen,
- unsigned int dlen, unsigned int dataBufSize )
-{
- unsigned int decCnt = 0; /* num of data decoded */
- char *dp, *jdp; /* current pointers for dataBuf and jData */
- unsigned int j;
-
- if (dlen > dataBufSize) { return INVALID_BUF_SIZE; }
-
- dp = dataBuf; jdp = jData;
- for (j=0; j<jdlen; j++) {
- if ( isxdigit(*jdp) ) {
- if (decCnt < dlen) {
- decCnt++;
- *dp++ = *jdp++;
- } else {
- break;
- }
- } else {
- jdp++;
- }
- }
- return decCnt;
-}
-
-
-/*
- * decode2() is similar to decode(), but uses offset2Hex to look for
- * applicable hex char in JS for decoding. Also, the decoding process
- * stops when JS_DELIMITER is encountered.
- */
-int decode2 (char *jData, char *dataBuf, unsigned int jdlen,
- unsigned int dataBufSize, int *fin )
-{
- unsigned int decCnt = 0; /* num of data decoded */
- char *dp, *jdp; /* current pointers for dataBuf and jData */
- int i,j;
- int cjdlen = jdlen;
-
- *fin = 0;
- dp = dataBuf; jdp = jData;
-
- i = offset2Hex(jdp, cjdlen, 0);
- while (i != -1) {
- // return if JS_DELIMITER exists between jdp and jdp+i
- for (j=0; j<i; j++) {
- if (*jdp == JS_DELIMITER) {
- *fin = 1;
- return decCnt;
- }
- jdp = jdp+1; cjdlen--;
- }
- // copy hex data from jdp to dp
- if (dataBufSize <= 0) {
- return decCnt;
- }
- *dp = *jdp;
- jdp = jdp+1; cjdlen--;
- dp = dp+1; dataBufSize--;
- decCnt++;
-
- // find the next hex char
- i = offset2Hex(jdp, cjdlen, 1);
- }
-
- // look for JS_DELIMITER between jdp to jData+jdlen
- while (jdp < jData+jdlen) {
- if (*jdp == JS_DELIMITER) {
- *fin = 1;
- break;
- }
- jdp = jdp+1;
- }
-
- return decCnt;
-}
-
-
-int decodeHTTPBody (char *jData, char *dataBuf, unsigned int jdlen,
- unsigned int dataBufSize, int *fin, int mode )
-{
- char *jsStart, *jsEnd;
- char *dp, *jdp; // current pointers for data and jData
- int scriptLen;
- int decCnt = 0;
- int n;
- int dlen = dataBufSize;
- dp = dataBuf; jdp = jData;
-
- if (mode == CONTENT_JAVASCRIPT) {
- decCnt = decode2(jData, dataBuf, jdlen, dataBufSize, fin);
- if (*fin == 0) {
- log_warn("Unable to find JS_DELIMITER");
- }
- }
- else if (mode == CONTENT_HTML_JAVASCRIPT) {
- *fin = 0;
- while (*fin == 0) {
- jsStart = strstr(jdp, startScriptTypeJS);
- if (jsStart == NULL) {
-#ifdef DEBUG
- printf("Can't find startScriptType for decoding data inside script type JS\n");
-#endif
- return decCnt;
- }
- jdp = jsStart+strlen(startScriptTypeJS);
- jsEnd = strstr(jdp, endScriptTypeJS);
- if (jsEnd == NULL) {
-#ifdef DEBUG
- printf("Can't find endScriptType for decoding data inside script type JS\n");
-#endif
- return decCnt;
- }
-
- // the JS for decoding data is between jsStart and jsEnd
- scriptLen = jsEnd - jdp;
- n = decode2(jdp, dp, scriptLen, dlen, fin);
- if (n > 0) {
- decCnt = decCnt+n; dlen=dlen-n; dp=dp+n;
- }
- jdp = jsEnd+strlen(endScriptTypeJS);
- } // while (*fin==0)
- } else {
- log_warn("Unknown mode (%d) for encode2()", mode);
- return 0;
- }
-
- return decCnt;
-}
-
-
-
-
-
-void printerr(int errno) {
- if (errno == INVALID_BUF_SIZE) {
- printf ("Error: Output buffer too small\n");
- }
- else if (errno == INVALID_DATA_CHAR) {
- printf ("Error: Non-hex char in data\n");
- }
- else {
- printf ("Unknown error: %i\n", errno);
- }
-}
-
-
-int testEncode(char *data, char *js, char *outBuf, unsigned int dlen, unsigned int jslen,
- unsigned int outBufLen, int testNum) {
- int r;
-
- printf ("***** Start of testEncode (%i) *****\n", testNum);
- printf ("Input:\n");
- printf ("data = %s\n", data);
- printf ("data len = %i\n", dlen);
- printf ("js = %s\n", js);
- printf ("js len = %i\n", jslen);
- r = encode (data, js, outBuf, dlen, jslen, outBufLen);
- if (r < 0) {
- printerr(r);
- } else {
- printf ("\nOutput:\n");
- printf ("%i char of data embedded in outBuf\n", r);
- outBuf[jslen] = '\0';
- printf ("outBuf = %s\n", outBuf);
- }
- printf ("***** End of testEncode (%i) *****\n", testNum);
- return r;
-}
-
-int testDecode(char *inBuf, char *outBuf, unsigned int inBufSize, unsigned int dlen,
- unsigned int outBufSize, int testNum) {
-
- int r;
-
- printf ("***** Start of testDecode (%i) *****\n", testNum);
- printf ("Input:\n");
- printf ("inBuf = %s\n", inBuf);
- printf ("inBuf size = %i\n", inBufSize);
- printf ("data len = %i\n", dlen);
- printf ("outBuf size = %i\n", outBufSize);
- r = decode(inBuf, outBuf, inBufSize, dlen, outBufSize);
- if (r < 0) {
- printerr(r);
- } else {
- printf ("\nOutput:\n");
- printf ("%i char of data recovered from inBuf (to outBuf)\n", r);
- outBuf[r] = '\0';
- printf ("outBuf = %s\n", outBuf);
- }
- printf ("***** End of testDecode (%i) *****\n", testNum);
- return r;
-}
-
-
-int testEncode2(char *data, char *js, char *outBuf,
- unsigned int dlen, unsigned int jslen, unsigned int outBufLen,
- int mode, int testNum) {
- int r;
- // int fin;
-
- printf ("***** Start of testEncode2 (%i) *****\n", testNum);
- printf ("Input:\n");
- printf ("data = %s\n", data);
- printf ("data len = %i\n", dlen);
- printf ("js = %s\n", js);
- printf ("js len = %i\n", jslen);
- // r = encode2(data, js, outBuf, dlen, jslen, outBufLen, &fin);
- r = encodeHTTPBody(data, js, outBuf, dlen, jslen, outBufLen, mode);
-
- if (r < 0) {
- printerr(r);
- }
- else {
- printf ("\nOutput:\n");
- printf ("%i char of data embedded in outBuf\n", r);
- // printf ("fin = %d\n", fin);
- outBuf[jslen] = '\0';
- printf ("outBuf = %s\n", outBuf);
-
- if ((unsigned int) r < dlen) {
- printf ("Incomplete data encoding\n");
- }
- }
- printf ("***** End of testEncode (%i) *****\n", testNum);
- return r;
-}
-
-
-
-
-int testDecode2(char *inBuf, char *outBuf,
- unsigned int inBufSize, unsigned int outBufSize,
- int mode, int testNum) {
- int r;
- int fin;
-
- printf ("***** Start of testDecode2 (%i) *****\n", testNum);
- printf ("Input:\n");
- printf ("inBuf = %s\n", inBuf);
- printf ("inBuf size = %i\n", inBufSize);
- printf ("outBuf size = %i\n", outBufSize);
- r = decodeHTTPBody(inBuf, outBuf, inBufSize, outBufSize, &fin, mode);
- if (r < 0) {
- printerr(r);
- } else {
- printf ("\nOutput:\n");
- printf ("%i char of data recovered from inBuf (to outBuf)\n", r);
- outBuf[r] = '\0';
- printf ("outBuf = %s\n", outBuf);
- }
- printf ("***** End of testDecode2 (%i) *****\n", testNum);
- return r;
-}
-
-
-int
-x_http2_server_JS_transmit (steg_t* s, struct evbuffer *source, conn_t *conn, unsigned int content_type) {
-
- struct evbuffer_iovec *iv;
- int nv;
- struct evbuffer *dest = conn_get_outbound(conn);
- size_t sbuflen = evbuffer_get_length(source);
- char *hend, *jsTemplate = NULL, *outbuf, *outbuf2;
- char data[(int) sbuflen*2];
- char newHdr[MAX_RESP_HDR_SIZE];
- unsigned int datalen = 0, cnt = 0, mjs = 0;
- int r, i, mode, jsLen, hLen, cLen, newHdrLen = 0, outbuf2len;
-
- int gzipMode = JS_GZIP_RESP;
-
-
- log_debug("sbuflen = %d\n", (int) sbuflen);
-
- if (content_type != HTTP_CONTENT_JAVASCRIPT &&
- content_type != HTTP_CONTENT_HTML) {
- log_warn("SERVER ERROR: Unknown content type (%d)", content_type);
- return -1;
- }
-
- // log_debug("SERVER: dumping data with length %d:", (int) sbuflen);
- // evbuffer_dump(source, stderr);
-
- nv = evbuffer_peek(source, sbuflen, NULL, NULL, 0);
- iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
-
- if (evbuffer_peek(source, sbuflen, NULL, iv, nv) != nv) {
- free(iv);
- return -1;
- }
-
- if (content_type == HTTP_CONTENT_JAVASCRIPT) {
- mjs = get_max_JS_capacity();
- } else if (content_type == HTTP_CONTENT_HTML) {
- mjs = get_max_HTML_capacity();
- }
-
- if (mjs <= 0) {
- log_warn("SERVER ERROR: No JavaScript found in jsTemplate");
- return -1;
- }
-
- if (sbuflen > (size_t) mjs) {
- log_warn("SERVER ERROR: jsTemplate cannot accommodate data %d %dn",
- (int) sbuflen, (int) mjs);
- return -1;
- }
-
- // Convert data in 'source' to hexadecimal and write it to data
- cnt = 0;
- for (i = 0; i < nv; i++) {
- const unsigned char *p = iv[i].iov_base;
- const unsigned char *limit = p + iv[i].iov_len;
- char c;
-
- while (p < limit && cnt < sbuflen) {
- c = *p++;
- data[datalen] = "0123456789abcdef"[(c & 0xF0) >> 4];
- data[datalen+1] = "0123456789abcdef"[(c & 0x0F) >> 0];
- datalen += 2;
- cnt++;
- }
- }
-
- free(iv);
-
- log_debug("SERVER encoded data in hex string (len %d):", datalen);
- // buf_dump((unsigned char*)data, datalen, stderr);
-
-
-
- if (get_payload(content_type, datalen, &jsTemplate, &jsLen) == 1) {
- log_debug("SERVER found the applicable HTTP response template with size %d", jsLen);
- } else {
- log_warn("SERVER couldn't find the applicable HTTP response template");
- return -1;
- }
-
- // log_debug("MJS %d %d", datalen, mjs);
- if (jsTemplate == NULL) {
- log_warn("NO suitable payload found %d %d", datalen, mjs);
- return -1;
- }
-
- // assumption: jsTemplate is null-terminated
- hend = strstr(jsTemplate, "\r\n\r\n");
- if (hend == NULL) {
- log_warn("Unable to find end of header in the HTTP template");
- return -1;
- }
-
- mode = has_eligible_HTTP_content (jsTemplate, jsLen, HTTP_CONTENT_JAVASCRIPT);
-
- // log_debug("SERVER: using HTTP resp template of length = %d", jsLen);
- // log_debug("HTTP resp tempmlate:");
- // buf_dump((unsigned char*)jsTemplate, jsLen, stderr);
-
- hLen = hend+4-jsTemplate;
- cLen = jsLen - hLen;
- outbuf = malloc(cLen);
- if (outbuf == NULL) {
- log_warn("malloc for outbuf fails");
- return -1;
- }
-
- r = encodeHTTPBody(data, hend+4, outbuf, datalen, cLen, cLen, mode);
-
- if (r < 0 || ((unsigned int) r < datalen)) {
- log_warn("SERVER ERROR: Incomplete data encoding");
- return -1;
- }
-
- // work in progress
- if (gzipMode == 1) {
- // conservative estimate:
- // sizeof outbuf2 = cLen + 10-byte for gzip header + 8-byte for crc
- outbuf2 = malloc(cLen+18);
- if (outbuf2 == NULL) {
- log_warn("malloc for outbuf2 fails");
- return -1;
- }
-
- outbuf2len = gzDeflate(outbuf, cLen, outbuf2, cLen+18, time(NULL));
-
- if (outbuf2len <= 0) {
- log_warn("gzDeflate for outbuf fails");
- free(outbuf2);
- return -1;
- }
- free(outbuf);
-
- } else {
- outbuf2 = outbuf;
- outbuf2len = cLen;
- }
-
- // outbuf2 points to the HTTP payload (of length outbuf2len) to be sent
-
- if (mode == CONTENT_JAVASCRIPT) { // JavaScript in HTTP body
- newHdrLen = gen_response_header((char*) "application/x-javascript", gzipMode,
- outbuf2len, newHdr, sizeof(newHdr));
- } else if (mode == CONTENT_HTML_JAVASCRIPT) { // JavaScript(s) embedded in HTML doc
- newHdrLen = gen_response_header((char*) "text/html", gzipMode,
- outbuf2len, newHdr, sizeof(newHdr));
- } else { // unknown mode
- log_warn("SERVER ERROR: unknown mode for creating the HTTP response header");
- free(outbuf2);
- return -1;
- }
- if (newHdrLen < 0) {
- log_warn("SERVER ERROR: gen_response_header fails for jsSteg");
- free(outbuf2);
- return -1;
- }
-
- // newHdr points to the HTTP header (of length newHdrLen) to be sent
-
- if (evbuffer_add(dest, newHdr, newHdrLen)) {
- log_warn("SERVER ERROR: evbuffer_add() fails for newHdr");
- free(outbuf2);
- return -1;
- }
-
- if (evbuffer_add(dest, outbuf2, outbuf2len)) {
- log_warn("SERVER ERROR: evbuffer_add() fails for outbuf2");
- free(outbuf2);
- return -1;
- }
-
- evbuffer_drain(source, sbuflen);
-
- free(outbuf2);
- conn_close_after_transmit(conn);
- // downcast_steg(s)->have_transmitted = 1;
- return 0;
-}
-
-
-
-
-
-
-int
-x_http2_handle_client_JS_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
- struct evbuffer_ptr s2;
- unsigned int response_len = 0;
- unsigned int content_len = 0;
- unsigned int hdrLen;
- char buf[10];
- char respMsg[HTTP_MSG_BUF_SIZE];
- char data[HTTP_MSG_BUF_SIZE];
- char buf2[HTTP_MSG_BUF_SIZE];
-
- unsigned char *field, *fieldStart, *fieldEnd, *fieldValStart;
- char *httpBody;
-
- int decCnt, fin, i, j, k, gzipMode=0, httpBodyLen, buf2len, contentType = 0;
- ev_ssize_t r;
- struct evbuffer * scratch;
- char c;
-
-
- s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
- if (s2.pos == -1) {
- log_debug("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
- // evbuffer_dump(source, stderr);
- return RECV_INCOMPLETE;
- }
-
- log_debug("CLIENT received response header with len %d", (int)s2.pos);
-
- response_len = 0;
- hdrLen = s2.pos + strlen("\r\n\r\n");
- response_len += hdrLen;
-
- // get content length, e.g., Content-Length: 22417
- field = evbuffer_pullup(source, s2.pos);
- if (field == NULL) {
- log_debug("CLIENT unable to pullup the complete HTTP header");
- return RECV_BAD;
- }
-
- fieldStart = (unsigned char*) strstr((char*) field, "Content-Length: ");
- if (fieldStart == NULL) {
- log_debug("CLIENT unable to find Content-Length in the header");
- return RECV_BAD;
- }
-
- fieldEnd = (unsigned char*) strstr((char *)fieldStart, "\r\n");
- if (fieldEnd == NULL) {
- log_debug("CLIENT unable to find end of line for Content-Length");
- return RECV_BAD;
- }
-
- fieldValStart = fieldStart+strlen("Content-Length: ");
- if ((unsigned int) (fieldEnd-fieldValStart) > (sizeof(buf)-1)) {
- log_debug("CLIENT: Value of Content-Length too large");
- return RECV_BAD;
- }
- memcpy(buf, fieldValStart, fieldEnd-fieldValStart);
- buf[fieldEnd-fieldValStart] = 0;
-
- content_len = atoi(buf);
- log_debug("CLIENT received Content-Length = %d\n", content_len);
-
- response_len += content_len;
-
- if (response_len > evbuffer_get_length(source))
- return RECV_INCOMPLETE;
-
- // read the entire HTTP resp
- if (response_len < HTTP_MSG_BUF_SIZE) {
- r = evbuffer_copyout(source, respMsg, response_len);
- log_debug("CLIENT %d char copied from source to respMsg (expected %d)", (int)r, response_len);
- if (r < 0) {
- log_debug("CLIENT ERROR: evbuffer_copyout fails");
- return RECV_INCOMPLETE;
- }
- if (r < response_len) {
- log_debug("CLIENT: evbuffer_copyout incomplete; got %d instead of %d", (int)r, response_len);
- return RECV_INCOMPLETE;
- }
- respMsg[response_len] = 0;
- } else {
- log_debug("CLIENT: HTTP response too large to handle");
- return RECV_BAD;
- }
-
- log_debug("CLIENT received HTTP response with length %d\n", response_len);
- // buf_dump((unsigned char*)respMsg, response_len, stderr);
- // log_debug("HTTP response header:");
- // buf_dump((unsigned char*)respMsg, hdrLen+80, stderr);
-
- contentType = findContentType (respMsg);
- if (contentType != HTTP_CONTENT_JAVASCRIPT && contentType != HTTP_CONTENT_HTML) {
- log_warn("ERROR: Invalid content type (%d)", contentType);
- return RECV_BAD;
- }
-
- httpBody = respMsg + hdrLen;
- httpBodyLen = response_len - hdrLen;
-
- gzipMode = isGzipContent(respMsg);
- if (gzipMode) {
- log_debug("gzip content encoding detected");
- buf2len = gzInflate(httpBody, httpBodyLen, buf2, HTTP_MSG_BUF_SIZE);
- if (buf2len <= 0) {
- log_warn("gzInflate for httpBody fails");
- fprintf(stderr, "gzInflate for httpBody fails");
- exit(-1);
- return RECV_BAD;
- }
- buf2[buf2len] = 0;
- httpBody = buf2;
- httpBodyLen = buf2len;
- }
-
- if (contentType == HTTP_CONTENT_JAVASCRIPT) {
- decCnt = decodeHTTPBody(httpBody, data, httpBodyLen, HTTP_MSG_BUF_SIZE,
- &fin, CONTENT_JAVASCRIPT);
- } else {
- decCnt = decodeHTTPBody(httpBody, data, httpBodyLen, HTTP_MSG_BUF_SIZE,
- &fin, CONTENT_HTML_JAVASCRIPT);
- }
- data[decCnt] = 0;
-
- log_debug("After decodeHTTPBody; decCnt: %d\n", decCnt);
-
- // decCnt is an odd number or data is not a hex string
- if (decCnt % 2) {
- fprintf(stderr, "CLIENT ERROR: An odd number of hex characters received\n");
- // buf_dump((unsigned char*)data, decCnt, stderr);
- return RECV_BAD;
- }
-
- if (! isxString(data)) {
- log_warn("CLIENT ERROR: Data received not hex");
- // buf_dump((unsigned char*)data, decCnt, stderr);
- return RECV_BAD;
- }
-
- // log_debug("Hex data received:");
- // buf_dump ((unsigned char*)data, decCnt, stderr);
-
- // get a scratch buffer
- scratch = evbuffer_new();
- if (!scratch) return RECV_BAD;
-
- if (evbuffer_expand(scratch, decCnt/2)) {
- log_warn("CLIENT ERROR: Evbuffer expand failed \n");
- evbuffer_free(scratch);
- return RECV_BAD;
- }
-
- // convert hex data back to binary
- for (i=0, j=0; i< decCnt; i=i+2, ++j) {
- sscanf(&data[i], "%2x", (unsigned int*) &k);
- c = (char)k;
- evbuffer_add(scratch, &c, 1);
- }
-
- // log_debug("CLIENT Done converting hex data to binary:\n");
- // evbuffer_dump(scratch, stderr);
-
-
- // fprintf(stderr, "CLIENT RECEIVED payload of size %d\n", (int) evbuffer_get_length(scratch));
- // add the scratch buffer (which contains the data) to dest
-
- if (evbuffer_add_buffer(dest, scratch)) {
- evbuffer_free(scratch);
- log_warn("CLIENT ERROR: Failed to transfer buffer");
- return RECV_BAD;
- }
- log_debug("Added scratch (buffer) to dest\n");
-
- evbuffer_free(scratch);
-
-
- if (response_len <= evbuffer_get_length(source)) {
- if (evbuffer_drain(source, response_len) == -1) {
- log_warn("CLIENT ERROR: Failed to drain source");
- return RECV_BAD;
- }
- }
- else {
- log_warn("response_len > buffer size... can't drain");
- exit(-1);
- }
-
-
- log_debug("Drained source for %d char\n", response_len);
-
- // downcast_steg(s)->have_received = 1;
- conn_expect_close(conn);
-
- return RECV_GOOD;
-}
-
-
-/*****
- int
- main() {
- int jDataSize = 1000;
- char jData[jDataSize];
- int outDataBufSize = 1000;
- char outDataBuf[outDataBufSize];
-
- int r;
- // test case 1: data embedded in javascript
- r = testEncode2(data1, js1, jData, strlen(data1), strlen(js1), jDataSize,
- CONTENT_JAVASCRIPT, 1);
- if (r > 0) { testDecode2(jData, outDataBuf, strlen(js1), outDataBufSize, CONTENT_JAVASCRIPT, 1); }
-
- // test case 4: data embedded in one script type javascript
- r = testEncode2(data1, js4, jData, strlen(data1), strlen(js4), jDataSize,
- CONTENT_HTML_JAVASCRIPT, 4);
- if (r > 0) { testDecode2(jData, outDataBuf, strlen(js4), outDataBufSize, CONTENT_HTML_JAVASCRIPT, 4); }
-
- // test case 5: data embedded in one script type javascript
- r = testEncode2(data1, js5, jData, strlen(data1), strlen(js5), jDataSize,
- CONTENT_HTML_JAVASCRIPT, 5);
- if (r > 0) { testDecode2(jData, outDataBuf, strlen(js5), outDataBufSize, CONTENT_HTML_JAVASCRIPT, 5); }
-
-
- return 0;
- }
-*****/
-
-/*****
- int
- main() {
- int jDataSize = 1000;
- char jData[jDataSize];
- int jDataSmallSize = 5;
- char jDataSmall[jDataSmallSize];
-
- int outDataBufSize = 1000;
- char outDataBuf[outDataBufSize];
- int outDataSmallSize = 5;
- char outDataSmall[outDataSmallSize];
-
- int r;
-
- // test case 1: data embedded in javascript
- r = testEncode(data1, js1, jData, strlen(data1), strlen(js1), jDataSize, 1);
- if (r > 0) { testDecode(jData, outDataBuf, strlen(js1), r, outDataBufSize, 1); }
-
- // test case 2: data embedded in javascript
- r = testEncode(data1, js2, jData, strlen(data1), strlen(js2), jDataSize, 2);
- if (r > 0) { testDecode(jData, outDataBuf, strlen(js2), r, outDataBufSize, 2); }
-
- // test case 3: data partially embedded in javascript; num of hex char in js < data len
- r = testEncode(data1, js3, jData, strlen(data1), strlen(js3), jDataSize, 3);
- if (r > 0) { testDecode(jData, outDataBuf, strlen(js3), r, outDataBufSize, 3); }
-
- // test case 4: data embedded in javascript; larger data
- r = testEncode(data2, js1, jData, strlen(data2), strlen(js1), jDataSize, 4);
- if (r > 0) { testDecode(jData, outDataBuf, strlen(js1), r, outDataBufSize, 4); }
-
- // test case 5 (for encode): err for non-hex data
- testEncode(nonhexstr, js1, jData, strlen(nonhexstr), strlen(js1), jDataSize, 5);
-
- // test case 6 (for encode): err for small output buf
- testEncode(data1, js1, jDataSmall, strlen(data1), strlen(js1), jDataSmallSize, 6);
-
- // test case 7 (for decode): err for small output buf
- r = testEncode(data1, js1, jData, strlen(data1), strlen(js1), jDataSize, 7);
- if (r > 0) { testDecode(jData, outDataSmall, strlen(js1), r, outDataSmallSize, 7); }
- }
-*****/
-
diff --git a/src/steg/jsSteg.cc b/src/steg/jsSteg.cc
new file mode 100644
index 0000000..1486255
--- /dev/null
+++ b/src/steg/jsSteg.cc
@@ -0,0 +1,1163 @@
+#include "payloads.h"
+#include "jsSteg.h"
+#include "cookies.h"
+
+void buf_dump(unsigned char* buf, int len, FILE *out);
+
+
+/*
+ * jsSteg: A Javascript-based steganography module
+ *
+ */
+
+
+/*
+ * int isxString(char *str)
+ *
+ * description:
+ * return 1 if all char in str are hexadecimal
+ * return 0 otherwise
+ *
+ */
+int isxString(char *str) {
+ unsigned int i;
+ char *dp = str;
+ for (i=0; i<strlen(str); i++) {
+ if (! isxdigit(*dp) ) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/*
+ * isGzipContent(char *msg)
+ *
+ * If the HTTP header of msg specifies that the content is gzipped,
+ * this function returns 1; otherwise, it returns 0
+ *
+ * Assumptions:
+ * msg is null terminated
+ *
+ */
+int isGzipContent (char *msg) {
+ char *ptr = msg, *end;
+ int gzipFlag = 0;
+
+ if (!strstr(msg, "\r\n\r\n"))
+ return 0;
+
+ while (1) {
+ end = strstr(ptr, "\r\n");
+ if (end == NULL) {
+ break;
+ }
+
+ if (!strncmp(ptr, "Content-Encoding: gzip", 22)) {
+ gzipFlag = 1;
+ break;
+ }
+
+ if (!strncmp(end, "\r\n\r\n", 4)){
+ break;
+ }
+ ptr = end+2;
+ }
+
+ return gzipFlag;
+}
+
+
+/*
+ * findContentType(char *msg)
+ *
+ * If the HTTP header of msg specifies that the content type:
+ * case (content type)
+ * javascript: return HTTP_CONTENT_JAVASCRIPT
+ * pdf: return HTTP_CONTENT_PDF
+ * shockwave: return HTTP_CONTENT_SWF
+ * html: return HTTP_CONTENT_HTML
+ * otherwise: return 0
+ *
+ * Assumptions:
+ * msg is null terminated
+ *
+ */
+int findContentType (char *msg) {
+ char *ptr = msg, *end;
+
+ if (!strstr(msg, "\r\n\r\n"))
+ return 0;
+
+ while (1) {
+ end = strstr(ptr, "\r\n");
+ if (end == NULL) {
+ break;
+ }
+
+ if (!strncmp(ptr, "Content-Type:", 13)) {
+
+ if (!strncmp(ptr+14, "text/javascript", 15) ||
+ !strncmp(ptr+14, "application/javascript", 22) ||
+ !strncmp(ptr+14, "application/x-javascript", 24)) {
+ return HTTP_CONTENT_JAVASCRIPT;
+ }
+ if (!strncmp(ptr+14, "text/html", 9)) {
+ return HTTP_CONTENT_HTML;
+ }
+ if (!strncmp(ptr+14, "application/pdf", 15) ||
+ !strncmp(ptr+14, "application/x-pdf", 17)) {
+ return HTTP_CONTENT_PDF;
+ }
+ if (!strncmp(ptr+14, "application/x-shockwave-flash", strlen("application/x-shockwave-flash"))) {
+ return HTTP_CONTENT_SWF;
+ }
+ }
+
+ if (!strncmp(end, "\r\n\r\n", 4)){
+ break;
+ }
+ ptr = end+2;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * int encode(char *data, char *jTemplate, char *jData,
+ * unsigned int dlen, unsigned int jtlen, unsigned int jdlen)
+ *
+ * description:
+ * embed hex-encoded data (data) in the input Javascript (jTemplate)
+ * and put the result in jData
+ * function returns the number of characters in data successfully
+ * embedded in jData, or returns one of the error codes
+ *
+ * approach:
+ * replaces characters in jTemplate that are hexadecimal (i.e., {0-9,a-f,A-F})
+ * with those in data, and leave the non-hex char in place
+ *
+ * input:
+ * - data[] : hex data to hide
+ * - dlen : size of data
+ * - jTemplate[] : Javascript
+ * - jlen : size of jTemplate
+ * - jdlen : size of jData, output buffer
+ *
+ * output:
+ * - jData : result of encoding data in jTemplate
+ *
+ * assumptions:
+ * - data is hex-encoded
+ *
+ * exceptions:
+ * - if (jdlen < jtlen) return INVALID_BUF_SIZE
+ * - if (data contains non-hex char) return INVALID_DATA_CHAR
+ *
+ * example:
+ * data = "0123456789ABCDEF"
+ * jTemplate = "dfp_ord=Math.random()*10000000000000000; dfp_tile = 1;"
+ * encode() returns 16
+ * jData = "01p_or2=M3th.r4n5om()*6789ABCDEF0000000; dfp_tile = 1;"
+ *
+ */
+int encode(char *data, char *jTemplate, char *jData,
+ unsigned int dlen, unsigned int jtlen, unsigned int jdlen )
+{
+ unsigned int encCnt = 0; /* num of data encoded in jData */
+ char *dp, *jtp, *jdp; /* current pointers for data, jTemplate, and jData */
+
+ unsigned int j;
+
+ /*
+ * insanity checks
+ */
+ if (jdlen < jtlen) { return INVALID_BUF_SIZE; }
+
+ dp = data; jtp = jTemplate; jdp = jData;
+
+ if (! isxString(dp) ) { return INVALID_DATA_CHAR; }
+
+ /* handling boundary case: dlen == 0 */
+ if (dlen < 1) { return 0; }
+
+
+ for (j=0; j<jtlen; j++) {
+ /* found a hex char in jTemplate that can be used for encoding data */
+ if ( isxdigit(*jtp) ) {
+ *jdp = *dp;
+ dp++;
+ encCnt++;
+ if (encCnt == dlen) {
+ jtp++; jdp++;
+ break;
+ }
+ } else {
+ *jdp = *jtp;
+ }
+ jtp++; jdp++;
+ }
+
+
+ /* copying the rest of jTemplate to jdata */
+ while (jtp < (jTemplate+jtlen)) {
+ *jdp++ = *jtp++;
+ }
+
+ return encCnt;
+}
+
+
+#define startScriptTypeJS "<script type=\"text/javascript\">"
+#define endScriptTypeJS "</script>"
+// #define JS_DELIMITER "?"
+// #define JS_DELIMITER_REPLACEMENT "."
+
+
+/*
+ * similar to encode(), but uses offset2Hex to look for usable hex char
+ * in JS for encoding. See offset2Hex for what hex char are considered
+ * usable. encode() also converts JS_DELIMITER that appears in the
+ * the JS to JS_DELIMITER_REPLACEMENT, before all the data is encoded.
+ *
+ * Output:
+ * fin - signal the caller whether all data has been encoded and
+ * a JS_DELIMITER has been added
+ */
+int encode2(char *data, char *jTemplate, char *jData,
+ unsigned int dlen, unsigned int jtlen,
+ unsigned int jdlen, int *fin)
+{
+ unsigned int encCnt = 0; /* num of data encoded in jData */
+ char *dp, *jtp, *jdp; /* current pointers for data, jTemplate, and jData */
+ int i,j;
+
+ /*
+ * insanity checks
+ */
+ if (jdlen < jtlen) { return INVALID_BUF_SIZE; }
+
+ dp = data; jtp = jTemplate; jdp = jData;
+
+ if (! isxString(dp) ) { return INVALID_DATA_CHAR; }
+
+ /* handling boundary case: dlen == 0 */
+ if (dlen < 1) { return 0; }
+
+
+ i = offset2Hex(jtp, (jTemplate+jtlen)-jtp, 0);
+ while (encCnt < dlen && i != -1) {
+ // copy next i char from jtp to jdp,
+ // except that if *jtp==JS_DELIMITER, copy
+ // JS_DELIMITER_REPLACEMENT to jdp instead
+ j = 0;
+ while (j < i) {
+ if (*jtp == JS_DELIMITER) {
+ *jdp = JS_DELIMITER_REPLACEMENT;
+ } else {
+ *jdp = *jtp;
+ }
+ jtp = jtp + 1; jdp = jdp + 1; j++;
+ }
+
+ *jdp = *dp;
+ encCnt++;
+ dp = dp + 1; jtp = jtp + 1; jdp = jdp + 1;
+
+ i = offset2Hex(jtp, (jTemplate+jtlen)-jtp, 1);
+ }
+
+
+
+ // copy the rest of jTemplate to jdata
+ // if we've encoded all data, replace the first
+ // char in jTemplate by JS_DELIMITER, if needed,
+ // to signal the end of data encoding
+
+#ifdef DEBUG2
+ printf("encode2: encCnt = %d; dlen = %d\n", encCnt, dlen);
+#endif
+
+ *fin = 0;
+ if (encCnt == dlen) {
+ // replace the next char in jTemplate by JS_DELIMITER
+ if (jtp < (jTemplate+jtlen)) {
+ *jdp = JS_DELIMITER;
+ }
+ jdp = jdp+1; jtp = jtp+1;
+ *fin = 1;
+ }
+
+ while (jtp < (jTemplate+jtlen)) {
+ if (*jtp == JS_DELIMITER) {
+ if (encCnt < dlen) {
+ *jdp = JS_DELIMITER_REPLACEMENT;
+ } else {
+ *jdp = *jtp;
+ }
+ // else if (isxdigit(*jtp)) {
+ // if (encCnt < dlen && *fin == 0) {
+ // *jdp = JS_DELIMITER;
+ // *fin = 1;
+ // } else {
+ // *jdp = *jtp;
+ // }
+ // }
+ } else {
+ *jdp = *jtp;
+ }
+ jdp = jdp+1; jtp = jtp+1;
+ }
+
+#ifdef DEBUG2
+ printf("encode2: encCnt = %d; dlen = %d\n", encCnt, dlen);
+ printf("encode2: fin= %d\n", *fin);
+#endif
+
+ return encCnt;
+
+}
+
+
+
+int encodeHTTPBody(char *data, char *jTemplate, char *jData,
+ unsigned int dlen, unsigned int jtlen,
+ unsigned int jdlen, int mode)
+{
+ char *dp, *jtp, *jdp; // current pointers for data, jTemplate, and jData
+ unsigned int encCnt = 0; // num of data encoded in jData
+ int n; // tmp for updating encCnt
+ char *jsStart, *jsEnd;
+ int skip;
+ int scriptLen;
+ int fin;
+ unsigned int dlen2 = dlen;
+ dp = data;
+ jtp = jTemplate;
+ jdp = jData;
+
+
+ if (mode == CONTENT_JAVASCRIPT) {
+ // assumption: the javascript pertaining to jTemplate has enough capacity
+ // to encode jData. thus, we only invoke encode() once here.
+ encCnt = encode2(dp, jtp, jdp, dlen, jtlen, jdlen, &fin);
+ // ensure that all dlen char from data have been encoded in jData
+#ifdef DEBUG
+ if (encCnt != dlen || fin == 0) {
+ printf("Problem encoding all data to the JS\n");
+ }
+#endif
+ return encCnt;
+
+ }
+
+ else if (mode == CONTENT_HTML_JAVASCRIPT) {
+ while (encCnt < dlen2) {
+ jsStart = strstr(jtp, startScriptTypeJS);
+ if (jsStart == NULL) {
+#ifdef DEBUG
+ printf("lack of usable JS; can't find startScriptType\n");
+#endif
+ return encCnt;
+ }
+ skip = strlen(startScriptTypeJS)+jsStart-jtp;
+#ifdef DEBUG2
+ printf("copying %d (skip) char from jtp to jdp\n", skip);
+#endif
+ memcpy(jdp, jtp, skip);
+ jtp = jtp+skip; jdp = jdp+skip;
+ jsEnd = strstr(jtp, endScriptTypeJS);
+ if (jsEnd == NULL) {
+#ifdef DEBUG
+ printf("lack of usable JS; can't find endScriptType\n");
+#endif
+ return encCnt;
+ }
+
+ // the JS for encoding data is between jsStart and jsEnd
+ scriptLen = jsEnd - jtp;
+ // n = encode2(dp, jtp, jdp, dlen, jtlen, jdlen, &fin);
+ n = encode2(dp, jtp, jdp, dlen, scriptLen, jdlen, &fin);
+ // update encCnt, dp, and dlen based on n
+ if (n > 0) {
+ encCnt = encCnt+n; dp = dp+n; dlen = dlen-n;
+ }
+ // update jtp, jdp, jdlen
+ skip = jsEnd-jtp;
+ jtp = jtp+skip; jdp = jdp+skip; jdlen = jdlen-skip;
+ skip = strlen(endScriptTypeJS);
+ memcpy(jdp, jtp, skip);
+ jtp = jtp+skip; jdp = jdp+skip; jdlen = jdlen-skip;
+ }
+
+ // copy the rest of jTemplate to jdp
+ skip = jTemplate+jtlen-jtp;
+
+ // handling the boundary case in which JS_DELIMITER hasn't been
+ // added by encode()
+ if (fin == 0 && dlen == 0) {
+ if (skip > 0) {
+ *jtp = JS_DELIMITER;
+ jtp = jtp+1; jdp = jdp+1;
+ skip--;
+ }
+ }
+ memcpy(jdp, jtp, skip);
+ return encCnt;
+
+ } else {
+ log_warn("Unknown mode (%d) for encode2()", mode);
+ return 0;
+ }
+
+
+}
+
+/*
+ * int decode(char *jData, char *dataBuf,
+ * unsigned int jdlen, unsigned int dlen, unsigned int dataBufSize)
+ *
+ * description:
+ * extract hex char from Javascript embedded with data (jData)
+ * and put the result in dataBuf
+ * function returns the number of hex char extracted from jData
+ * to dataBuf, or returns one of the error codes
+ *
+ * input:
+ * - jData[]: Javascript embedded with hex-encoded data
+ * - jdlen : size of jData
+ * - dlen : size of data to recover
+ * - dataBufSize : size of output data buffer (dataBuf)
+ *
+ * output:
+ * - dataBuf[] : output buffer for recovered data
+ *
+ * assumptions:
+ * - data is hex-encoded
+ *
+ * exceptions:
+ * - if (dlen > dataBufSize) return INVALID_BUF_SIZE
+ *
+ * example:
+ * jData = "01p_or2=M3th.r4n5om()*6789ABCDEF0000000; dfp_tile = 1;"
+ * jdlen = 54
+ * dlen = 16
+ * dataBufSize = 1000
+ * decode() returns 16
+ * dataBuf= "0123456789ABCDEF"
+ *
+ */
+int decode (char *jData, char *dataBuf, unsigned int jdlen,
+ unsigned int dlen, unsigned int dataBufSize )
+{
+ unsigned int decCnt = 0; /* num of data decoded */
+ char *dp, *jdp; /* current pointers for dataBuf and jData */
+ unsigned int j;
+
+ if (dlen > dataBufSize) { return INVALID_BUF_SIZE; }
+
+ dp = dataBuf; jdp = jData;
+ for (j=0; j<jdlen; j++) {
+ if ( isxdigit(*jdp) ) {
+ if (decCnt < dlen) {
+ decCnt++;
+ *dp++ = *jdp++;
+ } else {
+ break;
+ }
+ } else {
+ jdp++;
+ }
+ }
+ return decCnt;
+}
+
+
+/*
+ * decode2() is similar to decode(), but uses offset2Hex to look for
+ * applicable hex char in JS for decoding. Also, the decoding process
+ * stops when JS_DELIMITER is encountered.
+ */
+int decode2 (char *jData, char *dataBuf, unsigned int jdlen,
+ unsigned int dataBufSize, int *fin )
+{
+ unsigned int decCnt = 0; /* num of data decoded */
+ char *dp, *jdp; /* current pointers for dataBuf and jData */
+ int i,j;
+ int cjdlen = jdlen;
+
+ *fin = 0;
+ dp = dataBuf; jdp = jData;
+
+ i = offset2Hex(jdp, cjdlen, 0);
+ while (i != -1) {
+ // return if JS_DELIMITER exists between jdp and jdp+i
+ for (j=0; j<i; j++) {
+ if (*jdp == JS_DELIMITER) {
+ *fin = 1;
+ return decCnt;
+ }
+ jdp = jdp+1; cjdlen--;
+ }
+ // copy hex data from jdp to dp
+ if (dataBufSize <= 0) {
+ return decCnt;
+ }
+ *dp = *jdp;
+ jdp = jdp+1; cjdlen--;
+ dp = dp+1; dataBufSize--;
+ decCnt++;
+
+ // find the next hex char
+ i = offset2Hex(jdp, cjdlen, 1);
+ }
+
+ // look for JS_DELIMITER between jdp to jData+jdlen
+ while (jdp < jData+jdlen) {
+ if (*jdp == JS_DELIMITER) {
+ *fin = 1;
+ break;
+ }
+ jdp = jdp+1;
+ }
+
+ return decCnt;
+}
+
+
+int decodeHTTPBody (char *jData, char *dataBuf, unsigned int jdlen,
+ unsigned int dataBufSize, int *fin, int mode )
+{
+ char *jsStart, *jsEnd;
+ char *dp, *jdp; // current pointers for data and jData
+ int scriptLen;
+ int decCnt = 0;
+ int n;
+ int dlen = dataBufSize;
+ dp = dataBuf; jdp = jData;
+
+ if (mode == CONTENT_JAVASCRIPT) {
+ decCnt = decode2(jData, dataBuf, jdlen, dataBufSize, fin);
+ if (*fin == 0) {
+ log_warn("Unable to find JS_DELIMITER");
+ }
+ }
+ else if (mode == CONTENT_HTML_JAVASCRIPT) {
+ *fin = 0;
+ while (*fin == 0) {
+ jsStart = strstr(jdp, startScriptTypeJS);
+ if (jsStart == NULL) {
+#ifdef DEBUG
+ printf("Can't find startScriptType for decoding data inside script type JS\n");
+#endif
+ return decCnt;
+ }
+ jdp = jsStart+strlen(startScriptTypeJS);
+ jsEnd = strstr(jdp, endScriptTypeJS);
+ if (jsEnd == NULL) {
+#ifdef DEBUG
+ printf("Can't find endScriptType for decoding data inside script type JS\n");
+#endif
+ return decCnt;
+ }
+
+ // the JS for decoding data is between jsStart and jsEnd
+ scriptLen = jsEnd - jdp;
+ n = decode2(jdp, dp, scriptLen, dlen, fin);
+ if (n > 0) {
+ decCnt = decCnt+n; dlen=dlen-n; dp=dp+n;
+ }
+ jdp = jsEnd+strlen(endScriptTypeJS);
+ } // while (*fin==0)
+ } else {
+ log_warn("Unknown mode (%d) for encode2()", mode);
+ return 0;
+ }
+
+ return decCnt;
+}
+
+
+
+
+
+void printerr(int errno) {
+ if (errno == INVALID_BUF_SIZE) {
+ printf ("Error: Output buffer too small\n");
+ }
+ else if (errno == INVALID_DATA_CHAR) {
+ printf ("Error: Non-hex char in data\n");
+ }
+ else {
+ printf ("Unknown error: %i\n", errno);
+ }
+}
+
+
+int testEncode(char *data, char *js, char *outBuf, unsigned int dlen, unsigned int jslen,
+ unsigned int outBufLen, int testNum) {
+ int r;
+
+ printf ("***** Start of testEncode (%i) *****\n", testNum);
+ printf ("Input:\n");
+ printf ("data = %s\n", data);
+ printf ("data len = %i\n", dlen);
+ printf ("js = %s\n", js);
+ printf ("js len = %i\n", jslen);
+ r = encode (data, js, outBuf, dlen, jslen, outBufLen);
+ if (r < 0) {
+ printerr(r);
+ } else {
+ printf ("\nOutput:\n");
+ printf ("%i char of data embedded in outBuf\n", r);
+ outBuf[jslen] = '\0';
+ printf ("outBuf = %s\n", outBuf);
+ }
+ printf ("***** End of testEncode (%i) *****\n", testNum);
+ return r;
+}
+
+int testDecode(char *inBuf, char *outBuf, unsigned int inBufSize, unsigned int dlen,
+ unsigned int outBufSize, int testNum) {
+
+ int r;
+
+ printf ("***** Start of testDecode (%i) *****\n", testNum);
+ printf ("Input:\n");
+ printf ("inBuf = %s\n", inBuf);
+ printf ("inBuf size = %i\n", inBufSize);
+ printf ("data len = %i\n", dlen);
+ printf ("outBuf size = %i\n", outBufSize);
+ r = decode(inBuf, outBuf, inBufSize, dlen, outBufSize);
+ if (r < 0) {
+ printerr(r);
+ } else {
+ printf ("\nOutput:\n");
+ printf ("%i char of data recovered from inBuf (to outBuf)\n", r);
+ outBuf[r] = '\0';
+ printf ("outBuf = %s\n", outBuf);
+ }
+ printf ("***** End of testDecode (%i) *****\n", testNum);
+ return r;
+}
+
+
+int testEncode2(char *data, char *js, char *outBuf,
+ unsigned int dlen, unsigned int jslen, unsigned int outBufLen,
+ int mode, int testNum) {
+ int r;
+ // int fin;
+
+ printf ("***** Start of testEncode2 (%i) *****\n", testNum);
+ printf ("Input:\n");
+ printf ("data = %s\n", data);
+ printf ("data len = %i\n", dlen);
+ printf ("js = %s\n", js);
+ printf ("js len = %i\n", jslen);
+ // r = encode2(data, js, outBuf, dlen, jslen, outBufLen, &fin);
+ r = encodeHTTPBody(data, js, outBuf, dlen, jslen, outBufLen, mode);
+
+ if (r < 0) {
+ printerr(r);
+ }
+ else {
+ printf ("\nOutput:\n");
+ printf ("%i char of data embedded in outBuf\n", r);
+ // printf ("fin = %d\n", fin);
+ outBuf[jslen] = '\0';
+ printf ("outBuf = %s\n", outBuf);
+
+ if ((unsigned int) r < dlen) {
+ printf ("Incomplete data encoding\n");
+ }
+ }
+ printf ("***** End of testEncode (%i) *****\n", testNum);
+ return r;
+}
+
+
+
+
+int testDecode2(char *inBuf, char *outBuf,
+ unsigned int inBufSize, unsigned int outBufSize,
+ int mode, int testNum) {
+ int r;
+ int fin;
+
+ printf ("***** Start of testDecode2 (%i) *****\n", testNum);
+ printf ("Input:\n");
+ printf ("inBuf = %s\n", inBuf);
+ printf ("inBuf size = %i\n", inBufSize);
+ printf ("outBuf size = %i\n", outBufSize);
+ r = decodeHTTPBody(inBuf, outBuf, inBufSize, outBufSize, &fin, mode);
+ if (r < 0) {
+ printerr(r);
+ } else {
+ printf ("\nOutput:\n");
+ printf ("%i char of data recovered from inBuf (to outBuf)\n", r);
+ outBuf[r] = '\0';
+ printf ("outBuf = %s\n", outBuf);
+ }
+ printf ("***** End of testDecode2 (%i) *****\n", testNum);
+ return r;
+}
+
+
+int
+x_http2_server_JS_transmit (steg_t* s, struct evbuffer *source, conn_t *conn, unsigned int content_type) {
+
+ struct evbuffer_iovec *iv;
+ int nv;
+ struct evbuffer *dest = conn_get_outbound(conn);
+ size_t sbuflen = evbuffer_get_length(source);
+ char *hend, *jsTemplate = NULL, *outbuf, *outbuf2;
+ char data[(int) sbuflen*2];
+ char newHdr[MAX_RESP_HDR_SIZE];
+ unsigned int datalen = 0, cnt = 0, mjs = 0;
+ int r, i, mode, jsLen, hLen, cLen, newHdrLen = 0, outbuf2len;
+
+ int gzipMode = JS_GZIP_RESP;
+
+
+ log_debug("sbuflen = %d\n", (int) sbuflen);
+
+ if (content_type != HTTP_CONTENT_JAVASCRIPT &&
+ content_type != HTTP_CONTENT_HTML) {
+ log_warn("SERVER ERROR: Unknown content type (%d)", content_type);
+ return -1;
+ }
+
+ // log_debug("SERVER: dumping data with length %d:", (int) sbuflen);
+ // evbuffer_dump(source, stderr);
+
+ nv = evbuffer_peek(source, sbuflen, NULL, NULL, 0);
+ iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
+
+ if (evbuffer_peek(source, sbuflen, NULL, iv, nv) != nv) {
+ free(iv);
+ return -1;
+ }
+
+ if (content_type == HTTP_CONTENT_JAVASCRIPT) {
+ mjs = get_max_JS_capacity();
+ } else if (content_type == HTTP_CONTENT_HTML) {
+ mjs = get_max_HTML_capacity();
+ }
+
+ if (mjs <= 0) {
+ log_warn("SERVER ERROR: No JavaScript found in jsTemplate");
+ return -1;
+ }
+
+ if (sbuflen > (size_t) mjs) {
+ log_warn("SERVER ERROR: jsTemplate cannot accommodate data %d %dn",
+ (int) sbuflen, (int) mjs);
+ return -1;
+ }
+
+ // Convert data in 'source' to hexadecimal and write it to data
+ cnt = 0;
+ for (i = 0; i < nv; i++) {
+ const unsigned char *p = iv[i].iov_base;
+ const unsigned char *limit = p + iv[i].iov_len;
+ char c;
+
+ while (p < limit && cnt < sbuflen) {
+ c = *p++;
+ data[datalen] = "0123456789abcdef"[(c & 0xF0) >> 4];
+ data[datalen+1] = "0123456789abcdef"[(c & 0x0F) >> 0];
+ datalen += 2;
+ cnt++;
+ }
+ }
+
+ free(iv);
+
+ log_debug("SERVER encoded data in hex string (len %d):", datalen);
+ // buf_dump((unsigned char*)data, datalen, stderr);
+
+
+
+ if (get_payload(content_type, datalen, &jsTemplate, &jsLen) == 1) {
+ log_debug("SERVER found the applicable HTTP response template with size %d", jsLen);
+ } else {
+ log_warn("SERVER couldn't find the applicable HTTP response template");
+ return -1;
+ }
+
+ // log_debug("MJS %d %d", datalen, mjs);
+ if (jsTemplate == NULL) {
+ log_warn("NO suitable payload found %d %d", datalen, mjs);
+ return -1;
+ }
+
+ // assumption: jsTemplate is null-terminated
+ hend = strstr(jsTemplate, "\r\n\r\n");
+ if (hend == NULL) {
+ log_warn("Unable to find end of header in the HTTP template");
+ return -1;
+ }
+
+ mode = has_eligible_HTTP_content (jsTemplate, jsLen, HTTP_CONTENT_JAVASCRIPT);
+
+ // log_debug("SERVER: using HTTP resp template of length = %d", jsLen);
+ // log_debug("HTTP resp tempmlate:");
+ // buf_dump((unsigned char*)jsTemplate, jsLen, stderr);
+
+ hLen = hend+4-jsTemplate;
+ cLen = jsLen - hLen;
+ outbuf = malloc(cLen);
+ if (outbuf == NULL) {
+ log_warn("malloc for outbuf fails");
+ return -1;
+ }
+
+ r = encodeHTTPBody(data, hend+4, outbuf, datalen, cLen, cLen, mode);
+
+ if (r < 0 || ((unsigned int) r < datalen)) {
+ log_warn("SERVER ERROR: Incomplete data encoding");
+ return -1;
+ }
+
+ // work in progress
+ if (gzipMode == 1) {
+ // conservative estimate:
+ // sizeof outbuf2 = cLen + 10-byte for gzip header + 8-byte for crc
+ outbuf2 = malloc(cLen+18);
+ if (outbuf2 == NULL) {
+ log_warn("malloc for outbuf2 fails");
+ return -1;
+ }
+
+ outbuf2len = gzDeflate(outbuf, cLen, outbuf2, cLen+18, time(NULL));
+
+ if (outbuf2len <= 0) {
+ log_warn("gzDeflate for outbuf fails");
+ free(outbuf2);
+ return -1;
+ }
+ free(outbuf);
+
+ } else {
+ outbuf2 = outbuf;
+ outbuf2len = cLen;
+ }
+
+ // outbuf2 points to the HTTP payload (of length outbuf2len) to be sent
+
+ if (mode == CONTENT_JAVASCRIPT) { // JavaScript in HTTP body
+ newHdrLen = gen_response_header((char*) "application/x-javascript", gzipMode,
+ outbuf2len, newHdr, sizeof(newHdr));
+ } else if (mode == CONTENT_HTML_JAVASCRIPT) { // JavaScript(s) embedded in HTML doc
+ newHdrLen = gen_response_header((char*) "text/html", gzipMode,
+ outbuf2len, newHdr, sizeof(newHdr));
+ } else { // unknown mode
+ log_warn("SERVER ERROR: unknown mode for creating the HTTP response header");
+ free(outbuf2);
+ return -1;
+ }
+ if (newHdrLen < 0) {
+ log_warn("SERVER ERROR: gen_response_header fails for jsSteg");
+ free(outbuf2);
+ return -1;
+ }
+
+ // newHdr points to the HTTP header (of length newHdrLen) to be sent
+
+ if (evbuffer_add(dest, newHdr, newHdrLen)) {
+ log_warn("SERVER ERROR: evbuffer_add() fails for newHdr");
+ free(outbuf2);
+ return -1;
+ }
+
+ if (evbuffer_add(dest, outbuf2, outbuf2len)) {
+ log_warn("SERVER ERROR: evbuffer_add() fails for outbuf2");
+ free(outbuf2);
+ return -1;
+ }
+
+ evbuffer_drain(source, sbuflen);
+
+ free(outbuf2);
+ conn_close_after_transmit(conn);
+ // downcast_steg(s)->have_transmitted = 1;
+ return 0;
+}
+
+
+
+
+
+
+int
+x_http2_handle_client_JS_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
+ struct evbuffer_ptr s2;
+ unsigned int response_len = 0;
+ unsigned int content_len = 0;
+ unsigned int hdrLen;
+ char buf[10];
+ char respMsg[HTTP_MSG_BUF_SIZE];
+ char data[HTTP_MSG_BUF_SIZE];
+ char buf2[HTTP_MSG_BUF_SIZE];
+
+ unsigned char *field, *fieldStart, *fieldEnd, *fieldValStart;
+ char *httpBody;
+
+ int decCnt, fin, i, j, k, gzipMode=0, httpBodyLen, buf2len, contentType = 0;
+ ev_ssize_t r;
+ struct evbuffer * scratch;
+ char c;
+
+
+ s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
+ if (s2.pos == -1) {
+ log_debug("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
+ // evbuffer_dump(source, stderr);
+ return RECV_INCOMPLETE;
+ }
+
+ log_debug("CLIENT received response header with len %d", (int)s2.pos);
+
+ response_len = 0;
+ hdrLen = s2.pos + strlen("\r\n\r\n");
+ response_len += hdrLen;
+
+ // get content length, e.g., Content-Length: 22417
+ field = evbuffer_pullup(source, s2.pos);
+ if (field == NULL) {
+ log_debug("CLIENT unable to pullup the complete HTTP header");
+ return RECV_BAD;
+ }
+
+ fieldStart = (unsigned char*) strstr((char*) field, "Content-Length: ");
+ if (fieldStart == NULL) {
+ log_debug("CLIENT unable to find Content-Length in the header");
+ return RECV_BAD;
+ }
+
+ fieldEnd = (unsigned char*) strstr((char *)fieldStart, "\r\n");
+ if (fieldEnd == NULL) {
+ log_debug("CLIENT unable to find end of line for Content-Length");
+ return RECV_BAD;
+ }
+
+ fieldValStart = fieldStart+strlen("Content-Length: ");
+ if ((unsigned int) (fieldEnd-fieldValStart) > (sizeof(buf)-1)) {
+ log_debug("CLIENT: Value of Content-Length too large");
+ return RECV_BAD;
+ }
+ memcpy(buf, fieldValStart, fieldEnd-fieldValStart);
+ buf[fieldEnd-fieldValStart] = 0;
+
+ content_len = atoi(buf);
+ log_debug("CLIENT received Content-Length = %d\n", content_len);
+
+ response_len += content_len;
+
+ if (response_len > evbuffer_get_length(source))
+ return RECV_INCOMPLETE;
+
+ // read the entire HTTP resp
+ if (response_len < HTTP_MSG_BUF_SIZE) {
+ r = evbuffer_copyout(source, respMsg, response_len);
+ log_debug("CLIENT %d char copied from source to respMsg (expected %d)", (int)r, response_len);
+ if (r < 0) {
+ log_debug("CLIENT ERROR: evbuffer_copyout fails");
+ return RECV_INCOMPLETE;
+ }
+ if (r < response_len) {
+ log_debug("CLIENT: evbuffer_copyout incomplete; got %d instead of %d", (int)r, response_len);
+ return RECV_INCOMPLETE;
+ }
+ respMsg[response_len] = 0;
+ } else {
+ log_debug("CLIENT: HTTP response too large to handle");
+ return RECV_BAD;
+ }
+
+ log_debug("CLIENT received HTTP response with length %d\n", response_len);
+ // buf_dump((unsigned char*)respMsg, response_len, stderr);
+ // log_debug("HTTP response header:");
+ // buf_dump((unsigned char*)respMsg, hdrLen+80, stderr);
+
+ contentType = findContentType (respMsg);
+ if (contentType != HTTP_CONTENT_JAVASCRIPT && contentType != HTTP_CONTENT_HTML) {
+ log_warn("ERROR: Invalid content type (%d)", contentType);
+ return RECV_BAD;
+ }
+
+ httpBody = respMsg + hdrLen;
+ httpBodyLen = response_len - hdrLen;
+
+ gzipMode = isGzipContent(respMsg);
+ if (gzipMode) {
+ log_debug("gzip content encoding detected");
+ buf2len = gzInflate(httpBody, httpBodyLen, buf2, HTTP_MSG_BUF_SIZE);
+ if (buf2len <= 0) {
+ log_warn("gzInflate for httpBody fails");
+ fprintf(stderr, "gzInflate for httpBody fails");
+ exit(-1);
+ return RECV_BAD;
+ }
+ buf2[buf2len] = 0;
+ httpBody = buf2;
+ httpBodyLen = buf2len;
+ }
+
+ if (contentType == HTTP_CONTENT_JAVASCRIPT) {
+ decCnt = decodeHTTPBody(httpBody, data, httpBodyLen, HTTP_MSG_BUF_SIZE,
+ &fin, CONTENT_JAVASCRIPT);
+ } else {
+ decCnt = decodeHTTPBody(httpBody, data, httpBodyLen, HTTP_MSG_BUF_SIZE,
+ &fin, CONTENT_HTML_JAVASCRIPT);
+ }
+ data[decCnt] = 0;
+
+ log_debug("After decodeHTTPBody; decCnt: %d\n", decCnt);
+
+ // decCnt is an odd number or data is not a hex string
+ if (decCnt % 2) {
+ fprintf(stderr, "CLIENT ERROR: An odd number of hex characters received\n");
+ // buf_dump((unsigned char*)data, decCnt, stderr);
+ return RECV_BAD;
+ }
+
+ if (! isxString(data)) {
+ log_warn("CLIENT ERROR: Data received not hex");
+ // buf_dump((unsigned char*)data, decCnt, stderr);
+ return RECV_BAD;
+ }
+
+ // log_debug("Hex data received:");
+ // buf_dump ((unsigned char*)data, decCnt, stderr);
+
+ // get a scratch buffer
+ scratch = evbuffer_new();
+ if (!scratch) return RECV_BAD;
+
+ if (evbuffer_expand(scratch, decCnt/2)) {
+ log_warn("CLIENT ERROR: Evbuffer expand failed \n");
+ evbuffer_free(scratch);
+ return RECV_BAD;
+ }
+
+ // convert hex data back to binary
+ for (i=0, j=0; i< decCnt; i=i+2, ++j) {
+ sscanf(&data[i], "%2x", (unsigned int*) &k);
+ c = (char)k;
+ evbuffer_add(scratch, &c, 1);
+ }
+
+ // log_debug("CLIENT Done converting hex data to binary:\n");
+ // evbuffer_dump(scratch, stderr);
+
+
+ // fprintf(stderr, "CLIENT RECEIVED payload of size %d\n", (int) evbuffer_get_length(scratch));
+ // add the scratch buffer (which contains the data) to dest
+
+ if (evbuffer_add_buffer(dest, scratch)) {
+ evbuffer_free(scratch);
+ log_warn("CLIENT ERROR: Failed to transfer buffer");
+ return RECV_BAD;
+ }
+ log_debug("Added scratch (buffer) to dest\n");
+
+ evbuffer_free(scratch);
+
+
+ if (response_len <= evbuffer_get_length(source)) {
+ if (evbuffer_drain(source, response_len) == -1) {
+ log_warn("CLIENT ERROR: Failed to drain source");
+ return RECV_BAD;
+ }
+ }
+ else {
+ log_warn("response_len > buffer size... can't drain");
+ exit(-1);
+ }
+
+
+ log_debug("Drained source for %d char\n", response_len);
+
+ // downcast_steg(s)->have_received = 1;
+ conn_expect_close(conn);
+
+ return RECV_GOOD;
+}
+
+
+/*****
+ int
+ main() {
+ int jDataSize = 1000;
+ char jData[jDataSize];
+ int outDataBufSize = 1000;
+ char outDataBuf[outDataBufSize];
+
+ int r;
+ // test case 1: data embedded in javascript
+ r = testEncode2(data1, js1, jData, strlen(data1), strlen(js1), jDataSize,
+ CONTENT_JAVASCRIPT, 1);
+ if (r > 0) { testDecode2(jData, outDataBuf, strlen(js1), outDataBufSize, CONTENT_JAVASCRIPT, 1); }
+
+ // test case 4: data embedded in one script type javascript
+ r = testEncode2(data1, js4, jData, strlen(data1), strlen(js4), jDataSize,
+ CONTENT_HTML_JAVASCRIPT, 4);
+ if (r > 0) { testDecode2(jData, outDataBuf, strlen(js4), outDataBufSize, CONTENT_HTML_JAVASCRIPT, 4); }
+
+ // test case 5: data embedded in one script type javascript
+ r = testEncode2(data1, js5, jData, strlen(data1), strlen(js5), jDataSize,
+ CONTENT_HTML_JAVASCRIPT, 5);
+ if (r > 0) { testDecode2(jData, outDataBuf, strlen(js5), outDataBufSize, CONTENT_HTML_JAVASCRIPT, 5); }
+
+
+ return 0;
+ }
+*****/
+
+/*****
+ int
+ main() {
+ int jDataSize = 1000;
+ char jData[jDataSize];
+ int jDataSmallSize = 5;
+ char jDataSmall[jDataSmallSize];
+
+ int outDataBufSize = 1000;
+ char outDataBuf[outDataBufSize];
+ int outDataSmallSize = 5;
+ char outDataSmall[outDataSmallSize];
+
+ int r;
+
+ // test case 1: data embedded in javascript
+ r = testEncode(data1, js1, jData, strlen(data1), strlen(js1), jDataSize, 1);
+ if (r > 0) { testDecode(jData, outDataBuf, strlen(js1), r, outDataBufSize, 1); }
+
+ // test case 2: data embedded in javascript
+ r = testEncode(data1, js2, jData, strlen(data1), strlen(js2), jDataSize, 2);
+ if (r > 0) { testDecode(jData, outDataBuf, strlen(js2), r, outDataBufSize, 2); }
+
+ // test case 3: data partially embedded in javascript; num of hex char in js < data len
+ r = testEncode(data1, js3, jData, strlen(data1), strlen(js3), jDataSize, 3);
+ if (r > 0) { testDecode(jData, outDataBuf, strlen(js3), r, outDataBufSize, 3); }
+
+ // test case 4: data embedded in javascript; larger data
+ r = testEncode(data2, js1, jData, strlen(data2), strlen(js1), jDataSize, 4);
+ if (r > 0) { testDecode(jData, outDataBuf, strlen(js1), r, outDataBufSize, 4); }
+
+ // test case 5 (for encode): err for non-hex data
+ testEncode(nonhexstr, js1, jData, strlen(nonhexstr), strlen(js1), jDataSize, 5);
+
+ // test case 6 (for encode): err for small output buf
+ testEncode(data1, js1, jDataSmall, strlen(data1), strlen(js1), jDataSmallSize, 6);
+
+ // test case 7 (for decode): err for small output buf
+ r = testEncode(data1, js1, jData, strlen(data1), strlen(js1), jDataSize, 7);
+ if (r > 0) { testDecode(jData, outDataSmall, strlen(js1), r, outDataSmallSize, 7); }
+ }
+*****/
+
diff --git a/src/steg/payloads.c b/src/steg/payloads.c
deleted file mode 100644
index 2b82451..0000000
--- a/src/steg/payloads.c
+++ /dev/null
@@ -1,1669 +0,0 @@
-#include "util.h"
-#include "payloads.h"
-#include "swfSteg.h"
-
-
-/* These variables below are write-once, hence they should be race-safe */
-
-static int initTypePayload[MAX_CONTENT_TYPE];
-static int typePayloadCount[MAX_CONTENT_TYPE];
-static int typePayload[MAX_CONTENT_TYPE][MAX_PAYLOADS];
-static int typePayloadCap[MAX_CONTENT_TYPE][MAX_PAYLOADS];
-
-
-static unsigned int max_JS_capacity = 0;
-static unsigned int max_HTML_capacity = 0;
-static unsigned int max_PDF_capacity = 0;
-
-
-
-pentry_header payload_hdrs[MAX_PAYLOADS];
-char* payloads[MAX_PAYLOADS];
-int payload_count = 0;
-
-
-unsigned int get_max_JS_capacity() {
- return max_JS_capacity;
-}
-
-unsigned int get_max_HTML_capacity() {
- return max_HTML_capacity;
-}
-
-unsigned int get_max_PDF_capacity() {
- return max_PDF_capacity;
-}
-
-
-
-/*
- * fixContentLen corrects the Content-Length for an HTTP msg that
- * has been ungzipped, and removes the "Content-Encoding: gzip"
- * field from the header.
- *
- * The function returns -1 if no change to the HTTP msg has been made,
- * when the msg wasn't gzipped or an error has been encountered
- * If fixContentLen changes the msg header, it will put the new HTTP
- * msg in buf and returns the length of the new msg
- *
- * Input:
- * payload - pointer to the (input) HTTP msg
- * payloadLen - length of the (input) HTTP msg
- *
- * Ouptut:
- * buf - pointer to the buffer containing the new HTTP msg
- * bufLen - length of buf
- *
- */
-int fixContentLen (char* payload, int payloadLen, char *buf, int bufLen) {
-
- int gzipFlag=0, clFlag=0, clZeroFlag=0;
- char* ptr = payload;
- char* clPtr = payload;
- char* gzipPtr = payload;
- char* end;
-
-
- char *cp, *clEndPtr;
- int hdrLen, bodyLen, r, len;
-
-
-
-
-
- // note that the ordering between the Content-Length and the Content-Encoding
- // in an HTTP msg may be different for different msg
-
- // if payloadLen is larger than the size of our buffer,
- // stop and return -1
- if (payloadLen > bufLen) { return -1; }
-
- while (1) {
- end = strstr(ptr, "\r\n");
- if (end == NULL) {
- // log_debug("invalid header %d %d %s \n", payloadLen, (int) (ptr - payload), payload);
- return -1;
- }
-
- if (!strncmp(ptr, "Content-Encoding: gzip\r\n", 24)) {
- gzipFlag = 1;
- gzipPtr = ptr;
- } else if (!strncmp(ptr, "Content-Length: 0", 17)) {
- clZeroFlag = 1;
- } else if (!strncmp(ptr, "Content-Length:", 15)) {
- clFlag = 1;
- clPtr = ptr;
- }
-
- if (!strncmp(end, "\r\n\r\n", 4)){
- break;
- }
- ptr = end+2;
- }
-
- // stop if zero Content-Length or Content-Length not found
- if (clZeroFlag || ! clFlag) return -1;
-
- // end now points to the end of the header, before "\r\n\r\n"
- cp=buf;
- bodyLen = (int)(payloadLen - (end+4-payload));
-
- clEndPtr = strstr(clPtr, "\r\n");
- if (clEndPtr == NULL) {
- log_debug("unable to find end of line for Content-Length");
- return -1;
- }
- if (gzipFlag && clFlag) {
- if (gzipPtr < clPtr) { // Content-Encoding appears before Content-Length
-
- // copy the part of the header before Content-Encoding
- len = (int)(gzipPtr-payload);
- memcpy(cp, payload, len);
- cp = cp+len;
-
- // copy the part of the header between Content-Encoding and Content-Length
- // skip 24 char, the len of "Content-Encoding: gzip\r\n"
- // *** this is temporary; we'll remove this after the obfsproxy can perform gzip
- len = (int)(clPtr-(gzipPtr+24));
- memcpy(cp, gzipPtr+24, len);
- cp = cp+len;
-
- // put the new Content-Length
- memcpy(cp, "Content-Length: ", 16);
- cp = cp+16;
- r = sprintf(cp, "%d\r\n", bodyLen);
- if (r < 0) {
- log_debug("sprintf fails");
- return -1;
- }
- cp = cp+r;
-
- // copy the part of the header after Content-Length, if any
- if (clEndPtr != end) { // there is header info after Content-Length
- len = (int)(end-(clEndPtr+2));
- memcpy(cp, clEndPtr+2, len);
- cp = cp+len;
- memcpy(cp, "\r\n\r\n", 4);
- cp = cp+4;
- } else { // Content-Length is the last hdr field
- memcpy(cp, "\r\n", 2);
- cp = cp+2;
- }
-
- hdrLen = cp-buf;
-
-/****
-log_debug("orig: hdrLen = %d, bodyLen = %d, payloadLen = %d", (int)(end+4-payload), bodyLen, payloadLen);
-log_debug("new: hdrLen = %d, bodyLen = %d, payloadLen = %d", hdrLen, bodyLen, hdrLen+bodyLen);
- ****/
-
- // copy the HTTP body
- memcpy(cp, end+4, bodyLen);
- return (hdrLen+bodyLen);
-
- } else { // Content-Length before Content-Encoding
- // copy the part of the header before Content-Length
- len = (int)(clPtr-payload);
- memcpy(cp, payload, len);
- cp = cp+len;
-
- // put the new Content-Length
- memcpy(cp, "Content-Length: ", 16);
- cp = cp+16;
- r = sprintf(cp, "%d\r\n", bodyLen);
- if (r < 0) {
- log_debug("sprintf fails");
- return -1;
- }
- cp = cp+r;
-
- // copy the part of the header between Content-Length and Content-Encoding
- len = (int)(gzipPtr-(clEndPtr+2));
- memcpy(cp, clEndPtr+2, len);
- cp = cp+len;
-
- // copy the part of the header after Content-Encoding
- // skip 24 char, the len of "Content-Encoding: gzip\r\n"
- // *** this is temporary; we'll remove this after the obfsproxy can perform gzip
- if (end > (gzipPtr+24)) { // there is header info after Content-Encoding
- len = (int)(end-(gzipPtr+24));
- memcpy(cp, gzipPtr+24, len);
- cp = cp+len;
- memcpy(cp, "\r\n\r\n", 4);
- cp = cp+4;
- } else { // Content-Encoding is the last field in the hdr
- memcpy(cp, "\r\n", 2);
- cp = cp+2;
- }
- hdrLen = cp-buf;
-
-/****
-log_debug("orig: hdrLen = %d, bodyLen = %d, payloadLen = %d", (int)(end+4-payload), bodyLen, payloadLen);
-log_debug("new: hdrLen = %d, bodyLen = %d, payloadLen = %d", hdrLen, bodyLen, hdrLen+bodyLen);
- ****/
-
- // copy the HTTP body
- memcpy(cp, end+4, bodyLen);
- return (hdrLen+bodyLen);
- }
- }
- return -1;
-}
-
-void load_payloads(const char* fname) {
- FILE* f;
- char buf[HTTP_MSG_BUF_SIZE];
- char buf2[HTTP_MSG_BUF_SIZE];
- pentry_header pentry;
- int pentryLen;
- int r;
-
- if (payload_count != 0)
- return;
-
- srand(time(NULL));
- f = fopen(fname, "r");
- if (f == NULL) {
- fprintf(stderr, "Cannot open trace file %s. Exiting\n", fname);
- exit(1);
- }
-
- bzero(payload_hdrs, sizeof(payload_hdrs));
-
- while (payload_count < MAX_PAYLOADS) {
-
- if (fread(&pentry, 1, sizeof(pentry_header), f) < sizeof(pentry_header)) {
- break;
- }
-
- pentryLen = ntohl(pentry.length);
- if((unsigned int) pentryLen > sizeof(buf)) {
-#ifdef DEBUG
- // fprintf(stderr, "pentry too big %d %d\n", pentry.length, ntohl(pentry.length));
- fprintf(stderr, "pentry too big %d\n", pentryLen);
-#endif
- // skip to the next pentry
- if (fseek(f, pentryLen, SEEK_CUR)) {
- fprintf(stderr, "skipping to next pentry fails\n");
- }
- continue;
- // exit(0);
- }
-
- pentry.length = pentryLen;
- pentry.ptype = ntohs(pentry.ptype);
-
- if (fread(buf, 1, pentry.length, f) < (unsigned int) pentry.length)
- break;
-
- // todo:
- // fixed content length for gzip'd HTTP msg
- // fixContentLen returns -1, if no change to the msg
- // otherwise, it put the new HTTP msg (with hdr changed) in buf2
- // and returns the size of the new msg
-
- r = -1;
- if (pentry.ptype == TYPE_HTTP_RESPONSE) {
- r = fixContentLen (buf, pentry.length, buf2, HTTP_MSG_BUF_SIZE);
- // log_debug("for payload_count %d, fixContentLen returns %d", payload_count, r);
- }
- // else {
- // log_debug("for payload_count %d, pentry.ptype = %d", payload_count, pentry.ptype);
- // }
-
- if (r < 0) {
- payloads[payload_count] = malloc(pentry.length + 1);
- memcpy(payloads[payload_count], buf, pentry.length);
- } else {
- pentry.length = r;
- payloads[payload_count] = malloc(pentry.length + 1);
- memcpy(payloads[payload_count], buf2, pentry.length);
- }
- payload_hdrs[payload_count] = pentry;
- payloads[payload_count][pentry.length] = 0;
- payload_count++;
- } // while
-
-#ifdef DEBUG
- printf("loading payload count = %d\n", payload_count);
-#endif
-
- fclose(f);
-}
-
-
-
-
-
-void gen_rfc_1123_date(char* buf, int buf_size) {
- time_t t = time(NULL);
- struct tm *my_tm = gmtime(&t);
- strftime(buf, buf_size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", my_tm);
-}
-
-
-
-void gen_rfc_1123_expiry_date(char* buf, int buf_size) {
- time_t t = time(NULL) + rand() % 10000;
- struct tm *my_tm = gmtime(&t);
- strftime(buf, buf_size, "Expires: %a, %d %b %Y %H:%M:%S GMT\r\n", my_tm);
-}
-
-
-
-
-
-int gen_response_header(char* content_type, int gzip, int length, char* buf, int buflen) {
- char* ptr;
-
- // conservative assumption here....
- if (buflen < 400) {
- fprintf(stderr, "gen_response_header: buflen too small\n");
- return -1;
- }
-
- sprintf(buf, "HTTP/1.1 200 OK\r\n");
- ptr = buf + strlen("HTTP/1.1 200 OK\r\n");
- gen_rfc_1123_date(ptr, buflen - (ptr - buf));
- ptr = ptr + strlen(ptr);
-
- sprintf(ptr, "Server: Apache\r\n");
- ptr = ptr + strlen(ptr);
-
- switch(rand() % 9) {
- case 1:
- sprintf(ptr, "Vary: Cookie\r\n");
- ptr = ptr + strlen(ptr);
- break;
-
- case 2:
- sprintf(ptr, "Vary: Accept-Encoding, User-Agent\r\n");
- ptr = ptr + strlen(ptr);
- break;
-
- case 3:
- sprintf(ptr, "Vary: *\r\n");
- ptr = ptr + strlen(ptr);
- break;
-
- }
-
-
- switch(rand() % 4) {
- case 2:
- gen_rfc_1123_expiry_date(ptr, buflen - (ptr - buf));
- ptr = ptr + strlen(ptr);
- }
-
-
-
-
- if (gzip)
- sprintf(ptr, "Content-Length: %d\r\nContent-Encoding: gzip\r\nContent-Type: %s\r\n", length, content_type);
- else
- sprintf(ptr, "Content-Length: %d\r\nContent-Type: %s\r\n", length, content_type);
-
- ptr += strlen(ptr);
-
- switch(rand() % 4) {
- case 2:
- case 3:
- case 4:
- sprintf(ptr, "Connection: Keep-Alive\r\n\r\n");
- break;
- default:
- sprintf(ptr, "Connection: close\r\n\r\n");
- break;
- }
-
- ptr += strlen(ptr);
-
- return ptr - buf;
-}
-
-
-
-
-
-
-int parse_client_headers(char* inbuf, char* outbuf, int len) {
- // client-side
- // remove Host: field
- // remove referrer fields?
-
- char* ptr = inbuf;
- int outlen = 0;
-
- while (1) {
- // char* end = strstr(ptr, "\r\n", len - (ptr - inbuf));
- char* end = strstr(ptr, "\r\n");
- if (end == NULL) {
- fprintf(stderr, "invalid client header %d %d %s \n PTR = %s\n", len, (int) (len - (ptr - inbuf)), inbuf, ptr);
- // fprintf(stderr, "HERE %s\n", ptr);
- break;
- }
-
- if (!strncmp(ptr, "Host:", 5) ||
- !strncmp(ptr, "Referer:", 8) ||
- !strncmp(ptr, "Cookie:", 7)) {
- goto next;
- }
-
- memcpy(outbuf + outlen, ptr, end - ptr + 2);
- outlen += end - ptr + 2;
-
- next:
- if (!strncmp(end, "\r\n\r\n", 4)){
- break;
- }
- ptr = end+2;
- }
-
- return outlen;
-
- // server-side
- // fix date fields
- // fix content-length
-
-
-
-}
-
-
-
-
-/* first line is of the form....
- GET /XX/XXXX.swf[?YYYY] HTTP/1.1\r\n
-*/
-
-
-int
-find_uri_type(char* buf_orig, int buflen) {
-
- char* uri;
- char* ext;
-
- char* buf = malloc(buflen+1);
- char* uri_end;
-
-
- memcpy(buf, buf_orig, buflen);
- buf[buflen] = 0;
-
-
- if (strncmp(buf, "GET", 3) != 0
- && strncmp(buf, "POST", 4) != 0) {
- fprintf(stderr, "HERE %s\n", buf);
- return -1;
- }
-
-
-
- uri = strchr(buf, ' ') + 1;
-
- if (uri == NULL) {
- fprintf(stderr, "Invalid URL\n");
- return -1;
- }
-
- uri_end = strchr(uri, ' ');
-
- if (uri_end == NULL) {
- fprintf(stderr, "unterminated uri\n");
- return -1;
- }
-
- uri_end[0] = 0;
-
-
-
-
-
- ext = strrchr(uri, '/');
-
- if (ext == NULL) {
- fprintf(stderr, "no / in url: find_uri_type...");
- return -1;
- }
-
- ext = strchr(ext, '.');
-
-
- if (ext == NULL || !strncmp(ext, ".html", 5) || !strncmp(ext, ".htm", 4) || !strncmp(ext, ".php", 4)
- || !strncmp(ext, ".jsp", 4) || !strncmp(ext, ".asp", 4))
- return HTTP_CONTENT_HTML;
-
-
- if (!strncmp(ext, ".js", 3) || !strncmp(ext, ".JS", 3))
- return HTTP_CONTENT_JAVASCRIPT;
-
- if (!strncmp(ext, ".pdf", 4) || !strncmp(ext, ".PDF", 4))
- return HTTP_CONTENT_PDF;
-
-
- if (!strncmp(ext, ".swf", 4) || !strncmp(ext, ".SWF", 4))
- return HTTP_CONTENT_SWF;
-
-
-
- free(buf);
- return -1;
-
-}
-
-/*
-int
-find_uri_type(char* buf) {
-
- char* uri;
- int uri_len;
- char* ext;
-
- if (strncmp(buf, "GET", 3) != 0 && strncmp(buf, "POST", 4) != 0)
- return -1;
-
- buf = strchr(buf, ' ') + 1;
- uri_len = strchr(buf, ' ') - buf;
- uri = malloc(uri_len + 1);
-
- strncpy(uri, buf, uri_len);
- uri[uri_len] = 0;
-
- if (strchr(uri, '?'))
- ext = strchr(uri, '?') - 4;
- else
- ext = uri + uri_len - 4;
-
-
- if (!strncmp(ext, ".pdf", 4) || !strncmp(ext, ".PDF", 4))
- return HTTP_CONTENT_PDF;
-
- if (!strncmp(ext, ".swf", 4) || !strncmp(ext, ".SWF", 4))
- return HTTP_CONTENT_SWF;
-
- if (!strncmp(ext, ".js", 3) || !strncmp(ext, ".JS", 3))
- return HTTP_CONTENT_JAVASCRIPT;
-
- if (!strncmp(ext-1, "html", 4) || !strncmp(ext, "htm", 3) || strchr(ext-1, '.') == NULL)
- return HTTP_CONTENT_HTML;
-
- // default type
- return HTTP_CONTENT_HTML;
- // return HTTP_CONTENT_JAVASCRIPT;
- return -1;
-
-}
-
-*/
-
-
-
-
-
-
-
-
-unsigned int find_client_payload(char* buf, int len, int type) {
- int r = rand() % payload_count;
- int cnt = 0;
- char* inbuf;
-
-#ifdef DEBUG
- fprintf(stderr, "TRYING payload %d \n", r);
-#endif
- while (1) {
- pentry_header* p = &payload_hdrs[r];
- if (p->ptype == type) {
- inbuf = payloads[r];
- if (find_uri_type(inbuf, p->length) != HTTP_CONTENT_SWF &&
- find_uri_type(inbuf, p->length) != HTTP_CONTENT_HTML &&
- find_uri_type(inbuf, p->length) != HTTP_CONTENT_JAVASCRIPT &&
- find_uri_type(inbuf, p->length) != HTTP_CONTENT_PDF) {
- goto next;
- }
- if (p->length > len) {
- fprintf(stderr, "BUFFER TOO SMALL... \n");
- goto next;
- }
- else
- len = p->length;
- break;
- }
- next:
- r = (r+1) % payload_count;
-
-
- // no matching payloads...
- if (cnt++ == payload_count) {
- fprintf(stderr, "NO MATCHING PAYLOADS... \n");
- return 0;
- }
- }
-
- inbuf[len] = 0;
-
- // clean up the buffer...
- return parse_client_headers(inbuf, buf, len);
-
-}
-
-
-/*
- * skipJSPattern returns the number of characters to skip when
- * the input pointer matches the start of a common JavaScript
- * keyword
- *
- * todo:
- * Use a more efficient regular expression matching algo
- */
-
-
-
-int skipJSPattern(char *cp, int len) {
- int i,j;
-
-
- char keywords [21][10]= {"function", "return", "var", "int", "random", "Math", "while",
- "else", "for", "document", "write", "writeln", "true",
- "false", "True", "False", "window", "indexOf", "navigator", "case", "if"};
-
-
- if (len < 1) return 0;
-
- // change the limit to 21 to enable if as a keyword
- for (i=0; i < 20; i++) {
- char* word = keywords[i];
-
- if (len <= (int) strlen(word))
- continue;
-
- if (word[0] != cp[0])
- continue;
-
- for (j=1; j < (int) strlen(word); j++) {
- if (isxdigit(word[j])) {
- if (!isxdigit(cp[j]))
- goto next_word;
- else
- continue;
- }
-
- if (cp[j] != word[j])
- goto next_word;
- }
- if (!isalnum(cp[j]))
- return strlen(word)+1;
-
- next_word:
- continue;
- }
-
- return 0;
-}
-
-
-
-
-/* int skipJSPattern (char *cp, int len) { */
-
-/* // log_debug("Turning off skipJSPattern for debugging"); */
-/* // return 0; */
-
-/* if (len < 1) return 0; */
-
-/* if (len > 8) { */
-/* // "function " and "function(" */
-/* if (cp[0] == 'f' && */
-/* !strncmp(cp+1, "un", 2) && */
-/* isxdigit(cp[3]) && */
-/* !strncmp(cp+4, "tion", 4) && */
-/* (cp[8] == ' ' || cp[8] == '(')) */
-/* return 9; */
-/* } */
-
-/* if (len > 6) { */
-/* // "return " */
-/* if (cp[0] == 'r' && */
-/* isxdigit(cp[1]) && */
-/* !strncmp(cp+2, "turn ", 5)) */
-/* return 7; */
-/* // "switch " */
-/* if (cp[0] == 's' && */
-/* !strncmp(cp+1, "wit", 3) && */
-/* isxdigit(cp[4]) && */
-/* !strncmp(cp+5, "h ", 2)) */
-/* return 7; */
-/* } */
-
-/* if (len > 5) { */
-/* // "while " and "while(" */
-/* if (cp[0] == 'w' && */
-/* !strncmp(cp+1, "hil", 3) && */
-/* isxdigit(cp[4]) && */
-/* (cp[5] == ' ' || cp[5] == '(')) */
-/* return 6; */
-/* } */
-
-/* if (len > 4) { */
-/* // "else " and "else{" */
-/* if (cp[0] == 'e' && */
-/* !strncmp(cp, "ls", 2) && */
-/* isxdigit(cp[3]) && */
-/* (cp[4] == ' ' || cp[4] == '{')) */
-/* return 5; */
-/* } */
-
-/* if (len > 3) { */
-/* // "var " */
-/* if (cp[0] == 'v' && */
-/* isxdigit(cp[1]) && */
-/* cp[2] == 'r' && */
-/* cp[3] == ' ') */
-/* return 4; */
-/* } */
-
-/* return 0; */
-/* } */
-
-
-
-int isalnum_ (char c) {
- if (isalnum(c) || c == '_') return 1;
- else return 0;
-}
-
-int offset2Alnum_ (char *p, int range) {
- char *cp = p;
-
- while ((cp < (p+range)) && !isalnum_(*cp)) {
- cp++;
- }
-
- if (cp < (p+range)) {
- return (cp-p);
- } else {
- return -1;
- }
-}
-
-
-
-/*
- * offset2Hex returns the offset to the next usable hex char.
- * usable here refer to char that our steg module can use to encode
- * data. in particular, words that correspond to common JavaScript keywords
- * are not used for data encoding (see skipJSPattern). Also, because
- * JS var name must start with an underscore or a letter (but not a digit)
- * we don't use the first char of a word for encoding data
- *
- * e.g., the JS statement "var a;" won't be used for encoding data
- * because "var" is a common JS keyword and "a" is the first char of a word
- *
- * Input:
- * p - ptr to the starting pos
- * range - max number of char to look
- * isLastCharHex - is the char pointed to by (p-1) a hex char
- *
- * Output:
- * offset2Hex returns the offset to the next usable hex char
- * between p and (p+range), if it exists;
- * otherwise, it returns -1
- *
- */
-int offset2Hex (char *p, int range, int isLastCharHex) {
- char *cp = p;
- int i,j;
- int isFirstWordChar = 1;
-
- if (range < 1) return -1;
-
- // case 1: last char is hexadecimal
- if (isLastCharHex) {
- if (isxdigit(*cp)) return 0; // base case
- else {
- while (cp < (p+range) && isalnum_(*cp)) {
- cp++;
- if (isxdigit(*cp)) return (cp-p);
- }
- if (cp >= (p+range)) return -1;
- // non-alnum_ found
- // fallthru and handle case 2
- }
- }
-
- // case 2:
- // find the next word that starts with alnum or underscore,
- // which could be a variable, keyword, or literal inside a string
-
- i = offset2Alnum_(cp, p+range-cp);
- if (i == -1) return -1;
-
- while (cp < (p+range) && i != -1) {
-
- if (i == 0) {
- if (isFirstWordChar) {
- j = skipJSPattern(cp, p+range-cp);
- if (j > 0) {
- cp = cp+j;
- } else {
- cp++; isFirstWordChar = 0; // skip the 1st char of a word
- }
- } else { // we are in the middle of a word; no need to invoke skipJSPattern
- if (isxdigit(*cp)) return (cp-p);
- if (! isalnum_(*cp)) {
- isFirstWordChar = 1;
- }
- cp++;
- }
- } else {
- cp += i; isFirstWordChar = 1;
- }
- i = offset2Alnum_(cp, p+range-cp);
-
- } // while
-
- // cannot find next usable hex char
- return -1;
-
-}
-
-/*
- * capacityJS3 is the next iteration for capacityJS
- */
-unsigned int capacityJS3 (char* buf, int len, int mode) {
- char *hEnd, *bp, *jsStart, *jsEnd;
- int cnt=0;
- int j;
-
- // jump to the beginning of the body of the HTTP message
- hEnd = strstr(buf, "\r\n\r\n");
- if (hEnd == NULL) {
- // cannot find the separator between HTTP header and HTTP body
- return 0;
- }
- bp = hEnd + 4;
-
-
- if (mode == CONTENT_JAVASCRIPT) {
- j = offset2Hex(bp, (buf+len)-bp, 0);
- while (j != -1) {
- cnt++;
- if (j == 0) {
- bp = bp+1;
- } else {
- bp = bp+j+1;
- }
-
- if (len < buf + len - bp) {
- fprintf(stderr, "HERE\n");
- }
- j = offset2Hex(bp, (buf+len)-bp, 1);
- } // while
- return cnt;
- } else if (mode == CONTENT_HTML_JAVASCRIPT) {
- while (bp < (buf+len)) {
- jsStart = strstr(bp, "<script type=\"text/javascript\">");
- if (jsStart == NULL) break;
- bp = jsStart+31;
- jsEnd = strstr(bp, "</script>");
- if (jsEnd == NULL) break;
- // count the number of usable hex char between jsStart+31 and jsEnd
-
- j = offset2Hex(bp, jsEnd-bp, 0);
- while (j != -1) {
- cnt++;
- if (j == 0) {
- bp = bp+1;
- } else {
- bp = bp+j+1;
- }
-
- if (len < jsEnd - buf || len < jsEnd - bp) {
- fprintf(stderr, "HERE2\n");
- }
-
-
- j = offset2Hex(bp, jsEnd-bp, 1);
- } // while (j != -1)
-
- if (buf + len < bp + 9) {
- fprintf(stderr, "HERE3\n");
- }
-
-
- bp += 9;
- } // while (bp < (buf+len))
- return cnt;
- } else {
- fprintf(stderr, "Unknown mode (%d) for capacityJS() ... \n", mode);
- return 0;
- }
-}
-
-
-/*
- * strInBinary looks for char array pattern of length patternLen in a char array
- * blob of length blobLen
- *
- * return a pointer for the first occurrence of pattern in blob, if found
- * otherwise, return NULL
- *
- */
-char *
-strInBinary (const char *pattern, unsigned int patternLen,
- const char *blob, unsigned int blobLen) {
- int found = 0;
- char *cp = (char *)blob;
-
- while (1) {
- if (blob+blobLen-cp < patternLen) break;
- if (*cp == pattern[0]) {
- if (memcmp(cp, pattern, patternLen) == 0) {
- found = 1;
- break;
- }
- }
- cp++;
- }
- if (found) return cp;
- else return NULL;
-}
-
-
-/*
- * has_eligible_HTTP_content() identifies if the input HTTP message
- * contains a specified type of content, used by a steg module to
- * select candidate HTTP message as cover traffic
- */
-
-// for JavaScript, there are two cases:
-// 1) If Content-Type: has one of the following values
-// text/javascript
-// application/x-javascript
-// application/javascript
-// 2) Content-Type: text/html and
-// HTTP body contains <script type="text/javascript"> ... </script>
-// #define CONTENT_JAVASCRIPT 1 (for case 1)
-// #define CONTENT_HTML_JAVASCRIPT 2 (for case 2)
-//
-// for pdf, we look for the msgs whose Content-Type: has one of the
-// following values
-// 1) application/pdf
-// 2) application/x-pdf
-//
-
-int has_eligible_HTTP_content (char* buf, int len, int type) {
- char* ptr = buf;
- char* matchptr;
- int tjFlag=0, thFlag=0, ceFlag=0, teFlag=0, http304Flag=0, clZeroFlag=0, pdfFlag=0, swfFlag=0, gzipFlag=0;
- char* end, *cp;
-
-#ifdef DEBUG
- fprintf(stderr, "TESTING availabilty of js in payload ... \n");
-#endif
-
- if (type != HTTP_CONTENT_JAVASCRIPT &&
- type != HTTP_CONTENT_HTML &&
- type != HTTP_CONTENT_PDF && type != HTTP_CONTENT_SWF)
- return 0;
-
- // assumption: buf is null-terminated
- if (!strstr(buf, "\r\n\r\n"))
- return 0;
-
-
- while (1) {
- end = strstr(ptr, "\r\n");
- if (end == NULL) {
- break;
- }
-
- if (!strncmp(ptr, "Content-Type:", 13)) {
-
- if (!strncmp(ptr+14, "text/javascript", 15) ||
- !strncmp(ptr+14, "application/javascript", 22) ||
- !strncmp(ptr+14, "application/x-javascript", 24)) {
- tjFlag = 1;
- }
- if (!strncmp(ptr+14, "text/html", 9)) {
- thFlag = 1;
- }
- if (!strncmp(ptr+14, "application/pdf", 15) ||
- !strncmp(ptr+14, "application/x-pdf", 17)) {
- pdfFlag = 1;
- }
- if (!strncmp(ptr+14, "application/x-shockwave-flash", strlen("application/x-shockwave-flash"))) {
- swfFlag = 1;
- }
-
- } else if (!strncmp(ptr, "Content-Encoding: gzip", 22)) {
- gzipFlag = 1;
- } else if (!strncmp(ptr, "Content-Encoding:", 17)) { // Content-Encoding that is not gzip
- ceFlag = 1;
- } else if (!strncmp(ptr, "Transfer-Encoding:", 18)) {
- teFlag = 1;
- } else if (!strncmp(ptr, "HTTP/1.1 304 ", 13)) {
- http304Flag = 1;
- } else if (!strncmp(ptr, "Content-Length: 0", 17)) {
- clZeroFlag = 1;
- }
-
- if (!strncmp(end, "\r\n\r\n", 4)){
- break;
- }
- ptr = end+2;
- }
-
-#ifdef DEBUG
- printf("tjFlag=%d; thFlag=%d; gzipFlag=%d; ceFlag=%d; teFlag=%d; http304Flag=%d; clZeroFlag=%d\n",
- tjFlag, thFlag, gzipFlag, ceFlag, teFlag, http304Flag, clZeroFlag);
-#endif
-
- // if (type == HTTP_CONTENT_JAVASCRIPT)
- if (type == HTTP_CONTENT_JAVASCRIPT || type == HTTP_CONTENT_HTML) {
- // empty body if it's HTTP not modified (304) or zero Content-Length
- if (http304Flag || clZeroFlag) return 0;
-
- // for now, we're not dealing with Transfer-Encoding (e.g., chunked)
- // or Content-Encoding that is not gzip
- // if (teFlag) return 0;
- if (teFlag || ceFlag) return 0;
-
- if (tjFlag && ceFlag && end != NULL) {
- log_debug("(JS) gzip flag detected with hdr len %d", (int)(end-buf+4));
- } else if (thFlag && ceFlag && end != NULL) {
- log_debug("(HTML) gzip flag detected with hdr len %d", (int)(end-buf+4));
- }
-
- // case 1
- if (tjFlag) return 1;
-
- // case 2: check if HTTP body contains <script type="text/javascript">
- if (thFlag) {
- matchptr = strstr(ptr, "<script type=\"text/javascript\">");
- if (matchptr != NULL) {
- return 2;
- }
- }
- }
-
- if (type == HTTP_CONTENT_PDF && pdfFlag) {
- // reject msg with empty body: HTTP not modified (304) or zero Content-Length
- if (http304Flag || clZeroFlag) return 0;
-
- // for now, we're not dealing with Transfer-Encoding (e.g., chunked)
- // or Content-Encoding that is not gzip
- // if (teFlag) return 0;
- if (teFlag || ceFlag) return 0;
-
- // check if HTTP body contains "endstream";
- // strlen("endstream") == 9
-
- cp = strInBinary("endstream", 9, ptr, buf+len-ptr);
- if (cp != NULL) {
- // log_debug("Matched endstream!");
- return 1;
- }
- }
-
- if (type == HTTP_CONTENT_SWF && swfFlag == 1 &&
- ((len + buf - end) > SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 8))
- return 1;
-
- return 0;
-}
-
-
-
-unsigned int capacityPDF (char* buf, int len) {
- char *hEnd, *bp, *streamStart, *streamEnd;
- int cnt=0;
- int size;
-
- // jump to the beginning of the body of the HTTP message
- hEnd = strstr(buf, "\r\n\r\n");
- if (hEnd == NULL) {
- // cannot find the separator between HTTP header and HTTP body
- return 0;
- }
- bp = hEnd + 4;
-
- while (bp < (buf+len)) {
- streamStart = strInBinary("stream", 6, bp, (buf+len)-bp);
- // streamStart = strstr(bp, "stream");
- if (streamStart == NULL) break;
- bp = streamStart+6;
- streamEnd = strInBinary("endstream", 9, bp, (buf+len)-bp);
- // streamEnd = strstr(bp, "endstream");
- if (streamEnd == NULL) break;
- // count the number of char between streamStart+6 and streamEnd
- size = streamEnd - (streamStart+6) - 2; // 2 for \r\n before streamEnd
- if (size > 0) {
- cnt = cnt + size;
- log_debug("capacity of pdf increase by %d", size);
- }
- bp += 9;
- }
- return cnt;
-}
-
-
-
-
-
-
-
-
-
-/*
- * init_payload_pool initializes the arrays pertaining to
- * message payloads for the specified content type
- *
- * Specifically, it populates the following arrays
- * static int initTypePayload[MAX_CONTENT_TYPE];
- * static int typePayloadCount[MAX_CONTENT_TYPE];
- * static int typePayload[MAX_CONTENT_TYPE][MAX_PAYLOADS];
- * static int typePayloadCap[MAX_CONTENT_TYPE][MAX_PAYLOADS];
- *
- * Input:
- * len - max length of payload
- * type - ptype field value in pentry_header
- * contentType - (e.g, HTTP_CONTENT_JAVASCRIPT for JavaScript content)
- */
-
-
-
-
-int init_JS_payload_pool(int len, int type, int minCapacity) {
-
- // stat for usable payload
- int minPayloadSize = 0, maxPayloadSize = 0;
- int sumPayloadSize = 0;
- int minPayloadCap = 0, maxPayloadCap = 0;
- int sumPayloadCap = 0;
-
- unsigned int contentType = HTTP_CONTENT_JAVASCRIPT;
-
- int cnt = 0;
- int r;
- pentry_header* p;
- char* msgbuf;
- int cap;
- int mode;
-
-
-
- if (payload_count == 0) {
- log_debug("payload_count == 0; forgot to run load_payloads()?\n");
- return 0;
- }
-
- if (initTypePayload[contentType] != 0) return 1; // init is done already
-
-
- for (r = 0; r < payload_count; r++) {
- p = &payload_hdrs[r];
- if (p->ptype != type || p->length > len) {
- continue;
- }
-
- msgbuf = payloads[r];
-
- mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_JAVASCRIPT);
- if (mode == CONTENT_JAVASCRIPT) {
-
- cap = capacityJS3(msgbuf, p->length, mode);
- if (cap < JS_DELIMITER_SIZE)
- continue;
-
- cap = (cap - JS_DELIMITER_SIZE)/2;
-
- if (cap > minCapacity) {
- typePayloadCap[contentType][cnt] = cap; // (cap-JS_DELIMITER_SIZE)/2;
- // because we use 2 hex char to encode every data byte, the available
- // capacity for encoding data is divided by 2
- typePayload[contentType][cnt] = r;
- cnt++;
-
- // update stat
- if (cnt == 1) {
- minPayloadSize = p->length; maxPayloadSize = p->length;
- minPayloadCap = cap; maxPayloadCap = cap;
- }
- else {
- if (minPayloadSize > p->length) minPayloadSize = p->length;
- if (maxPayloadSize < p->length) maxPayloadSize = p->length;
- if (minPayloadCap > cap) minPayloadCap = cap;
- if (maxPayloadCap < cap) {
- maxPayloadCap = cap;
- }
-
- }
- sumPayloadSize += p->length; sumPayloadCap += cap;
- }
- }
- }
-
-
- max_JS_capacity = maxPayloadCap;
-
-
- initTypePayload[contentType] = 1;
- typePayloadCount[contentType] = cnt;
- log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
- contentType, typePayloadCount[contentType]);
- log_debug("minPayloadSize = %d", minPayloadSize);
- log_debug("maxPayloadSize = %d", maxPayloadSize);
- log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
- log_debug("minPayloadCap = %d", minPayloadCap);
- log_debug("maxPayloadCap = %d", maxPayloadCap);
- log_debug("avgPayloadCap = %f", (float)sumPayloadCap/(float)cnt);
- return 1;
-}
-
-
-int init_HTML_payload_pool(int len, int type, int minCapacity) {
-
- // stat for usable payload
- int minPayloadSize = 0, maxPayloadSize = 0;
- int sumPayloadSize = 0;
- int minPayloadCap = 0, maxPayloadCap = 0;
- int sumPayloadCap = 0;
-
- unsigned int contentType = HTTP_CONTENT_HTML;
-
- int cnt = 0;
- int r;
- pentry_header* p;
- char* msgbuf;
- int cap;
- int mode;
-
-
-
- if (payload_count == 0) {
- log_debug("payload_count == 0; forgot to run load_payloads()?\n");
- return 0;
- }
-
- if (initTypePayload[contentType] != 0) return 1; // init is done already
-
-
- for (r = 0; r < payload_count; r++) {
- p = &payload_hdrs[r];
- if (p->ptype != type || p->length > len) {
- continue;
- }
-
- msgbuf = payloads[r];
-
- mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_HTML);
- if (mode == CONTENT_HTML_JAVASCRIPT) {
-
- cap = capacityJS3(msgbuf, p->length, mode);
- if (cap < JS_DELIMITER_SIZE)
- continue;
-
- cap = (cap - JS_DELIMITER_SIZE)/2;
-
- if (cap > minCapacity) {
- typePayloadCap[contentType][cnt] = cap; // (cap-JS_DELIMITER_SIZE)/2;
- // because we use 2 hex char to encode every data byte, the available
- // capacity for encoding data is divided by 2
- typePayload[contentType][cnt] = r;
- cnt++;
-
- // update stat
- if (cnt == 1) {
- minPayloadSize = p->length; maxPayloadSize = p->length;
- minPayloadCap = cap; maxPayloadCap = cap;
- }
- else {
- if (minPayloadSize > p->length) minPayloadSize = p->length;
- if (maxPayloadSize < p->length) maxPayloadSize = p->length;
- if (minPayloadCap > cap) minPayloadCap = cap;
- if (maxPayloadCap < cap) {
- maxPayloadCap = cap;
- }
-
- }
- sumPayloadSize += p->length; sumPayloadCap += cap;
- }
- }
- }
-
-
- max_HTML_capacity = maxPayloadCap;
-
-
- initTypePayload[contentType] = 1;
- typePayloadCount[contentType] = cnt;
- log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
- contentType, typePayloadCount[contentType]);
- log_debug("minPayloadSize = %d", minPayloadSize);
- log_debug("maxPayloadSize = %d", maxPayloadSize);
- log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
- log_debug("minPayloadCap = %d", minPayloadCap);
- log_debug("maxPayloadCap = %d", maxPayloadCap);
- log_debug("avgPayloadCap = %f", (float)sumPayloadCap/(float)cnt);
- return 1;
-}
-
-
-
-
-
-
-
-
-int init_PDF_payload_pool(int len, int type, int minCapacity) {
-
- // stat for usable payload
- int minPayloadSize = 0, maxPayloadSize = 0;
- int sumPayloadSize = 0;
- int minPayloadCap = 0, maxPayloadCap = 0;
- int sumPayloadCap = 0;
-
- int cnt = 0;
- int r;
- pentry_header* p;
- char* msgbuf;
- int cap;
- int mode;
- unsigned int contentType = HTTP_CONTENT_PDF;
-
-
- if (payload_count == 0) {
- fprintf(stderr, "payload_count == 0; forgot to run load_payloads()?\n");
- return 0;
- }
-
- if (initTypePayload[contentType] != 0) return 1; // init is done already
-
-
- for (r = 0; r < payload_count; r++) {
- p = &payload_hdrs[r];
- if (p->ptype != type || p->length > len) {
- continue;
- }
-
- msgbuf = payloads[r];
-
- mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_PDF);
- if (mode > 0) {
- // use capacityPDF() to find out the amount of data that we
- // can encode in the pdf doc
- // cap = minCapacity+1;
- cap = capacityPDF(msgbuf, p->length);
- log_debug("got pdf (index %d) with capacity %d", r, cap);
- if (cap > minCapacity) {
- log_debug("pdf (index %d) greater than mincapacity %d", cnt, minCapacity);
- typePayloadCap[contentType][cnt] = (cap-PDF_DELIMITER_SIZE)/2;
- typePayload[contentType][cnt] = r;
- cnt++;
-
- // update stat
- if (cnt == 1) {
- minPayloadSize = p->length; maxPayloadSize = p->length;
- minPayloadCap = cap; maxPayloadCap = cap;
- }
- else {
- if (minPayloadSize > p->length) minPayloadSize = p->length;
- if (maxPayloadSize < p->length) maxPayloadSize = p->length;
- if (minPayloadCap > cap) minPayloadCap = cap;
- if (maxPayloadCap < cap) maxPayloadCap = cap;
- }
- sumPayloadSize += p->length; sumPayloadCap += cap;
- }
- }
- }
-
- max_PDF_capacity = maxPayloadCap;
- initTypePayload[contentType] = 1;
- typePayloadCount[contentType] = cnt;
- log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
- contentType, typePayloadCount[contentType]);
- log_debug("minPayloadSize = %d", minPayloadSize);
- log_debug("maxPayloadSize = %d", maxPayloadSize);
- log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
- log_debug("minPayloadCap = %d", minPayloadCap);
- log_debug("maxPayloadCap = %d", maxPayloadCap);
- log_debug("avgPayloadCap = %f", (float)sumPayloadCap/(float)cnt);
- return 1;
-}
-
-
-
-
-
-int init_SWF_payload_pool(int len, int type, int minCapacity) {
-
- // stat for usable payload
- int minPayloadSize = 0, maxPayloadSize = 0;
- int sumPayloadSize = 0;
-
- int cnt = 0;
- int r;
- pentry_header* p;
- char* msgbuf;
- int mode;
- unsigned int contentType = HTTP_CONTENT_SWF;
-
-
- if (payload_count == 0) {
- fprintf(stderr, "payload_count == 0; forgot to run load_payloads()?\n");
- return 0;
- }
-
- if (initTypePayload[contentType] != 0) return 1; // init is done already
-
-
- for (r = 0; r < payload_count; r++) {
- p = &payload_hdrs[r];
- if (p->ptype != type || p->length > len) {
- continue;
- }
-
- msgbuf = payloads[r];
- // found a payload corr to the specified contentType
-
- mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_SWF);
- if (mode > 0) {
- typePayload[contentType][cnt] = r;
- cnt++;
- // update stat
- if (cnt == 1) {
- minPayloadSize = p->length;
- maxPayloadSize = p->length;
- }
- else {
- if (minPayloadSize > p->length)
- minPayloadSize = p->length;
- if (maxPayloadSize < p->length)
- maxPayloadSize = p->length;
- }
- sumPayloadSize += p->length;
- }
- }
-
- initTypePayload[contentType] = 1;
- typePayloadCount[contentType] = cnt;
- log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
- contentType, typePayloadCount[contentType]);
- log_debug("minPayloadSize = %d", minPayloadSize);
- log_debug("maxPayloadSize = %d", maxPayloadSize);
- log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
- return 1;
-}
-
-
-
-
-
-
-
-
-
-int get_next_payload (int contentType, char** buf, int* size, int* cap) {
- int r;
-
- log_debug("get_next_payload: contentType = %d, initTypePayload = %d, typePayloadCount = %d",
- contentType, initTypePayload[contentType], typePayloadCount[contentType]);
-
-
- if (contentType <= 0 ||
- contentType >= MAX_CONTENT_TYPE ||
- initTypePayload[contentType] == 0 ||
- typePayloadCount[contentType] == 0)
- return 0;
-
- r = rand() % typePayloadCount[contentType];
-// int r = 1;
-// log_debug("SERVER: *** always choose the same payload ***");
-
- log_debug("SERVER: picked payload with index %d", r);
- *buf = payloads[typePayload[contentType][r]];
- *size = payload_hdrs[typePayload[contentType][r]].length;
- *cap = typePayloadCap[contentType][r];
- return 1;
-}
-
-
-
-
-
-
-
-
-int get_payload (int contentType, int cap, char** buf, int* size) {
- int r;
- unsigned int i = 0;
- unsigned int cnt = 0;
-
- log_debug("get_payload: contentType = %d, initTypePayload = %d, typePayloadCount = %d",
- contentType, initTypePayload[contentType], typePayloadCount[contentType]);
-
-
- if (contentType <= 0 ||
- contentType >= MAX_CONTENT_TYPE ||
- initTypePayload[contentType] == 0 ||
- typePayloadCount[contentType] == 0)
- return 0;
-
-
- cnt = typePayloadCount[contentType];
- r = rand() % cnt;
-
- for (i=0; i < cnt; i++) {
-
- if (typePayloadCap[contentType][(r+i) % cnt] <= cap)
- continue;
-
- *buf = payloads[typePayload[contentType][(r+i)%cnt]];
- *size = payload_hdrs[typePayload[contentType][(r+i)%cnt]].length;
- return 1;
- }
-
-
-
- return 0;
-
-}
-
-
-
-
-int
-find_content_length (char *hdr, int hlen) {
- char *clStart;
- char* clEnd;
- char *clValStart;
- int valLen;
- int contentLen;
- char buf[10];
-
- clStart = strstr(hdr, "Content-Length: ");
- if (clStart == NULL) {
- log_debug("Unable to find Content-Length in the header");
- return -1;
- }
-
- clEnd = strstr((char *)clStart, "\r\n");
- if (clEnd == NULL) {
- log_debug("Unable to find end of line for Content-Length");
- return -1;
- }
-
- // clValStart = clStart+strlen("Content-Length: ");
- clValStart = clStart+16;
-
- valLen = clEnd-clValStart;
- if (valLen > 9) return -1;
- memcpy(buf, clValStart, valLen);
- buf[valLen] = 0;
- contentLen = atoi(buf);
- return contentLen;
-}
-
-
-
-
-
-
-/*
-
-void testOffset2Alnum_skipJSPattern () {
- char s1[] = "for (i=0; i<10; i++) { print i; }";
-
- char s2[] = "***abcde*****";
- int d, i;
-
- printf("s1 = %s\n", s1);
- printf("s2 = %s\n", s2);
-
-
- d = offset2Alnum_(s1, strlen(s1));
- printf ("offset2Alnum_ for s1 = %d\n", d);
- d = offset2Alnum_(s2, strlen(s2));
- printf ("offset2Alnum_ for s2 = %d\n", d);
-
- i = skipJSPattern (s1, strlen(s1));
- printf ("skipJSPattern for s1 = %d\n", i);
- i = skipJSPattern (s2, strlen(s2));
- printf ("skipJSPattern for s2 = %d\n", i);
-}
-
-
-
-
-void testOffset2Hex () {
- int d;
- char s3[] = "for (bc=0; bc<10; bc++) { ad=2*bc+ad; }";
- printf("len(s3)=%d; s3 = |%s|\n", (int)strlen(s3), s3);
-
- d = offset2Alnum_(s3, strlen(s3));
- printf ("offset2Alnum_ for s3 = %d\n", d);
- d = offset2Hex(s3, strlen(s3), 0);
- printf ("offset2Hex for s3 = %d\n", d);
-}
-
-
-void testCapacityJS () {
- int d;
- char s4[] = "\r\n\r\n abc = abc + 1;";
- char s6[] = "\r\n\r\n <script type=\"text/javascript\">abc = abc + 1;</script>";
-
- printf("\nTest for CONTENT_JAVASCRIPT:\n");
- printf("len(s4)=%d; s4 = |%s|\n", (int)strlen(s4), s4);
-
- d = offset2Alnum_(s4, strlen(s4));
- printf ("offset2Alnum_ for s4 = %d\n", d);
- d = offset2Hex(s4, strlen(s4), 0);
- printf ("offset2Hex for s4 = %d\n", d);
-
- printf("capacityJS (JS) returns %d\n", capacityJS(s4, strlen(s4), CONTENT_JAVASCRIPT));
- printf("capacityJS3 (JS) returns %d\n", capacityJS3(s4, strlen(s4), CONTENT_JAVASCRIPT));
-
- printf("\nTest for CONTENT_HTML_JAVASCRIPT:\n");
- printf("len(s6)=%d; s6 = |%s|\n", (int)strlen(s6), s6);
-
- d = offset2Alnum_(s6, strlen(s6));
- printf ("offset2Alnum_ for s6 = %d\n", d);
- d = offset2Hex(s6, strlen(s6), 0);
- printf ("offset2Hex for s6 = %d\n", d);
-
- printf("capacityJS (HTML) returns %d\n", capacityJS(s6, strlen(s6), CONTENT_HTML_JAVASCRIPT));
- printf("capacityJS3 (HTML) returns %d\n", capacityJS3(s6, strlen(s6), CONTENT_HTML_JAVASCRIPT));
-}
-*/
-
-
-/*****
-int main() {
- char buf[HTTP_MSG_BUF_SIZE];
- bzero(buf, sizeof(buf));
- // test for TYPE_HTTP_REQUEST
- // load_payloads("../../traces/client.out");
- // int len = find_client_payload(buf, 10000, TYPE_HTTP_REQUEST);
- // printf("%s\n", buf);
-
- // test for TYPE_HTTP_RESPONSE
- // load_payloads("../../traces/server-cnn-nogzip.out");
- // load_payloads("../../traces/server-portals.out"); // ptype==1?
-
- // testOffset2Alnum_skipJSPattern();
- // testOffset2Hex();
- // testCapacityJS();
-
- load_payloads("../../traces/server.out");
- // int r;
- // r = find_server_payload(&buf, sizeof(buf), TYPE_HTTP_RESPONSE, HTTP_CONTENT_JAVASCRIPT);
- // if (r > 0) {
- // printf("Available payload capablity %d\n", r);
- // }
- // return r;
-
- return 0;
-}
- *****/
-
diff --git a/src/steg/payloads.cc b/src/steg/payloads.cc
new file mode 100644
index 0000000..2b82451
--- /dev/null
+++ b/src/steg/payloads.cc
@@ -0,0 +1,1669 @@
+#include "util.h"
+#include "payloads.h"
+#include "swfSteg.h"
+
+
+/* These variables below are write-once, hence they should be race-safe */
+
+static int initTypePayload[MAX_CONTENT_TYPE];
+static int typePayloadCount[MAX_CONTENT_TYPE];
+static int typePayload[MAX_CONTENT_TYPE][MAX_PAYLOADS];
+static int typePayloadCap[MAX_CONTENT_TYPE][MAX_PAYLOADS];
+
+
+static unsigned int max_JS_capacity = 0;
+static unsigned int max_HTML_capacity = 0;
+static unsigned int max_PDF_capacity = 0;
+
+
+
+pentry_header payload_hdrs[MAX_PAYLOADS];
+char* payloads[MAX_PAYLOADS];
+int payload_count = 0;
+
+
+unsigned int get_max_JS_capacity() {
+ return max_JS_capacity;
+}
+
+unsigned int get_max_HTML_capacity() {
+ return max_HTML_capacity;
+}
+
+unsigned int get_max_PDF_capacity() {
+ return max_PDF_capacity;
+}
+
+
+
+/*
+ * fixContentLen corrects the Content-Length for an HTTP msg that
+ * has been ungzipped, and removes the "Content-Encoding: gzip"
+ * field from the header.
+ *
+ * The function returns -1 if no change to the HTTP msg has been made,
+ * when the msg wasn't gzipped or an error has been encountered
+ * If fixContentLen changes the msg header, it will put the new HTTP
+ * msg in buf and returns the length of the new msg
+ *
+ * Input:
+ * payload - pointer to the (input) HTTP msg
+ * payloadLen - length of the (input) HTTP msg
+ *
+ * Ouptut:
+ * buf - pointer to the buffer containing the new HTTP msg
+ * bufLen - length of buf
+ *
+ */
+int fixContentLen (char* payload, int payloadLen, char *buf, int bufLen) {
+
+ int gzipFlag=0, clFlag=0, clZeroFlag=0;
+ char* ptr = payload;
+ char* clPtr = payload;
+ char* gzipPtr = payload;
+ char* end;
+
+
+ char *cp, *clEndPtr;
+ int hdrLen, bodyLen, r, len;
+
+
+
+
+
+ // note that the ordering between the Content-Length and the Content-Encoding
+ // in an HTTP msg may be different for different msg
+
+ // if payloadLen is larger than the size of our buffer,
+ // stop and return -1
+ if (payloadLen > bufLen) { return -1; }
+
+ while (1) {
+ end = strstr(ptr, "\r\n");
+ if (end == NULL) {
+ // log_debug("invalid header %d %d %s \n", payloadLen, (int) (ptr - payload), payload);
+ return -1;
+ }
+
+ if (!strncmp(ptr, "Content-Encoding: gzip\r\n", 24)) {
+ gzipFlag = 1;
+ gzipPtr = ptr;
+ } else if (!strncmp(ptr, "Content-Length: 0", 17)) {
+ clZeroFlag = 1;
+ } else if (!strncmp(ptr, "Content-Length:", 15)) {
+ clFlag = 1;
+ clPtr = ptr;
+ }
+
+ if (!strncmp(end, "\r\n\r\n", 4)){
+ break;
+ }
+ ptr = end+2;
+ }
+
+ // stop if zero Content-Length or Content-Length not found
+ if (clZeroFlag || ! clFlag) return -1;
+
+ // end now points to the end of the header, before "\r\n\r\n"
+ cp=buf;
+ bodyLen = (int)(payloadLen - (end+4-payload));
+
+ clEndPtr = strstr(clPtr, "\r\n");
+ if (clEndPtr == NULL) {
+ log_debug("unable to find end of line for Content-Length");
+ return -1;
+ }
+ if (gzipFlag && clFlag) {
+ if (gzipPtr < clPtr) { // Content-Encoding appears before Content-Length
+
+ // copy the part of the header before Content-Encoding
+ len = (int)(gzipPtr-payload);
+ memcpy(cp, payload, len);
+ cp = cp+len;
+
+ // copy the part of the header between Content-Encoding and Content-Length
+ // skip 24 char, the len of "Content-Encoding: gzip\r\n"
+ // *** this is temporary; we'll remove this after the obfsproxy can perform gzip
+ len = (int)(clPtr-(gzipPtr+24));
+ memcpy(cp, gzipPtr+24, len);
+ cp = cp+len;
+
+ // put the new Content-Length
+ memcpy(cp, "Content-Length: ", 16);
+ cp = cp+16;
+ r = sprintf(cp, "%d\r\n", bodyLen);
+ if (r < 0) {
+ log_debug("sprintf fails");
+ return -1;
+ }
+ cp = cp+r;
+
+ // copy the part of the header after Content-Length, if any
+ if (clEndPtr != end) { // there is header info after Content-Length
+ len = (int)(end-(clEndPtr+2));
+ memcpy(cp, clEndPtr+2, len);
+ cp = cp+len;
+ memcpy(cp, "\r\n\r\n", 4);
+ cp = cp+4;
+ } else { // Content-Length is the last hdr field
+ memcpy(cp, "\r\n", 2);
+ cp = cp+2;
+ }
+
+ hdrLen = cp-buf;
+
+/****
+log_debug("orig: hdrLen = %d, bodyLen = %d, payloadLen = %d", (int)(end+4-payload), bodyLen, payloadLen);
+log_debug("new: hdrLen = %d, bodyLen = %d, payloadLen = %d", hdrLen, bodyLen, hdrLen+bodyLen);
+ ****/
+
+ // copy the HTTP body
+ memcpy(cp, end+4, bodyLen);
+ return (hdrLen+bodyLen);
+
+ } else { // Content-Length before Content-Encoding
+ // copy the part of the header before Content-Length
+ len = (int)(clPtr-payload);
+ memcpy(cp, payload, len);
+ cp = cp+len;
+
+ // put the new Content-Length
+ memcpy(cp, "Content-Length: ", 16);
+ cp = cp+16;
+ r = sprintf(cp, "%d\r\n", bodyLen);
+ if (r < 0) {
+ log_debug("sprintf fails");
+ return -1;
+ }
+ cp = cp+r;
+
+ // copy the part of the header between Content-Length and Content-Encoding
+ len = (int)(gzipPtr-(clEndPtr+2));
+ memcpy(cp, clEndPtr+2, len);
+ cp = cp+len;
+
+ // copy the part of the header after Content-Encoding
+ // skip 24 char, the len of "Content-Encoding: gzip\r\n"
+ // *** this is temporary; we'll remove this after the obfsproxy can perform gzip
+ if (end > (gzipPtr+24)) { // there is header info after Content-Encoding
+ len = (int)(end-(gzipPtr+24));
+ memcpy(cp, gzipPtr+24, len);
+ cp = cp+len;
+ memcpy(cp, "\r\n\r\n", 4);
+ cp = cp+4;
+ } else { // Content-Encoding is the last field in the hdr
+ memcpy(cp, "\r\n", 2);
+ cp = cp+2;
+ }
+ hdrLen = cp-buf;
+
+/****
+log_debug("orig: hdrLen = %d, bodyLen = %d, payloadLen = %d", (int)(end+4-payload), bodyLen, payloadLen);
+log_debug("new: hdrLen = %d, bodyLen = %d, payloadLen = %d", hdrLen, bodyLen, hdrLen+bodyLen);
+ ****/
+
+ // copy the HTTP body
+ memcpy(cp, end+4, bodyLen);
+ return (hdrLen+bodyLen);
+ }
+ }
+ return -1;
+}
+
+void load_payloads(const char* fname) {
+ FILE* f;
+ char buf[HTTP_MSG_BUF_SIZE];
+ char buf2[HTTP_MSG_BUF_SIZE];
+ pentry_header pentry;
+ int pentryLen;
+ int r;
+
+ if (payload_count != 0)
+ return;
+
+ srand(time(NULL));
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Cannot open trace file %s. Exiting\n", fname);
+ exit(1);
+ }
+
+ bzero(payload_hdrs, sizeof(payload_hdrs));
+
+ while (payload_count < MAX_PAYLOADS) {
+
+ if (fread(&pentry, 1, sizeof(pentry_header), f) < sizeof(pentry_header)) {
+ break;
+ }
+
+ pentryLen = ntohl(pentry.length);
+ if((unsigned int) pentryLen > sizeof(buf)) {
+#ifdef DEBUG
+ // fprintf(stderr, "pentry too big %d %d\n", pentry.length, ntohl(pentry.length));
+ fprintf(stderr, "pentry too big %d\n", pentryLen);
+#endif
+ // skip to the next pentry
+ if (fseek(f, pentryLen, SEEK_CUR)) {
+ fprintf(stderr, "skipping to next pentry fails\n");
+ }
+ continue;
+ // exit(0);
+ }
+
+ pentry.length = pentryLen;
+ pentry.ptype = ntohs(pentry.ptype);
+
+ if (fread(buf, 1, pentry.length, f) < (unsigned int) pentry.length)
+ break;
+
+ // todo:
+ // fixed content length for gzip'd HTTP msg
+ // fixContentLen returns -1, if no change to the msg
+ // otherwise, it put the new HTTP msg (with hdr changed) in buf2
+ // and returns the size of the new msg
+
+ r = -1;
+ if (pentry.ptype == TYPE_HTTP_RESPONSE) {
+ r = fixContentLen (buf, pentry.length, buf2, HTTP_MSG_BUF_SIZE);
+ // log_debug("for payload_count %d, fixContentLen returns %d", payload_count, r);
+ }
+ // else {
+ // log_debug("for payload_count %d, pentry.ptype = %d", payload_count, pentry.ptype);
+ // }
+
+ if (r < 0) {
+ payloads[payload_count] = malloc(pentry.length + 1);
+ memcpy(payloads[payload_count], buf, pentry.length);
+ } else {
+ pentry.length = r;
+ payloads[payload_count] = malloc(pentry.length + 1);
+ memcpy(payloads[payload_count], buf2, pentry.length);
+ }
+ payload_hdrs[payload_count] = pentry;
+ payloads[payload_count][pentry.length] = 0;
+ payload_count++;
+ } // while
+
+#ifdef DEBUG
+ printf("loading payload count = %d\n", payload_count);
+#endif
+
+ fclose(f);
+}
+
+
+
+
+
+void gen_rfc_1123_date(char* buf, int buf_size) {
+ time_t t = time(NULL);
+ struct tm *my_tm = gmtime(&t);
+ strftime(buf, buf_size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", my_tm);
+}
+
+
+
+void gen_rfc_1123_expiry_date(char* buf, int buf_size) {
+ time_t t = time(NULL) + rand() % 10000;
+ struct tm *my_tm = gmtime(&t);
+ strftime(buf, buf_size, "Expires: %a, %d %b %Y %H:%M:%S GMT\r\n", my_tm);
+}
+
+
+
+
+
+int gen_response_header(char* content_type, int gzip, int length, char* buf, int buflen) {
+ char* ptr;
+
+ // conservative assumption here....
+ if (buflen < 400) {
+ fprintf(stderr, "gen_response_header: buflen too small\n");
+ return -1;
+ }
+
+ sprintf(buf, "HTTP/1.1 200 OK\r\n");
+ ptr = buf + strlen("HTTP/1.1 200 OK\r\n");
+ gen_rfc_1123_date(ptr, buflen - (ptr - buf));
+ ptr = ptr + strlen(ptr);
+
+ sprintf(ptr, "Server: Apache\r\n");
+ ptr = ptr + strlen(ptr);
+
+ switch(rand() % 9) {
+ case 1:
+ sprintf(ptr, "Vary: Cookie\r\n");
+ ptr = ptr + strlen(ptr);
+ break;
+
+ case 2:
+ sprintf(ptr, "Vary: Accept-Encoding, User-Agent\r\n");
+ ptr = ptr + strlen(ptr);
+ break;
+
+ case 3:
+ sprintf(ptr, "Vary: *\r\n");
+ ptr = ptr + strlen(ptr);
+ break;
+
+ }
+
+
+ switch(rand() % 4) {
+ case 2:
+ gen_rfc_1123_expiry_date(ptr, buflen - (ptr - buf));
+ ptr = ptr + strlen(ptr);
+ }
+
+
+
+
+ if (gzip)
+ sprintf(ptr, "Content-Length: %d\r\nContent-Encoding: gzip\r\nContent-Type: %s\r\n", length, content_type);
+ else
+ sprintf(ptr, "Content-Length: %d\r\nContent-Type: %s\r\n", length, content_type);
+
+ ptr += strlen(ptr);
+
+ switch(rand() % 4) {
+ case 2:
+ case 3:
+ case 4:
+ sprintf(ptr, "Connection: Keep-Alive\r\n\r\n");
+ break;
+ default:
+ sprintf(ptr, "Connection: close\r\n\r\n");
+ break;
+ }
+
+ ptr += strlen(ptr);
+
+ return ptr - buf;
+}
+
+
+
+
+
+
+int parse_client_headers(char* inbuf, char* outbuf, int len) {
+ // client-side
+ // remove Host: field
+ // remove referrer fields?
+
+ char* ptr = inbuf;
+ int outlen = 0;
+
+ while (1) {
+ // char* end = strstr(ptr, "\r\n", len - (ptr - inbuf));
+ char* end = strstr(ptr, "\r\n");
+ if (end == NULL) {
+ fprintf(stderr, "invalid client header %d %d %s \n PTR = %s\n", len, (int) (len - (ptr - inbuf)), inbuf, ptr);
+ // fprintf(stderr, "HERE %s\n", ptr);
+ break;
+ }
+
+ if (!strncmp(ptr, "Host:", 5) ||
+ !strncmp(ptr, "Referer:", 8) ||
+ !strncmp(ptr, "Cookie:", 7)) {
+ goto next;
+ }
+
+ memcpy(outbuf + outlen, ptr, end - ptr + 2);
+ outlen += end - ptr + 2;
+
+ next:
+ if (!strncmp(end, "\r\n\r\n", 4)){
+ break;
+ }
+ ptr = end+2;
+ }
+
+ return outlen;
+
+ // server-side
+ // fix date fields
+ // fix content-length
+
+
+
+}
+
+
+
+
+/* first line is of the form....
+ GET /XX/XXXX.swf[?YYYY] HTTP/1.1\r\n
+*/
+
+
+int
+find_uri_type(char* buf_orig, int buflen) {
+
+ char* uri;
+ char* ext;
+
+ char* buf = malloc(buflen+1);
+ char* uri_end;
+
+
+ memcpy(buf, buf_orig, buflen);
+ buf[buflen] = 0;
+
+
+ if (strncmp(buf, "GET", 3) != 0
+ && strncmp(buf, "POST", 4) != 0) {
+ fprintf(stderr, "HERE %s\n", buf);
+ return -1;
+ }
+
+
+
+ uri = strchr(buf, ' ') + 1;
+
+ if (uri == NULL) {
+ fprintf(stderr, "Invalid URL\n");
+ return -1;
+ }
+
+ uri_end = strchr(uri, ' ');
+
+ if (uri_end == NULL) {
+ fprintf(stderr, "unterminated uri\n");
+ return -1;
+ }
+
+ uri_end[0] = 0;
+
+
+
+
+
+ ext = strrchr(uri, '/');
+
+ if (ext == NULL) {
+ fprintf(stderr, "no / in url: find_uri_type...");
+ return -1;
+ }
+
+ ext = strchr(ext, '.');
+
+
+ if (ext == NULL || !strncmp(ext, ".html", 5) || !strncmp(ext, ".htm", 4) || !strncmp(ext, ".php", 4)
+ || !strncmp(ext, ".jsp", 4) || !strncmp(ext, ".asp", 4))
+ return HTTP_CONTENT_HTML;
+
+
+ if (!strncmp(ext, ".js", 3) || !strncmp(ext, ".JS", 3))
+ return HTTP_CONTENT_JAVASCRIPT;
+
+ if (!strncmp(ext, ".pdf", 4) || !strncmp(ext, ".PDF", 4))
+ return HTTP_CONTENT_PDF;
+
+
+ if (!strncmp(ext, ".swf", 4) || !strncmp(ext, ".SWF", 4))
+ return HTTP_CONTENT_SWF;
+
+
+
+ free(buf);
+ return -1;
+
+}
+
+/*
+int
+find_uri_type(char* buf) {
+
+ char* uri;
+ int uri_len;
+ char* ext;
+
+ if (strncmp(buf, "GET", 3) != 0 && strncmp(buf, "POST", 4) != 0)
+ return -1;
+
+ buf = strchr(buf, ' ') + 1;
+ uri_len = strchr(buf, ' ') - buf;
+ uri = malloc(uri_len + 1);
+
+ strncpy(uri, buf, uri_len);
+ uri[uri_len] = 0;
+
+ if (strchr(uri, '?'))
+ ext = strchr(uri, '?') - 4;
+ else
+ ext = uri + uri_len - 4;
+
+
+ if (!strncmp(ext, ".pdf", 4) || !strncmp(ext, ".PDF", 4))
+ return HTTP_CONTENT_PDF;
+
+ if (!strncmp(ext, ".swf", 4) || !strncmp(ext, ".SWF", 4))
+ return HTTP_CONTENT_SWF;
+
+ if (!strncmp(ext, ".js", 3) || !strncmp(ext, ".JS", 3))
+ return HTTP_CONTENT_JAVASCRIPT;
+
+ if (!strncmp(ext-1, "html", 4) || !strncmp(ext, "htm", 3) || strchr(ext-1, '.') == NULL)
+ return HTTP_CONTENT_HTML;
+
+ // default type
+ return HTTP_CONTENT_HTML;
+ // return HTTP_CONTENT_JAVASCRIPT;
+ return -1;
+
+}
+
+*/
+
+
+
+
+
+
+
+
+unsigned int find_client_payload(char* buf, int len, int type) {
+ int r = rand() % payload_count;
+ int cnt = 0;
+ char* inbuf;
+
+#ifdef DEBUG
+ fprintf(stderr, "TRYING payload %d \n", r);
+#endif
+ while (1) {
+ pentry_header* p = &payload_hdrs[r];
+ if (p->ptype == type) {
+ inbuf = payloads[r];
+ if (find_uri_type(inbuf, p->length) != HTTP_CONTENT_SWF &&
+ find_uri_type(inbuf, p->length) != HTTP_CONTENT_HTML &&
+ find_uri_type(inbuf, p->length) != HTTP_CONTENT_JAVASCRIPT &&
+ find_uri_type(inbuf, p->length) != HTTP_CONTENT_PDF) {
+ goto next;
+ }
+ if (p->length > len) {
+ fprintf(stderr, "BUFFER TOO SMALL... \n");
+ goto next;
+ }
+ else
+ len = p->length;
+ break;
+ }
+ next:
+ r = (r+1) % payload_count;
+
+
+ // no matching payloads...
+ if (cnt++ == payload_count) {
+ fprintf(stderr, "NO MATCHING PAYLOADS... \n");
+ return 0;
+ }
+ }
+
+ inbuf[len] = 0;
+
+ // clean up the buffer...
+ return parse_client_headers(inbuf, buf, len);
+
+}
+
+
+/*
+ * skipJSPattern returns the number of characters to skip when
+ * the input pointer matches the start of a common JavaScript
+ * keyword
+ *
+ * todo:
+ * Use a more efficient regular expression matching algo
+ */
+
+
+
+int skipJSPattern(char *cp, int len) {
+ int i,j;
+
+
+ char keywords [21][10]= {"function", "return", "var", "int", "random", "Math", "while",
+ "else", "for", "document", "write", "writeln", "true",
+ "false", "True", "False", "window", "indexOf", "navigator", "case", "if"};
+
+
+ if (len < 1) return 0;
+
+ // change the limit to 21 to enable if as a keyword
+ for (i=0; i < 20; i++) {
+ char* word = keywords[i];
+
+ if (len <= (int) strlen(word))
+ continue;
+
+ if (word[0] != cp[0])
+ continue;
+
+ for (j=1; j < (int) strlen(word); j++) {
+ if (isxdigit(word[j])) {
+ if (!isxdigit(cp[j]))
+ goto next_word;
+ else
+ continue;
+ }
+
+ if (cp[j] != word[j])
+ goto next_word;
+ }
+ if (!isalnum(cp[j]))
+ return strlen(word)+1;
+
+ next_word:
+ continue;
+ }
+
+ return 0;
+}
+
+
+
+
+/* int skipJSPattern (char *cp, int len) { */
+
+/* // log_debug("Turning off skipJSPattern for debugging"); */
+/* // return 0; */
+
+/* if (len < 1) return 0; */
+
+/* if (len > 8) { */
+/* // "function " and "function(" */
+/* if (cp[0] == 'f' && */
+/* !strncmp(cp+1, "un", 2) && */
+/* isxdigit(cp[3]) && */
+/* !strncmp(cp+4, "tion", 4) && */
+/* (cp[8] == ' ' || cp[8] == '(')) */
+/* return 9; */
+/* } */
+
+/* if (len > 6) { */
+/* // "return " */
+/* if (cp[0] == 'r' && */
+/* isxdigit(cp[1]) && */
+/* !strncmp(cp+2, "turn ", 5)) */
+/* return 7; */
+/* // "switch " */
+/* if (cp[0] == 's' && */
+/* !strncmp(cp+1, "wit", 3) && */
+/* isxdigit(cp[4]) && */
+/* !strncmp(cp+5, "h ", 2)) */
+/* return 7; */
+/* } */
+
+/* if (len > 5) { */
+/* // "while " and "while(" */
+/* if (cp[0] == 'w' && */
+/* !strncmp(cp+1, "hil", 3) && */
+/* isxdigit(cp[4]) && */
+/* (cp[5] == ' ' || cp[5] == '(')) */
+/* return 6; */
+/* } */
+
+/* if (len > 4) { */
+/* // "else " and "else{" */
+/* if (cp[0] == 'e' && */
+/* !strncmp(cp, "ls", 2) && */
+/* isxdigit(cp[3]) && */
+/* (cp[4] == ' ' || cp[4] == '{')) */
+/* return 5; */
+/* } */
+
+/* if (len > 3) { */
+/* // "var " */
+/* if (cp[0] == 'v' && */
+/* isxdigit(cp[1]) && */
+/* cp[2] == 'r' && */
+/* cp[3] == ' ') */
+/* return 4; */
+/* } */
+
+/* return 0; */
+/* } */
+
+
+
+int isalnum_ (char c) {
+ if (isalnum(c) || c == '_') return 1;
+ else return 0;
+}
+
+int offset2Alnum_ (char *p, int range) {
+ char *cp = p;
+
+ while ((cp < (p+range)) && !isalnum_(*cp)) {
+ cp++;
+ }
+
+ if (cp < (p+range)) {
+ return (cp-p);
+ } else {
+ return -1;
+ }
+}
+
+
+
+/*
+ * offset2Hex returns the offset to the next usable hex char.
+ * usable here refer to char that our steg module can use to encode
+ * data. in particular, words that correspond to common JavaScript keywords
+ * are not used for data encoding (see skipJSPattern). Also, because
+ * JS var name must start with an underscore or a letter (but not a digit)
+ * we don't use the first char of a word for encoding data
+ *
+ * e.g., the JS statement "var a;" won't be used for encoding data
+ * because "var" is a common JS keyword and "a" is the first char of a word
+ *
+ * Input:
+ * p - ptr to the starting pos
+ * range - max number of char to look
+ * isLastCharHex - is the char pointed to by (p-1) a hex char
+ *
+ * Output:
+ * offset2Hex returns the offset to the next usable hex char
+ * between p and (p+range), if it exists;
+ * otherwise, it returns -1
+ *
+ */
+int offset2Hex (char *p, int range, int isLastCharHex) {
+ char *cp = p;
+ int i,j;
+ int isFirstWordChar = 1;
+
+ if (range < 1) return -1;
+
+ // case 1: last char is hexadecimal
+ if (isLastCharHex) {
+ if (isxdigit(*cp)) return 0; // base case
+ else {
+ while (cp < (p+range) && isalnum_(*cp)) {
+ cp++;
+ if (isxdigit(*cp)) return (cp-p);
+ }
+ if (cp >= (p+range)) return -1;
+ // non-alnum_ found
+ // fallthru and handle case 2
+ }
+ }
+
+ // case 2:
+ // find the next word that starts with alnum or underscore,
+ // which could be a variable, keyword, or literal inside a string
+
+ i = offset2Alnum_(cp, p+range-cp);
+ if (i == -1) return -1;
+
+ while (cp < (p+range) && i != -1) {
+
+ if (i == 0) {
+ if (isFirstWordChar) {
+ j = skipJSPattern(cp, p+range-cp);
+ if (j > 0) {
+ cp = cp+j;
+ } else {
+ cp++; isFirstWordChar = 0; // skip the 1st char of a word
+ }
+ } else { // we are in the middle of a word; no need to invoke skipJSPattern
+ if (isxdigit(*cp)) return (cp-p);
+ if (! isalnum_(*cp)) {
+ isFirstWordChar = 1;
+ }
+ cp++;
+ }
+ } else {
+ cp += i; isFirstWordChar = 1;
+ }
+ i = offset2Alnum_(cp, p+range-cp);
+
+ } // while
+
+ // cannot find next usable hex char
+ return -1;
+
+}
+
+/*
+ * capacityJS3 is the next iteration for capacityJS
+ */
+unsigned int capacityJS3 (char* buf, int len, int mode) {
+ char *hEnd, *bp, *jsStart, *jsEnd;
+ int cnt=0;
+ int j;
+
+ // jump to the beginning of the body of the HTTP message
+ hEnd = strstr(buf, "\r\n\r\n");
+ if (hEnd == NULL) {
+ // cannot find the separator between HTTP header and HTTP body
+ return 0;
+ }
+ bp = hEnd + 4;
+
+
+ if (mode == CONTENT_JAVASCRIPT) {
+ j = offset2Hex(bp, (buf+len)-bp, 0);
+ while (j != -1) {
+ cnt++;
+ if (j == 0) {
+ bp = bp+1;
+ } else {
+ bp = bp+j+1;
+ }
+
+ if (len < buf + len - bp) {
+ fprintf(stderr, "HERE\n");
+ }
+ j = offset2Hex(bp, (buf+len)-bp, 1);
+ } // while
+ return cnt;
+ } else if (mode == CONTENT_HTML_JAVASCRIPT) {
+ while (bp < (buf+len)) {
+ jsStart = strstr(bp, "<script type=\"text/javascript\">");
+ if (jsStart == NULL) break;
+ bp = jsStart+31;
+ jsEnd = strstr(bp, "</script>");
+ if (jsEnd == NULL) break;
+ // count the number of usable hex char between jsStart+31 and jsEnd
+
+ j = offset2Hex(bp, jsEnd-bp, 0);
+ while (j != -1) {
+ cnt++;
+ if (j == 0) {
+ bp = bp+1;
+ } else {
+ bp = bp+j+1;
+ }
+
+ if (len < jsEnd - buf || len < jsEnd - bp) {
+ fprintf(stderr, "HERE2\n");
+ }
+
+
+ j = offset2Hex(bp, jsEnd-bp, 1);
+ } // while (j != -1)
+
+ if (buf + len < bp + 9) {
+ fprintf(stderr, "HERE3\n");
+ }
+
+
+ bp += 9;
+ } // while (bp < (buf+len))
+ return cnt;
+ } else {
+ fprintf(stderr, "Unknown mode (%d) for capacityJS() ... \n", mode);
+ return 0;
+ }
+}
+
+
+/*
+ * strInBinary looks for char array pattern of length patternLen in a char array
+ * blob of length blobLen
+ *
+ * return a pointer for the first occurrence of pattern in blob, if found
+ * otherwise, return NULL
+ *
+ */
+char *
+strInBinary (const char *pattern, unsigned int patternLen,
+ const char *blob, unsigned int blobLen) {
+ int found = 0;
+ char *cp = (char *)blob;
+
+ while (1) {
+ if (blob+blobLen-cp < patternLen) break;
+ if (*cp == pattern[0]) {
+ if (memcmp(cp, pattern, patternLen) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ cp++;
+ }
+ if (found) return cp;
+ else return NULL;
+}
+
+
+/*
+ * has_eligible_HTTP_content() identifies if the input HTTP message
+ * contains a specified type of content, used by a steg module to
+ * select candidate HTTP message as cover traffic
+ */
+
+// for JavaScript, there are two cases:
+// 1) If Content-Type: has one of the following values
+// text/javascript
+// application/x-javascript
+// application/javascript
+// 2) Content-Type: text/html and
+// HTTP body contains <script type="text/javascript"> ... </script>
+// #define CONTENT_JAVASCRIPT 1 (for case 1)
+// #define CONTENT_HTML_JAVASCRIPT 2 (for case 2)
+//
+// for pdf, we look for the msgs whose Content-Type: has one of the
+// following values
+// 1) application/pdf
+// 2) application/x-pdf
+//
+
+int has_eligible_HTTP_content (char* buf, int len, int type) {
+ char* ptr = buf;
+ char* matchptr;
+ int tjFlag=0, thFlag=0, ceFlag=0, teFlag=0, http304Flag=0, clZeroFlag=0, pdfFlag=0, swfFlag=0, gzipFlag=0;
+ char* end, *cp;
+
+#ifdef DEBUG
+ fprintf(stderr, "TESTING availabilty of js in payload ... \n");
+#endif
+
+ if (type != HTTP_CONTENT_JAVASCRIPT &&
+ type != HTTP_CONTENT_HTML &&
+ type != HTTP_CONTENT_PDF && type != HTTP_CONTENT_SWF)
+ return 0;
+
+ // assumption: buf is null-terminated
+ if (!strstr(buf, "\r\n\r\n"))
+ return 0;
+
+
+ while (1) {
+ end = strstr(ptr, "\r\n");
+ if (end == NULL) {
+ break;
+ }
+
+ if (!strncmp(ptr, "Content-Type:", 13)) {
+
+ if (!strncmp(ptr+14, "text/javascript", 15) ||
+ !strncmp(ptr+14, "application/javascript", 22) ||
+ !strncmp(ptr+14, "application/x-javascript", 24)) {
+ tjFlag = 1;
+ }
+ if (!strncmp(ptr+14, "text/html", 9)) {
+ thFlag = 1;
+ }
+ if (!strncmp(ptr+14, "application/pdf", 15) ||
+ !strncmp(ptr+14, "application/x-pdf", 17)) {
+ pdfFlag = 1;
+ }
+ if (!strncmp(ptr+14, "application/x-shockwave-flash", strlen("application/x-shockwave-flash"))) {
+ swfFlag = 1;
+ }
+
+ } else if (!strncmp(ptr, "Content-Encoding: gzip", 22)) {
+ gzipFlag = 1;
+ } else if (!strncmp(ptr, "Content-Encoding:", 17)) { // Content-Encoding that is not gzip
+ ceFlag = 1;
+ } else if (!strncmp(ptr, "Transfer-Encoding:", 18)) {
+ teFlag = 1;
+ } else if (!strncmp(ptr, "HTTP/1.1 304 ", 13)) {
+ http304Flag = 1;
+ } else if (!strncmp(ptr, "Content-Length: 0", 17)) {
+ clZeroFlag = 1;
+ }
+
+ if (!strncmp(end, "\r\n\r\n", 4)){
+ break;
+ }
+ ptr = end+2;
+ }
+
+#ifdef DEBUG
+ printf("tjFlag=%d; thFlag=%d; gzipFlag=%d; ceFlag=%d; teFlag=%d; http304Flag=%d; clZeroFlag=%d\n",
+ tjFlag, thFlag, gzipFlag, ceFlag, teFlag, http304Flag, clZeroFlag);
+#endif
+
+ // if (type == HTTP_CONTENT_JAVASCRIPT)
+ if (type == HTTP_CONTENT_JAVASCRIPT || type == HTTP_CONTENT_HTML) {
+ // empty body if it's HTTP not modified (304) or zero Content-Length
+ if (http304Flag || clZeroFlag) return 0;
+
+ // for now, we're not dealing with Transfer-Encoding (e.g., chunked)
+ // or Content-Encoding that is not gzip
+ // if (teFlag) return 0;
+ if (teFlag || ceFlag) return 0;
+
+ if (tjFlag && ceFlag && end != NULL) {
+ log_debug("(JS) gzip flag detected with hdr len %d", (int)(end-buf+4));
+ } else if (thFlag && ceFlag && end != NULL) {
+ log_debug("(HTML) gzip flag detected with hdr len %d", (int)(end-buf+4));
+ }
+
+ // case 1
+ if (tjFlag) return 1;
+
+ // case 2: check if HTTP body contains <script type="text/javascript">
+ if (thFlag) {
+ matchptr = strstr(ptr, "<script type=\"text/javascript\">");
+ if (matchptr != NULL) {
+ return 2;
+ }
+ }
+ }
+
+ if (type == HTTP_CONTENT_PDF && pdfFlag) {
+ // reject msg with empty body: HTTP not modified (304) or zero Content-Length
+ if (http304Flag || clZeroFlag) return 0;
+
+ // for now, we're not dealing with Transfer-Encoding (e.g., chunked)
+ // or Content-Encoding that is not gzip
+ // if (teFlag) return 0;
+ if (teFlag || ceFlag) return 0;
+
+ // check if HTTP body contains "endstream";
+ // strlen("endstream") == 9
+
+ cp = strInBinary("endstream", 9, ptr, buf+len-ptr);
+ if (cp != NULL) {
+ // log_debug("Matched endstream!");
+ return 1;
+ }
+ }
+
+ if (type == HTTP_CONTENT_SWF && swfFlag == 1 &&
+ ((len + buf - end) > SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 8))
+ return 1;
+
+ return 0;
+}
+
+
+
+unsigned int capacityPDF (char* buf, int len) {
+ char *hEnd, *bp, *streamStart, *streamEnd;
+ int cnt=0;
+ int size;
+
+ // jump to the beginning of the body of the HTTP message
+ hEnd = strstr(buf, "\r\n\r\n");
+ if (hEnd == NULL) {
+ // cannot find the separator between HTTP header and HTTP body
+ return 0;
+ }
+ bp = hEnd + 4;
+
+ while (bp < (buf+len)) {
+ streamStart = strInBinary("stream", 6, bp, (buf+len)-bp);
+ // streamStart = strstr(bp, "stream");
+ if (streamStart == NULL) break;
+ bp = streamStart+6;
+ streamEnd = strInBinary("endstream", 9, bp, (buf+len)-bp);
+ // streamEnd = strstr(bp, "endstream");
+ if (streamEnd == NULL) break;
+ // count the number of char between streamStart+6 and streamEnd
+ size = streamEnd - (streamStart+6) - 2; // 2 for \r\n before streamEnd
+ if (size > 0) {
+ cnt = cnt + size;
+ log_debug("capacity of pdf increase by %d", size);
+ }
+ bp += 9;
+ }
+ return cnt;
+}
+
+
+
+
+
+
+
+
+
+/*
+ * init_payload_pool initializes the arrays pertaining to
+ * message payloads for the specified content type
+ *
+ * Specifically, it populates the following arrays
+ * static int initTypePayload[MAX_CONTENT_TYPE];
+ * static int typePayloadCount[MAX_CONTENT_TYPE];
+ * static int typePayload[MAX_CONTENT_TYPE][MAX_PAYLOADS];
+ * static int typePayloadCap[MAX_CONTENT_TYPE][MAX_PAYLOADS];
+ *
+ * Input:
+ * len - max length of payload
+ * type - ptype field value in pentry_header
+ * contentType - (e.g, HTTP_CONTENT_JAVASCRIPT for JavaScript content)
+ */
+
+
+
+
+int init_JS_payload_pool(int len, int type, int minCapacity) {
+
+ // stat for usable payload
+ int minPayloadSize = 0, maxPayloadSize = 0;
+ int sumPayloadSize = 0;
+ int minPayloadCap = 0, maxPayloadCap = 0;
+ int sumPayloadCap = 0;
+
+ unsigned int contentType = HTTP_CONTENT_JAVASCRIPT;
+
+ int cnt = 0;
+ int r;
+ pentry_header* p;
+ char* msgbuf;
+ int cap;
+ int mode;
+
+
+
+ if (payload_count == 0) {
+ log_debug("payload_count == 0; forgot to run load_payloads()?\n");
+ return 0;
+ }
+
+ if (initTypePayload[contentType] != 0) return 1; // init is done already
+
+
+ for (r = 0; r < payload_count; r++) {
+ p = &payload_hdrs[r];
+ if (p->ptype != type || p->length > len) {
+ continue;
+ }
+
+ msgbuf = payloads[r];
+
+ mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_JAVASCRIPT);
+ if (mode == CONTENT_JAVASCRIPT) {
+
+ cap = capacityJS3(msgbuf, p->length, mode);
+ if (cap < JS_DELIMITER_SIZE)
+ continue;
+
+ cap = (cap - JS_DELIMITER_SIZE)/2;
+
+ if (cap > minCapacity) {
+ typePayloadCap[contentType][cnt] = cap; // (cap-JS_DELIMITER_SIZE)/2;
+ // because we use 2 hex char to encode every data byte, the available
+ // capacity for encoding data is divided by 2
+ typePayload[contentType][cnt] = r;
+ cnt++;
+
+ // update stat
+ if (cnt == 1) {
+ minPayloadSize = p->length; maxPayloadSize = p->length;
+ minPayloadCap = cap; maxPayloadCap = cap;
+ }
+ else {
+ if (minPayloadSize > p->length) minPayloadSize = p->length;
+ if (maxPayloadSize < p->length) maxPayloadSize = p->length;
+ if (minPayloadCap > cap) minPayloadCap = cap;
+ if (maxPayloadCap < cap) {
+ maxPayloadCap = cap;
+ }
+
+ }
+ sumPayloadSize += p->length; sumPayloadCap += cap;
+ }
+ }
+ }
+
+
+ max_JS_capacity = maxPayloadCap;
+
+
+ initTypePayload[contentType] = 1;
+ typePayloadCount[contentType] = cnt;
+ log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
+ contentType, typePayloadCount[contentType]);
+ log_debug("minPayloadSize = %d", minPayloadSize);
+ log_debug("maxPayloadSize = %d", maxPayloadSize);
+ log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
+ log_debug("minPayloadCap = %d", minPayloadCap);
+ log_debug("maxPayloadCap = %d", maxPayloadCap);
+ log_debug("avgPayloadCap = %f", (float)sumPayloadCap/(float)cnt);
+ return 1;
+}
+
+
+int init_HTML_payload_pool(int len, int type, int minCapacity) {
+
+ // stat for usable payload
+ int minPayloadSize = 0, maxPayloadSize = 0;
+ int sumPayloadSize = 0;
+ int minPayloadCap = 0, maxPayloadCap = 0;
+ int sumPayloadCap = 0;
+
+ unsigned int contentType = HTTP_CONTENT_HTML;
+
+ int cnt = 0;
+ int r;
+ pentry_header* p;
+ char* msgbuf;
+ int cap;
+ int mode;
+
+
+
+ if (payload_count == 0) {
+ log_debug("payload_count == 0; forgot to run load_payloads()?\n");
+ return 0;
+ }
+
+ if (initTypePayload[contentType] != 0) return 1; // init is done already
+
+
+ for (r = 0; r < payload_count; r++) {
+ p = &payload_hdrs[r];
+ if (p->ptype != type || p->length > len) {
+ continue;
+ }
+
+ msgbuf = payloads[r];
+
+ mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_HTML);
+ if (mode == CONTENT_HTML_JAVASCRIPT) {
+
+ cap = capacityJS3(msgbuf, p->length, mode);
+ if (cap < JS_DELIMITER_SIZE)
+ continue;
+
+ cap = (cap - JS_DELIMITER_SIZE)/2;
+
+ if (cap > minCapacity) {
+ typePayloadCap[contentType][cnt] = cap; // (cap-JS_DELIMITER_SIZE)/2;
+ // because we use 2 hex char to encode every data byte, the available
+ // capacity for encoding data is divided by 2
+ typePayload[contentType][cnt] = r;
+ cnt++;
+
+ // update stat
+ if (cnt == 1) {
+ minPayloadSize = p->length; maxPayloadSize = p->length;
+ minPayloadCap = cap; maxPayloadCap = cap;
+ }
+ else {
+ if (minPayloadSize > p->length) minPayloadSize = p->length;
+ if (maxPayloadSize < p->length) maxPayloadSize = p->length;
+ if (minPayloadCap > cap) minPayloadCap = cap;
+ if (maxPayloadCap < cap) {
+ maxPayloadCap = cap;
+ }
+
+ }
+ sumPayloadSize += p->length; sumPayloadCap += cap;
+ }
+ }
+ }
+
+
+ max_HTML_capacity = maxPayloadCap;
+
+
+ initTypePayload[contentType] = 1;
+ typePayloadCount[contentType] = cnt;
+ log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
+ contentType, typePayloadCount[contentType]);
+ log_debug("minPayloadSize = %d", minPayloadSize);
+ log_debug("maxPayloadSize = %d", maxPayloadSize);
+ log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
+ log_debug("minPayloadCap = %d", minPayloadCap);
+ log_debug("maxPayloadCap = %d", maxPayloadCap);
+ log_debug("avgPayloadCap = %f", (float)sumPayloadCap/(float)cnt);
+ return 1;
+}
+
+
+
+
+
+
+
+
+int init_PDF_payload_pool(int len, int type, int minCapacity) {
+
+ // stat for usable payload
+ int minPayloadSize = 0, maxPayloadSize = 0;
+ int sumPayloadSize = 0;
+ int minPayloadCap = 0, maxPayloadCap = 0;
+ int sumPayloadCap = 0;
+
+ int cnt = 0;
+ int r;
+ pentry_header* p;
+ char* msgbuf;
+ int cap;
+ int mode;
+ unsigned int contentType = HTTP_CONTENT_PDF;
+
+
+ if (payload_count == 0) {
+ fprintf(stderr, "payload_count == 0; forgot to run load_payloads()?\n");
+ return 0;
+ }
+
+ if (initTypePayload[contentType] != 0) return 1; // init is done already
+
+
+ for (r = 0; r < payload_count; r++) {
+ p = &payload_hdrs[r];
+ if (p->ptype != type || p->length > len) {
+ continue;
+ }
+
+ msgbuf = payloads[r];
+
+ mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_PDF);
+ if (mode > 0) {
+ // use capacityPDF() to find out the amount of data that we
+ // can encode in the pdf doc
+ // cap = minCapacity+1;
+ cap = capacityPDF(msgbuf, p->length);
+ log_debug("got pdf (index %d) with capacity %d", r, cap);
+ if (cap > minCapacity) {
+ log_debug("pdf (index %d) greater than mincapacity %d", cnt, minCapacity);
+ typePayloadCap[contentType][cnt] = (cap-PDF_DELIMITER_SIZE)/2;
+ typePayload[contentType][cnt] = r;
+ cnt++;
+
+ // update stat
+ if (cnt == 1) {
+ minPayloadSize = p->length; maxPayloadSize = p->length;
+ minPayloadCap = cap; maxPayloadCap = cap;
+ }
+ else {
+ if (minPayloadSize > p->length) minPayloadSize = p->length;
+ if (maxPayloadSize < p->length) maxPayloadSize = p->length;
+ if (minPayloadCap > cap) minPayloadCap = cap;
+ if (maxPayloadCap < cap) maxPayloadCap = cap;
+ }
+ sumPayloadSize += p->length; sumPayloadCap += cap;
+ }
+ }
+ }
+
+ max_PDF_capacity = maxPayloadCap;
+ initTypePayload[contentType] = 1;
+ typePayloadCount[contentType] = cnt;
+ log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
+ contentType, typePayloadCount[contentType]);
+ log_debug("minPayloadSize = %d", minPayloadSize);
+ log_debug("maxPayloadSize = %d", maxPayloadSize);
+ log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
+ log_debug("minPayloadCap = %d", minPayloadCap);
+ log_debug("maxPayloadCap = %d", maxPayloadCap);
+ log_debug("avgPayloadCap = %f", (float)sumPayloadCap/(float)cnt);
+ return 1;
+}
+
+
+
+
+
+int init_SWF_payload_pool(int len, int type, int minCapacity) {
+
+ // stat for usable payload
+ int minPayloadSize = 0, maxPayloadSize = 0;
+ int sumPayloadSize = 0;
+
+ int cnt = 0;
+ int r;
+ pentry_header* p;
+ char* msgbuf;
+ int mode;
+ unsigned int contentType = HTTP_CONTENT_SWF;
+
+
+ if (payload_count == 0) {
+ fprintf(stderr, "payload_count == 0; forgot to run load_payloads()?\n");
+ return 0;
+ }
+
+ if (initTypePayload[contentType] != 0) return 1; // init is done already
+
+
+ for (r = 0; r < payload_count; r++) {
+ p = &payload_hdrs[r];
+ if (p->ptype != type || p->length > len) {
+ continue;
+ }
+
+ msgbuf = payloads[r];
+ // found a payload corr to the specified contentType
+
+ mode = has_eligible_HTTP_content(msgbuf, p->length, HTTP_CONTENT_SWF);
+ if (mode > 0) {
+ typePayload[contentType][cnt] = r;
+ cnt++;
+ // update stat
+ if (cnt == 1) {
+ minPayloadSize = p->length;
+ maxPayloadSize = p->length;
+ }
+ else {
+ if (minPayloadSize > p->length)
+ minPayloadSize = p->length;
+ if (maxPayloadSize < p->length)
+ maxPayloadSize = p->length;
+ }
+ sumPayloadSize += p->length;
+ }
+ }
+
+ initTypePayload[contentType] = 1;
+ typePayloadCount[contentType] = cnt;
+ log_debug("init_payload_pool: typePayloadCount for contentType %d = %d",
+ contentType, typePayloadCount[contentType]);
+ log_debug("minPayloadSize = %d", minPayloadSize);
+ log_debug("maxPayloadSize = %d", maxPayloadSize);
+ log_debug("avgPayloadSize = %f", (float)sumPayloadSize/(float)cnt);
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+int get_next_payload (int contentType, char** buf, int* size, int* cap) {
+ int r;
+
+ log_debug("get_next_payload: contentType = %d, initTypePayload = %d, typePayloadCount = %d",
+ contentType, initTypePayload[contentType], typePayloadCount[contentType]);
+
+
+ if (contentType <= 0 ||
+ contentType >= MAX_CONTENT_TYPE ||
+ initTypePayload[contentType] == 0 ||
+ typePayloadCount[contentType] == 0)
+ return 0;
+
+ r = rand() % typePayloadCount[contentType];
+// int r = 1;
+// log_debug("SERVER: *** always choose the same payload ***");
+
+ log_debug("SERVER: picked payload with index %d", r);
+ *buf = payloads[typePayload[contentType][r]];
+ *size = payload_hdrs[typePayload[contentType][r]].length;
+ *cap = typePayloadCap[contentType][r];
+ return 1;
+}
+
+
+
+
+
+
+
+
+int get_payload (int contentType, int cap, char** buf, int* size) {
+ int r;
+ unsigned int i = 0;
+ unsigned int cnt = 0;
+
+ log_debug("get_payload: contentType = %d, initTypePayload = %d, typePayloadCount = %d",
+ contentType, initTypePayload[contentType], typePayloadCount[contentType]);
+
+
+ if (contentType <= 0 ||
+ contentType >= MAX_CONTENT_TYPE ||
+ initTypePayload[contentType] == 0 ||
+ typePayloadCount[contentType] == 0)
+ return 0;
+
+
+ cnt = typePayloadCount[contentType];
+ r = rand() % cnt;
+
+ for (i=0; i < cnt; i++) {
+
+ if (typePayloadCap[contentType][(r+i) % cnt] <= cap)
+ continue;
+
+ *buf = payloads[typePayload[contentType][(r+i)%cnt]];
+ *size = payload_hdrs[typePayload[contentType][(r+i)%cnt]].length;
+ return 1;
+ }
+
+
+
+ return 0;
+
+}
+
+
+
+
+int
+find_content_length (char *hdr, int hlen) {
+ char *clStart;
+ char* clEnd;
+ char *clValStart;
+ int valLen;
+ int contentLen;
+ char buf[10];
+
+ clStart = strstr(hdr, "Content-Length: ");
+ if (clStart == NULL) {
+ log_debug("Unable to find Content-Length in the header");
+ return -1;
+ }
+
+ clEnd = strstr((char *)clStart, "\r\n");
+ if (clEnd == NULL) {
+ log_debug("Unable to find end of line for Content-Length");
+ return -1;
+ }
+
+ // clValStart = clStart+strlen("Content-Length: ");
+ clValStart = clStart+16;
+
+ valLen = clEnd-clValStart;
+ if (valLen > 9) return -1;
+ memcpy(buf, clValStart, valLen);
+ buf[valLen] = 0;
+ contentLen = atoi(buf);
+ return contentLen;
+}
+
+
+
+
+
+
+/*
+
+void testOffset2Alnum_skipJSPattern () {
+ char s1[] = "for (i=0; i<10; i++) { print i; }";
+
+ char s2[] = "***abcde*****";
+ int d, i;
+
+ printf("s1 = %s\n", s1);
+ printf("s2 = %s\n", s2);
+
+
+ d = offset2Alnum_(s1, strlen(s1));
+ printf ("offset2Alnum_ for s1 = %d\n", d);
+ d = offset2Alnum_(s2, strlen(s2));
+ printf ("offset2Alnum_ for s2 = %d\n", d);
+
+ i = skipJSPattern (s1, strlen(s1));
+ printf ("skipJSPattern for s1 = %d\n", i);
+ i = skipJSPattern (s2, strlen(s2));
+ printf ("skipJSPattern for s2 = %d\n", i);
+}
+
+
+
+
+void testOffset2Hex () {
+ int d;
+ char s3[] = "for (bc=0; bc<10; bc++) { ad=2*bc+ad; }";
+ printf("len(s3)=%d; s3 = |%s|\n", (int)strlen(s3), s3);
+
+ d = offset2Alnum_(s3, strlen(s3));
+ printf ("offset2Alnum_ for s3 = %d\n", d);
+ d = offset2Hex(s3, strlen(s3), 0);
+ printf ("offset2Hex for s3 = %d\n", d);
+}
+
+
+void testCapacityJS () {
+ int d;
+ char s4[] = "\r\n\r\n abc = abc + 1;";
+ char s6[] = "\r\n\r\n <script type=\"text/javascript\">abc = abc + 1;</script>";
+
+ printf("\nTest for CONTENT_JAVASCRIPT:\n");
+ printf("len(s4)=%d; s4 = |%s|\n", (int)strlen(s4), s4);
+
+ d = offset2Alnum_(s4, strlen(s4));
+ printf ("offset2Alnum_ for s4 = %d\n", d);
+ d = offset2Hex(s4, strlen(s4), 0);
+ printf ("offset2Hex for s4 = %d\n", d);
+
+ printf("capacityJS (JS) returns %d\n", capacityJS(s4, strlen(s4), CONTENT_JAVASCRIPT));
+ printf("capacityJS3 (JS) returns %d\n", capacityJS3(s4, strlen(s4), CONTENT_JAVASCRIPT));
+
+ printf("\nTest for CONTENT_HTML_JAVASCRIPT:\n");
+ printf("len(s6)=%d; s6 = |%s|\n", (int)strlen(s6), s6);
+
+ d = offset2Alnum_(s6, strlen(s6));
+ printf ("offset2Alnum_ for s6 = %d\n", d);
+ d = offset2Hex(s6, strlen(s6), 0);
+ printf ("offset2Hex for s6 = %d\n", d);
+
+ printf("capacityJS (HTML) returns %d\n", capacityJS(s6, strlen(s6), CONTENT_HTML_JAVASCRIPT));
+ printf("capacityJS3 (HTML) returns %d\n", capacityJS3(s6, strlen(s6), CONTENT_HTML_JAVASCRIPT));
+}
+*/
+
+
+/*****
+int main() {
+ char buf[HTTP_MSG_BUF_SIZE];
+ bzero(buf, sizeof(buf));
+ // test for TYPE_HTTP_REQUEST
+ // load_payloads("../../traces/client.out");
+ // int len = find_client_payload(buf, 10000, TYPE_HTTP_REQUEST);
+ // printf("%s\n", buf);
+
+ // test for TYPE_HTTP_RESPONSE
+ // load_payloads("../../traces/server-cnn-nogzip.out");
+ // load_payloads("../../traces/server-portals.out"); // ptype==1?
+
+ // testOffset2Alnum_skipJSPattern();
+ // testOffset2Hex();
+ // testCapacityJS();
+
+ load_payloads("../../traces/server.out");
+ // int r;
+ // r = find_server_payload(&buf, sizeof(buf), TYPE_HTTP_RESPONSE, HTTP_CONTENT_JAVASCRIPT);
+ // if (r > 0) {
+ // printf("Available payload capablity %d\n", r);
+ // }
+ // return r;
+
+ return 0;
+}
+ *****/
+
diff --git a/src/steg/pdfSteg.c b/src/steg/pdfSteg.c
deleted file mode 100644
index 81efdf4..0000000
--- a/src/steg/pdfSteg.c
+++ /dev/null
@@ -1,630 +0,0 @@
-#include "payloads.h"
-#include "pdfSteg.h"
-
-void buf_dump(unsigned char* buf, int len, FILE *out);
-
-#define STREAM_BEGIN ">>stream"
-#define STREAM_BEGIN_SIZE 8
-#define STREAM_END "endstream"
-#define STREAM_END_SIZE 9
-
-#define DEBUG
-
-
-/*
- * pdfSteg: A PDF-based steganography module
- *
- */
-
-
-/*
- * addDelimiter processes the input buffer (inbuf) of length inbuflen,
- * copies it to output buffer (outbuf) of size outbufsize,
- * and adds a two-char-long, end-of-data pattern at the end of outbuf
- * based on delimiter1 and delimiter2.
- *
- * The end-of-data pattern consists of delimiter1 followed by a char
- * that is not delimiter1. Thus, delimiter1 and delimiter2 must be
- * different.
- *
- * If delimiter1 appears in the input buffer, addDelimiter puts two
- * delimiter1 char in output buffer (to enable removeDelimiter to perform
- * the back transformation)
- *
- * addDelimiter returns the length of the data written to outbuf, including
- * the end-of-data pattern, if the transformation succeeds;
- * otherwise, it returns -1
- *
- */
-int
-addDelimiter(char *inbuf, int inbuflen, char *outbuf, int outbuflen,
- const char delimiter1, const char delimiter2)
-{
- int cnt;
- char *ibp, ic, rc;
-
- if (delimiter1 == delimiter2) return -1;
-
- cnt = 0;
- ibp = inbuf;
- while ((ibp-inbuf)<inbuflen && cnt<(outbuflen-2)) {
- ic = *(ibp++);
- if (ic != delimiter1) {
- outbuf[cnt++] = ic;
- } else {
- outbuf[cnt++] = delimiter1;
- outbuf[cnt++] = delimiter1;
- }
- }
-
- // error if outbuf is no large enough for storing the resulting data
- if (cnt >= (outbuflen-2)) return -1;
-
- // put delimiter1 and a char that is not a delimiter1
- // as the end-of-data pattern at the end of outbuf
- outbuf[cnt++] = delimiter1;
- // try to get a random char (that is not delimiter1)
- rc = (char) (rand() % 256);
- if (rc != delimiter1) {
- outbuf[cnt++] = rc;
- } else { // unable to get a rand char != delimiter1, use delimiter2
- outbuf[cnt++] = delimiter2;
- }
- return cnt;
-}
-
-
-/*
- * removeDelimiter performs the reverse transformation of addDelimiter.
- *
- * returns the length of data written to outbuf, if succeed;
- * otherwise, it returns -1
- *
- * endFlag indicates whether the end-of-encoding byte pattern (i.e.,
- * delimiter1 followed by non-delimiter1) is detected
- *
- * escape indicates if a dangling delimiter1 has been
- * seen in the previous invocation of removeDelimiter
- */
-int
-removeDelimiter(char *inbuf, int inbuflen, char *outbuf, int outbuflen,
- const char delimiter1, int *endFlag, int *escape)
-{
- int cnt;
- char *ibp, ic1, ic2;
-
- cnt = 0;
- *endFlag = 0;
- ibp = inbuf;
-
- if (inbuflen <= 0) return -1;
-
- // special case: 2-char, end-of-data pattern could be in two buffers
- // if *escape == true, we need to see if
- // 1) (*ibp == delimiter1) -> put delimiter1 in outbuf
- // 2) (*ibp != delimiter1) -> end-of-data detected
- if (*escape) {
- ic1 = *ibp;
- if (ic1 == delimiter1) {
- outbuf[cnt++] = ic1; ibp++;
- } else {
- *endFlag = 1;
- return 0;
- }
- }
-
- *escape = 0;
- while ((ibp-inbuf+1)<inbuflen && cnt<outbuflen) {
- ic1 = *(ibp++);
- if (ic1 != delimiter1) {
- outbuf[cnt++] = ic1;
- } else {
- // lookahead 1 char
- ic2 = *ibp;
- // if the next char is delimiter1
- if (ic2 == delimiter1) {
- outbuf[cnt++] = delimiter1; ibp++;
- } else { // end-of-data pattern detected
- *endFlag = 1;
- return cnt;
- }
- }
- }
-
- if (ibp-inbuf == inbuflen) return cnt;
-
- // handling the last char in inbuf, if needed
- ic1 = *ibp;
- if (ic1 != delimiter1) {
- outbuf[cnt++] = ic1;
- } else {
- // look at the next stream obj to handle the special cases
- *escape = 1;
- }
-
- return cnt;
-}
-
-
-
-/*
- * pdfWrap embeds data of length dlen inside the stream objects of the PDF
- * document (length plen) that appears in the body of a HTTP msg, and
- * stores the result in the output buffer of size outsize
- *
- * pdfWrap returns the length of the pdf document with the data embedded
- * inside, if succeed; otherwise, it returns -1 to indicate an error
- *
- */
-int
-pdfWrap (char *data, unsigned int dlen,
- char *pdfTemplate, unsigned int plen,
- char *outbuf, unsigned int outbufsize)
-{
- char data2[dlen*2+2];
- char *tp, *dp, *op, *streamStart, *streamEnd, *plimit;
- int data2len, cnt, size, size2;
-
- // assumption: pdfWrap is length-preserving
- if (outbufsize < plen) return -1;
-
- data2len = addDelimiter(data, dlen, data2, HTTP_MSG_BUF_SIZE, PDF_DELIMITER, PDF_DELIMITER2);
- if (data2len < 1) return -1;
-
-
- op = outbuf; // current pointer for output buffer
- tp = pdfTemplate; // current pointer for http msg template
- dp = data2; // current pointer for data2
- cnt = 0; // number of data char encoded
- plimit = pdfTemplate+plen;
-
- while (tp < plimit) {
- // find the next stream obj
- streamStart = strInBinary(STREAM_BEGIN, STREAM_BEGIN_SIZE, tp, plimit-tp);
- if (streamStart == NULL) {
- log_warn("Cannot find stream in pdf");
- return -1;
- }
-
- // copy everything between tp and "stream" (inclusive) to outbuf
- size = streamStart - tp + STREAM_BEGIN_SIZE;
- memcpy(op, tp, size);
- op += size;
- tp = streamStart + STREAM_BEGIN_SIZE;
-
- streamEnd = strInBinary(STREAM_END, STREAM_END_SIZE, tp, plimit-tp);
- if (streamEnd == NULL) {
- log_warn("Cannot find endstream in pdf");
- return -1;
- }
-
- // count the number of usable char between tp and streamEnd
- size = streamEnd-tp;
-
- // encoding data in the stream obj
- if (size > 0) {
- size2 = data2len - cnt;
- if (size < size2) {
- memcpy(op, dp, size);
- op += size; tp += size; dp += size;
- memcpy(op, tp, STREAM_END_SIZE);
- op += STREAM_END_SIZE; tp += STREAM_END_SIZE;
- cnt += size;
- } else { // done encoding data
- memcpy(op, dp, size2);
- op += size2; tp += size2; dp += size2;
- cnt += size2;
- // printf("Encoded %d char in pdf. Done encoding\n", size2);
- break;
- }
- log_debug("Encoded %d char in pdf", size);
- } else { // empty stream
- memcpy(op, tp, STREAM_END_SIZE);
- op += STREAM_END_SIZE; tp += STREAM_END_SIZE;
- }
-
- if (cnt >= data2len) break; // this shouldn't happen ...
- }
-
- // copy the rest of pdfTemplate to outbuf
- size = plimit-tp;
- log_debug("copying the rest of pdfTemplate to outbuf (size %d)", size);
- memcpy(op, tp, size);
- op += size;
- return (op-outbuf);
-}
-
-
-
-
-/*
- * pdfUnwrap is the inverse operation of pdfWrap
- */
-int
-pdfUnwrap (char *data, unsigned int dlen,
- char *outbuf, unsigned int outbufsize)
-{
- char *dp, *op, *streamStart, *streamEnd, *dlimit, *olimit;
- int cnt, size, size2, endFlag;
- int escape = 0;
-
- dp = data; // current pointer for data
- op = outbuf; // current pointer for outbuf
- cnt = 0; // number of char decoded
- dlimit = data+dlen;
- olimit = outbuf+outbufsize;
-
- while (dp < dlimit) {
- // find the next stream obj
- streamStart = strInBinary(STREAM_BEGIN, STREAM_BEGIN_SIZE, dp, dlimit-dp);
- if (streamStart == NULL) {
- log_warn("Cannot find stream in pdf");
- return -1;
- }
-
- dp = streamStart + STREAM_BEGIN_SIZE;
- streamEnd = strInBinary(STREAM_END, STREAM_END_SIZE, dp, dlimit-dp);
- if (streamEnd == NULL) {
- log_warn("Cannot find endstream in pdf");
- return -1;
- }
-
- // count the number of usable char between tp and streamEnd
- size = streamEnd-dp;
-
- if (size > 0) {
- size2 = removeDelimiter(dp, size, op, olimit-op, PDF_DELIMITER, &endFlag, &escape);
- if (size2 < 0) {
- return -1;
- }
- cnt += size2;
- if (endFlag) { // Done decoding
- break;
- } else { // Continue decoding
- op += size2;
- dp = streamEnd + STREAM_END_SIZE;
- }
- } else { // empty stream obj
- dp = streamEnd + STREAM_END_SIZE;
- }
- }
-
- return cnt;
-}
-
-
-
-
-
-int x_http2_server_PDF_transmit (steg_t* s, struct evbuffer *source, conn_t *conn) {
-
- struct evbuffer *dest = conn_get_outbound(conn);
- size_t sbuflen = evbuffer_get_length(source);
- unsigned int mpdf;
- char *pdfTemplate = NULL, *hend;
- int pdfTemplateSize = 0;
- // char data1[HTTP_MSG_BUF_SIZE];
- char data1[(int) sbuflen];
- char outbuf[HTTP_MSG_BUF_SIZE];
- int cnt, hLen, outbuflen, i;
-
- char newHdr[MAX_RESP_HDR_SIZE];
- int newHdrLen = 0;
-
- struct evbuffer_iovec *iv;
- int nv;
-
- // for debugging pdfWrap and pdfUnwrap
- // char data2[(int) sbuflen];
- // int data2len;
-
- log_debug("Entering SERVER PDF transmit with sbuflen %d", (int)sbuflen);
-
- nv = evbuffer_peek(source, sbuflen, NULL, NULL, 0);
- iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
-
- if (evbuffer_peek(source, sbuflen, NULL, iv, nv) != nv) {
- free(iv);
- return -1;
- }
-
- cnt = 0;
- for (i = 0; i < nv; i++) {
- const unsigned char *p = iv[i].iov_base;
- const unsigned char *limit = p + iv[i].iov_len;
- while (p < limit && cnt < (int)sbuflen) {
- data1[cnt++] = *p++;
- }
- }
-
- free(iv);
-
- log_debug("SERVER sbuflen = %d; cnt = %d", (int)sbuflen, cnt);
-
- mpdf = get_max_PDF_capacity();
-
- if (mpdf <= 0) {
- log_warn("SERVER ERROR: No pdfTemplate found\n");
- return -1;
- }
-
- if (sbuflen > (size_t) mpdf) {
- log_warn("SERVER ERROR: pdfTemplate cannot accommodate data %d %dn",
- (int) sbuflen, (int) mpdf);
- return -1;
- }
-
- if (get_payload(HTTP_CONTENT_PDF, sbuflen, &pdfTemplate, &pdfTemplateSize) == 1) {
- log_debug("SERVER found the next HTTP response template with size %d", pdfTemplateSize);
- } else {
- log_warn("SERVER couldn't find the next HTTP response template");
- return -1;
- }
-
- hend = strstr(pdfTemplate, "\r\n\r\n");
- if (hend == NULL) {
- log_warn("SERVER unable to find end of header in the HTTP template");
- return -1;
- }
-
- hLen = hend+4-pdfTemplate;
-
- log_debug("SERVER calling pdfWrap for data1 with length %d", cnt);
- outbuflen = pdfWrap(data1, cnt, hend+4, pdfTemplateSize-hLen, outbuf, HTTP_MSG_BUF_SIZE);
- if (outbuflen < 0) {
- log_warn("SERVER pdfWrap fails");
- return -1;
- }
- log_debug("SERVER pdfSteg sends resp with hdr len %d body len %d", hLen, outbuflen);
-
-
- // debugging
- // buf_dump((unsigned char *)data1, cnt, stderr);
-
- // data2len = pdfUnwrap(outbuf, outbuflen, data2, sbuflen);
- // if ((int)sbuflen == data2len) {
- // log_warn("sbuflen == data2len == %d", (int)sbuflen);
- // if (memcmp(data1, data2, sbuflen) == 0) {
- // log_warn("data1 and data2 match");
- // } else {
- // log_warn("data1 and data2 DO NOT match!! Dumping data1 ...");
- // buf_dump((unsigned char *)data1, cnt, stderr);
- // log_warn("data1 and data2 DO NOT match!! Dumping data2...");
- // buf_dump((unsigned char *)data2, data2len, stderr);
- // }
- // } else {
- // log_warn("*** sbuflen = %d, data2len = %d *** Dumping data1 ...", (int)sbuflen, data2len);
- // buf_dump((unsigned char *)data1, cnt, stderr);
- // log_warn("*** sbuflen = %d, data2len = %d *** Dumping data2 ...", (int)sbuflen, data2len);
- // buf_dump((unsigned char *)data2, data2len, stderr);
- // }
-
-
- newHdrLen = gen_response_header((char*) "application/pdf", 0, outbuflen, newHdr, sizeof(newHdr));
- if (newHdrLen < 0) {
- log_warn("SERVER ERROR: gen_response_header fails for pdfSteg");
- return -1;
- }
-
- if (evbuffer_add(dest, newHdr, newHdrLen)) {
- log_warn("SERVER ERROR: evbuffer_add() fails for newHdr");
- return -1;
- }
- // if (evbuffer_add(dest, pdfTemplate, hLen)) {
- // log_warn("SERVER ERROR: evbuffer_add() fails for pdfTemplate");
- // return -1;
- // }
-
- if (evbuffer_add(dest, outbuf, outbuflen)) {
- log_warn("SERVER ERROR: evbuffer_add() fails for outbuf");
- return -1;
- }
-
- evbuffer_drain(source, sbuflen);
-
- conn_close_after_transmit(conn);
- // downcast_steg(s)->have_transmitted = 1;
- return 0;
-}
-
-
-
-int
-x_http2_handle_client_PDF_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
- struct evbuffer_ptr s2;
- unsigned int response_len = 0, hdrLen;
- char outbuf[HTTP_MSG_BUF_SIZE];
- int content_len = 0, outbuflen;
- char *httpHdr, *httpBody;
-
- log_debug("Entering CLIENT PDF receive");
-
- s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
- if (s2.pos == -1) {
- log_warn("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
- // evbuffer_dump(source, stderr);
- return RECV_INCOMPLETE;
- }
-
- log_debug("CLIENT received response header with len %d", (int)s2.pos);
-
- response_len = 0;
- hdrLen = s2.pos + strlen("\r\n\r\n");
- response_len += hdrLen;
-
- httpHdr = (char *) evbuffer_pullup(source, s2.pos);
- if (httpHdr == NULL) {
- log_warn("CLIENT unable to pullup the complete HTTP header");
- return RECV_BAD;
- }
-
- content_len = find_content_length(httpHdr, hdrLen);
- if (content_len < 0) {
- log_warn("CLIENT unable to find content length");
- return RECV_BAD;
- }
- log_debug("CLIENT received Content-Length = %d\n", content_len);
-
- response_len += content_len;
-
- if (response_len > evbuffer_get_length(source))
- return RECV_INCOMPLETE;
-
- httpHdr = (char *) evbuffer_pullup(source, response_len);
-
- if (httpHdr == NULL) {
- log_warn("CLIENT unable to pullup the complete HTTP body");
- return RECV_BAD;
- }
-
-
- httpBody = httpHdr + hdrLen;
-
-
- outbuflen = pdfUnwrap(httpBody, content_len, outbuf, HTTP_MSG_BUF_SIZE);
- if (outbuflen < 0) {
- log_warn("CLIENT ERROR: pdfUnwrap fails\n");
- return RECV_BAD;
- }
-
- log_debug("CLIENT unwrapped data of length %d:", outbuflen);
-
-
- if (evbuffer_add(dest, outbuf, outbuflen)) {
- log_warn("CLIENT ERROR: evbuffer_add to dest fails\n");
- return RECV_BAD;
- }
-
- // log_debug("Drained source for %d char\n", response_len);
- if (evbuffer_drain(source, response_len) == -1) {
- log_warn("CLIENT ERROR: failed to drain source\n");
- return RECV_BAD;
- }
-
- // downcast_steg(s)->have_received = 1;
- conn_expect_close(conn);
- return RECV_GOOD;
-}
-
-
-
-
-/*****
-int main() {
- char data1[] = "this is a test?? yes!";
- char data2[100];
- char data3[100];
- int dlen1, dlen2, dlen3, end;
- char last = ' ';
- printf("hello world\n");
-
- dlen2 = addDelimiter(data1, strlen(data1), data2, 100, '?', '.');
- printf("dlen2 = %d\n", dlen2);
- dlen3 = removeDelimiter(data2, dlen2, data3, 100, '?', &end, &last);
- printf("endflag = %d", end);
- printf("dlen3 = %d\n", dlen3);
- if (memcmp(data1, data3, dlen3) == 0) {
- data1[dlen3] = 0;
- printf("removeDelimiter(addDelimiter(x)) == x for |%s|\n", data1);
- } else {
- printf("removeDelimiter(addDelimiter(x)) != x for |%s|\n", data1);
- }
- return 1;
-}
- *****/
-
-/*****
-int main() {
- char data1[] = "12345";
- char data2[] = "123456789012";
- char data3[] = "12345678901";
- char data4[] = "1234567890?";
- char pdf1[] = "[PDFHDR][STUFFS1]>>streamABCDEFGHIJYYendstream[STUFFS2]>>streamABCDEFGHIJYYendstream[STUFF3][PDFTRAILER]";
- char out[200];
- char orig[200];
- int r1, r2;
-
- printf("********************\n");
- printf("pdfwrap for %s\n", data1);
- printf("strlen(pdf1) = %d\n", (int)strlen(pdf1));
- r1 = pdfWrap(data1, strlen(data1), pdf1, strlen(pdf1), out, (int)sizeof(out));
- if (r1 > 0) {
- printf("pdfWrap returns %d\n", r1);
- out[r1] = 0;
- printf("out[] contains |%s|\n", out);
- } else {
- printf("pdfWrap returns %d\n", r1);
- }
-
- r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
- if (r2 > 0) {
- printf("pdfUnwrap returns %d\n", r2);
- orig[r2] = 0;
- printf("orig[] contains |%s|\n", orig);
- } else {
- printf("pdfUnwrap returns %d\n", r2);
- }
-
- printf("********************\n");
- printf("pdfwrap for %s\n", data2);
- r1 = pdfWrap(data2, strlen(data2), pdf1, strlen(pdf1), out, (int)sizeof(out));
- if (r1 > 0) {
- printf("pdfWrap returns %d\n", r1);
- out[r1] = 0;
- printf("out[] contains |%s|\n", out);
- } else {
- printf("pdfWrap returns %d\n", r1);
- }
-
- r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
- if (r2 > 0) {
- printf("pdfUnwrap returns %d\n", r2);
- orig[r2] = 0;
- printf("orig[] contains |%s|\n", orig);
- } else {
- printf("pdfUnwrap returns %d\n", r2);
- }
-
- printf("********************\n");
- printf("pdfwrap for %s\n", data3);
- r1 = pdfWrap(data3, strlen(data3), pdf1, strlen(pdf1), out, (int)sizeof(out));
- if (r1 > 0) {
- printf("pdfWrap returns %d\n", r1);
- out[r1] = 0;
- printf("out[] contains |%s|\n", out);
- } else {
- printf("pdfWrap returns %d\n", r1);
- }
-
- r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
- if (r2 > 0) {
- printf("pdfUnwrap returns %d\n", r2);
- orig[r2] = 0;
- printf("orig[] contains |%s|\n", orig);
- } else {
- printf("pdfUnwrap returns %d\n", r2);
- }
-
- printf("********************\n");
- printf("pdfwrap for %s\n", data4);
- r1 = pdfWrap(data4, strlen(data4), pdf1, strlen(pdf1), out, (int)sizeof(out));
- if (r1 > 0) {
- printf("pdfWrap returns %d\n", r1);
- out[r1] = 0;
- printf("out[] contains |%s|\n", out);
- } else {
- printf("pdfWrap returns %d\n", r1);
- }
-
- r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
- if (r2 > 0) {
- printf("pdfUnwrap returns %d\n", r2);
- orig[r2] = 0;
- printf("orig[] contains |%s|\n", orig);
- } else {
- printf("pdfUnwrap returns %d\n", r2);
- }
-
- return 0;
-}
- *****/
diff --git a/src/steg/pdfSteg.cc b/src/steg/pdfSteg.cc
new file mode 100644
index 0000000..81efdf4
--- /dev/null
+++ b/src/steg/pdfSteg.cc
@@ -0,0 +1,630 @@
+#include "payloads.h"
+#include "pdfSteg.h"
+
+void buf_dump(unsigned char* buf, int len, FILE *out);
+
+#define STREAM_BEGIN ">>stream"
+#define STREAM_BEGIN_SIZE 8
+#define STREAM_END "endstream"
+#define STREAM_END_SIZE 9
+
+#define DEBUG
+
+
+/*
+ * pdfSteg: A PDF-based steganography module
+ *
+ */
+
+
+/*
+ * addDelimiter processes the input buffer (inbuf) of length inbuflen,
+ * copies it to output buffer (outbuf) of size outbufsize,
+ * and adds a two-char-long, end-of-data pattern at the end of outbuf
+ * based on delimiter1 and delimiter2.
+ *
+ * The end-of-data pattern consists of delimiter1 followed by a char
+ * that is not delimiter1. Thus, delimiter1 and delimiter2 must be
+ * different.
+ *
+ * If delimiter1 appears in the input buffer, addDelimiter puts two
+ * delimiter1 char in output buffer (to enable removeDelimiter to perform
+ * the back transformation)
+ *
+ * addDelimiter returns the length of the data written to outbuf, including
+ * the end-of-data pattern, if the transformation succeeds;
+ * otherwise, it returns -1
+ *
+ */
+int
+addDelimiter(char *inbuf, int inbuflen, char *outbuf, int outbuflen,
+ const char delimiter1, const char delimiter2)
+{
+ int cnt;
+ char *ibp, ic, rc;
+
+ if (delimiter1 == delimiter2) return -1;
+
+ cnt = 0;
+ ibp = inbuf;
+ while ((ibp-inbuf)<inbuflen && cnt<(outbuflen-2)) {
+ ic = *(ibp++);
+ if (ic != delimiter1) {
+ outbuf[cnt++] = ic;
+ } else {
+ outbuf[cnt++] = delimiter1;
+ outbuf[cnt++] = delimiter1;
+ }
+ }
+
+ // error if outbuf is no large enough for storing the resulting data
+ if (cnt >= (outbuflen-2)) return -1;
+
+ // put delimiter1 and a char that is not a delimiter1
+ // as the end-of-data pattern at the end of outbuf
+ outbuf[cnt++] = delimiter1;
+ // try to get a random char (that is not delimiter1)
+ rc = (char) (rand() % 256);
+ if (rc != delimiter1) {
+ outbuf[cnt++] = rc;
+ } else { // unable to get a rand char != delimiter1, use delimiter2
+ outbuf[cnt++] = delimiter2;
+ }
+ return cnt;
+}
+
+
+/*
+ * removeDelimiter performs the reverse transformation of addDelimiter.
+ *
+ * returns the length of data written to outbuf, if succeed;
+ * otherwise, it returns -1
+ *
+ * endFlag indicates whether the end-of-encoding byte pattern (i.e.,
+ * delimiter1 followed by non-delimiter1) is detected
+ *
+ * escape indicates if a dangling delimiter1 has been
+ * seen in the previous invocation of removeDelimiter
+ */
+int
+removeDelimiter(char *inbuf, int inbuflen, char *outbuf, int outbuflen,
+ const char delimiter1, int *endFlag, int *escape)
+{
+ int cnt;
+ char *ibp, ic1, ic2;
+
+ cnt = 0;
+ *endFlag = 0;
+ ibp = inbuf;
+
+ if (inbuflen <= 0) return -1;
+
+ // special case: 2-char, end-of-data pattern could be in two buffers
+ // if *escape == true, we need to see if
+ // 1) (*ibp == delimiter1) -> put delimiter1 in outbuf
+ // 2) (*ibp != delimiter1) -> end-of-data detected
+ if (*escape) {
+ ic1 = *ibp;
+ if (ic1 == delimiter1) {
+ outbuf[cnt++] = ic1; ibp++;
+ } else {
+ *endFlag = 1;
+ return 0;
+ }
+ }
+
+ *escape = 0;
+ while ((ibp-inbuf+1)<inbuflen && cnt<outbuflen) {
+ ic1 = *(ibp++);
+ if (ic1 != delimiter1) {
+ outbuf[cnt++] = ic1;
+ } else {
+ // lookahead 1 char
+ ic2 = *ibp;
+ // if the next char is delimiter1
+ if (ic2 == delimiter1) {
+ outbuf[cnt++] = delimiter1; ibp++;
+ } else { // end-of-data pattern detected
+ *endFlag = 1;
+ return cnt;
+ }
+ }
+ }
+
+ if (ibp-inbuf == inbuflen) return cnt;
+
+ // handling the last char in inbuf, if needed
+ ic1 = *ibp;
+ if (ic1 != delimiter1) {
+ outbuf[cnt++] = ic1;
+ } else {
+ // look at the next stream obj to handle the special cases
+ *escape = 1;
+ }
+
+ return cnt;
+}
+
+
+
+/*
+ * pdfWrap embeds data of length dlen inside the stream objects of the PDF
+ * document (length plen) that appears in the body of a HTTP msg, and
+ * stores the result in the output buffer of size outsize
+ *
+ * pdfWrap returns the length of the pdf document with the data embedded
+ * inside, if succeed; otherwise, it returns -1 to indicate an error
+ *
+ */
+int
+pdfWrap (char *data, unsigned int dlen,
+ char *pdfTemplate, unsigned int plen,
+ char *outbuf, unsigned int outbufsize)
+{
+ char data2[dlen*2+2];
+ char *tp, *dp, *op, *streamStart, *streamEnd, *plimit;
+ int data2len, cnt, size, size2;
+
+ // assumption: pdfWrap is length-preserving
+ if (outbufsize < plen) return -1;
+
+ data2len = addDelimiter(data, dlen, data2, HTTP_MSG_BUF_SIZE, PDF_DELIMITER, PDF_DELIMITER2);
+ if (data2len < 1) return -1;
+
+
+ op = outbuf; // current pointer for output buffer
+ tp = pdfTemplate; // current pointer for http msg template
+ dp = data2; // current pointer for data2
+ cnt = 0; // number of data char encoded
+ plimit = pdfTemplate+plen;
+
+ while (tp < plimit) {
+ // find the next stream obj
+ streamStart = strInBinary(STREAM_BEGIN, STREAM_BEGIN_SIZE, tp, plimit-tp);
+ if (streamStart == NULL) {
+ log_warn("Cannot find stream in pdf");
+ return -1;
+ }
+
+ // copy everything between tp and "stream" (inclusive) to outbuf
+ size = streamStart - tp + STREAM_BEGIN_SIZE;
+ memcpy(op, tp, size);
+ op += size;
+ tp = streamStart + STREAM_BEGIN_SIZE;
+
+ streamEnd = strInBinary(STREAM_END, STREAM_END_SIZE, tp, plimit-tp);
+ if (streamEnd == NULL) {
+ log_warn("Cannot find endstream in pdf");
+ return -1;
+ }
+
+ // count the number of usable char between tp and streamEnd
+ size = streamEnd-tp;
+
+ // encoding data in the stream obj
+ if (size > 0) {
+ size2 = data2len - cnt;
+ if (size < size2) {
+ memcpy(op, dp, size);
+ op += size; tp += size; dp += size;
+ memcpy(op, tp, STREAM_END_SIZE);
+ op += STREAM_END_SIZE; tp += STREAM_END_SIZE;
+ cnt += size;
+ } else { // done encoding data
+ memcpy(op, dp, size2);
+ op += size2; tp += size2; dp += size2;
+ cnt += size2;
+ // printf("Encoded %d char in pdf. Done encoding\n", size2);
+ break;
+ }
+ log_debug("Encoded %d char in pdf", size);
+ } else { // empty stream
+ memcpy(op, tp, STREAM_END_SIZE);
+ op += STREAM_END_SIZE; tp += STREAM_END_SIZE;
+ }
+
+ if (cnt >= data2len) break; // this shouldn't happen ...
+ }
+
+ // copy the rest of pdfTemplate to outbuf
+ size = plimit-tp;
+ log_debug("copying the rest of pdfTemplate to outbuf (size %d)", size);
+ memcpy(op, tp, size);
+ op += size;
+ return (op-outbuf);
+}
+
+
+
+
+/*
+ * pdfUnwrap is the inverse operation of pdfWrap
+ */
+int
+pdfUnwrap (char *data, unsigned int dlen,
+ char *outbuf, unsigned int outbufsize)
+{
+ char *dp, *op, *streamStart, *streamEnd, *dlimit, *olimit;
+ int cnt, size, size2, endFlag;
+ int escape = 0;
+
+ dp = data; // current pointer for data
+ op = outbuf; // current pointer for outbuf
+ cnt = 0; // number of char decoded
+ dlimit = data+dlen;
+ olimit = outbuf+outbufsize;
+
+ while (dp < dlimit) {
+ // find the next stream obj
+ streamStart = strInBinary(STREAM_BEGIN, STREAM_BEGIN_SIZE, dp, dlimit-dp);
+ if (streamStart == NULL) {
+ log_warn("Cannot find stream in pdf");
+ return -1;
+ }
+
+ dp = streamStart + STREAM_BEGIN_SIZE;
+ streamEnd = strInBinary(STREAM_END, STREAM_END_SIZE, dp, dlimit-dp);
+ if (streamEnd == NULL) {
+ log_warn("Cannot find endstream in pdf");
+ return -1;
+ }
+
+ // count the number of usable char between tp and streamEnd
+ size = streamEnd-dp;
+
+ if (size > 0) {
+ size2 = removeDelimiter(dp, size, op, olimit-op, PDF_DELIMITER, &endFlag, &escape);
+ if (size2 < 0) {
+ return -1;
+ }
+ cnt += size2;
+ if (endFlag) { // Done decoding
+ break;
+ } else { // Continue decoding
+ op += size2;
+ dp = streamEnd + STREAM_END_SIZE;
+ }
+ } else { // empty stream obj
+ dp = streamEnd + STREAM_END_SIZE;
+ }
+ }
+
+ return cnt;
+}
+
+
+
+
+
+int x_http2_server_PDF_transmit (steg_t* s, struct evbuffer *source, conn_t *conn) {
+
+ struct evbuffer *dest = conn_get_outbound(conn);
+ size_t sbuflen = evbuffer_get_length(source);
+ unsigned int mpdf;
+ char *pdfTemplate = NULL, *hend;
+ int pdfTemplateSize = 0;
+ // char data1[HTTP_MSG_BUF_SIZE];
+ char data1[(int) sbuflen];
+ char outbuf[HTTP_MSG_BUF_SIZE];
+ int cnt, hLen, outbuflen, i;
+
+ char newHdr[MAX_RESP_HDR_SIZE];
+ int newHdrLen = 0;
+
+ struct evbuffer_iovec *iv;
+ int nv;
+
+ // for debugging pdfWrap and pdfUnwrap
+ // char data2[(int) sbuflen];
+ // int data2len;
+
+ log_debug("Entering SERVER PDF transmit with sbuflen %d", (int)sbuflen);
+
+ nv = evbuffer_peek(source, sbuflen, NULL, NULL, 0);
+ iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
+
+ if (evbuffer_peek(source, sbuflen, NULL, iv, nv) != nv) {
+ free(iv);
+ return -1;
+ }
+
+ cnt = 0;
+ for (i = 0; i < nv; i++) {
+ const unsigned char *p = iv[i].iov_base;
+ const unsigned char *limit = p + iv[i].iov_len;
+ while (p < limit && cnt < (int)sbuflen) {
+ data1[cnt++] = *p++;
+ }
+ }
+
+ free(iv);
+
+ log_debug("SERVER sbuflen = %d; cnt = %d", (int)sbuflen, cnt);
+
+ mpdf = get_max_PDF_capacity();
+
+ if (mpdf <= 0) {
+ log_warn("SERVER ERROR: No pdfTemplate found\n");
+ return -1;
+ }
+
+ if (sbuflen > (size_t) mpdf) {
+ log_warn("SERVER ERROR: pdfTemplate cannot accommodate data %d %dn",
+ (int) sbuflen, (int) mpdf);
+ return -1;
+ }
+
+ if (get_payload(HTTP_CONTENT_PDF, sbuflen, &pdfTemplate, &pdfTemplateSize) == 1) {
+ log_debug("SERVER found the next HTTP response template with size %d", pdfTemplateSize);
+ } else {
+ log_warn("SERVER couldn't find the next HTTP response template");
+ return -1;
+ }
+
+ hend = strstr(pdfTemplate, "\r\n\r\n");
+ if (hend == NULL) {
+ log_warn("SERVER unable to find end of header in the HTTP template");
+ return -1;
+ }
+
+ hLen = hend+4-pdfTemplate;
+
+ log_debug("SERVER calling pdfWrap for data1 with length %d", cnt);
+ outbuflen = pdfWrap(data1, cnt, hend+4, pdfTemplateSize-hLen, outbuf, HTTP_MSG_BUF_SIZE);
+ if (outbuflen < 0) {
+ log_warn("SERVER pdfWrap fails");
+ return -1;
+ }
+ log_debug("SERVER pdfSteg sends resp with hdr len %d body len %d", hLen, outbuflen);
+
+
+ // debugging
+ // buf_dump((unsigned char *)data1, cnt, stderr);
+
+ // data2len = pdfUnwrap(outbuf, outbuflen, data2, sbuflen);
+ // if ((int)sbuflen == data2len) {
+ // log_warn("sbuflen == data2len == %d", (int)sbuflen);
+ // if (memcmp(data1, data2, sbuflen) == 0) {
+ // log_warn("data1 and data2 match");
+ // } else {
+ // log_warn("data1 and data2 DO NOT match!! Dumping data1 ...");
+ // buf_dump((unsigned char *)data1, cnt, stderr);
+ // log_warn("data1 and data2 DO NOT match!! Dumping data2...");
+ // buf_dump((unsigned char *)data2, data2len, stderr);
+ // }
+ // } else {
+ // log_warn("*** sbuflen = %d, data2len = %d *** Dumping data1 ...", (int)sbuflen, data2len);
+ // buf_dump((unsigned char *)data1, cnt, stderr);
+ // log_warn("*** sbuflen = %d, data2len = %d *** Dumping data2 ...", (int)sbuflen, data2len);
+ // buf_dump((unsigned char *)data2, data2len, stderr);
+ // }
+
+
+ newHdrLen = gen_response_header((char*) "application/pdf", 0, outbuflen, newHdr, sizeof(newHdr));
+ if (newHdrLen < 0) {
+ log_warn("SERVER ERROR: gen_response_header fails for pdfSteg");
+ return -1;
+ }
+
+ if (evbuffer_add(dest, newHdr, newHdrLen)) {
+ log_warn("SERVER ERROR: evbuffer_add() fails for newHdr");
+ return -1;
+ }
+ // if (evbuffer_add(dest, pdfTemplate, hLen)) {
+ // log_warn("SERVER ERROR: evbuffer_add() fails for pdfTemplate");
+ // return -1;
+ // }
+
+ if (evbuffer_add(dest, outbuf, outbuflen)) {
+ log_warn("SERVER ERROR: evbuffer_add() fails for outbuf");
+ return -1;
+ }
+
+ evbuffer_drain(source, sbuflen);
+
+ conn_close_after_transmit(conn);
+ // downcast_steg(s)->have_transmitted = 1;
+ return 0;
+}
+
+
+
+int
+x_http2_handle_client_PDF_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
+ struct evbuffer_ptr s2;
+ unsigned int response_len = 0, hdrLen;
+ char outbuf[HTTP_MSG_BUF_SIZE];
+ int content_len = 0, outbuflen;
+ char *httpHdr, *httpBody;
+
+ log_debug("Entering CLIENT PDF receive");
+
+ s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
+ if (s2.pos == -1) {
+ log_warn("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
+ // evbuffer_dump(source, stderr);
+ return RECV_INCOMPLETE;
+ }
+
+ log_debug("CLIENT received response header with len %d", (int)s2.pos);
+
+ response_len = 0;
+ hdrLen = s2.pos + strlen("\r\n\r\n");
+ response_len += hdrLen;
+
+ httpHdr = (char *) evbuffer_pullup(source, s2.pos);
+ if (httpHdr == NULL) {
+ log_warn("CLIENT unable to pullup the complete HTTP header");
+ return RECV_BAD;
+ }
+
+ content_len = find_content_length(httpHdr, hdrLen);
+ if (content_len < 0) {
+ log_warn("CLIENT unable to find content length");
+ return RECV_BAD;
+ }
+ log_debug("CLIENT received Content-Length = %d\n", content_len);
+
+ response_len += content_len;
+
+ if (response_len > evbuffer_get_length(source))
+ return RECV_INCOMPLETE;
+
+ httpHdr = (char *) evbuffer_pullup(source, response_len);
+
+ if (httpHdr == NULL) {
+ log_warn("CLIENT unable to pullup the complete HTTP body");
+ return RECV_BAD;
+ }
+
+
+ httpBody = httpHdr + hdrLen;
+
+
+ outbuflen = pdfUnwrap(httpBody, content_len, outbuf, HTTP_MSG_BUF_SIZE);
+ if (outbuflen < 0) {
+ log_warn("CLIENT ERROR: pdfUnwrap fails\n");
+ return RECV_BAD;
+ }
+
+ log_debug("CLIENT unwrapped data of length %d:", outbuflen);
+
+
+ if (evbuffer_add(dest, outbuf, outbuflen)) {
+ log_warn("CLIENT ERROR: evbuffer_add to dest fails\n");
+ return RECV_BAD;
+ }
+
+ // log_debug("Drained source for %d char\n", response_len);
+ if (evbuffer_drain(source, response_len) == -1) {
+ log_warn("CLIENT ERROR: failed to drain source\n");
+ return RECV_BAD;
+ }
+
+ // downcast_steg(s)->have_received = 1;
+ conn_expect_close(conn);
+ return RECV_GOOD;
+}
+
+
+
+
+/*****
+int main() {
+ char data1[] = "this is a test?? yes!";
+ char data2[100];
+ char data3[100];
+ int dlen1, dlen2, dlen3, end;
+ char last = ' ';
+ printf("hello world\n");
+
+ dlen2 = addDelimiter(data1, strlen(data1), data2, 100, '?', '.');
+ printf("dlen2 = %d\n", dlen2);
+ dlen3 = removeDelimiter(data2, dlen2, data3, 100, '?', &end, &last);
+ printf("endflag = %d", end);
+ printf("dlen3 = %d\n", dlen3);
+ if (memcmp(data1, data3, dlen3) == 0) {
+ data1[dlen3] = 0;
+ printf("removeDelimiter(addDelimiter(x)) == x for |%s|\n", data1);
+ } else {
+ printf("removeDelimiter(addDelimiter(x)) != x for |%s|\n", data1);
+ }
+ return 1;
+}
+ *****/
+
+/*****
+int main() {
+ char data1[] = "12345";
+ char data2[] = "123456789012";
+ char data3[] = "12345678901";
+ char data4[] = "1234567890?";
+ char pdf1[] = "[PDFHDR][STUFFS1]>>streamABCDEFGHIJYYendstream[STUFFS2]>>streamABCDEFGHIJYYendstream[STUFF3][PDFTRAILER]";
+ char out[200];
+ char orig[200];
+ int r1, r2;
+
+ printf("********************\n");
+ printf("pdfwrap for %s\n", data1);
+ printf("strlen(pdf1) = %d\n", (int)strlen(pdf1));
+ r1 = pdfWrap(data1, strlen(data1), pdf1, strlen(pdf1), out, (int)sizeof(out));
+ if (r1 > 0) {
+ printf("pdfWrap returns %d\n", r1);
+ out[r1] = 0;
+ printf("out[] contains |%s|\n", out);
+ } else {
+ printf("pdfWrap returns %d\n", r1);
+ }
+
+ r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
+ if (r2 > 0) {
+ printf("pdfUnwrap returns %d\n", r2);
+ orig[r2] = 0;
+ printf("orig[] contains |%s|\n", orig);
+ } else {
+ printf("pdfUnwrap returns %d\n", r2);
+ }
+
+ printf("********************\n");
+ printf("pdfwrap for %s\n", data2);
+ r1 = pdfWrap(data2, strlen(data2), pdf1, strlen(pdf1), out, (int)sizeof(out));
+ if (r1 > 0) {
+ printf("pdfWrap returns %d\n", r1);
+ out[r1] = 0;
+ printf("out[] contains |%s|\n", out);
+ } else {
+ printf("pdfWrap returns %d\n", r1);
+ }
+
+ r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
+ if (r2 > 0) {
+ printf("pdfUnwrap returns %d\n", r2);
+ orig[r2] = 0;
+ printf("orig[] contains |%s|\n", orig);
+ } else {
+ printf("pdfUnwrap returns %d\n", r2);
+ }
+
+ printf("********************\n");
+ printf("pdfwrap for %s\n", data3);
+ r1 = pdfWrap(data3, strlen(data3), pdf1, strlen(pdf1), out, (int)sizeof(out));
+ if (r1 > 0) {
+ printf("pdfWrap returns %d\n", r1);
+ out[r1] = 0;
+ printf("out[] contains |%s|\n", out);
+ } else {
+ printf("pdfWrap returns %d\n", r1);
+ }
+
+ r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
+ if (r2 > 0) {
+ printf("pdfUnwrap returns %d\n", r2);
+ orig[r2] = 0;
+ printf("orig[] contains |%s|\n", orig);
+ } else {
+ printf("pdfUnwrap returns %d\n", r2);
+ }
+
+ printf("********************\n");
+ printf("pdfwrap for %s\n", data4);
+ r1 = pdfWrap(data4, strlen(data4), pdf1, strlen(pdf1), out, (int)sizeof(out));
+ if (r1 > 0) {
+ printf("pdfWrap returns %d\n", r1);
+ out[r1] = 0;
+ printf("out[] contains |%s|\n", out);
+ } else {
+ printf("pdfWrap returns %d\n", r1);
+ }
+
+ r2 = pdfUnwrap(out, r1, orig, (int)sizeof(orig));
+ if (r2 > 0) {
+ printf("pdfUnwrap returns %d\n", r2);
+ orig[r2] = 0;
+ printf("orig[] contains |%s|\n", orig);
+ } else {
+ printf("pdfUnwrap returns %d\n", r2);
+ }
+
+ return 0;
+}
+ *****/
diff --git a/src/steg/swfSteg.c b/src/steg/swfSteg.c
deleted file mode 100644
index ad3d5c8..0000000
--- a/src/steg/swfSteg.c
+++ /dev/null
@@ -1,282 +0,0 @@
-#include "swfSteg.h"
-
-
-static const char http_response_1[] =
- "HTTP/1.1 200 OK\r\n"
- "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n"
- "Cache-Control: no-store\r\n"
- "Connection: close\r\n"
- "Content-Type: application/x-shockwave-flash\r\n"
- "Content-Length: ";
-
-
-
-
-
-
-
-
-
-
-
-unsigned int
-swf_wrap(char* inbuf, int in_len, char* outbuf, int out_sz) {
-
- char* swf;
- int in_swf_len;
-
- char* tmp_buf;
- int out_swf_len;
-
- char* resp;
- int resp_len;
-
- char hdr[512];
- unsigned int hdr_len;
-
- char* tmp_buf2;
-
-
-
- if (!get_payload(HTTP_CONTENT_SWF, -1, &resp, &resp_len)) {
- log_warn("swfsteg: no suitable payload found\n");
- return -1;
- }
-
- swf = strstr(resp, "\r\n\r\n") + 4;
- in_swf_len = resp_len - (swf - resp);
-
-
-
-
- if (out_sz - in_len < (SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 8 + 512)) {
- fprintf(stderr, "swfsteg: outbuf too small %d \n", out_sz - in_len);
-
- log_warn("swfsteg: outbuf too small\n");
- return -1;
- }
-
-
- tmp_buf = malloc(in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN);
-
- if (tmp_buf == NULL) {
- log_warn("swfsteg: malloc failed\n");
- return -1;
- }
-
-
- tmp_buf2 = malloc(in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN + 512);
-
- if (tmp_buf2 == NULL) {
- free(tmp_buf);
- log_warn("swfsteg: malloc failed\n");
- return -1;
- }
-
-
- memcpy(tmp_buf, swf+8, SWF_SAVE_HEADER_LEN);
- memcpy(tmp_buf+SWF_SAVE_HEADER_LEN, inbuf, in_len);
- memcpy(tmp_buf+SWF_SAVE_HEADER_LEN+in_len, swf + in_swf_len - SWF_SAVE_FOOTER_LEN, SWF_SAVE_FOOTER_LEN);
- out_swf_len = def(tmp_buf, SWF_SAVE_HEADER_LEN + in_len + SWF_SAVE_FOOTER_LEN, tmp_buf2+8,
- in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN + 512-8,
- Z_DEFAULT_COMPRESSION);
-
- // sprintf(hdr, "%s%d\r\n\r\n", http_response_1, out_swf_len + 8);
-
-
-
- // fprintf(stderr, "out_swf_len = %d\n", out_swf_len);
-
-
- hdr_len = gen_response_header((char*) "application/x-shockwave-flash", 0, out_swf_len + 8, hdr, sizeof(hdr));
-
- // fprintf(stderr, "hdr = %s\n", hdr);
-
- memcpy(tmp_buf2, swf, 4);
- ((int*) (tmp_buf2))[1] = out_swf_len;
-
- memcpy(outbuf, hdr, hdr_len);
- memcpy(outbuf+hdr_len, tmp_buf2, out_swf_len + 8);
-
- free(tmp_buf);
- free(tmp_buf2);
- return out_swf_len + 8 + hdr_len;
-}
-
-
-
-
-unsigned int
-swf_unwrap(char* inbuf, int in_len, char* outbuf, int out_sz) {
- char* tmp_buf;
- int inf_len;
-
- tmp_buf = malloc(in_len * 8);
-
- inf_len = inf(inbuf + 8, in_len - 8, tmp_buf, in_len * 8);
-
- // fprintf(stderr, "in_swf_len = %d\n", in_len -8 );
-
-
- if (inf_len < 0 || out_sz < inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN) {
- fprintf(stderr, "inf_len = %d\n", inf_len);
- free(tmp_buf);
- // buf_dump((unsigned char*) (inbuf+8), in_len -8, stderr);
-
-
-
- return -1;
- }
-
- memcpy(outbuf, tmp_buf + SWF_SAVE_HEADER_LEN, inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN);
- return inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN;
-}
-
-
-
-
-
-int
-x_http2_server_SWF_transmit (steg_t* s, struct evbuffer *source, conn_t *conn) {
-
- struct evbuffer *dest = conn_get_outbound(conn);
- size_t sbuflen = evbuffer_get_length(source);
- char* inbuf;
- char* outbuf;
- int outlen;
-
-
-
- inbuf = malloc(sbuflen);
-
- if (inbuf == NULL) {
- log_warn("malloc inbuf failed\n");
- return -1;
- }
-
-
- if (evbuffer_remove(source, inbuf, sbuflen) == -1) {
- log_debug("evbuffer_remove failed in x_http2_server_SWF_transmit");
- return -1;
- }
-
- outbuf = malloc(4*sbuflen + SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 512);
-
- if (outbuf == NULL) {
- free(inbuf);
- log_warn("malloc outbuf failed\n");
- return -1;
- }
-
- // fprintf(stderr, "server wrapping swf len %d\n", (int) sbuflen);
- outlen = swf_wrap(inbuf, sbuflen, outbuf, 4*sbuflen + SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 512);
-
- if (outlen < 0) {
- log_warn("swf_wrap failed\n");
- // fprintf(stderr, "swf_wrap failed\n");
- free(inbuf);
- free(outbuf);
- return -1;
- }
-
-
- if (evbuffer_add(dest, outbuf, outlen)) {
- log_debug("SERVER ERROR: x_http2_server_transmit: evbuffer_add() fails for jsTemplate");
- free(inbuf);
- free(outbuf);
- return -1;
- }
-
-
- // conn_cease_transmission(conn);
- conn_close_after_transmit(conn);
-
-
- free(inbuf);
- free(outbuf);
- return 0;
-}
-
-
-
-
-int
-x_http2_handle_client_SWF_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
- struct evbuffer_ptr s2;
- unsigned int response_len = 0, hdrLen;
- char outbuf[HTTP_MSG_BUF_SIZE];
- int content_len = 0, outbuflen;
- char *httpHdr, *httpBody;
-
-
-
- s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
- if (s2.pos == -1) {
- log_warn("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
- fprintf(stderr, "client did not find end of HTTP header\n");
-
- // evbuffer_dump(source, stderr);
- return RECV_INCOMPLETE;
- }
-
- log_debug("CLIENT received response header with len %d", (int)s2.pos);
-
- response_len = 0;
- hdrLen = s2.pos + strlen("\r\n\r\n");
- response_len += hdrLen;
-
- httpHdr = (char *) evbuffer_pullup(source, s2.pos);
- if (httpHdr == NULL) {
- log_warn("CLIENT unable to pullup the complete HTTP header");
- return RECV_BAD;
- }
-
- content_len = find_content_length(httpHdr, hdrLen);
-
-
-
- if (content_len < 0) {
- log_warn("CLIENT unable to find content length");
- return RECV_BAD;
- }
- log_debug("CLIENT received Content-Length = %d\n", content_len);
-
-
-
- response_len += content_len;
-
- if (response_len > evbuffer_get_length(source))
- return RECV_INCOMPLETE;
-
-
-
- httpHdr = (char *) evbuffer_pullup(source, response_len);
- httpBody = httpHdr + hdrLen;
-
-
- outbuflen = swf_unwrap(httpBody, content_len, outbuf, HTTP_MSG_BUF_SIZE);
-
- if (outbuflen < 0) {
- fprintf(stderr, "swf_unwrap failed\n");
- log_debug("CLIENT ERROR: swf_unwrap failed\n");
- return RECV_BAD;
- }
-
- // fprintf(stderr, "CLIENT unwrapped data of length %d:", outbuflen);
- // buf_dump(outbuf, outbuflen, stderr);
-
- if (evbuffer_add(dest, outbuf, outbuflen)) {
- log_debug("CLIENT ERROR: evbuffer_add to dest fails\n");
- return RECV_BAD;
- }
-
- // log_debug("Drained source for %d char\n", response_len);
- if (evbuffer_drain(source, response_len) == -1) {
- log_debug("CLIENT ERROR: failed to drain source\n");
- return RECV_BAD;
- }
-
- // downcast_steg(s)->have_received = 1;
- conn_expect_close(conn);
- return RECV_GOOD;
-}
diff --git a/src/steg/swfSteg.c.old b/src/steg/swfSteg.c.old
deleted file mode 100644
index 833ea9f..0000000
--- a/src/steg/swfSteg.c.old
+++ /dev/null
@@ -1,264 +0,0 @@
-#include "swfSteg.h"
-
-
-static const char http_response_1[] =
- "HTTP/1.1 200 OK\r\n"
- "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n"
- "Cache-Control: no-store\r\n"
- "Connection: close\r\n"
- "Content-Type: application/x-shockwave-flash\r\n"
- "Content-Length: ";
-
-
-
-
-
-
-
-
-
-
-
-unsigned int
-swf_wrap(char* inbuf, int in_len, char* outbuf, int out_sz) {
-
- char* swf;
- int in_swf_len;
-
- char* tmp_buf;
- int out_swf_len;
-
- char* resp;
- int resp_len;
-
- char hdr[512];
- unsigned int hdr_len;
-
- char* tmp_buf2;
-
-
-
- if (!get_payload(HTTP_CONTENT_SWF, -1, &resp, &resp_len)) {
- log_warn("swfsteg: no suitable payload found\n");
- return -1;
- }
-
- swf = strstr(resp, "\r\n\r\n") + 4;
- in_swf_len = resp_len - (swf - resp);
-
-
-
-
- if (out_sz - in_len < (SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 8 + 512)) {
- fprintf(stderr, "swfsteg: outbuf too small %d \n", out_sz - in_len);
-
- log_warn("swfsteg: outbuf too small\n");
- return -1;
- }
-
-
- tmp_buf = malloc(in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN);
-
- if (tmp_buf == NULL) {
- log_warn("swfsteg: malloc failed\n");
- return -1;
- }
-
-
- tmp_buf2 = malloc(in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN + 512);
-
- if (tmp_buf2 == NULL) {
- free(tmp_buf);
- log_warn("swfsteg: malloc failed\n");
- return -1;
- }
-
-
- memcpy(tmp_buf, swf+8, SWF_SAVE_HEADER_LEN);
- memcpy(tmp_buf+SWF_SAVE_HEADER_LEN, inbuf, in_len);
- memcpy(tmp_buf+SWF_SAVE_HEADER_LEN+in_len, swf + in_swf_len - SWF_SAVE_FOOTER_LEN, SWF_SAVE_FOOTER_LEN);
- out_swf_len = def(tmp_buf, SWF_SAVE_HEADER_LEN + in_len + SWF_SAVE_FOOTER_LEN, tmp_buf2+8,
- in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN + 512-8,
- Z_DEFAULT_COMPRESSION);
-
- // sprintf(hdr, "%s%d\r\n\r\n", http_response_1, out_swf_len + 8);
-
-
- hdr_len = gen_response_header((char*) "application/x-shockwave-flash", 0, out_swf_len + 8, hdr, sizeof(hdr));
-
- // fprintf(stderr, "hdr = %s\n", hdr);
-
- memcpy(tmp_buf2, swf, 4);
- ((int*) (tmp_buf2))[1] = out_swf_len;
-
- memcpy(outbuf, hdr, hdr_len);
- memcpy(outbuf+hdr_len, tmp_buf2, out_swf_len + 8);
-
- free(tmp_buf);
- free(tmp_buf2);
- return out_swf_len + 8 + hdr_len;
-}
-
-
-
-unsigned int
-swf_unwrap(char* inbuf, int in_len, char* outbuf, int out_sz) {
- char* tmp_buf;
- int inf_len;
-
- tmp_buf = malloc(in_len * 5);
- inf_len = inf(inbuf + 8, in_len - 8, tmp_buf, in_len * 5);
-
- if (inf_len < 0 || out_sz < inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN) {
- fprintf(stderr, "swf_unwrap failed \n");
- free(tmp_buf);
- return -1;
- }
-
- memcpy(outbuf, tmp_buf + SWF_SAVE_HEADER_LEN, inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN);
- return inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN;
-}
-
-
-
-
-
-int
-x_http2_server_SWF_transmit (steg_t* s, struct evbuffer *source, conn_t *conn) {
-
- struct evbuffer *dest = conn_get_outbound(conn);
- size_t sbuflen = evbuffer_get_length(source);
- char* inbuf;
- char* outbuf;
- int outlen;
-
-
-
- inbuf = malloc(sbuflen);
-
- if (inbuf == NULL) {
- log_warn("malloc inbuf failed\n");
- return -1;
- }
-
-
- if (evbuffer_remove(source, inbuf, sbuflen) == -1) {
- log_debug("evbuffer_remove failed in x_http2_server_SWF_transmit");
- return -1;
- }
-
- outbuf = malloc(4*sbuflen + SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 512);
-
- if (outbuf == NULL) {
- free(inbuf);
- log_warn("malloc outbuf failed\n");
- return -1;
- }
-
- // fprintf(stderr, "server wrapping swf len %d\n", (int) sbuflen);
- outlen = swf_wrap(inbuf, sbuflen, outbuf, 4*sbuflen + SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 512);
-
- if (outlen < 0) {
- log_warn("swf_wrap failed\n");
- fprintf(stderr, "swf_wrap failed\n");
- free(inbuf);
- free(outbuf);
- return -1;
- }
-
-
- if (evbuffer_add(dest, outbuf, outlen)) {
- log_debug("SERVER ERROR: x_http2_server_transmit: evbuffer_add() fails for jsTemplate");
- free(inbuf);
- free(outbuf);
- return -1;
- }
-
-
- // conn_cease_transmission(conn);
- conn_close_after_transmit(conn);
-
-
- free(inbuf);
- free(outbuf);
- return 0;
-}
-
-
-
-
-int
-x_http2_handle_client_SWF_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
- struct evbuffer_ptr s2;
- unsigned int response_len = 0, hdrLen;
- char outbuf[HTTP_MSG_BUF_SIZE];
- int content_len = 0, outbuflen;
- char *httpHdr, *httpBody;
-
-
-
- s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
- if (s2.pos == -1) {
- log_warn("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
- fprintf(stderr, "client did not find end of HTTP header\n");
-
- // evbuffer_dump(source, stderr);
- return RECV_INCOMPLETE;
- }
-
- log_debug("CLIENT received response header with len %d", (int)s2.pos);
-
- response_len = 0;
- hdrLen = s2.pos + strlen("\r\n\r\n");
- response_len += hdrLen;
-
- httpHdr = (char *) evbuffer_pullup(source, s2.pos);
- if (httpHdr == NULL) {
- log_warn("CLIENT unable to pullup the complete HTTP header");
- return RECV_BAD;
- }
-
- content_len = find_content_length(httpHdr, hdrLen);
-
-
-
- if (content_len < 0) {
- log_warn("CLIENT unable to find content length");
- return RECV_BAD;
- }
- log_debug("CLIENT received Content-Length = %d\n", content_len);
-
-
-
- response_len += content_len;
-
- if (response_len > evbuffer_get_length(source))
- return RECV_INCOMPLETE;
-
- httpBody = httpHdr + hdrLen;
- outbuflen = swf_unwrap(httpBody, content_len, outbuf, HTTP_MSG_BUF_SIZE);
-
- if (outbuflen < 0) {
- fprintf(stderr, "swf_unwrap failed\n");
- log_debug("CLIENT ERROR: swf_unwrap failed\n");
- return RECV_BAD;
- }
-
- // fprintf(stderr, "CLIENT unwrapped data of length %d:", outbuflen);
- // buf_dump(outbuf, outbuflen, stderr);
-
- if (evbuffer_add(dest, outbuf, outbuflen)) {
- log_debug("CLIENT ERROR: evbuffer_add to dest fails\n");
- return RECV_BAD;
- }
-
- // log_debug("Drained source for %d char\n", response_len);
- if (evbuffer_drain(source, response_len) == -1) {
- log_debug("CLIENT ERROR: failed to drain source\n");
- return RECV_BAD;
- }
-
- // downcast_steg(s)->have_received = 1;
- conn_expect_close(conn);
- return RECV_GOOD;
-}
diff --git a/src/steg/swfSteg.cc b/src/steg/swfSteg.cc
new file mode 100644
index 0000000..ad3d5c8
--- /dev/null
+++ b/src/steg/swfSteg.cc
@@ -0,0 +1,282 @@
+#include "swfSteg.h"
+
+
+static const char http_response_1[] =
+ "HTTP/1.1 200 OK\r\n"
+ "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n"
+ "Cache-Control: no-store\r\n"
+ "Connection: close\r\n"
+ "Content-Type: application/x-shockwave-flash\r\n"
+ "Content-Length: ";
+
+
+
+
+
+
+
+
+
+
+
+unsigned int
+swf_wrap(char* inbuf, int in_len, char* outbuf, int out_sz) {
+
+ char* swf;
+ int in_swf_len;
+
+ char* tmp_buf;
+ int out_swf_len;
+
+ char* resp;
+ int resp_len;
+
+ char hdr[512];
+ unsigned int hdr_len;
+
+ char* tmp_buf2;
+
+
+
+ if (!get_payload(HTTP_CONTENT_SWF, -1, &resp, &resp_len)) {
+ log_warn("swfsteg: no suitable payload found\n");
+ return -1;
+ }
+
+ swf = strstr(resp, "\r\n\r\n") + 4;
+ in_swf_len = resp_len - (swf - resp);
+
+
+
+
+ if (out_sz - in_len < (SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 8 + 512)) {
+ fprintf(stderr, "swfsteg: outbuf too small %d \n", out_sz - in_len);
+
+ log_warn("swfsteg: outbuf too small\n");
+ return -1;
+ }
+
+
+ tmp_buf = malloc(in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN);
+
+ if (tmp_buf == NULL) {
+ log_warn("swfsteg: malloc failed\n");
+ return -1;
+ }
+
+
+ tmp_buf2 = malloc(in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN + 512);
+
+ if (tmp_buf2 == NULL) {
+ free(tmp_buf);
+ log_warn("swfsteg: malloc failed\n");
+ return -1;
+ }
+
+
+ memcpy(tmp_buf, swf+8, SWF_SAVE_HEADER_LEN);
+ memcpy(tmp_buf+SWF_SAVE_HEADER_LEN, inbuf, in_len);
+ memcpy(tmp_buf+SWF_SAVE_HEADER_LEN+in_len, swf + in_swf_len - SWF_SAVE_FOOTER_LEN, SWF_SAVE_FOOTER_LEN);
+ out_swf_len = def(tmp_buf, SWF_SAVE_HEADER_LEN + in_len + SWF_SAVE_FOOTER_LEN, tmp_buf2+8,
+ in_len + SWF_SAVE_HEADER_LEN + SWF_SAVE_FOOTER_LEN + 512-8,
+ Z_DEFAULT_COMPRESSION);
+
+ // sprintf(hdr, "%s%d\r\n\r\n", http_response_1, out_swf_len + 8);
+
+
+
+ // fprintf(stderr, "out_swf_len = %d\n", out_swf_len);
+
+
+ hdr_len = gen_response_header((char*) "application/x-shockwave-flash", 0, out_swf_len + 8, hdr, sizeof(hdr));
+
+ // fprintf(stderr, "hdr = %s\n", hdr);
+
+ memcpy(tmp_buf2, swf, 4);
+ ((int*) (tmp_buf2))[1] = out_swf_len;
+
+ memcpy(outbuf, hdr, hdr_len);
+ memcpy(outbuf+hdr_len, tmp_buf2, out_swf_len + 8);
+
+ free(tmp_buf);
+ free(tmp_buf2);
+ return out_swf_len + 8 + hdr_len;
+}
+
+
+
+
+unsigned int
+swf_unwrap(char* inbuf, int in_len, char* outbuf, int out_sz) {
+ char* tmp_buf;
+ int inf_len;
+
+ tmp_buf = malloc(in_len * 8);
+
+ inf_len = inf(inbuf + 8, in_len - 8, tmp_buf, in_len * 8);
+
+ // fprintf(stderr, "in_swf_len = %d\n", in_len -8 );
+
+
+ if (inf_len < 0 || out_sz < inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN) {
+ fprintf(stderr, "inf_len = %d\n", inf_len);
+ free(tmp_buf);
+ // buf_dump((unsigned char*) (inbuf+8), in_len -8, stderr);
+
+
+
+ return -1;
+ }
+
+ memcpy(outbuf, tmp_buf + SWF_SAVE_HEADER_LEN, inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN);
+ return inf_len - SWF_SAVE_HEADER_LEN - SWF_SAVE_FOOTER_LEN;
+}
+
+
+
+
+
+int
+x_http2_server_SWF_transmit (steg_t* s, struct evbuffer *source, conn_t *conn) {
+
+ struct evbuffer *dest = conn_get_outbound(conn);
+ size_t sbuflen = evbuffer_get_length(source);
+ char* inbuf;
+ char* outbuf;
+ int outlen;
+
+
+
+ inbuf = malloc(sbuflen);
+
+ if (inbuf == NULL) {
+ log_warn("malloc inbuf failed\n");
+ return -1;
+ }
+
+
+ if (evbuffer_remove(source, inbuf, sbuflen) == -1) {
+ log_debug("evbuffer_remove failed in x_http2_server_SWF_transmit");
+ return -1;
+ }
+
+ outbuf = malloc(4*sbuflen + SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 512);
+
+ if (outbuf == NULL) {
+ free(inbuf);
+ log_warn("malloc outbuf failed\n");
+ return -1;
+ }
+
+ // fprintf(stderr, "server wrapping swf len %d\n", (int) sbuflen);
+ outlen = swf_wrap(inbuf, sbuflen, outbuf, 4*sbuflen + SWF_SAVE_FOOTER_LEN + SWF_SAVE_HEADER_LEN + 512);
+
+ if (outlen < 0) {
+ log_warn("swf_wrap failed\n");
+ // fprintf(stderr, "swf_wrap failed\n");
+ free(inbuf);
+ free(outbuf);
+ return -1;
+ }
+
+
+ if (evbuffer_add(dest, outbuf, outlen)) {
+ log_debug("SERVER ERROR: x_http2_server_transmit: evbuffer_add() fails for jsTemplate");
+ free(inbuf);
+ free(outbuf);
+ return -1;
+ }
+
+
+ // conn_cease_transmission(conn);
+ conn_close_after_transmit(conn);
+
+
+ free(inbuf);
+ free(outbuf);
+ return 0;
+}
+
+
+
+
+int
+x_http2_handle_client_SWF_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
+ struct evbuffer_ptr s2;
+ unsigned int response_len = 0, hdrLen;
+ char outbuf[HTTP_MSG_BUF_SIZE];
+ int content_len = 0, outbuflen;
+ char *httpHdr, *httpBody;
+
+
+
+ s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
+ if (s2.pos == -1) {
+ log_warn("CLIENT Did not find end of HTTP header %d", (int) evbuffer_get_length(source));
+ fprintf(stderr, "client did not find end of HTTP header\n");
+
+ // evbuffer_dump(source, stderr);
+ return RECV_INCOMPLETE;
+ }
+
+ log_debug("CLIENT received response header with len %d", (int)s2.pos);
+
+ response_len = 0;
+ hdrLen = s2.pos + strlen("\r\n\r\n");
+ response_len += hdrLen;
+
+ httpHdr = (char *) evbuffer_pullup(source, s2.pos);
+ if (httpHdr == NULL) {
+ log_warn("CLIENT unable to pullup the complete HTTP header");
+ return RECV_BAD;
+ }
+
+ content_len = find_content_length(httpHdr, hdrLen);
+
+
+
+ if (content_len < 0) {
+ log_warn("CLIENT unable to find content length");
+ return RECV_BAD;
+ }
+ log_debug("CLIENT received Content-Length = %d\n", content_len);
+
+
+
+ response_len += content_len;
+
+ if (response_len > evbuffer_get_length(source))
+ return RECV_INCOMPLETE;
+
+
+
+ httpHdr = (char *) evbuffer_pullup(source, response_len);
+ httpBody = httpHdr + hdrLen;
+
+
+ outbuflen = swf_unwrap(httpBody, content_len, outbuf, HTTP_MSG_BUF_SIZE);
+
+ if (outbuflen < 0) {
+ fprintf(stderr, "swf_unwrap failed\n");
+ log_debug("CLIENT ERROR: swf_unwrap failed\n");
+ return RECV_BAD;
+ }
+
+ // fprintf(stderr, "CLIENT unwrapped data of length %d:", outbuflen);
+ // buf_dump(outbuf, outbuflen, stderr);
+
+ if (evbuffer_add(dest, outbuf, outbuflen)) {
+ log_debug("CLIENT ERROR: evbuffer_add to dest fails\n");
+ return RECV_BAD;
+ }
+
+ // log_debug("Drained source for %d char\n", response_len);
+ if (evbuffer_drain(source, response_len) == -1) {
+ log_debug("CLIENT ERROR: failed to drain source\n");
+ return RECV_BAD;
+ }
+
+ // downcast_steg(s)->have_received = 1;
+ conn_expect_close(conn);
+ return RECV_GOOD;
+}
diff --git a/src/steg/x_http.c.old b/src/steg/x_http.c.old
deleted file mode 100644
index 2799078..0000000
--- a/src/steg/x_http.c.old
+++ /dev/null
@@ -1,337 +0,0 @@
-/* Copyright 2011 Zack Weinberg
- See LICENSE for other credits and copying information
-*/
-
-#include "util.h"
-#include "connections.h"
-#include "steg.h"
-
-#include <event2/buffer.h>
-
-
-
-/* This is an example steganography module. Don't use it to disguise real
- traffic! It packages client->server traffic as HTTP GET requests and
- server->client traffic as HTTP responses, but makes no actual attempt
- to obscure the data proper. */
-
-struct x_http_steg_t
-{
- steg_t super;
- /* no extra stuff is presently necessary */
-};
-
-STEG_DEFINE_MODULE(x_http,
- 1024, /* client-server max data rate - made up */
- 10240, /* server-client max data rate - ditto */
- 1, /* max concurrent connections per IP */
- 1); /* max concurrent IPs */
-
-/* Canned HTTP query and response headers. */
-static const char http_query_1[] =
- "GET /";
-static const char http_query_2[] =
- " HTTP/1.1\r\n"
- "Host: ";
-static const char http_query_3[] =
- "\r\n"
- "Connection: close\r\n\r\n";
-
-static const char http_response_1[] =
- "HTTP/1.1 200 OK\r\n"
- "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n"
- "Cache-Control: no-store\r\n"
- "Connection: close\r\n"
- "Content-Type: application/octet-stream\r\n"
- "Content-Length: ";
-static const char http_response_2[] =
- "%lu\r\n"
- "\r\n";
-
-
-steg_t *
-x_http_new(rng_t *rng, unsigned int is_clientside)
-{
- STEG_NEW(x_http, state, rng, is_clientside);
- /* if there were extra stuff to fill in, you would do it here */
- return upcast_steg(state);
-}
-
-void
-x_http_del(steg_t *s)
-{
- x_http_steg_t *state = downcast_steg(s);
- STEG_DEL(s);
- /* if there were extra stuff to deallocate, you would do it here */
- free(state);
-}
-
-unsigned int
-x_http_detect(conn_t *conn)
-{
- struct evbuffer *buf = conn_get_inbound(conn);
- unsigned char *data;
-
- return 0;
-
- /* Look for the text of http_response_1. */
- if (evbuffer_get_length(buf) >= sizeof http_response_1 - 1) {
- data = evbuffer_pullup(buf, sizeof http_response_1 - 1);
- if (!memcmp(data, http_response_1, sizeof http_response_1 - 1))
- return 1;
- }
-
- /* The client always transmits "GET /" followed by at least four
- characters that are either lowercase hex digits or equals
- signs, so we need nine bytes of incoming data. */
- if (evbuffer_get_length(buf) >= 9) {
- data = evbuffer_pullup(buf, 9);
- if (!memcmp(data, "GET /", 5) &&
- (ascii_isxdigit(data[5]) || data[5] == '=') &&
- (ascii_isxdigit(data[6]) || data[6] == '=') &&
- (ascii_isxdigit(data[7]) || data[7] == '=') &&
- (ascii_isxdigit(data[8]) || data[8] == '='))
- return 1;
- }
-
- /* Didn't find either the client or the server pattern. */
- return 0;
-}
-
-size_t
-x_http_transmit_room(steg_t *s, conn_t *conn)
-{
- if (s->is_clientside)
- /* per http://www.boutell.com/newfaq/misc/urllength.html,
- IE<9 can handle no more than 2048 characters in the path
- component of a URL; we're not talking to IE, but this limit
- means longer paths look fishy; we hex-encode the path, so
- we have to cut the number in half. */
- return 1024;
- else
- /* no practical limit applies */
- return SIZE_MAX;
-}
-
-int
-x_http_transmit(steg_t *s, struct evbuffer *source, conn_t *conn)
-{
- struct evbuffer *dest = conn_get_outbound(conn);
-
- if (s->is_clientside) {
- /* On the client side, we have to embed the data in a GET query somehow;
- the only plausible places to put it are the URL and cookies. This
- presently uses the URL. And it can't be binary. */
- struct evbuffer *scratch;
- struct evbuffer_iovec *iv;
- int i, nv;
-
- /* Convert all the data in 'source' to hexadecimal and write it to
- 'scratch'. Data is padded to a multiple of four characters with
- equals signs. */
- size_t slen = evbuffer_get_length(source);
- size_t dlen = slen * 2;
-
- dlen = dlen + 3 - (dlen-1)%4;
- if (dlen == 0) dlen = 4;
-
- scratch = evbuffer_new();
- if (!scratch) return -1;
- if (evbuffer_expand(scratch, dlen)) {
- evbuffer_free(scratch);
- return -1;
- }
-
- nv = evbuffer_peek(source, slen, NULL, NULL, 0);
- iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
- if (evbuffer_peek(source, slen, NULL, iv, nv) != nv) {
- evbuffer_free(scratch);
- free(iv);
- return -1;
- }
-
- for (i = 0; i < nv; i++) {
- const unsigned char *p = iv[i].iov_base;
- const unsigned char *limit = p + iv[i].iov_len;
- char hex[2], c;
- while (p < limit) {
- c = *p++;
- hex[0] = "0123456789abcdef"[(c & 0xF0) >> 4];
- hex[1] = "0123456789abcdef"[(c & 0x0F) >> 0];
- evbuffer_add(scratch, hex, 2);
- }
- }
- free(iv);
- while (evbuffer_get_length(scratch) == 0 ||
- evbuffer_get_length(scratch) % 4 != 0)
- evbuffer_add(scratch, "=", 1);
-
- if (evbuffer_add(dest, http_query_1, sizeof http_query_1-1) ||
- evbuffer_add_buffer(dest, scratch) ||
- evbuffer_add(dest, http_query_2, sizeof http_query_2-1) ||
- evbuffer_add(dest, conn->peername, strlen(conn->peername)) ||
- evbuffer_add(dest, http_query_3, sizeof http_query_3-1)) {
- evbuffer_free(scratch);
- return -1;
- }
-
- evbuffer_free(scratch);
- evbuffer_drain(source, slen);
- conn_cease_transmission(conn);
- return 0;
-
- } else {
- /* On the server side, we just fake up some HTTP response headers and
- then splat the data we were given. Binary is OK. */
-
- if (evbuffer_add(dest, http_response_1, sizeof http_response_1-1))
- return -1;
- if (evbuffer_add_printf(dest, http_response_2,
- (unsigned long)evbuffer_get_length(source)) == -1)
- return -1;
- if (evbuffer_add_buffer(dest, source))
- return -1;
-
- conn_close_after_transmit(conn);
- return 0;
- }
-}
-
-// enum recv_ret
-static int
-x_http_receive(steg_t *s, conn_t *conn, struct evbuffer *dest)
-{
- struct evbuffer *source = conn_get_inbound(conn);
- if (s->is_clientside) {
- /* This loop should not be necessary, but we are currently not
- enforcing the query-response pattern, so we can get more than
- one response per request. */
- do {
- /* Linearize the buffer out past the longest possible
- Content-Length header and subsequent blank line. 2**64 fits in
- 20 characters, and then we have two CRLFs; minus one for the
- NUL in sizeof http_response_1. Note that this does _not_
- guarantee that that much data is available. */
-
- unsigned char *data = evbuffer_pullup(source, sizeof http_response_1 + 23);
- size_t hlen = evbuffer_get_length(source);
- if (hlen > sizeof http_response_1 + 23)
- hlen = sizeof http_response_1 + 23;
-
- /* Validate response headers. */
- if (hlen < sizeof http_response_1 - 1)
- return 0; // RECV_INCOMPLETE;
- if (memcmp(data, http_response_1, sizeof http_response_1 - 1))
- return -1; // RECV_BAD;
-
- /* There should be an unsigned number immediately after the text of
- http_response_1, followed by the four characters \r\n\r\n.
- We may not have the complete number yet. */
- unsigned char *p = data + sizeof http_response_1 - 1;
- unsigned char *limit = data + hlen;
- uint64_t clen = 0;
- while (p < limit && '0' <= *p && *p <= '9') {
- clen = clen*10 + *p - '0';
- p++;
- }
- if (p+4 > limit)
- return 0; // RECV_INCOMPLETE;
- if (p[0] != '\r' || p[1] != '\n' || p[2] != '\r' || p[3] != '\n')
- return -1; // RECV_BAD;
-
- p += 4;
- hlen = p - data;
- /* Now we know how much data we're expecting after the blank line. */
- if (evbuffer_get_length(source) < hlen + clen)
- return 0; // RECV_INCOMPLETE;
-
- /* we are go */
- if (evbuffer_drain(source, hlen))
- return -1; // RECV_BAD;
-
- if (evbuffer_remove_buffer(source, dest, clen) != clen)
- return -1; // RECV_BAD;
-
- } while (evbuffer_get_length(source));
-
- conn_expect_close(conn);
- return 0; // RECV_GOOD;
- } else {
- /* We need a scratch buffer here because the contract is that if
- we hit a decode error we *don't* write anything to 'dest'. */
- struct evbuffer *scratch;
-
- /* This loop should not be necessary either, but is, for the same
- reason given above */
- do {
- /* Search for the second and third invariant bits of the query headers
- we expect. We completely ignore the contents of the Host header. */
- struct evbuffer_ptr s2 = evbuffer_search(source, http_query_2,
- sizeof http_query_2 - 1,
- NULL);
- if (s2.pos == -1) {
- log_debug("Did not find second piece of HTTP query");
- return 0; // RECV_INCOMPLETE;
- }
- struct evbuffer_ptr s3 = evbuffer_search(source, http_query_3,
- sizeof http_query_3 - 1,
- &s2);
- if (s3.pos == -1) {
- log_debug("Did not find third piece of HTTP query");
- return 0; // RECV_INCOMPLETE;
- }
- obfs_assert(s3.pos + sizeof http_query_3 - 1
- <= evbuffer_get_length(source));
-
- unsigned char *data = evbuffer_pullup(source, s2.pos);
- if (memcmp(data, "GET /", sizeof "GET /"-1)) {
- log_debug("Unexpected HTTP verb: %.*s", 5, data);
- return -1; // RECV_BAD;
- }
-
- unsigned char *p = data + sizeof "GET /"-1;
- unsigned char *limit = data + s2.pos;
-
- scratch = evbuffer_new();
- if (!scratch) return -1; // RECV_BAD;
- if (evbuffer_expand(scratch, (limit - p)/2)) {
- evbuffer_free(scratch);
- return -1; // RECV_BAD;
- }
-
- unsigned char c, h, secondhalf = 0;
- while (p < limit) {
- if (!secondhalf) c = 0;
- if ('0' <= *p && *p <= '9') h = *p - '0';
- else if ('a' <= *p && *p <= 'f') h = *p - 'a' + 10;
- else if ('A' <= *p && *p <= 'F') h = *p - 'A' + 10;
- else if (*p == '=' && !secondhalf) {
- p++;
- continue;
- } else {
- evbuffer_free(scratch);
- log_debug("Decode error: unexpected URI character %c", *p);
- return -1; // RECV_BAD;
- }
-
- c = (c << 4) + h;
- if (secondhalf)
- evbuffer_add(scratch, &c, 1);
- secondhalf = !secondhalf;
- p++;
- }
-
- if (evbuffer_add_buffer(dest, scratch)) {
- evbuffer_free(scratch);
- log_debug("Failed to transfer buffer");
- return -1; // RECV_BAD;
- }
- evbuffer_drain(source, s3.pos + sizeof http_query_3 - 1);
- evbuffer_free(scratch);
-
- } while (evbuffer_get_length(source));
-
- conn_transmit_soon(conn, 100);
- return 0; // RECV_GOOD;
- }
-}
diff --git a/src/steg/x_http.cc b/src/steg/x_http.cc
deleted file mode 100644
index e1d9780..0000000
--- a/src/steg/x_http.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-/* Copyright 2011 Zack Weinberg
- See LICENSE for other credits and copying information
-*/
-
-#include "util.h"
-#include "connections.h"
-#include "steg.h"
-#include "crypt.h"
-
-#include <event2/buffer.h>
-
-/* This is an example steganography module. Don't use it to disguise real
- traffic! It packages client->server traffic as HTTP GET requests and
- server->client traffic as HTTP responses, but makes no actual attempt
- to obscure the data proper. */
-
-namespace {
- struct x_http : steg_t
- {
- bool have_transmitted : 1;
- bool have_received : 1;
- STEG_DECLARE_METHODS(x_http);
- };
-}
-
-STEG_DEFINE_MODULE(x_http,
- 1024, /* client-server max data rate - made up */
- 10240, /* server-client max data rate - ditto */
- 1, /* max concurrent connections per IP */
- 1); /* max concurrent IPs */
-
-/* Canned HTTP query and response headers. */
-static const char http_query_1[] =
- "GET /";
-static const char http_query_2[] =
- " HTTP/1.1\r\n"
- "Host: ";
-static const char http_query_3[] =
- "\r\n"
- "Connection: close\r\n\r\n";
-
-static const char http_response_1[] =
- "HTTP/1.1 200 OK\r\n"
- "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n"
- "Cache-Control: no-store\r\n"
- "Connection: close\r\n"
- "Content-Type: application/octet-stream\r\n"
- "Content-Length: ";
-
-
-x_http::x_http()
- : have_transmitted(false), have_received(false)
-{}
-
-x_http::~x_http()
-{}
-
-bool
-x_http::detect(conn_t *conn)
-{
- struct evbuffer *buf = conn_get_inbound(conn);
- uint8_t *data;
- return 0;
-
- /* Look for the text of http_response_1. */
- if (evbuffer_get_length(buf) >= sizeof http_response_1 - 1) {
- data = evbuffer_pullup(buf, sizeof http_response_1 - 1);
- if (!memcmp(data, http_response_1, sizeof http_response_1 - 1))
- return true;
- }
-
- /* The client always transmits "GET /" followed by at least four
- characters that are either lowercase hex digits or equals
- signs, so we need nine bytes of incoming data. */
- if (evbuffer_get_length(buf) >= 9) {
- data = evbuffer_pullup(buf, 9);
- if (!memcmp(data, "GET /", 5) &&
- (ascii_isxdigit(data[5]) || data[5] == '=') &&
- (ascii_isxdigit(data[6]) || data[6] == '=') &&
- (ascii_isxdigit(data[7]) || data[7] == '=') &&
- (ascii_isxdigit(data[8]) || data[8] == '='))
- return true;
- }
-
- /* Didn't find either the client or the server pattern. */
- return false;
-}
-
-size_t
-x_http::transmit_room(conn_t *)
-{
- if (this->have_transmitted)
- /* can't send any more on this connection */
- return 0;
-
- if (this->is_clientside)
- /* per http://www.boutell.com/newfaq/misc/urllength.html,
- IE<9 can handle no more than 2048 characters in the path
- component of a URL; we're not talking to IE, but this limit
- means longer paths look fishy; we hex-encode the path, so
- we have to cut the number in half. */
- return 1024;
- else {
- if (!this->have_received)
- return 0;
- /* no practical limit applies */
- return SIZE_MAX;
- }
-}
-
-int
-x_http::transmit(struct evbuffer *source, conn_t *conn)
-{
- struct evbuffer *dest = conn_get_outbound(conn);
-
- if (this->is_clientside) {
- /* On the client side, we have to embed the data in a GET query somehow;
- the only plausible places to put it are the URL and cookies. This
- presently uses the URL. And it can't be binary. */
- struct evbuffer *scratch;
- struct evbuffer_iovec *iv;
- int i, nv;
-
- /* Convert all the data in 'source' to hexadecimal and write it to
- 'scratch'. Data is padded to a multiple of four characters with
- equals signs. */
- size_t slen = evbuffer_get_length(source);
- size_t dlen = slen * 2;
-
- dlen = dlen + 3 - (dlen-1)%4;
- if (dlen == 0) dlen = 4;
-
- scratch = evbuffer_new();
- if (!scratch) return -1;
- if (evbuffer_expand(scratch, dlen)) {
- evbuffer_free(scratch);
- return -1;
- }
-
- nv = evbuffer_peek(source, slen, NULL, NULL, 0);
- iv = (struct evbuffer_iovec *)xzalloc(sizeof(struct evbuffer_iovec) * nv);
- if (evbuffer_peek(source, slen, NULL, iv, nv) != nv) {
- evbuffer_free(scratch);
- free(iv);
- return -1;
- }
-
- for (i = 0; i < nv; i++) {
- const uint8_t *p = (const uint8_t *)iv[i].iov_base;
- const uint8_t *limit = p + iv[i].iov_len;
- char hex[2], c;
- while (p < limit) {
- c = *p++;
- hex[0] = "0123456789abcdef"[(c & 0xF0) >> 4];
- hex[1] = "0123456789abcdef"[(c & 0x0F) >> 0];
- evbuffer_add(scratch, hex, 2);
- }
- }
- free(iv);
- while (evbuffer_get_length(scratch) == 0 ||
- evbuffer_get_length(scratch) % 4 != 0)
- evbuffer_add(scratch, "=", 1);
-
- if (evbuffer_add(dest, http_query_1, sizeof http_query_1-1) ||
- evbuffer_add_buffer(dest, scratch) ||
- evbuffer_add(dest, http_query_2, sizeof http_query_2-1) ||
- evbuffer_add(dest, conn->peername, strlen(conn->peername)) ||
- evbuffer_add(dest, http_query_3, sizeof http_query_3-1)) {
- evbuffer_free(scratch);
- return -1;
- }
-
- evbuffer_free(scratch);
- evbuffer_drain(source, slen);
- conn_cease_transmission(conn);
- this->have_transmitted = true;
- return 0;
-
- } else {
- /* On the server side, we just fake up some HTTP response headers
- and then splat the data we were given. Binary is OK. */
- if (evbuffer_add(dest, http_response_1, sizeof http_response_1-1))
- return -1;
- if (evbuffer_add_printf(dest, "%lu\r\n\r\n",
- (unsigned long)evbuffer_get_length(source)) == -1)
- return -1;
- if (evbuffer_add_buffer(dest, source))
- return -1;
-
- conn_close_after_transmit(conn);
- this->have_transmitted = true;
- return 0;
- }
-}
-
-int
-x_http::receive(conn_t *conn, struct evbuffer *dest)
-{
- struct evbuffer *source = conn_get_inbound(conn);
- if (this->is_clientside) {
- /* Linearize the buffer out past the longest possible
- Content-Length header and subsequent blank line. 2**64 fits in
- 20 characters, and then we have two CRLFs; minus one for the
- NUL in sizeof http_response_1. Note that this does _not_
- guarantee that that much data is available. */
-
- size_t hlen = evbuffer_get_length(source);
- uint8_t *data, *p, *limit;
- uint64_t clen;
-
- log_debug("x_http: %lu byte response stream available%s",
- (unsigned long)hlen,
- hlen >= sizeof http_response_1 - 1 ? "" : " (incomplete)");
-
- if (this->have_received) {
- log_warn("x_http: protocol error: multiple responses");
- return -1;
- }
-
- if (hlen < sizeof http_response_1 - 1)
- return 0; /* incomplete */
-
- if (hlen > sizeof http_response_1 + 23)
- hlen = sizeof http_response_1 + 23;
-
- data = evbuffer_pullup(source, hlen);
- /* Validate response headers. */
- if (memcmp(data, http_response_1, sizeof http_response_1 - 1))
- return -1;
-
- /* There should be an unsigned number immediately after the text of
- http_response_1, followed by the four characters \r\n\r\n.
- We may not have the complete number yet. */
- p = data + sizeof http_response_1 - 1;
- limit = data + hlen;
- clen = 0;
- while (p < limit && '0' <= *p && *p <= '9') {
- clen = clen*10 + *p - '0';
- p++;
- }
- if (p+4 > limit)
- return 0; /* incomplete */
- if (p[0] != '\r' || p[1] != '\n' || p[2] != '\r' || p[3] != '\n')
- return -1;
-
- p += 4;
- hlen = p - data;
- /* Now we know how much data we're expecting after the blank line. */
- if (evbuffer_get_length(source) < hlen + clen)
- return 0; /* incomplete */
-
- /* we are go */
- if (evbuffer_drain(source, hlen))
- return -1;
-
- if ((uint64_t)evbuffer_remove_buffer(source, dest, clen) != clen)
- return -1;
-
- log_debug("x_http: decoded %lu byte response",
- (unsigned long)(hlen + clen));
-
- if (evbuffer_get_length(source) > 0) {
- log_warn("x_http: protocol error: extra response data");
- return -1;
- }
-
- this->have_received = 1;
- conn_expect_close(conn);
- return 0;
- } else {
- /* We need a scratch buffer here because the contract is that if
- we hit a decode error we *don't* write anything to 'dest'. */
- struct evbuffer *scratch;
- struct evbuffer_ptr s2, s3;
- uint8_t *data, *p, *limit;
- uint8_t c, h, secondhalf;
-
- log_debug("x_http: %lu byte query stream available",
- (unsigned long)evbuffer_get_length(source));
-
- if (this->have_received) {
- log_warn("x_http: protocol error: multiple queries");
- return -1;
- }
-
- /* Search for the second and third invariant bits of the query headers
- we expect. We completely ignore the contents of the Host header. */
- s2 = evbuffer_search(source, http_query_2,
- sizeof http_query_2 - 1, NULL);
- if (s2.pos == -1) {
- log_debug("x_http: did not find second piece of HTTP query");
- return 0;
- }
- s3 = evbuffer_search(source, http_query_3,
- sizeof http_query_3 - 1, &s2);
- if (s3.pos == -1) {
- log_debug("x_http: did not find third piece of HTTP query");
- return 0;
- }
- log_assert(s3.pos + sizeof http_query_3 - 1
- <= evbuffer_get_length(source));
-
- data = evbuffer_pullup(source, s2.pos);
- if (memcmp(data, "GET /", sizeof "GET /"-1)) {
- log_debug("x_http: unexpected HTTP verb: %.*s", 5, data);
- return -1;
- }
-
- p = data + sizeof "GET /"-1;
- limit = data + s2.pos;
-
- scratch = evbuffer_new();
- if (!scratch) return -1;
- if (evbuffer_expand(scratch, (limit - p)/2)) {
- evbuffer_free(scratch);
- return -1;
- }
-
- secondhalf = 0;
- while (p < limit) {
- if (!secondhalf) c = 0;
- if ('0' <= *p && *p <= '9') h = *p - '0';
- else if ('a' <= *p && *p <= 'f') h = *p - 'a' + 10;
- else if ('A' <= *p && *p <= 'F') h = *p - 'A' + 10;
- else if (*p == '=' && !secondhalf) {
- p++;
- continue;
- } else {
- evbuffer_free(scratch);
- log_debug("x_http: decode error: unexpected URI character %c", *p);
- return -1;
- }
-
- c = (c << 4) + h;
- if (secondhalf)
- evbuffer_add(scratch, &c, 1);
- secondhalf = !secondhalf;
- p++;
- }
-
- if (evbuffer_add_buffer(dest, scratch)) {
- evbuffer_free(scratch);
- log_debug("x_http: failed to transfer buffer");
- return -1;
- }
- evbuffer_drain(source, s3.pos + sizeof http_query_3 - 1);
- evbuffer_free(scratch);
- log_debug("x_http: decoded %lu byte query",
- (unsigned long)(s3.pos + sizeof http_query_3 - 1));
-
- if (evbuffer_get_length(source) > 0) {
- log_warn("x_http: protocol error: extra query data");
- return -1;
- }
-
- this->have_received = 1;
- conn_transmit_soon(conn, 2);
- return 0;
- }
-}
diff --git a/src/steg/x_http2.c b/src/steg/x_http2.c
deleted file mode 100644
index 7377196..0000000
--- a/src/steg/x_http2.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/* Copyright (c) 2011, SRI International
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-
- * Neither the names of the copyright owners nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- Contributors: Zack Weinberg, Vinod Yegneswaran
- See LICENSE for other credits and copying information
-*/
-
-
-
-#include "util.h"
-#include "connections.h"
-#include "steg.h"
-#include "payloads.h"
-#include "cookies.h"
-#include "swfSteg.h"
-#include "pdfSteg.h"
-#include "jsSteg.h"
-
-#include <event2/buffer.h>
-#include <stdio.h>
-
-
-
-
-
-
-#define MIN_COOKIE_SIZE 24
-#define MAX_COOKIE_SIZE 1024
-
-
-int
-x_http2_server_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source);
-
-int
-lookup_peer_name_from_ip(char* p_ip, char* p_name);
-
-
-static int has_peer_name = 0;
-static char peername[512];
-
-
-struct x_http2_steg_t
-{
- steg_t super;
-
- int have_transmitted;
- int have_received;
- int type;
-};
-
-
-STEG_DEFINE_MODULE(x_http2,
- 1024, /* client-server max data rate - made up */
- 10240, /* server-client max data rate - ditto */
- 1, /* max concurrent connections per IP */
- 1); /* max concurrent IPs */
-
-
-
-
-
-
-int x_http2_client_uri_transmit (steg_t *s, struct evbuffer *source, conn_t *conn);
-int x_http2_client_cookie_transmit (steg_t *s, struct evbuffer *source, conn_t *conn);
-
-void evbuffer_dump(struct evbuffer *buf, FILE *out);
-void buf_dump(unsigned char* buf, int len, FILE *out);
-int gen_uri_field(char* uri, unsigned int uri_sz, char* data, int datalen);
-
-
-void
-evbuffer_dump(struct evbuffer *buf, FILE *out)
-{
- int nextent = evbuffer_peek(buf, SSIZE_MAX, 0, 0, 0);
- struct evbuffer_iovec v[nextent];
- int i;
- const unsigned char *p, *limit;
-
- if (evbuffer_peek(buf, -1, 0, v, nextent) != nextent)
- abort();
-
- for (i = 0; i < nextent; i++) {
- p = v[i].iov_base;
- limit = p + v[i].iov_len;
-
- putc('|', out);
- while (p < limit) {
- if (*p < 0x20 || *p >= 0x7F || *p == '\\' || *p == '|')
- fprintf(out, "\\x%02x", *p);
- else
- putc(*p, out);
- p++;
- }
- }
- putc('|', out);
-}
-
-
-
-
-
-void
-buf_dump(unsigned char* buf, int len, FILE *out)
-{
- int i=0;
- putc('|', out);
- while (i < len) {
- if (buf[i] < 0x20 || buf[i] >= 0x7F || buf[i] == '\\' || buf[i]== '|')
- fprintf(out, "\\x%02x", buf[i]);
- else
- putc(buf[i], out);
- i++;
- }
- putc('|', out);
- putc('\n', out);
-}
-
-
-
-
-
-steg_t *
-x_http2_new(rng_t *rng, unsigned int is_clientside)
-{
-
- STEG_NEW(x_http2, state, rng, is_clientside);
-
- if (is_clientside)
- load_payloads("traces/client.out");
- else {
- load_payloads("traces/server.out");
- init_JS_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, JS_MIN_AVAIL_SIZE);
- // init_JS_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, JS_MIN_AVAIL_SIZE, HTTP_CONTENT_HTML);
- init_HTML_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, HTML_MIN_AVAIL_SIZE);
- init_PDF_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, PDF_MIN_AVAIL_SIZE);
- init_SWF_payload_pool(HTTP_MSG_BUF_SIZE, TYPE_HTTP_RESPONSE, 0);
- }
-
-
- /* if there were extra stuff to fill in, you would do it here */
- return upcast_steg(state);
-}
-
-void
-x_http2_del(steg_t *s)
-{
- x_http2_steg_t *state = downcast_steg(s);
-
- STEG_DEL(s);
-
- /* if there were extra stuff to deallocate, you would do it here */
- free(state);
-}
-
-
-// x_http2_detect determines if a packet should be processed by the http2 steg module
-unsigned int
-x_http2_detect(conn_t *conn)
-{
- struct evbuffer *buf = conn_get_inbound(conn);
- unsigned char *data;
-
- //return 0;
-/*****
- Here is a list of HTTP response codes extracted from the server-portals.out trace
-
-7369 HTTP/1.1 200 OK
- 470 HTTP/1.1 302 Found
- 350 HTTP/1.1 304 Not Modified
- 212 HTTP/1.1 302 Moved Temporarily
- 184 HTTP/1.1 204 No Content
- 451 HTTP/1.0 200 OK
- 36 HTTP/1.0 204 No Content
- 21 HTTP/1.1 301 Moved Permanently
- 19 HTTP/1.1 302 Object moved
- 15 HTTP/1.1 404 Not Found
-
- 7 HTTP/1.0 304 Not Modified
- 6 HTTP/1.1 302 Redirect
- 3 HTTP/1.0 200 Ok
- 2 HTTP/1.1 303 Object Moved
- 2 HTTP/1.0 301 Moved Permanently
- 2 HTTP/1.0 302 Moved Temporarily
- 2 HTTP/1.0 400 Bad request
- 2 HTTP/1.0 403 Forbidden
- 1 HTTP/1.0 404 Not Found
- 1 HTTP/1.1 200
- 1 HTTP/1.1 302 FOUND
- 1 HTTP/1.1 304
- 1 HTTP/1.1 400 Bad Request
- 1 HTTP/1.1 403 Forbidden
- 1 HTTP/1.1 503 Service Unavailable.
- *****/
-
- // The first part of a valid HTTP response should be of the form
- // HTTP/1.x nnn
-
- if (evbuffer_get_length(buf) >= 12) {
- data = evbuffer_pullup(buf, 12);
-
- if (data != NULL &&
- ((!memcmp(data, "HTTP/1.1 200", 12)) ||
- (!memcmp(data, "HTTP/1.1 302", 12)) ||
- (!memcmp(data, "HTTP/1.1 304", 12)) ||
- (!memcmp(data, "HTTP/1.1 204", 12)) ||
- (!memcmp(data, "HTTP/1.0 200", 12)) ||
- (!memcmp(data, "HTTP/1.0 204", 12)) ||
- (!memcmp(data, "HTTP/1.1 301", 12)) ||
- (!memcmp(data, "HTTP/1.1 302", 12)) ||
- (!memcmp(data, "HTTP/1.1 404", 12)))) {
- log_debug("x_http2_detect: valid response");
- return 1;
- }
- }
-
-
-
-
-
- // SC: if we are only interested in jsSteg, we may want to
- // consider HTTP/1.1 and HTTP/1.0 responses whose code is 200 only
-
- // check to see if this is a valid HTTP request
- //
- // the following is for HTTP requests used by the http2 steg module
- // The client always transmits "GET /" followed by at least four
- // characters that are either lowercase hex digits or equals
- // signs, so we need nine bytes of incoming data.
-
-
-
- if (evbuffer_get_length(buf) >= 9) {
- data = evbuffer_pullup(buf, 9);
- if (data != NULL && (!memcmp(data, "GET /", 5) || !memcmp(data, "POST /", 5) || !memcmp(data, "Cookie", 6))) {
- log_debug("x_http2_detect: valid request");
- return 1;
- }
- }
-
- log_debug("x_http2_detect: didn't find either HTTP request or response");
- /* Didn't find either the client or the server pattern. */
- return 0;
-}
-
-size_t
-x_http2_transmit_room(steg_t *s, conn_t *conn)
-{
- unsigned int mjc;
-
- if (downcast_steg(s)->have_transmitted)
- /* can't send any more on this connection */
- return 0;
-
-
- if (s->is_clientside) {
- /* per http://www.boutell.com/newfaq/misc/urllength.html,
- IE<9 can handle no more than 2048 characters in the path
- component of a URL; we're not talking to IE, but this limit
- means longer paths look fishy; we hex-encode the path, so
- we have to cut the number in half. */
- return (MIN_COOKIE_SIZE + rand() % (MAX_COOKIE_SIZE - MIN_COOKIE_SIZE)) / 4;
- // return 1024;
- }
- else {
-
- if (!downcast_steg(s)->have_received)
- return 0;
-
- switch(downcast_steg(s)->type) {
-
- case HTTP_CONTENT_SWF:
- return 1024;
-
- case HTTP_CONTENT_JAVASCRIPT:
- mjc = get_max_JS_capacity() / 2;
- if (mjc > 1024) {
- // it should be 1024 + ...., but seems like we need to be a little bit smaller (chopper bug?)
- int rval = 512 + rand()%(mjc - 1024);
- // fprintf(stderr, "returning rval %d, mjc %d\n", rval, mjc);
- return rval;
- }
- log_warn("js capacity too small\n");
- exit(-1);
-
- case HTTP_CONTENT_HTML:
- mjc = get_max_HTML_capacity() / 2;
- if (mjc > 1024) {
- // it should be 1024 + ...., but seems like we need to be a little bit smaller (chopper bug?)
- int rval = 512 + rand()%(mjc - 1024);
- // fprintf(stderr, "returning rval %d, mjc %d\n", rval, mjc);
- return rval;
- }
- log_warn("js capacity too small\n");
- exit(-1);
-
- case HTTP_CONTENT_PDF:
- // return 1024 + rand()%(get_max_PDF_capacity() - 1024)
- return PDF_MIN_AVAIL_SIZE;
- }
-
- return SIZE_MAX;
- }
-}
-
-
-
-
-
-
-int
-lookup_peer_name_from_ip(char* p_ip, char* p_name) {
- struct addrinfo* ailist;
- struct addrinfo* aip;
- struct addrinfo hint;
- char buf[128];
-
- hint.ai_flags = AI_CANONNAME;
- hint.ai_family = 0;
- hint.ai_socktype = 0;
- hint.ai_protocol = 0;
- hint.ai_addrlen = 0;
- hint.ai_canonname = NULL;
- hint.ai_addr = NULL;
- hint.ai_next = NULL;
-
- strcpy(buf, p_ip);
- buf[strchr(buf, ':') - buf] = 0;
-
-
- if (getaddrinfo(buf, NULL, &hint, &ailist)) {
- fprintf(stderr, "error: getaddrinfo() %s\n", p_ip);
- exit(1);
- }
-
- for (aip = ailist; aip != NULL; aip = aip->ai_next) {
- char buf[512];
- if (getnameinfo(aip->ai_addr, sizeof(struct sockaddr), buf, 512, NULL, 0, 0) == 0) {
- sprintf(p_name, "%s", buf);
- return 1;
- }
- }
-
- return 0;
-}
-
-
-
-
-
-
-
-
-int
-x_http2_client_cookie_transmit (steg_t *s, struct evbuffer *source, conn_t *conn) {
-
- /* On the client side, we have to embed the data in a GET query somehow;
- the only plausible places to put it are the URL and cookies. This
- presently uses the URL. And it can't be binary. */
- // struct evbuffer *scratch;
- struct evbuffer_iovec *iv;
- int i, nv;
- struct evbuffer *dest = conn_get_outbound(conn);
- size_t sbuflen = evbuffer_get_length(source);
- char buf[10000];
- unsigned char data[(int) sbuflen*2];
- // unsigned char outbuf[MAX_COOKIE_SIZE];
-
- unsigned char outbuf[(int) sbuflen*8];
- int datalen;
-
-
- // size_t sofar = 0;
- size_t cookie_len;
-
-
- /* Convert all the data in 'source' to hexadecimal and write it to
- 'scratch'. Data is padded to a multiple of four characters with
- equals signs. */
-
-
- unsigned int len = 0;
- unsigned int cnt = 0;
-
-
-
- datalen = 0;
- cookie_len = 4 * sbuflen + rand() % 4;
-
-
- nv = evbuffer_peek(source, sbuflen, NULL, NULL, 0);
- iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
-
- if (evbuffer_peek(source, sbuflen, NULL, iv, nv) != nv) {
- free(iv);
- return -1;
- }
-
- // retry up to 10 times
- while (!len) {
- len = find_client_payload(buf, sizeof(buf), TYPE_HTTP_REQUEST);
- if (cnt++ == 10) return -1;
- }
-
-
- if (has_peer_name == 0 && lookup_peer_name_from_ip((char*) conn->peername, peername))
- has_peer_name = 1;
-
- // if (find_uri_type(buf) != HTTP_CONTENT_SWF) {
- // fprintf(stderr, "%s\n", buf);
- // exit(-1);
- // }
-
-
-
- cnt = 0;
-
- for (i = 0; i < nv; i++) {
- const unsigned char *p = iv[i].iov_base;
- const unsigned char *limit = p + iv[i].iov_len;
- char c;
- while (p < limit && cnt < sbuflen) {
- c = *p++;
- data[datalen] = "0123456789abcdef"[(c & 0xF0) >> 4];
- data[datalen+1] = "0123456789abcdef"[(c & 0x0F) >> 0];
- datalen += 2;
- cnt++;
- }
- }
-
- free(iv);
-
- if (cookie_len < 4) cookie_len = 4;
-
- datalen = gen_cookie_field(outbuf, cookie_len, data, datalen);
- log_debug("CLIENT: sending cookie of length = %d %d\n", datalen, (int) cookie_len);
- // fprintf(stderr, "CLIENT: sending cookie of length = %d %d\n", datalen, (int) cookie_len);
-
- if (datalen < 0) {
- log_debug("cookie generation failed\n");
- return -1;
- }
-
-
- if (evbuffer_add(dest, buf, strstr(buf, "\r\n") - buf + 2) || // add uri field
- evbuffer_add(dest, "Host: ", 6) ||
- evbuffer_add(dest, peername, strlen(peername)) ||
- evbuffer_add(dest, strstr(buf, "\r\n"), len - (unsigned int) (strstr(buf, "\r\n") - buf)) || // add everything but first line
- evbuffer_add(dest, "Cookie: ", 8) ||
- evbuffer_add(dest, outbuf, cookie_len) ||
- evbuffer_add(dest, "\r\n\r\n", 4)) {
- log_debug("error ***********************");
- return -1;
- }
-
- // debug
- // log_warn("CLIENT HTTP request header:");
- // buf_dump((unsigned char*)buf, len, stderr);
-
- // sofar += datalen/2;
- evbuffer_drain(source, datalen/2);
-
- log_debug("CLIENT TRANSMITTED payload %d\n", (int) sbuflen);
-
- conn_cease_transmission(conn);
-
- downcast_steg(s)->type = find_uri_type(buf, sizeof(buf));
- downcast_steg(s)->have_transmitted = 1;
- return 0;
-}
-
-
-
-
-int gen_uri_field(char* uri, unsigned int uri_sz, char* data, int datalen) {
- unsigned int so_far = 0;
- uri[0] = 0;
-
- strcat(uri, "GET /");
- so_far = 5;
-
- while (datalen > 0) {
- unsigned int r = rand() % 4;
-
- if (r == 1) {
- r = rand() % 46;
- if (r < 20)
- uri[so_far++] = 'g' + r;
- else
- uri[so_far++] = 'A' + r - 20;
- }
- else {
- uri[so_far++] = data[0];
- data++;
- datalen--;
- }
-
-
-
- r = rand() % 8;
-
- if (r == 0 && datalen > 0)
- uri[so_far++] = '/';
-
- if (r == 2 && datalen > 0)
- uri[so_far++] = '_';
-
-
- if (so_far > uri_sz - 6) {
- fprintf(stderr, "too small\n");
- return 0;
- }
- }
-
- switch(rand()%4){
- case 1:
- memcpy(uri+so_far, ".htm ", 6);
- break;
- case 2:
- memcpy(uri+so_far, ".html ", 7);
- break;
- case 3:
- memcpy(uri+so_far, ".js ", 5);
- break;
- case 0:
- memcpy(uri+so_far, ".swf ", 6);
- break;
-
- }
-
- return strlen(uri);
-
-}
-
-
-
-
-
-int
-x_http2_client_uri_transmit (steg_t *s, struct evbuffer *source, conn_t *conn) {
-
-
- struct evbuffer *dest = conn_get_outbound(conn);
-
-
- struct evbuffer_iovec *iv;
- int i, nv;
-
- /* Convert all the data in 'source' to hexadecimal and write it to
- 'scratch'. Data is padded to a multiple of four characters with
- equals signs. */
- size_t slen = evbuffer_get_length(source);
- size_t datalen = 0;
- int cnt = 0;
- char data[2*slen];
-
- char outbuf[1024];
- int len =0;
- char buf[10000];
-
-
- if (has_peer_name == 0 && lookup_peer_name_from_ip((char*) conn->peername, peername))
- has_peer_name = 1;
-
-
-
- nv = evbuffer_peek(source, slen, NULL, NULL, 0);
- iv = xzalloc(sizeof(struct evbuffer_iovec) * nv);
- if (evbuffer_peek(source, slen, NULL, iv, nv) != nv) {
- free(iv);
- return -1;
- }
-
- for (i = 0; i < nv; i++) {
- const unsigned char *p = iv[i].iov_base;
- const unsigned char *limit = p + iv[i].iov_len;
- char c;
- while (p < limit) {
- c = *p++;
- data[datalen++] = "0123456789abcdef"[(c & 0xF0) >> 4];
- data[datalen++] = "0123456789abcdef"[(c & 0x0F) >> 0];
- }
- }
- free(iv);
-
-
-
- do {
- datalen = gen_uri_field(outbuf, sizeof(outbuf), data, datalen);
- } while (datalen == 0);
-
-
-
-
- // retry up to 10 times
- while (!len) {
- len = find_client_payload(buf, sizeof(buf), TYPE_HTTP_REQUEST);
- if (cnt++ == 10) return -1;
- }
-
-
- // fprintf(stderr, "outbuf = %s\n", outbuf);
-
- if (evbuffer_add(dest, outbuf, datalen) || // add uri field
- evbuffer_add(dest, "HTTP/1.1\r\nHost: ", 19) ||
- evbuffer_add(dest, peername, strlen(peername)) ||
- evbuffer_add(dest, strstr(buf, "\r\n"), len - (unsigned int) (strstr(buf, "\r\n") - buf)) || // add everything but first line
- evbuffer_add(dest, "\r\n", 2)) {
- log_debug("error ***********************");
- return -1;
- }
-
-
-
- evbuffer_drain(source, slen);
- conn_cease_transmission(conn);
- downcast_steg(s)->type = find_uri_type(outbuf, sizeof(outbuf));
- downcast_steg(s)->have_transmitted = 1;
- return 0;
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-int
-x_http2_transmit(steg_t *s, struct evbuffer *source, conn_t *conn)
-{
- // struct evbuffer *dest = conn_get_outbound(conn);
-
- // fprintf(stderr, "in x_http2_ transmit %d\n", downcast_steg(s)->type);
-
-
-
- if (s->is_clientside) {
- /* On the client side, we have to embed the data in a GET query somehow;
- the only plausible places to put it are the URL and cookies. This
- presently uses the URL. And it can't be binary. */
-
- if (evbuffer_get_length(source) < 72)
- return x_http2_client_uri_transmit(s, source, conn); //@@
- return x_http2_client_cookie_transmit(s, source, conn); //@@
- }
- else {
- int rval = -1;
- switch(downcast_steg(s)->type) {
-
- case HTTP_CONTENT_SWF:
- rval = x_http2_server_SWF_transmit(s, source, conn);
- break;
-
- case HTTP_CONTENT_JAVASCRIPT:
- rval = x_http2_server_JS_transmit(s, source, conn, HTTP_CONTENT_JAVASCRIPT);
- break;
-
- case HTTP_CONTENT_HTML:
- rval = x_http2_server_JS_transmit(s, source, conn, HTTP_CONTENT_HTML);
- break;
-
- case HTTP_CONTENT_PDF:
- rval = x_http2_server_PDF_transmit(s, source, conn);
- break;
- }
-
- if (rval == 0) downcast_steg(s)->have_transmitted = 1;
- return rval;
- }
-}
-
-
-
-
-
-
-int
-x_http2_server_receive(steg_t *s, conn_t *conn, struct evbuffer *dest, struct evbuffer* source) {
-
- int cnt = 0;
- unsigned char* data;
- int type;
-
- do {
- struct evbuffer_ptr s2 = evbuffer_search(source, "\r\n\r\n", sizeof ("\r\n\r\n") -1 , NULL);
- unsigned char *p;
- unsigned char c, h, secondhalf;
- char outbuf[MAX_COOKIE_SIZE];
- int sofar = 0;
- int cookie_mode = 0;
-
-
- if (s2.pos == -1) {
- log_debug("Did not find end of request %d", (int) evbuffer_get_length(source));
- // evbuffer_dump(source, stderr);
- return RECV_INCOMPLETE;
- }
-
- log_debug("SERVER received request header of length %d", (int)s2.pos);
-
- data = evbuffer_pullup(source, s2.pos+4);
-
- if (data == NULL) {
- log_debug("SERVER evbuffer_pullup fails");
- return RECV_BAD;
- }
-
-
- data[s2.pos+3] = 0;
-
- type = find_uri_type((char *)data, s2.pos+4);
-
- if (strstr((char*) data, "Cookie") != NULL) {
- p = (unsigned char*) strstr((char*) data, "Cookie:") + sizeof "Cookie: "-1;
- cookie_mode = 1;
- }
- else
- p = data + sizeof "GET /" -1;
-
-
- secondhalf = 0;
- c = 0;
-
-
- while (strncmp((char*) p, "\r\n", 2) != 0 && (cookie_mode != 0 || p[0] != '.')) {
- if (!secondhalf)
- c = 0;
- if ('0' <= *p && *p <= '9')
- h = *p - '0';
- else if ('a' <= *p && *p <= 'f')
- h = *p - 'a' + 10;
- else {
- p++;
- continue;
- }
-
- c = (c << 4) + h;
- if (secondhalf) {
- outbuf[sofar++] = c;
- cnt++;
- }
- secondhalf = !secondhalf;
- p++;
- }
-
- outbuf[sofar] = 0;
-
- if (secondhalf) {
- fprintf(stderr, "incorrect cookie or uri recovery \n");
- exit(-1);
- }
-
-
-
- if (evbuffer_add(dest, outbuf, sofar)) {
- log_debug("Failed to transfer buffer");
- return RECV_BAD;
- }
- evbuffer_drain(source, s2.pos + sizeof("\r\n\r\n") - 1);
- } while (evbuffer_get_length(source));
-
-
- downcast_steg(s)->have_received = 1;
- downcast_steg(s)->type = type;
- // fprintf(stderr, "SERVER RECEIVED payload %d %d\n", cnt, type);
-
- conn_transmit_soon(conn, 100);
- return RECV_GOOD;
-}
-
-
-
-
-
-
-
-
-
-
-
-static int
-x_http2_receive(steg_t *s, conn_t *conn, struct evbuffer *dest)
-{
- struct evbuffer *source = conn_get_inbound(conn);
- // unsigned int type;
- int rval = RECV_BAD;
-
-
- if (s->is_clientside) {
-
- // fprintf(stderr, "client type = %d\n", downcast_steg(s)->type);
-
- switch(downcast_steg(s)->type) {
-
- case HTTP_CONTENT_SWF:
- rval = x_http2_handle_client_SWF_receive(s, conn, dest, source);
- break;
-
- case HTTP_CONTENT_JAVASCRIPT:
- case HTTP_CONTENT_HTML:
- rval = x_http2_handle_client_JS_receive(s, conn, dest, source);
- break;
-
- case HTTP_CONTENT_PDF:
- rval = x_http2_handle_client_PDF_receive(s, conn, dest, source);
- break;
- }
-
- if (rval == RECV_GOOD) downcast_steg(s)->have_received = 1;
- return rval;
-
- } else {
- return x_http2_server_receive(s, conn, dest, source);
- }
-
-
-}
diff --git a/src/steg/zpack.c b/src/steg/zpack.c
deleted file mode 100644
index 63aa412..0000000
--- a/src/steg/zpack.c
+++ /dev/null
@@ -1,408 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <time.h>
-#include <stdlib.h>
-#include "zlib.h"
-#include "zpack.h"
-
-
-#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
-# include <fcntl.h>
-# include <io.h>
-# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
-#else
-# define SET_BINARY_MODE(file)
-#endif
-
-#define CHUNK 16384
-
-/* Compress from file source to file dest until EOF on source.
- def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
- allocated for processing, Z_STREAM_ERROR if an invalid compression
- level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
- version of the library linked do not match, or Z_ERRNO if there is
- an error reading or writing the files. */
-
-
-int def(char *source, int slen, char *dest, int dlen, int level)
-{
- int ret, flush;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
- int dlen_orig = dlen;
-
- /* allocate deflate state */
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- ret = deflateInit(&strm, level);
- if (ret != Z_OK)
- return ret;
-
- /* compress until end of file */
- do {
-
- if (slen > CHUNK)
- strm.avail_in = CHUNK;
- else
- strm.avail_in = slen;
-
- memcpy (in, source, strm.avail_in);
- slen = slen - strm.avail_in;
- source = source + strm.avail_in;
-
- flush = (slen == 0) ? Z_FINISH : Z_NO_FLUSH;
- strm.next_in = in;
-
- /* run deflate() on input until output buffer not full, finish
- compression if all of source has been read in */
- do {
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = deflate(&strm, flush); /* no bad return value */
- assert(ret != Z_STREAM_ERROR); /* state not clobbered */
- have = CHUNK - strm.avail_out;
-
- if ((unsigned int) dlen < have) {
- fprintf(stderr, "dest buf too small!\n");
- return Z_ERRNO;
- }
-
- memcpy(dest, out, have);
- dest += have;
- dlen = dlen - have;
- } while (strm.avail_out == 0);
- assert(strm.avail_in == 0); /* all input will be used */
-
- /* done when last data in file processed */
- } while (flush != Z_FINISH);
- assert(ret == Z_STREAM_END); /* stream will be complete */
-
- /* clean up and return */
- (void)deflateEnd(&strm);
-
- printf("hello here...\n");
- return (dlen_orig - dlen);
- // return Z_OK;
-}
-
-/* Decompress from file source to file dest until stream ends or EOF.
- inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
- allocated for processing, Z_DATA_ERROR if the deflate data is
- invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
- the version of the library linked do not match, or Z_ERRNO if there
- is an error reading or writing the files. */
-
-
-
-
-int inf(char *source, int slen, char *dest, int dlen)
-{
- int ret;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
- int dlen_orig = dlen;
-
-
- /* allocate inflate state */
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
- ret = inflateInit(&strm);
- if (ret != Z_OK)
- return ret;
-
- /* decompress until deflate stream ends or end of file */
- do {
-
- if (slen == 0)
- break;
-
- if (slen > CHUNK)
- strm.avail_in = CHUNK;
- else
- strm.avail_in = slen;
-
- memcpy(in, source, strm.avail_in);
- slen = slen - strm.avail_in;
- source = source + strm.avail_in;
-
-
-
- strm.next_in = in;
-
- /* run inflate() on input until output buffer not full */
- do {
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = inflate(&strm, Z_NO_FLUSH);
- assert(ret != Z_STREAM_ERROR); /* state not clobbered */
- switch (ret) {
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR; /* and fall through */
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- (void)inflateEnd(&strm);
- return ret;
- }
- have = CHUNK - strm.avail_out;
-
-
- if ((unsigned int) dlen < have) {
- fprintf(stderr, "dest buf too small!\n");
- return Z_ERRNO;
- }
-
- memcpy(dest, out, have);
- dest += have;
- dlen = dlen - have;
-
- } while (strm.avail_out == 0);
-
- /* done when inflate() says it's done */
- } while (ret != Z_STREAM_END);
-
- /* clean up and return */
- (void)inflateEnd(&strm);
-
- if (ret == Z_STREAM_END)
- return dlen_orig - dlen;
- return Z_DATA_ERROR;
-}
-
-/* report a zlib or i/o error */
-void zerr(int ret)
-
-{
- fputs("zpipe: ", stderr);
- switch (ret) {
- case Z_ERRNO:
- if (ferror(stdin))
- fputs("error reading stdin\n", stderr);
- if (ferror(stdout))
- fputs("error writing stdout\n", stderr);
- break;
- case Z_STREAM_ERROR:
- fputs("invalid compression level\n", stderr);
- break;
- case Z_DATA_ERROR:
- fputs("invalid or incomplete deflate data\n", stderr);
- break;
- case Z_MEM_ERROR:
- fputs("out of memory\n", stderr);
- break;
- case Z_VERSION_ERROR:
- fputs("zlib version mismatch!\n", stderr);
- }
-}
-
-
-
-
-
-
-
-
-/* assumes that we know there is exactly 10 bytes of gzip header */
-
-int gzInflate(char *source, int slen, char *dest, int dlen)
-{
- int ret;
- unsigned have;
- z_stream strm;
- unsigned char in[CHUNK];
- unsigned char out[CHUNK];
- int dlen_orig = dlen;
-
-
- /* allocate inflate state */
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
-
-
- ret = inflateInit2(&strm, -MAX_WBITS);
- if (ret != Z_OK)
- return ret;
-
- source = source + 10;
- slen -= 10;
-
- /* decompress until deflate stream ends or end of file */
- do {
-
- if (slen == 0)
- break;
-
- if (slen > CHUNK)
- strm.avail_in = CHUNK;
- else
- strm.avail_in = slen;
-
- memcpy(in, source, strm.avail_in);
- slen = slen - strm.avail_in;
- source = source + strm.avail_in;
-
-
-
- strm.next_in = in;
-
- /* run inflate() on input until output buffer not full */
- do {
- strm.avail_out = CHUNK;
- strm.next_out = out;
- ret = inflate(&strm, Z_NO_FLUSH);
- assert(ret != Z_STREAM_ERROR); /* state not clobbered */
- switch (ret) {
- case Z_NEED_DICT:
- ret = Z_DATA_ERROR; /* and fall through */
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- (void)inflateEnd(&strm);
- return ret;
- }
- have = CHUNK - strm.avail_out;
-
- if ((unsigned int) dlen < have) {
- fprintf(stderr, "dest buf too small!\n");
- return Z_ERRNO;
- }
-
- memcpy(dest, out, have);
- dest += have;
- dlen = dlen - have;
-
- } while (strm.avail_out == 0);
-
- /* done when inflate() says it's done */
- } while (ret != Z_STREAM_END);
-
- /* clean up and return */
- (void)inflateEnd(&strm);
-
- if (ret == Z_STREAM_END)
- return dlen_orig - dlen;
- return Z_DATA_ERROR;
-}
-
-
-
-
-
-
-
-int gzDeflate(char* start, off_t insz, char *buf, off_t outsz, time_t mtime) {
- unsigned char *c;
- unsigned long crc;
- z_stream z;
-
- z.zalloc = Z_NULL;
- z.zfree = Z_NULL;
- z.opaque = Z_NULL;
-
- if (Z_OK != deflateInit2(&z,
- Z_DEFAULT_COMPRESSION,
- Z_DEFLATED,
- -MAX_WBITS, /* supress zlib-header */
- 8,
- Z_DEFAULT_STRATEGY)) {
- return -1;
- }
-
- z.next_in = (unsigned char *)start;
- z.avail_in = insz;
- z.total_in = 0;
-
-
- /* write gzip header */
-
- c = (unsigned char *) buf;
- c[0] = 0x1f;
- c[1] = 0x8b;
- c[2] = Z_DEFLATED;
- c[3] = 0; /* options */
- c[4] = (mtime >> 0) & 0xff;
- c[5] = (mtime >> 8) & 0xff;
- c[6] = (mtime >> 16) & 0xff;
- c[7] = (mtime >> 24) & 0xff;
- c[8] = 0x00; /* extra flags */
- c[9] = 0x03; /* UNIX */
-
- z.next_out = c + 10;
- z.avail_out = outsz - 10 - 8;
- z.total_out = 0;
-
- if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
- deflateEnd(&z);
- return -1;
- }
-
-
- crc = generate_crc32c(start, insz);
-
- c = (unsigned char *)buf + 10 + z.total_out;
-
- c[0] = (crc >> 0) & 0xff;
- c[1] = (crc >> 8) & 0xff;
- c[2] = (crc >> 16) & 0xff;
- c[3] = (crc >> 24) & 0xff;
- c[4] = (z.total_in >> 0) & 0xff;
- c[5] = (z.total_in >> 8) & 0xff;
- c[6] = (z.total_in >> 16) & 0xff;
- c[7] = (z.total_in >> 24) & 0xff;
-
-
-
- if (Z_OK != deflateEnd(&z)) {
- return -1;
- }
-
- return 10 + z.total_out + 8;
-
-}
-
-
-
-
-
-/* compress or decompress from stdin to stdout */
-/* int main(int argc, char **argv) */
-/* { */
-/* int ret; */
-/* char buf1[32] = "abcasdfadfadfadf23fasdfa23sdfsdf"; */
-/* char buf2[100]; */
-/* char buf3[100]; */
-/* int i; */
-
-/* bzero(buf2, sizeof(buf2)); */
-/* bzero(buf3, sizeof(buf3)); */
-
-
-/* // ret = def(buf1, 3, buf2, 100, Z_DEFAULT_COMPRESSION); */
-/* ret = gzDeflate(buf1, sizeof(buf1), buf2, sizeof(buf2), time(NULL)); */
-/* if (ret <= 0) */
-/* zerr(ret); */
-
-/* /\* for (i=0; i < ret; i++) */
-/* putc(buf2[i], stdout); */
-/* *\/ */
-
-
-/* // printf("len = %d\n", ret); */
-
-/* ret = gzInflate(buf2, ret, buf3, 100); */
-/* if (ret <= 0) */
-/* zerr(ret); */
-/* printf("hello %s\n", buf3); */
-
-
-/* } */
diff --git a/src/steg/zpack.cc b/src/steg/zpack.cc
new file mode 100644
index 0000000..63aa412
--- /dev/null
+++ b/src/steg/zpack.cc
@@ -0,0 +1,408 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include "zlib.h"
+#include "zpack.h"
+
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#define CHUNK 16384
+
+/* Compress from file source to file dest until EOF on source.
+ def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+ allocated for processing, Z_STREAM_ERROR if an invalid compression
+ level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
+ version of the library linked do not match, or Z_ERRNO if there is
+ an error reading or writing the files. */
+
+
+int def(char *source, int slen, char *dest, int dlen, int level)
+{
+ int ret, flush;
+ unsigned have;
+ z_stream strm;
+ unsigned char in[CHUNK];
+ unsigned char out[CHUNK];
+ int dlen_orig = dlen;
+
+ /* allocate deflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = deflateInit(&strm, level);
+ if (ret != Z_OK)
+ return ret;
+
+ /* compress until end of file */
+ do {
+
+ if (slen > CHUNK)
+ strm.avail_in = CHUNK;
+ else
+ strm.avail_in = slen;
+
+ memcpy (in, source, strm.avail_in);
+ slen = slen - strm.avail_in;
+ source = source + strm.avail_in;
+
+ flush = (slen == 0) ? Z_FINISH : Z_NO_FLUSH;
+ strm.next_in = in;
+
+ /* run deflate() on input until output buffer not full, finish
+ compression if all of source has been read in */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = deflate(&strm, flush); /* no bad return value */
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ have = CHUNK - strm.avail_out;
+
+ if ((unsigned int) dlen < have) {
+ fprintf(stderr, "dest buf too small!\n");
+ return Z_ERRNO;
+ }
+
+ memcpy(dest, out, have);
+ dest += have;
+ dlen = dlen - have;
+ } while (strm.avail_out == 0);
+ assert(strm.avail_in == 0); /* all input will be used */
+
+ /* done when last data in file processed */
+ } while (flush != Z_FINISH);
+ assert(ret == Z_STREAM_END); /* stream will be complete */
+
+ /* clean up and return */
+ (void)deflateEnd(&strm);
+
+ printf("hello here...\n");
+ return (dlen_orig - dlen);
+ // return Z_OK;
+}
+
+/* Decompress from file source to file dest until stream ends or EOF.
+ inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+ allocated for processing, Z_DATA_ERROR if the deflate data is
+ invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
+ the version of the library linked do not match, or Z_ERRNO if there
+ is an error reading or writing the files. */
+
+
+
+
+int inf(char *source, int slen, char *dest, int dlen)
+{
+ int ret;
+ unsigned have;
+ z_stream strm;
+ unsigned char in[CHUNK];
+ unsigned char out[CHUNK];
+ int dlen_orig = dlen;
+
+
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm);
+ if (ret != Z_OK)
+ return ret;
+
+ /* decompress until deflate stream ends or end of file */
+ do {
+
+ if (slen == 0)
+ break;
+
+ if (slen > CHUNK)
+ strm.avail_in = CHUNK;
+ else
+ strm.avail_in = slen;
+
+ memcpy(in, source, strm.avail_in);
+ slen = slen - strm.avail_in;
+ source = source + strm.avail_in;
+
+
+
+ strm.next_in = in;
+
+ /* run inflate() on input until output buffer not full */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR; /* and fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ return ret;
+ }
+ have = CHUNK - strm.avail_out;
+
+
+ if ((unsigned int) dlen < have) {
+ fprintf(stderr, "dest buf too small!\n");
+ return Z_ERRNO;
+ }
+
+ memcpy(dest, out, have);
+ dest += have;
+ dlen = dlen - have;
+
+ } while (strm.avail_out == 0);
+
+ /* done when inflate() says it's done */
+ } while (ret != Z_STREAM_END);
+
+ /* clean up and return */
+ (void)inflateEnd(&strm);
+
+ if (ret == Z_STREAM_END)
+ return dlen_orig - dlen;
+ return Z_DATA_ERROR;
+}
+
+/* report a zlib or i/o error */
+void zerr(int ret)
+
+{
+ fputs("zpipe: ", stderr);
+ switch (ret) {
+ case Z_ERRNO:
+ if (ferror(stdin))
+ fputs("error reading stdin\n", stderr);
+ if (ferror(stdout))
+ fputs("error writing stdout\n", stderr);
+ break;
+ case Z_STREAM_ERROR:
+ fputs("invalid compression level\n", stderr);
+ break;
+ case Z_DATA_ERROR:
+ fputs("invalid or incomplete deflate data\n", stderr);
+ break;
+ case Z_MEM_ERROR:
+ fputs("out of memory\n", stderr);
+ break;
+ case Z_VERSION_ERROR:
+ fputs("zlib version mismatch!\n", stderr);
+ }
+}
+
+
+
+
+
+
+
+
+/* assumes that we know there is exactly 10 bytes of gzip header */
+
+int gzInflate(char *source, int slen, char *dest, int dlen)
+{
+ int ret;
+ unsigned have;
+ z_stream strm;
+ unsigned char in[CHUNK];
+ unsigned char out[CHUNK];
+ int dlen_orig = dlen;
+
+
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+
+
+ ret = inflateInit2(&strm, -MAX_WBITS);
+ if (ret != Z_OK)
+ return ret;
+
+ source = source + 10;
+ slen -= 10;
+
+ /* decompress until deflate stream ends or end of file */
+ do {
+
+ if (slen == 0)
+ break;
+
+ if (slen > CHUNK)
+ strm.avail_in = CHUNK;
+ else
+ strm.avail_in = slen;
+
+ memcpy(in, source, strm.avail_in);
+ slen = slen - strm.avail_in;
+ source = source + strm.avail_in;
+
+
+
+ strm.next_in = in;
+
+ /* run inflate() on input until output buffer not full */
+ do {
+ strm.avail_out = CHUNK;
+ strm.next_out = out;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR; /* and fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ return ret;
+ }
+ have = CHUNK - strm.avail_out;
+
+ if ((unsigned int) dlen < have) {
+ fprintf(stderr, "dest buf too small!\n");
+ return Z_ERRNO;
+ }
+
+ memcpy(dest, out, have);
+ dest += have;
+ dlen = dlen - have;
+
+ } while (strm.avail_out == 0);
+
+ /* done when inflate() says it's done */
+ } while (ret != Z_STREAM_END);
+
+ /* clean up and return */
+ (void)inflateEnd(&strm);
+
+ if (ret == Z_STREAM_END)
+ return dlen_orig - dlen;
+ return Z_DATA_ERROR;
+}
+
+
+
+
+
+
+
+int gzDeflate(char* start, off_t insz, char *buf, off_t outsz, time_t mtime) {
+ unsigned char *c;
+ unsigned long crc;
+ z_stream z;
+
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ z.opaque = Z_NULL;
+
+ if (Z_OK != deflateInit2(&z,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ -MAX_WBITS, /* supress zlib-header */
+ 8,
+ Z_DEFAULT_STRATEGY)) {
+ return -1;
+ }
+
+ z.next_in = (unsigned char *)start;
+ z.avail_in = insz;
+ z.total_in = 0;
+
+
+ /* write gzip header */
+
+ c = (unsigned char *) buf;
+ c[0] = 0x1f;
+ c[1] = 0x8b;
+ c[2] = Z_DEFLATED;
+ c[3] = 0; /* options */
+ c[4] = (mtime >> 0) & 0xff;
+ c[5] = (mtime >> 8) & 0xff;
+ c[6] = (mtime >> 16) & 0xff;
+ c[7] = (mtime >> 24) & 0xff;
+ c[8] = 0x00; /* extra flags */
+ c[9] = 0x03; /* UNIX */
+
+ z.next_out = c + 10;
+ z.avail_out = outsz - 10 - 8;
+ z.total_out = 0;
+
+ if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
+ deflateEnd(&z);
+ return -1;
+ }
+
+
+ crc = generate_crc32c(start, insz);
+
+ c = (unsigned char *)buf + 10 + z.total_out;
+
+ c[0] = (crc >> 0) & 0xff;
+ c[1] = (crc >> 8) & 0xff;
+ c[2] = (crc >> 16) & 0xff;
+ c[3] = (crc >> 24) & 0xff;
+ c[4] = (z.total_in >> 0) & 0xff;
+ c[5] = (z.total_in >> 8) & 0xff;
+ c[6] = (z.total_in >> 16) & 0xff;
+ c[7] = (z.total_in >> 24) & 0xff;
+
+
+
+ if (Z_OK != deflateEnd(&z)) {
+ return -1;
+ }
+
+ return 10 + z.total_out + 8;
+
+}
+
+
+
+
+
+/* compress or decompress from stdin to stdout */
+/* int main(int argc, char **argv) */
+/* { */
+/* int ret; */
+/* char buf1[32] = "abcasdfadfadfadf23fasdfa23sdfsdf"; */
+/* char buf2[100]; */
+/* char buf3[100]; */
+/* int i; */
+
+/* bzero(buf2, sizeof(buf2)); */
+/* bzero(buf3, sizeof(buf3)); */
+
+
+/* // ret = def(buf1, 3, buf2, 100, Z_DEFAULT_COMPRESSION); */
+/* ret = gzDeflate(buf1, sizeof(buf1), buf2, sizeof(buf2), time(NULL)); */
+/* if (ret <= 0) */
+/* zerr(ret); */
+
+/* /\* for (i=0; i < ret; i++) */
+/* putc(buf2[i], stdout); */
+/* *\/ */
+
+
+/* // printf("len = %d\n", ret); */
+
+/* ret = gzInflate(buf2, ret, buf3, 100); */
+/* if (ret <= 0) */
+/* zerr(ret); */
+/* printf("hello %s\n", buf3); */
+
+
+/* } */
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits