今日openVPN連不上了,抓包發(fā)現(xiàn)剛一握手結(jié)束便收到了一個(gè)RST包,導(dǎo)致一直連不上。
可以看到,三次握手剛完畢,客戶(hù)端發(fā)送第一個(gè)控制消息到服務(wù)端,便收到了服務(wù)端發(fā)送的RST數(shù)據(jù)包,一直如此。
應(yīng)該是有中間設(shè)備搞的鬼,于是我又到服務(wù)器端抓取了些數(shù)據(jù):
果然的,服務(wù)器也收到了RST數(shù)據(jù)包,于是兩者的連接便斷開(kāi)了。
再仔細(xì)分析下客戶(hù)端的RST數(shù)據(jù)包:
IP包的序號(hào)是12345,TTL是120。再看正常的數(shù)據(jù)包:
IP包的序號(hào)是0,TTL是46。很明顯RST數(shù)據(jù)包的TTL比正常的要大,而且每次RST的IP序號(hào)都是12345,應(yīng)該是GFW沒(méi)錯(cuò)了。
正常情況下初始的TTL是64,正常收到的TTL是46,跳數(shù)是15,說(shuō)明我的電腦到服務(wù)器之間經(jīng)過(guò)了15個(gè)路由設(shè)備。
為了證明這點(diǎn),查看服務(wù)端收到的正常數(shù)據(jù)包:
服務(wù)器收到的TTL是50,因?yàn)槲业碾娔X還要經(jīng)過(guò)內(nèi)部的一個(gè)路由器,所以TTL差了1。
同時(shí)查看服務(wù)端RST數(shù)據(jù)包的TTL值:
TTL值為117,因此得到的信息如下:
客戶(hù)端->服務(wù)器:15、GWF->服務(wù)器:117、GFW->客戶(hù)端:120。
假設(shè)GFW每次發(fā)送的TTL值都固定不變且為x,則有:x-117+x-120=15;得x=126。
所以GFW和我的電腦的跳數(shù)應(yīng)該是6:
圖示的應(yīng)該就是GFW的位置。
接下來(lái)問(wèn)題來(lái)了,她是怎么識(shí)別出openVPN流量的呢?
我猜測(cè)是根據(jù)數(shù)據(jù)包的特征來(lái)識(shí)別的,那么我單獨(dú)發(fā)送單個(gè)數(shù)據(jù)包,應(yīng)該也會(huì)返回RST數(shù)據(jù),根據(jù)這一理論,我用scapy發(fā)送了單個(gè)的數(shù)據(jù)包,內(nèi)容和三次握手之后客戶(hù)端發(fā)送的第一個(gè)數(shù)據(jù)包一樣,但結(jié)果是失望的,并沒(méi)有收到RST數(shù)據(jù)包。
于是進(jìn)一步猜測(cè),TCP連接之后再發(fā)送相應(yīng)的數(shù)據(jù)包,應(yīng)該能收到RST,于是又根據(jù)這一理論,寫(xiě)下了如下代碼:
from?scapy.all?import?* vpn_payload?=?"\x00\x0e\x38\x24\x5d\x21\xaa\x3a\x11\x2f\xb3\x00\x00\x00\x00\x00" conf.verb?=?0 vpn_s?=?IP(dst="yovey.me",id=12345)/TCP(sport=58620,dport=1194,flags="S",seq=0) print?"sending?syn" vpn_s.show() ans0,unans0?=?sr(vpn_s) print?"recv?packet,seq?=?",ans0[0][1].seq ans0[0][1].show() vpn_sa?=?IP(dst="yovey.me",id=12346)/TCP(sport=58620,dport=1194,flags="A",seq=1,ack=ans0[0][1].seq+1) print?"sending?ack" vpn_sa.show() ans1,unasn1?=?sr(vpn_sa,timeout=1) vpn?=?IP(dst="yovey.me",id=12347)/TCP(sport=58620,dport=1194,flags="PA",seq=1,ack=ans0[0][1].seq+1)/vpn_payload print?"sending?vpn?payload" ans2,unasn2?=?sr(vpn) ans2[0][1].show()
運(yùn)行程序,還是沒(méi)有收到RST數(shù)據(jù)包。
于是我打開(kāi)tcpdump,抓取了發(fā)包過(guò)程的數(shù)據(jù)包,發(fā)現(xiàn)了問(wèn)題:
在服務(wù)器返回syn+ack之后,客戶(hù)端居然發(fā)送了RST到服務(wù)器,導(dǎo)致連接斷開(kāi)。經(jīng)過(guò)短暫的思考,才明白客戶(hù)端網(wǎng)卡在收到來(lái)自服務(wù)器的syn+ack之后,發(fā)現(xiàn)并沒(méi)有進(jìn)程在監(jiān)聽(tīng)該數(shù)據(jù)包的端口,于是發(fā)送了RST數(shù)據(jù)包給服務(wù)器。
必須讓客戶(hù)端不發(fā)送RST數(shù)據(jù)包才行,想到可以通過(guò)iptable來(lái)過(guò)濾數(shù)據(jù)包,于是在iptable中添加如下規(guī)則:
iptables?-t?filter?-A?OUTPUT?-p?tcp?--tcp-flags?RST?RST?-j?DROP
再運(yùn)行程序,一切都在計(jì)劃之中:
還是熟悉的IP序號(hào),還是熟悉的TTL,看來(lái)GFW已經(jīng)可以根據(jù)連接來(lái)識(shí)別流量了,真是下了血本啊。
想到建立連接,我立馬聯(lián)想到不用建立連接的UDP,是不是UDP數(shù)據(jù)只需要根據(jù)單個(gè)數(shù)據(jù)包就能識(shí)別了?于是將服務(wù)器配置成UDP模式,再次打開(kāi)openVPN,特么的居然連上了!于是問(wèn)題解決了,將配置改成UDP就能正常連接了。