[tor-commits] [stegotorus/master] Merge branch 'master' into stegotorus
zwol at torproject.org
zwol at torproject.org
Fri Jul 20 23:17:06 UTC 2012
commit 250e0f9ceaae483ae78e934529682c528d2ac7c0
Merge: 15ccb15 200c1ea
Author: Zack Weinberg <zackw at cmu.edu>
Date: Thu Dec 1 23:29:48 2011 +0000
Merge branch 'master' into stegotorus
.gitignore | 6 +-
LICENSE | 39 +-
Makefile.am | 99 ++--
README | 8 +-
autogen.sh | 2 -
configure.ac | 55 +-
doc/TODO | 30 +-
doc/protocol-spec.txt | 104 ---
doc/tor-obfs-howto.txt | 101 ---
doc/tor-st-howto.txt | 101 +++
m4/pkg.m4 | 10 +-
src/connections.c | 392 -----------
src/connections.cc | 400 ++++++++++++
src/connections.h | 103 +++-
src/container.c | 1438 -----------------------------------------
src/container.h | 683 -------------------
src/crypt.c | 216 ------
src/crypt.cc | 269 ++++++++
src/crypt.h | 152 +++--
src/genmodtable.sh | 12 +-
src/ht.h | 471 --------------
src/main.c | 399 ------------
src/main.cc | 398 ++++++++++++
src/network.c | 827 -----------------------
src/network.cc | 826 +++++++++++++++++++++++
src/protocol.c | 58 --
src/protocol.cc | 41 ++
src/protocol.h | 314 ++++------
src/protocol/chop.cc | 1308 +++++++++++++++++++++++++++++++++++++
src/protocol/x_null.cc | 243 +++++++
src/protocols/chop.c | 1379 ---------------------------------------
src/protocols/dummy.c | 256 --------
src/protocols/obfs2.c | 659 -------------------
src/protocols/obfs2.h | 81 ---
src/protocols/x_dsteg.c | 572 ----------------
src/protocols/x_rr.c | 1072 ------------------------------
src/rng.cc | 88 +++
src/rng.h | 19 +-
src/sha256.c | 290 ---------
src/sha256.h | 16 -
src/socks.c | 614 ------------------
src/socks.cc | 612 ++++++++++++++++++
src/socks.h | 4 +-
src/steg.c | 67 --
src/steg.cc | 44 ++
src/steg.h | 151 +++---
src/steg/x_http.c | 371 -----------
src/steg/x_http.cc | 360 ++++++++++
src/test/genunitgrps.sh | 2 +-
src/test/itestlib.py | 165 +++++
src/test/obfstestlib.py | 165 -----
src/test/test_socks.py | 10 +-
src/test/test_tl.py | 36 +-
src/test/tinytest.c | 383 -----------
src/test/tinytest.cc | 383 +++++++++++
src/test/tltester.c | 662 -------------------
src/test/tltester.cc | 659 +++++++++++++++++++
src/test/unittest.c | 209 ------
src/test/unittest.cc | 119 ++++
src/test/unittest.h | 4 -
src/test/unittest_config.c | 131 ----
src/test/unittest_config.cc | 86 +++
src/test/unittest_container.c | 768 ----------------------
src/test/unittest_crypt.c | 180 -----
src/test/unittest_crypt.cc | 407 ++++++++++++
src/test/unittest_obfs2.c | 268 --------
src/test/unittest_socks.c | 597 -----------------
src/test/unittest_socks.cc | 597 +++++++++++++++++
src/test/unittest_transfer.c | 146 -----
src/test/unittest_transfer.cc | 113 ++++
src/util.c | 709 --------------------
src/util.cc | 706 ++++++++++++++++++++
src/util.h | 170 +++--
73 files changed, 8524 insertions(+), 14911 deletions(-)
diff --cc Makefile.am
index e8b68f5,de3c9b2..ebf44d9
--- a/Makefile.am
+++ b/Makefile.am
@@@ -2,72 -2,55 +2,63 @@@
# Copyright 2011 Nick Mathewson, George Kadianakis, Zack Weinberg
# See LICENSE for other credits and copying information
- ACLOCAL_AMFLAGS = -I m4
- WARNINGS = -std=gnu99 -pedantic -Wall -Wextra -Wformat=2 -Wwrite-strings \
- -Wstrict-prototypes -Wmissing-prototypes -Wdeclaration-after-statement \
- -Wno-unused-parameter -Wno-overlength-strings -Wno-long-long -Werror
- AM_CPPFLAGS = -I. -I$(srcdir)/src -D_FORTIFY_SOURCE=2
- AM_CFLAGS = $(WARNINGS) @libevent_CFLAGS@ @libcrypto_CFLAGS@
- LDADD = libobfsproxy.a @libevent_LIBS@ @libcrypto_LIBS@ @ws32_LIBS@
+ ACLOCAL_AMFLAGS = -I m4 --install
- bin_PROGRAMS = obfsproxy
- noinst_LIBRARIES = libobfsproxy.a
- noinst_PROGRAMS = unittests tltester
+ WARNINGS = -Werror -Wall -Wextra -Wformat=2
+
+ AM_CXXFLAGS = -std=c++98 $(WARNINGS)
+ AM_CPPFLAGS = -I. -I$(srcdir)/src -D_FORTIFY_SOURCE=2 $(lib_CPPFLAGS)
+ LDADD = libstegotorus.a
+
+ noinst_LIBRARIES = libstegotorus.a
+ noinst_PROGRAMS = unittests tltester
+ bin_PROGRAMS = stegotorus
PROTOCOLS = \
- src/protocols/dummy.c \
- src/protocols/chop.c \
- src/protocols/obfs2.c \
- src/protocols/x_dsteg.c \
- src/protocols/x_rr.c
+ src/protocol/chop.cc \
+ src/protocol/x_null.cc
STEGANOGRAPHERS = \
- src/steg/x_http.c \
- src/steg/x_http.cc
++ 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
- libobfsproxy_a_SOURCES = \
- src/connections.c \
- src/container.c \
- src/crypt.c \
- src/network.c \
- src/protocol.c \
- src/socks.c \
- src/steg.c \
- src/util.c \
+ libstegotorus_a_SOURCES = \
+ src/connections.cc \
+ src/crypt.cc \
+ src/network.cc \
+ src/protocol.cc \
+ src/rng.cc \
+ src/socks.cc \
+ src/steg.cc \
+ src/util.cc \
$(PROTOCOLS) $(STEGANOGRAPHERS)
- nodist_libobfsproxy_a_SOURCES = protolist.c steglist.c
-
- if NEED_SHA256
- libobfsproxy_a_SOURCES += src/sha256.c
- endif
+ nodist_libstegotorus_a_SOURCES = protolist.cc steglist.cc
- obfsproxy_SOURCES = \
- src/main.c
+ stegotorus_SOURCES = \
+ src/main.cc
UTGROUPS = \
- src/test/unittest_container.c \
- src/test/unittest_crypt.c \
- src/test/unittest_socks.c \
- src/test/unittest_obfs2.c \
- src/test/unittest_config.c \
- src/test/unittest_transfer.c
+ src/test/unittest_crypt.cc \
+ src/test/unittest_socks.cc \
+ src/test/unittest_config.cc \
+ src/test/unittest_transfer.cc
unittests_SOURCES = \
- src/test/tinytest.c \
- src/test/unittest.c \
+ src/test/tinytest.cc \
+ src/test/unittest.cc \
$(UTGROUPS)
- nodist_unittests_SOURCES = unitgrplist.c
+ nodist_unittests_SOURCES = unitgrplist.cc
- tltester_SOURCES = src/test/tltester.c
+ tltester_SOURCES = src/test/tltester.cc
noinst_HEADERS = \
src/connections.h \
diff --cc src/steg/x_http.cc
index 0000000,9ee6eb5..e1d9780
mode 000000,100644..100644
--- a/src/steg/x_http.cc
+++ b/src/steg/x_http.cc
@@@ -1,0 -1,359 +1,360 @@@
+ /* 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;
+ }
+ }
More information about the tor-commits
mailing list