Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kcp用着用着偶尔就会断开{伪解决方案} #228

Closed
feizhenzhuang opened this issue Oct 20, 2016 · 57 comments
Closed

Kcp用着用着偶尔就会断开{伪解决方案} #228

feizhenzhuang opened this issue Oct 20, 2016 · 57 comments
Labels

Comments

@feizhenzhuang
Copy link

feizhenzhuang commented Oct 20, 2016

VPS:搬瓦工
OS :Debian 7.0 x86_64
客户端版本=服务器版本 :0922
ssr版本:3.7.4.1
问题描述:最近这几天当我打开KCP和SS配合翻墙观看youtube视频时,开始没有什么问题,网速也很快,但是过了大概十分钟左右后,突然就不能翻墙了,此时我切换ss直连vps, 经测试连接没有问题。在这种无法使用kcp的情况下,经过大概半小时 我再测试使用kcp配合翻墙,发现又可以使用了。请问这是为什么呢?
PS: 我在网上查询相关问题时 有不少人遇到和我类似的问题,有人说是isp封锁了UDP端口 (不知道对错)

谢谢您的帮助,感激不尽
(客户端参数未调整,只是用的ssr版本的shadowsocks,把UDP over TCP 勾选后(见楼下图),经过我接近三个小时的youtube视频播放测试,之前的视频播放一段时间就断开现象没有遇到,之后的几天,该问题也没有遇到。所以我认为这应该算是一个解决方案吧。逃)
update:最近我的ssr即使打开 UDP over TCP 也是会看一会视频就断开 过几天试试降低MTU值

@xtaci
Copy link
Owner

xtaci commented Oct 20, 2016

参数也不贴

@loveproe
Copy link

loveproe commented Oct 21, 2016

和参数没关系,我测试过半年多的时间并且不管是移动和电信网络都试过。。这个问题在所有使用kcp都出现是udp大流量被运营商自动封这个ip的udp连接。这个时间你们技术宅可能没有耐心测试,我因为一天24小时开youtube看skynews,他的断流时间也不固定可能一个小时也可能几十分钟,可能你和附近udp的国外带宽有关,如果断流了你只要等待十几分钟到半个小时就正常。解决这个问题只有finalspeed采用的将udp封装成tcp来发包。就从来不断线,我测试了大概一周都不断流。当然用finalspeed的udp模式和kcptun一样出现这个问题,v2ray 所使用的mkcp也同样有这个问题。只要用udp大量发包的必定被自动断流一段时间。

至于用搬瓦工的openvz的兄弟你们是无解的。。。速度换kvm的vps吧

可惜我每个版本都测试了,这个问题无解,只有等作者把udp封装成tcp的功能出现再使用了。。。

@feizhenzhuang
Copy link
Author

很抱歉,现在才看到作者的回复 我现在把参数贴一下 。
version: 20160922
listening on: [::]:8989
encryption: aes
nodelay parameters: 0 20 2 1
remote address: 45.78.27.211:29900
sndwnd: 128 rcvwnd: 1024
compression: true
mtu: 1350
datashard: 10 parityshard: 3
acknodelay: false
dscp: 0
sockbuf: 4194304
keepalive: 10
conn: 1
autoexpire: 0
谢谢作者的帮助,

@feizhenzhuang
Copy link
Author

看到楼上“loveproe”所说的:“ 至于用搬瓦工的openvz的兄弟你们是无解的。。。速度换kvm的vps吧.”
我之前看到 搬瓦工应该也可以安装finalspeed吧。
default

PS: 我所使用的shadowsocksR有一个功能是UDP over TCP 不知道将这个选上 配合kcp 能不能实现绕过UDP封锁.

@gatalon
Copy link

gatalon commented Oct 22, 2016

搬瓦工用finalspeed只能UDP。
我遇到的情况跟你差不多,UDP似乎都是被封了,玩warframe跟朋友联机提示让我打开端口,我防火墙都是关闭的。

@xtaci xtaci added the ISP label Oct 24, 2016
@shutup
Copy link

shutup commented Oct 24, 2016

我当时测试发现,公司的网络出国的UDP数据绝对被干扰了。也可能和时间有关?我在家使用没什么问题。

@xtaci
Copy link
Owner

xtaci commented Oct 24, 2016

尝试降低MTU=512

@CuminLo
Copy link

CuminLo commented Oct 24, 2016

@xtaci 服务端和客户端都需要降低么?

@xtaci
Copy link
Owner

xtaci commented Oct 24, 2016

是的,参考 #218

@feizhenzhuang feizhenzhuang changed the title Kcp用着用着偶尔就会断开 Kcp用着用着偶尔就会断开{附解决方案} Oct 25, 2016
@linhua55
Copy link

linhua55 commented Dec 4, 2016

鹏博士的网,搬瓦工的VPS,也是频繁断开,10分钟-半小时左右会恢复。

经测试,断开后,除了80和443端口以外的所有TCP端口都被封,而且是Server --> Client的下行流量被封,上行没有影响

UDP端口似乎都被封了(也只是下行 被封),还没有找到简便的测试方法,不确定,留待测试。

而ICMP ping命令始终能通,这使人不禁寄希望于 ICMPTunnel ,不过据说速度很慢。

应该是 端口封锁/Qos,不含端口的VPN协议流量应该可以通过,但是又会碰上GFW的封锁。

如果只是 对UDP端口单独进行统计流量,流量过大就触发封锁规则的话,那么 在Server端 用iptables工具,实现随机化端口发送数据(Server --> Client),应该可以解决

测试方法,对于TCP,使用netcat或nmap(可选:可辅助用tcpdump,wireshark进行确认)

测试单个端口:

$ nc -zv <your-server-ip>  <your-tcp-port>

这里的端口可以是没有监听的, 如果可以连通,出来的警告是connection refused。如果是被封了,出来的警告是connection time out。(这个可以使用tcpdump/wireshark进行确认)

$ sudo tcpdump -nnq host  <your-server-ip> and not port 80

批量测试:

$ sudo nmap -sS  --top-ports 1000  <your-server-ip>

对于UDP,不能使用nmap进行批量测试,因为UDP没有三次握手,从而没有返回包(Server--> Client)。
只能使用 echo server 对单一端口进行手动测试

@feizhenzhuang feizhenzhuang changed the title Kcp用着用着偶尔就会断开{附解决方案} Kcp用着用着偶尔就会断开{伪解决方案} Dec 6, 2016
@linhua55
Copy link

linhua55 commented Dec 6, 2016

@feizhenzhuang
可以试试 随机化端口方案
https://gist.github.com/suikatomoki/89b1221dab19f64ba2b3

例如

Client ➜   sudo iptables -t nat -I OUTPUT -d <your_vps_ip> -p udp --dport <your_kcp_server_port> -j DNAT --to-destination <your_vps_ip>:4000-5000 --random
Server root@default:~# iptables -t nat -A PREROUTING -p udp -m multiport --dport 4000:5000 -j REDIRECT --to-ports <your_kcp_server_port>

同时要调大connection参数(其实不知connection参数具体影响什么!!!)

不过这个 不是针对 每个 packet 随机化端口,而是针对 每一个connection 随机化端口。
https://serverfault.com/questions/716346/randomize-destination-port-for-every-packet-with-iptables

下面这个好像是针对 packet的
https://www.haiyun.me/archives/1024.html/comment-page-1
上条链接的命令有点问题,是针对老版本的iptables的,现在的可参考
https://serverfault.com/questions/490854/rotating-outgoing-ips-using-iptables/491517#491517

如何控制 kcptun 每个connection的流量大小?

@CuminLo
Copy link

CuminLo commented Dec 8, 2016

@linhua55 我也是鹏博士的网,那有什么好的解决办法么?

@linhua55
Copy link

linhua55 commented Dec 8, 2016

好奇怪,这两天没断了,也没用上面提到过的随机化端口方案,也没改小mtu。只是前几天,把ssh服务端端口改为了80端口。 你可以试一下把ssh端口改为80443端口试试。
可能如果 80443端口没开,就会把你加入黑名单,进行特殊照顾

今天中午又开始断了,看来不是这个原因

@cjjdaq
Copy link

cjjdaq commented Dec 9, 2016

一直断,所以用了上面的随机端口方案,但发现,封的时候不是封服务器的udp,而且是对宽带本身的udp进出进行封堵,重新拨号换ip后就能连上了。。这就无解了。。。

@linhua55
Copy link

linhua55 commented Dec 9, 2016

@cjjdaq
应该不会封宽带本身的, 有好多的宽带都是分的内网的ip,如果封宽带本身的,就会牵连其他用户。你如果有另外的vps服务器,可以尝试一下看看能否连通。
你重新拨号可以,还可以有另外的解释:就是换出口ip后,这个 新的 出口ip或中间路由ip中对应的服务器中的Qos服务 没有把你的服务器ip记录在黑名单里

我在客户端用nc,服务端用tcpdump测试: 客户端用nc访问一个udp端口,在服务端的tcpdump可以看到收到了从客户端访问这个udp端口的包。 从此看来是,客户端到服务端的udp上行流量不受影响

你试试 调大 connection 参数试试,那天,把connection参数调为了10

@cjjdaq
Copy link

cjjdaq commented Dec 9, 2016

我的宽带电信的,公网ip,断的时候,我宽带的udp出不去进不来(只有等待解封,要么重新拨号),但我用其它省的宽带(电信固定ip)连接到服务器的udp一切正常。

@linhua55
Copy link

linhua55 commented Dec 9, 2016

@cjjdaq
因为路由变了呀

@cjjdaq
Copy link

cjjdaq commented Dec 9, 2016

其它省的连接一直正常,就我这里的电信封,我日

@wkingfly
Copy link

wkingfly commented Dec 9, 2016 via email

@linhua55
Copy link

linhua55 commented Dec 13, 2016

@cjjdaq
#323 (comment)
刚才测试了一下,发现封锁策略变了,现象和你的一样了。TCP端口 没被封,但UDP上行流量(Client--> Server)被封。因客户端处在内网中,故没法测试UDP下行流量是否通畅

UDP通畅的时候,在服务端tcpdump中显示的 ip地址 和 用TCP时显示的本地ip 地址不一样。看来是TCP和UDP流量走了不同的路由,导致出口ip不一样。

显示的出口ip是一样的

@linhua55
Copy link

linhua55 commented Dec 14, 2016

@cjjdaq
客户端分别用ncnmap测试UDP端口连通性,服务端用tcpdump查看流量。发现虽然用nc测试,没有日志,即UDP上行流量(Client--> Server)被封。但是用nmap测试可以看到UDP的日志,虽然UDP包的字节数为0。nmap用了UDP host discovery(UDP ping) 去测试UDP端口的连通性,需要等待ICMP应答。如果这样可以的话,上行流量可以伪装成 这个的 流量。或上行流量用TCP,下行流量用UDP。
具体命令:

Client $ nc -dv <your_server_ip> 5879 -u
Server $ tcpdump -nnq host  <your_server_ip>  and not port 80  and not port 443 and not tcp

Client $ sudo nmap -sU <your_server_ip>  -p5879 -Pn

http://thesprawl.org/research/host-discovery/#udp-ping
https://bt3gl.github.io/black-hat-python-building-a-udp-scanner.html
https://www.oschina.net/translate/building-a-udp-scanner-with-pythons-socket-module

用python程序测试了一下,确实是UDP上行流量 不通,UDP下行流量是通的。但是如果UDP上行流量只发送0字节也是可以通过 到达服务器的(就像用上条nmap命令的效果)(可以用此特性来维护NAT长连接,但不能传输上行流量)。 因此上行流量用TCP,下行流量用UDP这个方案,原理上是可以实现的

@linhua55
Copy link

linhua55 commented Dec 20, 2016

上行流量用TCP,下行流量用UDP方案原理图
kcptun

其中,python程序client/server需要实现的功能是:

  1. 发送0字节UDP数据,维护NAT长连接,确保下行流量可到达客户端
  2. 下行流量的UDP转发
  3. 将上行UDP流量转化为TCP流量(客户端),及将TCP流量还原为UDP流量(服务端)

@xtaci
Copy link
Owner

xtaci commented Dec 20, 2016

你是要搞扩频通信啊 ,两组 UDP亦可

@linhua55
Copy link

linhua55 commented Dec 20, 2016

@xtaci
UDP上行流量(Client --> Server)不通,被ISP封锁了。 UDP下行流量经之前的测试是可以的。

@cjjdaq
这是测试UDP下行流量是否通的代码:

注意:这是python3的代码
服务端: udpServer.py

#!/usr/bin/env python
# -*- coding:utf8 -*- 

import socket

class UdpServer(object):
    def tcpServer(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind(('', 9527))
 
        while True:
            revcData, (remoteHost, remotePort) = sock.recvfrom(1024)
            print("[%s:%s] connect" % (remoteHost, remotePort))
 
            sendDataLen = sock.sendto(b"this is send  data from server", (remoteHost, remotePort))
            print("revcData: ", revcData)
            print("sendDataLen: ", sendDataLen)
 
        sock.close()
 
if __name__ == "__main__":
    udpServer = UdpServer()
    udpServer.tcpServer()

客户端:udpClient.py 需要将YOUR_SERVER_IP改为自己服务器的真实ip

#!/usr/bin/env python
# -*- coding:utf8 -*-   

import socket

# send empty byte
MESSAGE = b""  # b"a" 
class UdpClient(object):
    def tcpclient(self, MESSAGE):
        clientSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        sendDataLen = clientSock.sendto(MESSAGE, ('YOUR_SERVER_IP', 9527))
        recvData = clientSock.recvfrom(1024)
        print("sendDataLen: ", sendDataLen)
        print("recvData: ", recvData)

        clientSock.close()


if __name__ == "__main__":
    udpClient = UdpClient()
    udpClient.tcpclient(MESSAGE)

@linhua55
Copy link

@cjjdaq
更新了说明,欢迎测试

@linhua55
Copy link

封锁策略又变为封UDP下行流量,UDP上行流量没被封

@xtaci
Copy link
Owner

xtaci commented Dec 28, 2016

@linhua55 会不会是路由器本身的问题,比如这个参数太小
@bettermanbao

net.core.rmem_max = 26214400

启动的时候,有没有出现setsocket buffer报错

@bettermanbao
Copy link

bettermanbao commented Dec 28, 2016

[root@5K-W20:/proc/sys/net/core]#cat rmem_default
163840
[root@5K-W20:/proc/sys/net/core]#cat rmem_max
163840

这是我的路由器上的值,确实比你小很多。会影响吗?

启动的时候,setsocket buffer不会报错。

@xtaci
Copy link
Owner

xtaci commented Dec 28, 2016

kcptun默认是设置4MB, 如果太小,udp包太快,kcp处理太慢,可能会内核丢包。

@bettermanbao
Copy link

这种丢包能通过什么数据看到吗?我最近开了FEC,流量一大以后路由器的CPU必定满载。

@xtaci
Copy link
Owner

xtaci commented Dec 28, 2016

/proc/net/snmp应该能看到

@linhua55
Copy link

@xtaci
用的 #228 (comment) 中的脚本测得的

路由器不受我控制。 服务端的话,用tcpdump查看了,有发出去的包,但在客户端用tcpdump查看只有发出去的包没有进来的包

@baggiogogo
Copy link

自家的话,我觉得排查下路由是有必要的,这个状况,要么ISP要么路由,必有其一要背这个锅。
复杂环境,比如公司或者长宽这种,只要路由上开着QOS,对KCPTUN就是麻烦,我在自家环境尝试QOS,只要一开,无论到不到设定的阈值,都会被丢包,多少而已。
我个人的使用情况,自从@xtaci换库以来,即便遇到抽风,卡是有的,但从未遇到过断流。
还有个情况,当遇到断流的时候,可以尝试用站长工具用全国同一运营商的不同地点IP去PING主机,如果多数都PING超时,那就VPS去背这个锅。

@linhua55
Copy link

linhua55 commented Jan 12, 2017

现在连TCP 443端口也限制了,使用原生的Shadowsocks没有速度, 必须使用带混淆功能的ShadowsocksR。 配合net-speeder (双倍发包),竟然也能达到自身带宽的一半速度。但是这种无脑双倍发包还是浪费带宽。 搜索了一下 单/双边加速方案, 发现似乎可以在openvz上实现 用户态的网络协议栈(user space network stack)。 然后看到了这一句话:

比如说,由于运营商一般会对UDP流量进行策略化监管或者限速,目前,有一种非常简单的UDP双边加速的方式就是,仅仅将协议号由UDP改成TCP即可!而UDP允许一定程度的丢包,所以说,路由器交换机的AQM对其而言,就是刑不上大夫!

http://blog.csdn.net/dog250/article/details/53730374

改协议号说不定可行!!! 当然,改协议号之后还得混淆(成http/https流量)

@xtaci xtaci closed this as completed Jan 13, 2017
@linhua55
Copy link

linhua55 commented Jan 15, 2017

初步实现了 用TCP传输UDP(不进行三次握手),通过使用raw socket(/pcap)(需要以root运行) 伪造数据包类型,绕过正常的内核协议栈。 但还没进行混淆
https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket

不过测试一下,带宽利用率还没有net-speeder高(即不到一半带宽),可能是参数没调好,或该程序有bug

@linhua55
Copy link

https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket
重复发包,导致带宽利用率不到一半的问题已解决

@Chion82
Copy link

Chion82 commented Jan 28, 2017

借鉴了 https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket ,使用raw socket和libev,远端通信为伪TCP报文,重新实现了kcptun的最基本功能(未实现加密和纠错等,仍在测试),只需一个程序即可,不需要再另外建立UDP over TCP隧道,不容易“卡住”,欢迎试用
https://github.com/Chion82/kcptun-raw

@wangyu-
Copy link

wangyu- commented Aug 10, 2017

借鉴了楼上的relayRawSocket和kcptun-raw。
专门应对UDP 封锁和UDP QoS 的通用解决方案。用raw socket把udp协议包装成tcp,有模拟3次握手,模拟序号,模拟tcp option;还可以把流量包装成icmp。支持几乎任何udp应用。包括kcptun和finalspeed。支持openvz。支持NAT穿透。稳定。
https://github.com/wangyu-/udp2raw-tunnel
==updated==
还有个功能是心跳保活、自动重连,udp2raw重连可以恢复上次的连接,重连后上层连接继续有效,底层掉线上层不掉线。也可以有效解决连接断开的问题(就算你拔掉网线重插,或者重新拨号获得新ip,上层的kcp也不会断线)。(功能借鉴自kcptun-raw)
image
udp2raw+kcptun step by step教程:
https://github.com/wangyu-/udp2raw-tunnel/blob/master/doc/kcptun_step_by_step.md

@HongdaWang
Copy link

HongdaWang commented Aug 10, 2017 via email

@wangyu-
Copy link

wangyu- commented Aug 10, 2017

@HongdaWang 暂时没做windows客户端,但是windows配合vmware或者openwrt路由器可以稳定使用。

==updated==
只需要把udp2raw运行在vmware或路由器上,kcptun可以继续使用window的客户端,其他上层应用也仍然是运行在window上的(比如你的浏览器,ss客户端)。

@HongdaWang
Copy link

HongdaWang commented Aug 10, 2017 via email

@ccsexyz
Copy link

ccsexyz commented Aug 10, 2017

@wangyu- 感觉已经被你刷屏了

@wangyu-
Copy link

wangyu- commented Aug 10, 2017

@ccsexyz
我确实在很多udp屏蔽和qos相关的issue都提到了我的repo。我知道你也做过类似的项目,但是之前我翻遍了这个项目的所有issue遇到很多人提到udp屏蔽和qos,却没看到相关的连接(如果我早就看到你的项目,可能就不开发自己的了)。有很多人受udp屏蔽和udp qos的困扰,可是却找不到解决方案,回复几个issue也不过分吧。

我把@ccsexyz的项目也贴出来 ,https://github.com/ccsexyz/tunnel

跟udp2raw 比侧重点不同,各有优劣。

@ccsexyz
Copy link

ccsexyz commented Aug 10, 2017

@wangyu- 我的意思是贴一次就可以了,像Chion82那样。因为每回复一次就会给watch这个项目的人发一封邮件。

@wangyu-
Copy link

wangyu- commented Aug 10, 2017

多谢提醒,我注意。之前我只注意到了回复issue会给issue的参与人员发一封邮件。没注意到会给watch项目的所有人发。 造成困扰,不好意思。

@sqwwqw5
Copy link

sqwwqw5 commented Aug 11, 2017

@wangyu-
有一个疑惑,如果udp over tcp的话不就失去kcptun的意义了?
本来就是因为tcp协议效率低才会用Kcptun吧?

@wangyu-
Copy link

wangyu- commented Aug 11, 2017

@sqwwqw5 这是个非常好的问题。

如果是普通的udp over tcp确实就失去意义了。

udp2raw只是给udp加上了伪造的tcp header,本质上还是udp,不存在udp over tcp的问题。

@xiebruce
Copy link

@xtaci 希望后面kcptun直接支持这样的功能啊,就不用我们各种配置了哈哈,这个有可能吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests