Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
The obfs patch obsfucate OpenVPN traffic, make it looks like random traffic. The obfs patch add two options for OpenVPN. --obfs-salt <string> is a secret to generate the input XOR stream. To enable the obfs patch, this options must be set. --obfs-padlen <num> is a positive integer max to 255. This option tells obfs patch to padding random conten…
--- openvpn-2.2.2.orig/options.c 2011-12-14 00:58:56.000000000 +0800
+++ openvpn-2.2.2/options.c 2012-12-21 10:44:57.683130505 +0800
@@ -54,6 +54,10 @@
#include "memdbg.h"
+extern char* _socket_obfs_salt;
+extern int _socket_obfs_salt_len;
+extern int _socket_obfs_padlen;
+
const char title_string[] =
PACKAGE_STRING
" " TARGET_ALIAS
@@ -6008,6 +6012,19 @@
options->persist_mode = 1;
}
#endif
+ else if (streq (p[0], "obfs-salt") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ _socket_obfs_salt = p[1];
+ _socket_obfs_salt_len = strlen(_socket_obfs_salt);
+ }
+ else if (streq (p[0], "obfs-padlen") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ _socket_obfs_padlen = atoi(p[1]);
+ if (_socket_obfs_padlen < 0)
+ msg(M_ERR, "--obfs-padlen must be positive");
+ }
else
{
if (file)
--- openvpn-2.2.2.orig/socket.c 2011-12-14 00:58:56.000000000 +0800
+++ openvpn-2.2.2/socket.c 2012-12-21 10:44:57.707131191 +0800
@@ -35,6 +35,10 @@
#include "memdbg.h"
+const char* _socket_obfs_salt = NULL;
+int _socket_obfs_salt_len = 0;
+int _socket_obfs_padlen = 0;
+
const int proto_overhead[] = { /* indexed by PROTO_x */
IPv4_UDP_HEADER_SIZE,
IPv4_TCP_HEADER_SIZE,
@@ -42,6 +46,49 @@
IPv4_TCP_HEADER_SIZE
};
+/**
+ * @return int The length of the random string that should be padding to the packet
+ */
+int obfs_buffer(const struct buffer* buf, const void* rand, int randlen, int maxpadlen) {
+ unsigned char md[SHA_DIGEST_LENGTH];
+ unsigned char iv[randlen + _socket_obfs_salt_len + SHA_DIGEST_LENGTH];
+ unsigned char *c;
+ int i, len, pad_len = 0;
+
+ if (maxpadlen > 255)
+ maxpadlen = 255;
+
+ /* key_1 = SHA1(rand + obfs_salt) */
+ /* pad_len = Low _rand_pad_level_ bits of (unsigned char)MD5(rand + obfs_salt)[0] */
+ memcpy(iv, rand, randlen);
+ memcpy(iv + randlen, _socket_obfs_salt, _socket_obfs_salt_len);
+
+ /* Caculate length of padding string */
+ ASSERT(SHA_DIGEST_LENGTH >= MD5_DIGEST_LENGTH);
+ MD5(iv, randlen + _socket_obfs_salt_len, md); /* SHA_DIGEST_LENGTH is bigger than MD5_DIGEST_LENGTH, it's safe here */
+ if (maxpadlen <= 0)
+ pad_len = 0;
+ else
+ pad_len = md[0] % (maxpadlen + 1);
+
+ /* Obsfucation data */
+ len = BLEN(buf);
+ SHA1(iv, randlen + _socket_obfs_salt_len, md);
+ for (i = 0, c = BPTR(buf); i < len; i++, c++)
+ {
+ *c ^= md[i % SHA_DIGEST_LENGTH];
+
+ /* Regenerate obsfuction key: key_n+1 = SHA1(key_n) */
+ if (i % SHA_DIGEST_LENGTH == SHA_DIGEST_LENGTH - 1)
+ {
+ memcpy(iv, md, SHA_DIGEST_LENGTH);
+ SHA1(iv, SHA_DIGEST_LENGTH, md);
+ }
+ }
+
+ return pad_len;
+}
+
/*
* Convert sockflags/getaddr_flags into getaddr_flags
*/
--- openvpn-2.2.2.orig/socket.h 2011-12-14 00:58:56.000000000 +0800
+++ openvpn-2.2.2/socket.h 2013-01-24 10:48:37.559033278 +0800
@@ -36,6 +36,11 @@
#include "socks.h"
#include "misc.h"
+extern int _socket_obfs_salt_len;
+extern int _socket_obfs_padlen;
+
+int obfs_buffer(const struct buffer* buf, const void* rand, int randlen, int rand_pad_level);
+
/*
* OpenVPN's default port number as assigned by IANA.
*/
@@ -740,28 +745,60 @@
int maxsize,
struct link_socket_actual *from)
{
+ int res;
+
+ struct buffer tbuf;
+
+
if (sock->info.proto == PROTO_UDPv4)
{
- int res;
-
#ifdef WIN32
res = link_socket_read_udp_win32 (sock, buf, from);
#else
res = link_socket_read_udp_posix (sock, buf, maxsize, from);
#endif
- return res;
}
else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT)
{
/* from address was returned by accept */
from->dest.sa = sock->info.lsa->actual.dest.sa;
- return link_socket_read_tcp (sock, buf);
+ res = link_socket_read_tcp (sock, buf);
}
else
{
ASSERT (0);
return -1; /* NOTREACHED */
}
+
+ /* Decode obsfucated traffic */
+ if (_socket_obfs_salt_len > 0 && BLEN(buf) > 4)
+ {
+ int r;
+ int pad_len = 0;
+
+ memcpy((void*)&r, BPTR(buf), 4);
+
+ msg(M_DEBUG, "1, read buflen=%d", BLEN(buf));
+
+ tbuf = alloc_buf(BLEN(buf) - 4);
+ buf_copy_range(&tbuf, 0, buf, 4, BLEN(buf) - 4);
+ pad_len = obfs_buffer(&tbuf, &r, 4, _socket_obfs_padlen);
+
+ /* Remove padding random string */
+ buf_clear(buf);
+ buf_prepend(buf, BLEN(&tbuf) - pad_len);
+ buf_copy_range(buf, 0, &tbuf, 0, BLEN(&tbuf) - pad_len);
+
+ msg(M_DEBUG, "1, read buflen=%d, padlen=%d", BLEN(buf), pad_len);
+
+ free_buf(&tbuf);
+
+ res -= 4;
+ res -= pad_len;
+
+ }
+
+ return res;
}
/*
@@ -846,6 +883,37 @@
struct buffer *buf,
struct link_socket_actual *to)
{
+ struct buffer tbuf;
+
+ /* Obsfucate traffic */
+ if (_socket_obfs_salt_len > 0)
+ {
+ int pad_len, i;
+ int r = rand();
+
+ msg(M_DEBUG, "1, write buflen=%d", BLEN(buf));
+
+ pad_len = obfs_buffer(buf, &r, sizeof(r), _socket_obfs_padlen);
+
+ tbuf = alloc_buf(BLEN(buf) + 4 + pad_len);
+ buf_write(&tbuf, (void*)&r, 4);
+ buf_copy_range(&tbuf, 4, buf, 0, BLEN(buf));
+ for (i = 0; i < pad_len; i++)
+ {
+ if (unlikely(i % 4 == 0))
+ r = rand();
+
+ buf_write(&tbuf, (void*)&r + i % 4, 1);
+ }
+
+ buf_copy_range(buf, 0, &tbuf, 0, BLEN(&tbuf));
+
+ msg(M_DEBUG, "2, write buflen=%d", BLEN(buf));
+
+ free_buf(&tbuf);
+ }
+
+
if (sock->info.proto == PROTO_UDPv4)
{
return link_socket_write_udp (sock, buf, to);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment