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);
@greensea
Copy link
Author

修复在 TCP 模式下客户端无法连接的问题。只修改了两行代码,diff 文件的 diff 如下:
Fix connection in TCP mode, two lines changed, diff of diff is below:

@@ -192,8 +200,9 @@
 +      buf_write(&tbuf, (void*)&r + i % 4, 1);
 +    }
 +    
-+    buf_clear(buf);
-+    buf_copy(buf, &tbuf);
++    buf_copy_range(buf, 0, &tbuf, 0, BLEN(&tbuf));
 +          
 +    free_buf(&tbuf);
 +  }

@jiabin924
Copy link

在Visual Studio 2010里出错! m:\openvpn-build\openvpn-2.2.2\socket.h(906) : error C2036: “void ”: 未知的大
我改成 buf_write(&tbuf, (char
)&r + i % 4, 1); 这样!
unsigned char iv[randlen + _socket_obfs_salt_len + SHA_DIGEST_LENGTH]; 这里还是编译不过!

socket.c(56) : error C2057: 应输入常量表达式
socket.c(56) : error C2466: 不能分配常量大小为 0 的数组
socket.c(56) : error C2133: “iv”: 未知的大小
哈哈!有人帮忙吗!
unsigned char *iv=(unsigned char * ) malloc(randlen + _socket_obfs_salt_len + SHA_DIGEST_LENGTH);
暂时改成这样! 有人知道vc10 怎样静态编译!啊!

@welkinwalker
Copy link

在socket.c中加上

define MD5_DIGEST_LENGTH 16

define SHA_DIGEST_LENGTH 20

我这么编译过的

@welkinwalker
Copy link

现在openvpn出2.3版了,更新很多的功能,能再搞个2.3版本的流量混淆补丁么?
最好联系一下samuli,叫他把流量混淆补丁放到官方的分支里面,要不然以后官方升级还是个麻烦事

@cj1324
Copy link

cj1324 commented Mar 14, 2013

在freebsd系统中
测试超过半个小时 发现挺稳定 继续看效果

@greensea
Copy link
Author

@welkinwalker Patch for 2.3.0: https://gist.github.com/wzyboy/1fe3dae6a243e1502d7d
I am plan to make a obsfucated port forward program, obsfucate method can be customize, so both OpenVPN and SSH and other protocol traffic could be obsfucated.

@Ksyou
Copy link

Ksyou commented Mar 18, 2013

我打了楼主说的最新的补丁可是还是不支持TCP.会显示socket.c什么什么的错误.

Windows下也编译成功了,版本是2.2.2的

https://www.gsea.com.cn/blog/wp-content/uploads/2012/12/OpenVPN-2.2.2-obfs1.patch

今天突然使用有一个奇怪的问题就是上去半个小时-一个小时就会突然自动断开重新连接
由于只能使用UDP所以我把如下参数调整成30了.
keepalive 10 30
可是发现过一段时间还是会断也没有什么特殊的日志显示
希望楼主留个联系方式...

我也是再在socket.c中加上这么编译过的

define MD5_DIGEST_LENGTH 16

define SHA_DIGEST_LENGTH 20

@puppywang
Copy link

@greensea,obfsproxy from tor project do the same thing as you want, here is the link: https://www.torproject.org/projects/obfsproxy.html.en

@vvtommy
Copy link

vvtommy commented Mar 25, 2013

@welkinwalker 求windows版本,windows实在搞不定哈Tunnelblick倒是用的很爽

@cj1324
Copy link

cj1324 commented Apr 1, 2013

好像现在握手比较困难 握手后倒是蛮流畅的

@yestop
Copy link

yestop commented Apr 2, 2013

win下咋编译呢。。。。。悲剧

@warriorpaw
Copy link

这个补丁也失效了吗??
编译好,在连接PPTP的情况下测试连接正常
但是断开pptp 再连接 还是卡在tls那里,,和没补丁一样,,,53、80端口都这样
日志如下:
Wed Apr 10 19:28:36 2013 us=374965 UDPv4 link local: [undef]
Wed Apr 10 19:28:36 2013 us=374973 UDPv4 link remote: 198.xx.xx.xx:80
Wed Apr 10 19:28:36 2013 us=375003 1, write buflen=14
Wed Apr 10 19:28:36 2013 us=375010 2, write buflen=26
Wed Apr 10 19:28:36 2013 us=583592 1, read buflen=33
Wed Apr 10 19:28:36 2013 us=583624 1, read buflen=26, padlen=3
Wed Apr 10 19:28:36 2013 us=583641 TLS: Initial packet from 198.xx.xx.xx:80, sid=72c47717 75864f06
Wed Apr 10 19:28:36 2013 us=583706 1, write buflen=22
Wed Apr 10 19:28:36 2013 us=583716 2, write buflen=49
Wed Apr 10 19:28:36 2013 us=583794 1, write buflen=102
Wed Apr 10 19:28:36 2013 us=583806 2, write buflen=131
Wed Apr 10 19:28:36 2013 us=794376 1, read buflen=139
Wed Apr 10 19:28:36 2013 us=794416 1, read buflen=126, padlen=9
Wed Apr 10 19:28:36 2013 us=794479 1, write buflen=22
Wed Apr 10 19:28:36 2013 us=794487 2, write buflen=45
Wed Apr 10 19:28:36 2013 us=794594 1, read buflen=141
Wed Apr 10 19:28:36 2013 us=794606 1, read buflen=114, padlen=23
Wed Apr 10 19:28:36 2013 us=794625 1, write buflen=22
Wed Apr 10 19:28:36 2013 us=794632 2, write buflen=48
Wed Apr 10 19:28:36 2013 us=794708 1, read buflen=124
Wed Apr 10 19:28:36 2013 us=794719 1, read buflen=114, padlen=6
Wed Apr 10 19:28:36 2013 us=794738 1, write buflen=22
Wed Apr 10 19:28:36 2013 us=794745 2, write buflen=35
Wed Apr 10 19:28:36 2013 us=794794 1, read buflen=137
Wed Apr 10 19:28:36 2013 us=794806 1, read buflen=114, padlen=19
Wed Apr 10 19:28:36 2013 us=794824 1, write buflen=22
Wed Apr 10 19:28:36 2013 us=794831 2, write buflen=53
Wed Apr 10 19:28:37 2013 us=54876 1, read buflen=120
Wed Apr 10 19:28:37 2013 us=54911 1, read buflen=114, padlen=2
Wed Apr 10 19:28:37 2013 us=54958 1, write buflen=22
Wed Apr 10 19:28:37 2013 us=54965 2, write buflen=26
Wed Apr 10 19:28:37 2013 us=55032 1, read buflen=126
Wed Apr 10 19:28:37 2013 us=55044 1, read buflen=114, padlen=8
Wed Apr 10 19:28:37 2013 us=55063 1, write buflen=22
Wed Apr 10 19:28:37 2013 us=55069 2, write buflen=52
Wed Apr 10 19:28:37 2013 us=68431 1, read buflen=145
Wed Apr 10 19:28:37 2013 us=68466 1, read buflen=114, padlen=27
Wed Apr 10 19:28:37 2013 us=68514 1, write buflen=22
Wed Apr 10 19:28:37 2013 us=68521 2, write buflen=42
Wed Apr 10 19:28:37 2013 us=69470 1, read buflen=140
Wed Apr 10 19:28:37 2013 us=69505 1, read buflen=114, padlen=22
Wed Apr 10 19:28:37 2013 us=69551 1, write buflen=22
Wed Apr 10 19:28:37 2013 us=69558 2, write buflen=30
Wed Apr 10 19:28:37 2013 us=361670 1, read buflen=137
Wed Apr 10 19:28:37 2013 us=361706 1, read buflen=114, padlen=19
Wed Apr 10 19:28:37 2013 us=361844 1, write buflen=22
Wed Apr 10 19:28:37 2013 us=361857 2, write buflen=55
Wed Apr 10 19:28:41 2013 us=836458 1, read buflen=128
Wed Apr 10 19:28:41 2013 us=836516 1, read buflen=114, padlen=10
Wed Apr 10 19:28:42 2013 us=876067 1, read buflen=121
Wed Apr 10 19:28:42 2013 us=876117 1, read buflen=114, padlen=3
Wed Apr 10 19:28:51 2013 us=828841 1, read buflen=147
Wed Apr 10 19:28:51 2013 us=828876 1, read buflen=114, padlen=29
Wed Apr 10 19:28:55 2013 us=332424 1, read buflen=136
Wed Apr 10 19:28:55 2013 us=332494 1, read buflen=114, padlen=18
Wed Apr 10 19:29:37 2013 us=70255 TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)
Wed Apr 10 19:29:37 2013 us=70291 TLS Error: TLS handshake failed
Wed Apr 10 19:29:37 2013 us=70385 TCP/UDP: Closing socket

@warriorpaw
Copy link

https://gist.github.com/warriorpaw/5354603
我在怀疑是不是GFW会随机的改数据包 ,就照着本patch 稍微修改下,加进去CRC,放在发送buf最前端,然后用CRC值对随机数XOR了一下
可是证明我错了,还是挂上pptp就OK;直接连,无限卡TLS握手
但至少发现发送和接收的CRC是一致的。。。。。。
唉,这什么蛋疼问题造成的啊~~!
--------------------蛋疼的分割线-----------------------
貌似不是GFW的问题,我弄了个国内电信的PPTP连接上去,然后连openvpn居然也连接上去了。。。
艹!!谁能告诉我为啥...
--------------------蛋疼的分割线2-----------------------
发现问题了,丢包,对比vps上openvpn输出和本地的,在握手这段,vps那边write 一大堆,这边就read到没几个
应该是各地GFW规则还不太一样,我这哈尔滨联通

@cj1324
Copy link

cj1324 commented May 4, 2013

@warriorpaw 北京联通 遇到和你相同的问题 但是 一般 重试5分钟左右 就可以连上。 家里宽带好像走重庆移动 所以没这个问题

@freeyoung
Copy link

@Ksyou 你的问题可能是 mss 大小不对,调整为 1380 左右试试?

@Itwastaken
Copy link

mark 一下

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment