OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx

上传人:b****6 文档编号:21190000 上传时间:2023-01-28 格式:DOCX 页数:18 大小:24.03KB
下载 相关 举报
OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx_第1页
第1页 / 共18页
OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx_第2页
第2页 / 共18页
OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx_第3页
第3页 / 共18页
OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx_第4页
第4页 / 共18页
OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx

《OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx(18页珍藏版)》请在冰豆网上搜索。

OpenVPN莫名其妙断线的问题及其解决Word格式文档下载.docx

18014ACKoutputsequencebroken:

[5]1234

16GETINSTBYREAL:

218.242.253.131:

18014[succeeded]

18014UDPv4READ[22]from218.242.253.131:

18014:

P_ACK_V1kid=0[1]

18014UDPv4WRITE[114]to218.242.253.131:

P_CONTROL_V1kid=0[]pid=5DATAlen=100

[6]5234

P_ACK_V1kid=0[2]

P_CONTROL_V1kid=0[]pid=6DATAlen=100

[7]5634

P_ACK_V1kid=0[3]

P_CONTROL_V1kid=0[]pid=7DATAlen=100

[8]5674

P_ACK_V1kid=0[4]

P_CONTROL_V1kid=0[]pid=8DATAlen=100

[9]5678

P_ACK_V1kid=0[5]

P_CONTROL_V1kid=0[]pid=9DATAlen=100

[10]9678

P_ACK_V1kid=0[6]

P_CONTROL_V1kid=0[]pid=10DATAlen=100

[11]91078

P_ACK_V1kid=0[7]

P_CONTROL_V1kid=0[]pid=11DATAlen=100

[12]910118

P_ACK_V1kid=0[9]

[12]10118

17MULTI:

REAPrange240->

256

17GETINSTBYREAL:

17Test证书/218.242.253.131:

P_ACK_V1kid=0[10]

[12]118

P_ACK_V1kid=0[11]

[12]8

18MULTI:

REAPrange0->

16

18Test证书/218.242.253.131:

18014TLS:

tls_pre_encrypt:

key_id=0

18014SENTPING

18014UDPv4WRITE[53]to218.242.253.131:

P_DATA_V1kid=0DATAlen=52

....持续了60秒没有收到ID为8的ACK,因此一直都是ACKoutputsequencebroken:

54:

15Test证书/218.242.253.131:

18014TLSError:

TLSkeynegotiationfailedtooccurwithin60seconds(checkyournetworkconnectivity)

TLShandshakefailedwithpeer0.0.0.0

没隔一段时间就会断一次,并且重连还不一定总能重连成功!

因此这里的问题有两点:

a.连接正常时断开(ping-restart的情况,上述日志没有展示)

b.重连时不成功(上述日志展示的)

2.分析

使用UDP的OpenVPN就是事多,为了避免重传叠加,在恶劣环境下还真得用UDP。

然而OpenVPN实现的UDPreliable层是一个高度简化的“按序确认连接”层,它仅仅确保了数据安序到达,并且有确认机制,和TCP那是没法比。

不过如果看一下TCP最初的方案,你会发现,TCP的精髓其实就是OpenVPN的reliable层,后来的复杂性都是针对特定情况的优化!

和TCP的实现一样,不对ACK进行ACK对发送端提出了重传滑动窗口未确认包的要求,因为纯ACK可能会丢失,这里先不讨论捎带ACK。

ACK一旦丢失,发送端肯定就要重传没有被ACK的包,关键是“什么时候去重传它?

”,协议本身一般都有一个或者多个Timer,Timer到期就重传,然而我个人认为这个Timer不能依赖上层,而要在协议本身实现,毕竟重传这种事对上层是不可见的!

然而,OpenVPN的reliable层在ACK丢失的应对方面却什么都没有实现,通过以上的日志可以看出,连续的:

Test证书/218.242.253.131:

说明ID为8的包一直都得不到重传,并且从:

这几行日志可以看出,确实是没有收到ID为8的包地ACK,说明它丢失了,接下来发送的数据包将持续填充发送窗口,直到填满,ID为8的包还未重传并且收到对端对其的ACK,因此就导致了ACKoutputsequencebroken,通过查代码,12-8=4,而4正是发送窗口的长度。

持续了很久ACKoutputsequencebroken之后,还是没有重传,直到:

a.隧道建立之后的ping-restart过期

b.隧道建立阶段的TLShandshakefailed

实际上,正确的方式应该是,检测到窗口爆满就应该马上重传。

TCP通过三次重复ACK知晓丢包,而OpenVPN的reliable则通过ACKoutputsequencebroken知晓ACK丢失,这是一个信号,应该在获取这个信号后做点什么了!

3.原始方案

方案很简单,那就是在打印ACKoutputsequencebroken的逻辑块内重传所有未确认的包,然而作为一种优化,仅仅重传ID最小的包即可。

这是因为,之所以到达ACKoutputsequencebroken,是因为窗口满了,之所以满是因为ID最小的包未确认,占据了很大的一块空间以及其后面的实际上可能已经确认了的空间,因此只要ID最小的包被确认,窗口就放开了,故而仅重传ID最小的包,以期待对端能再次给出确认。

方案虽简单,但是不落实到代码还是0,以下是一些尝试

4.第一次尝试-出错

7月25日下班后,又睡不着了,自己躲在女儿的小屋,开始了coding。

首先确认一下对于乱序或者重放的包,对端也能ACK,如果不能,那就要大改了,找到了ssl.c的代码,在tls_pre_decrypt中:

[plain]viewplaincopy

if(op!

=P_ACK_V1&

&

reliable_can_get(ks->

rec_reliable)){

packet_id_typeid;

/*ExtractthepacketIDfromthepacket*/

if(reliable_ack_read_packet_id(buf,&

id)){

/*Avoiddeadlockbyrejectingpacketthatwouldde-sequentializereceivebuffer*/

if(reliable_wont_break_tiality(ks->

rec_reliable,id)){

if(reliable_not_replay(ks->

/*Saveincomingciphertextpackettoreliablebuffer*/

structbuffer*in=reliable_get_buf(ks->

rec_reliable);

ASSERT(in);

ASSERT(buf_copy(in,buf));

reliable_mark_active_incoming(ks->

rec_reliable,in,id,op);

}

//注意这个注释,即使是重放包也ACK!

而我解决ACK丢失的思路正是重放那个迟迟收不到

//ACK的包,期待对端发送ACK,按照随机丢包概率,针对该包的ACK总不能一直丢失吧!

/*Processoutgoingacknowledgmentforpacketjustreceived,evenifit'

sareplay*/

reliable_ack_acknowledge_packet_id(ks->

rec_ack,id);

}

有了以上的基础,起码我知道,针对OpenVPN的reliable层修改的代码不多!

接下来就是找到修改哪里了,当然是哪里出问题修改哪里!

之所以僵持在那里,就是因为“ACKoutputsequencebroken”,所以说我找到了打印这个的地方,在reliable_get_buf_output_sequenced函数中:

structbuffer*

reliable_get_buf_output_sequenced(structreliable*rel)

{

structgc_arenagc=gc_new();

inti;

packet_id_typemin_id=0;

boolmin_id_defined=false;

structbuffer*ret=NULL;

/*findminimumactivepacket_id*/

for(i=0;

i<

rel->

size;

++i){

conststructreliable_entry*e=&

rel->

array[i];

if(e->

active){

if(!

min_id_defined||e->

packet_id<

min_id){

min_id_defined=true;

min_id=e->

packet_id;

//以下判断没有通过的原因,在上面的日志中已经找到了:

//...ACKoutputsequencebroken:

[12]8

//12-8=4,而#defineTLS_RELIABLE_N_SEND_BUFFERS4

min_id_defined||(int)(rel->

packet_id-min_id)<

size){

ret=reliable_get_buf(rel);

}else{

dmsg(D_REL_LOW,"

ACKoutputsequencebroken:

%s"

reliable_print_ids(re

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 幼儿读物

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1