Last active
March 22, 2023 09:17
-
-
Save greensea/4372285 to your computer and use it in GitHub Desktop.
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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); |
@warriorpaw 北京联通 遇到和你相同的问题 但是 一般 重试5分钟左右 就可以连上。 家里宽带好像走重庆移动 所以没这个问题
@Ksyou 你的问题可能是 mss 大小不对,调整为 1380 左右试试?
mark 一下
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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规则还不太一样,我这哈尔滨联通