Changeset View
Changeset View
Standalone View
Standalone View
openvpn23/files/extra-tunnelblick-openvpn_xorpatch
| Property | Old Value | New Value |
|---|---|---|
| fbsd:nokeywords | null | yes \ No newline at end of property |
| svn:eol-style | null | native \ No newline at end of property |
| svn:mime-type | null | text/plain \ No newline at end of property |
| This work allows obfuscation of the OpenVPN header to make it harder for | |||||
| layer 7 inspection to identify such traffic, which may come with blocking | |||||
| or recording actions in certain territories of the world. This patch, in | |||||
| a nutshell, can increase privacy and range of communication for its users. | |||||
| The `scramble' option introduced hereby is off by default. | |||||
| The option's usage, history and controversy of the patch is explained in | |||||
| detail on the following wiki page: | |||||
| https://tunnelblick.net/cOpenvpn_xorpatch.html | |||||
| --- src/openvpn/forward.c.orig 2016-08-23 14:16:28 UTC | |||||
| +++ src/openvpn/forward.c | |||||
| @@ -674,7 +674,10 @@ read_incoming_link (struct context *c) | |||||
| status = link_socket_read (c->c2.link_socket, | |||||
| &c->c2.buf, | |||||
| - &c->c2.from); | |||||
| + &c->c2.from, | |||||
| + c->options.ce.xormethod, | |||||
| + c->options.ce.xormask, | |||||
| + c->options.ce.xormasklen); | |||||
| if (socket_connection_reset (c->c2.link_socket, status)) | |||||
| { | |||||
| @@ -1151,7 +1154,10 @@ process_outgoing_link (struct context *c | |||||
| /* Send packet */ | |||||
| size = link_socket_write (c->c2.link_socket, | |||||
| &c->c2.to_link, | |||||
| - to_addr); | |||||
| + to_addr, | |||||
| + c->options.ce.xormethod, | |||||
| + c->options.ce.xormask, | |||||
| + c->options.ce.xormasklen); | |||||
| #ifdef ENABLE_SOCKS | |||||
| /* Undo effect of prepend */ | |||||
| --- src/openvpn/options.c.orig 2016-08-23 14:16:22 UTC | |||||
| +++ src/openvpn/options.c | |||||
| @@ -792,6 +792,9 @@ init_options (struct options *o, const b | |||||
| o->max_routes = MAX_ROUTES_DEFAULT; | |||||
| o->resolve_retry_seconds = RESOLV_RETRY_INFINITE; | |||||
| o->proto_force = -1; | |||||
| + o->ce.xormethod = 0; | |||||
| + o->ce.xormask = "\0"; | |||||
| + o->ce.xormasklen = 0; | |||||
| #ifdef ENABLE_OCC | |||||
| o->occ = true; | |||||
| #endif | |||||
| @@ -907,6 +910,9 @@ setenv_connection_entry (struct env_set | |||||
| setenv_int_i (es, "local_port", e->local_port, i); | |||||
| setenv_str_i (es, "remote", e->remote, i); | |||||
| setenv_int_i (es, "remote_port", e->remote_port, i); | |||||
| + setenv_int_i (es, "xormethod", e->xormethod, i); | |||||
| + setenv_str_i (es, "xormask", e->xormask, i); | |||||
| + setenv_int_i (es, "xormasklen", e->xormasklen, i); | |||||
| #ifdef ENABLE_HTTP_PROXY | |||||
| if (e->http_proxy_options) | |||||
| @@ -1366,6 +1372,9 @@ show_connection_entry (const struct conn | |||||
| SHOW_INT (connect_retry_seconds); | |||||
| SHOW_INT (connect_timeout); | |||||
| SHOW_INT (connect_retry_max); | |||||
| + SHOW_INT (xormethod); | |||||
| + SHOW_STR (xormask); | |||||
| + SHOW_INT (xormasklen); | |||||
| #ifdef ENABLE_HTTP_PROXY | |||||
| if (o->http_proxy_options) | |||||
| @@ -5131,6 +5140,46 @@ add_option (struct options *options, | |||||
| options->proto_force = proto_force; | |||||
| options->force_connection_list = true; | |||||
| } | |||||
| + else if (streq (p[0], "scramble") && p[1]) | |||||
| + { | |||||
| + VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); | |||||
| + if (streq (p[1], "xormask") && p[2] && (!p[3])) | |||||
| + { | |||||
| + options->ce.xormethod = 1; | |||||
| + options->ce.xormask = p[2]; | |||||
| + options->ce.xormasklen = strlen(options->ce.xormask); | |||||
| + } | |||||
| + else if (streq (p[1], "xorptrpos") && (!p[2])) | |||||
| + { | |||||
| + options->ce.xormethod = 2; | |||||
| + options->ce.xormask = NULL; | |||||
| + options->ce.xormasklen = 0; | |||||
| + } | |||||
| + else if (streq (p[1], "reverse") && (!p[2])) | |||||
| + { | |||||
| + options->ce.xormethod = 3; | |||||
| + options->ce.xormask = NULL; | |||||
| + options->ce.xormasklen = 0; | |||||
| + } | |||||
| + else if (streq (p[1], "obfuscate") && p[2] && (!p[3])) | |||||
| + { | |||||
| + options->ce.xormethod = 4; | |||||
| + options->ce.xormask = p[2]; | |||||
| + options->ce.xormasklen = strlen(options->ce.xormask); | |||||
| + } | |||||
| + else if (!p[2]) | |||||
| + { | |||||
| + msg (M_WARN, "WARNING: No recognized 'scramble' method specified; using 'scramble xormask \"%s\"'", p[1]); | |||||
| + options->ce.xormethod = 1; | |||||
| + options->ce.xormask = p[1]; | |||||
| + options->ce.xormasklen = strlen(options->ce.xormask); | |||||
| + } | |||||
| + else | |||||
| + { | |||||
| + msg (msglevel, "No recognized 'scramble' method specified or extra parameters for 'scramble'"); | |||||
| + goto err; | |||||
| + } | |||||
| + } | |||||
| #ifdef ENABLE_HTTP_PROXY | |||||
| else if (streq (p[0], "http-proxy") && p[1]) | |||||
| { | |||||
| --- src/openvpn/options.h.orig 2016-08-23 14:16:22 UTC | |||||
| +++ src/openvpn/options.h | |||||
| @@ -100,6 +100,9 @@ struct connection_entry | |||||
| int connect_retry_max; | |||||
| int connect_timeout; | |||||
| bool connect_timeout_defined; | |||||
| + int xormethod; | |||||
| + const char *xormask; | |||||
| + int xormasklen; | |||||
| #ifdef ENABLE_HTTP_PROXY | |||||
| struct http_proxy_options *http_proxy_options; | |||||
| #endif | |||||
| --- src/openvpn/socket.c.orig 2016-08-23 14:16:22 UTC | |||||
| +++ src/openvpn/socket.c | |||||
| @@ -52,6 +52,53 @@ const int proto_overhead[] = { /* indexe | |||||
| IPv6_TCP_HEADER_SIZE, | |||||
| }; | |||||
| +int buffer_mask (struct buffer *buf, const char *mask, int xormasklen) { | |||||
| + int i; | |||||
| + uint8_t *b; | |||||
| + if ( xormasklen > 0 ) { | |||||
| + for (i = 0, b = BPTR (buf); i < BLEN(buf); i++, b++) { | |||||
| + *b = *b ^ mask[i % xormasklen]; | |||||
| + } | |||||
| + } | |||||
| + return BLEN (buf); | |||||
| +} | |||||
| + | |||||
| +int buffer_xorptrpos (struct buffer *buf) { | |||||
| + int i; | |||||
| + uint8_t *b; | |||||
| + for (i = 0, b = BPTR (buf); i < BLEN(buf); i++, b++) { | |||||
| + *b = *b ^ i+1; | |||||
| + } | |||||
| + return BLEN (buf); | |||||
| +} | |||||
| + | |||||
| +int buffer_reverse (struct buffer *buf) { | |||||
| +/* This function has been rewritten for Tunnelblick. The buffer_reverse function at | |||||
| + * https://github.com/clayface/openvpn_xorpatch | |||||
| + * makes a copy of the buffer and it writes to the byte **after** the | |||||
| + * buffer contents, so if the buffer is full then it writes outside of the buffer. | |||||
| + * This rewritten version does neither. | |||||
| + * | |||||
| + * For interoperability, this rewritten version preserves the behavior of the original | |||||
| + * function: it does not modify the first character of the buffer. So it does not | |||||
| + * actually reverse the contents of the buffer. Instead, it changes 'abcde' to 'aedcb'. | |||||
| + * (Of course, the actual buffer contents are bytes, and not necessarily characters.) | |||||
| + */ | |||||
| + int len = BLEN(buf); | |||||
| + if ( len > 2 ) { /* Leave '', 'a', and 'ab' alone */ | |||||
| + int i; | |||||
| + uint8_t *b_start = BPTR (buf) + 1; /* point to first byte to swap */ | |||||
| + uint8_t *b_end = BPTR (buf) + (len - 1); /* point to last byte to swap */ | |||||
| + uint8_t tmp; | |||||
| + for (i = 0; i < (len-1)/2; i++, b_start++, b_end--) { | |||||
| + tmp = *b_start; | |||||
| + *b_start = *b_end; | |||||
| + *b_end = tmp; | |||||
| + } | |||||
| + } | |||||
| + return len; | |||||
| +} | |||||
| + | |||||
| /* | |||||
| * Convert sockflags/getaddr_flags into getaddr_flags | |||||
| */ | |||||
| --- src/openvpn/socket.h.orig 2016-08-23 14:16:22 UTC | |||||
| +++ src/openvpn/socket.h | |||||
| @@ -245,6 +245,10 @@ struct link_socket | |||||
| #endif | |||||
| }; | |||||
| +int buffer_mask (struct buffer *buf, const char *xormask, int xormasklen); | |||||
| +int buffer_xorptrpos (struct buffer *buf); | |||||
| +int buffer_reverse (struct buffer *buf); | |||||
| + | |||||
| /* | |||||
| * Some Posix/Win32 differences. | |||||
| */ | |||||
| @@ -873,30 +877,56 @@ int link_socket_read_udp_posix (struct l | |||||
| static inline int | |||||
| link_socket_read (struct link_socket *sock, | |||||
| struct buffer *buf, | |||||
| - struct link_socket_actual *from) | |||||
| + struct link_socket_actual *from, | |||||
| + int xormethod, | |||||
| + const char *xormask, | |||||
| + int xormasklen) | |||||
| { | |||||
| + int res; | |||||
| if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ | |||||
| { | |||||
| - int res; | |||||
| #ifdef WIN32 | |||||
| res = link_socket_read_udp_win32 (sock, buf, from); | |||||
| #else | |||||
| res = link_socket_read_udp_posix (sock, buf, from); | |||||
| #endif | |||||
| - return res; | |||||
| } | |||||
| else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ | |||||
| { | |||||
| /* from address was returned by accept */ | |||||
| addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest); | |||||
| - return link_socket_read_tcp (sock, buf); | |||||
| + res = link_socket_read_tcp (sock, buf); | |||||
| } | |||||
| else | |||||
| { | |||||
| ASSERT (0); | |||||
| return -1; /* NOTREACHED */ | |||||
| } | |||||
| + switch(xormethod) | |||||
| + { | |||||
| + case 0: | |||||
| + break; | |||||
| + case 1: | |||||
| + buffer_mask(buf,xormask,xormasklen); | |||||
| + break; | |||||
| + case 2: | |||||
| + buffer_xorptrpos(buf); | |||||
| + break; | |||||
| + case 3: | |||||
| + buffer_reverse(buf); | |||||
| + break; | |||||
| + case 4: | |||||
| + buffer_mask(buf,xormask,xormasklen); | |||||
| + buffer_xorptrpos(buf); | |||||
| + buffer_reverse(buf); | |||||
| + buffer_xorptrpos(buf); | |||||
| + break; | |||||
| + default: | |||||
| + ASSERT (0); | |||||
| + return -1; /* NOTREACHED */ | |||||
| + } | |||||
| + return res; | |||||
| } | |||||
| /* | |||||
| @@ -980,8 +1010,34 @@ link_socket_write_udp (struct link_socke | |||||
| static inline int | |||||
| link_socket_write (struct link_socket *sock, | |||||
| struct buffer *buf, | |||||
| - struct link_socket_actual *to) | |||||
| + struct link_socket_actual *to, | |||||
| + int xormethod, | |||||
| + const char *xormask, | |||||
| + int xormasklen) | |||||
| { | |||||
| + switch(xormethod) | |||||
| + { | |||||
| + case 0: | |||||
| + break; | |||||
| + case 1: | |||||
| + buffer_mask(buf,xormask,xormasklen); | |||||
| + break; | |||||
| + case 2: | |||||
| + buffer_xorptrpos(buf); | |||||
| + break; | |||||
| + case 3: | |||||
| + buffer_reverse(buf); | |||||
| + break; | |||||
| + case 4: | |||||
| + buffer_xorptrpos(buf); | |||||
| + buffer_reverse(buf); | |||||
| + buffer_xorptrpos(buf); | |||||
| + buffer_mask(buf,xormask,xormasklen); | |||||
| + break; | |||||
| + default: | |||||
| + ASSERT (0); | |||||
| + return -1; /* NOTREACHED */ | |||||
| + } | |||||
| if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ | |||||
| { | |||||
| return link_socket_write_udp (sock, buf, to); | |||||