linux ack linux考试
大家好,linux ack相信很多的网友都不是很明白,包括linux考试也是一样,不过没有关系,接下来就来为大家分享关于linux ack和linux考试的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧!
畅谈linux下TCP(上)
tcp协议是互联网中最常用的协议,开发人员基本上天天和它打交道,对它进行深入了解。可以帮助我们排查定位bug和进行程序优化。下面我将就TCP几个点做深入的探讨
客户端:收到 ack后分配连接资源。发送数据
服务器:收到 syn后立即分配连接资源
客户端:收到ACK,立即分配资源
服务器:收到ACK,立即分配资源
既然三次握手也不是100%可靠,那四次,五次,六次。。。呢?其实都一样,不管多少次都有丢包问题。
client只发送一个 SYN, server分配一个tcb,放入syn队列中。这时候连接叫半连接状态;如果server收不到 client的ACK,会不停重试发送 ACK-SYN给client。重试间隔为 2的 N次方叠加(2^0, 2^1, 2^2....);直至超时才释放syn队列中的这个 TCB;
在半连接状态下,一方面会占用队列配额资源,另一方面占用内存资源。我们应该让半连接状态存在时间尽可能的小
当client向一个未打开的端口发起连接请求时,会收到一个RST回复包
当listen的 backlog和 somaxconn都设置了得时候,取两者min值
Recv-Q是accept队列当前个数, Send-Q设置最大值
这种SYN洪水攻击是一种常见攻击方式,就是利用半连接队列特性,占满syn队列的资源,导致 client无法连接上。
解决方案:
为什么不像握手那样合并成三次挥手?因为和刚开始连接情况,连接是大家都从0开始,关闭时有历史包袱的。server(被动关闭方)收到 client(主动关闭方)的关闭请求FIN包。这时候可能还有未发送完的数据,不能丢弃。所以需要分开。事实可能是这样
当然,在没有待发数据,并且允许 Delay ACK情况下, FIN-ACK合并还是非常常见的事情,这是三次挥手是可以的。
同上
CLOSE_WAIT是被动关闭方才有的状态。
被动关闭方 [收到 FIN包发送 ACK应答]到 [发送FIN,收到ACK ]期间的状态为 CLOSE_WAIT,这个状态仍然能发送数据。我们叫做半关闭,下面用个例子来分析:
这个是我实际生产环境碰到的一个问题,长连接会话场景,server端收到client的rpc call请求1,处理发现请求包有问题,就强制关闭结束这次会话,但是因为client发送第二次请求之前,并没有去调用recv,所以并不知道这个连接被server关闭,继续发送请求2,此时是半连接,能够成功发送到对端机器,但是recv结果后,遇到连接已经关闭错误。
如果 client和 server恰好同时发起关闭连接。这种情况下,两边都是主动连接,都会进入 TIME_WAIT状态
1、被动关闭方在LAST_ACK状态(已经发送FIN),等待主动关闭方的ACK应答,但是 ACK丢掉,主动方并不知道,以为成功关闭。因为没有TIME_WAIT等待时间,可以立即创建新的连接,新的连接发送SYN到前面那个未关闭的被动方,被动方认为是收到错误指令,会发送RST。导致创建连接失败。
2、主动关闭方断开连接,如果没有TIME_WAIT等待时间,可以马上建立一个新的连接,但是前一个已经断开连接的,延迟到达的数据包。被新建的连接接收,如果刚好seq和 ack字段都正确, seq在滑动窗口范围内(只能说机率非常小,但是还是有可能会发生),会被当成正确数据包接收,导致数据串包。如果不在window范围内,则没有影响(发送一个确认报文(ack字段为期望ack的序列号,seq为当前发送序列号),状态变保持原样)
TIME_WAIT问题比较比较常见,特别是CGI机器,并发量高,大量连接后段服务的tcp短连接。因此也衍生出了多种手段解决。虽然每种方法解决不是那么完美,但是带来的好处一般多于坏处。还是在日常工作中会使用。
1、改短TIME_WAIT等待时间
这个是第一个想到的解决办法,既然等待时间太长,就改成时间短,快速回收端口。但是实际情况往往不乐观,对于并发的机器,你改多短才能保证回收速度呢,有时候几秒钟就几万个连接。太短的话,就会有前面两种问题小概率发生。
2、禁止Socket lingering
这种情况下关闭连接,会直接抛弃缓冲区中待发送的数据,会发送一个RST给对端,相当于直接抛弃TIME_WAIT,进入CLOSE状态。同样因为取消了 TIME_WAIT状态,会有前面两种问题小概率发生。
3、tcp_tw_reuse
net.ipv4.tcp_tw_reuse选项是从 TIME_WAIT状态的队列中,选取条件:1、remote的 ip和端口相同, 2、选取一个时间戳小于当前时间戳;用来解决端口不足的尴尬。
现在端口可以复用了,看看如何面对前面TIME_WAIT那两种问题。我们仔细回顾用一下前面两种问题。都是在新建连接中收到老连接的包导致的问题,那么如果我能在新连接中识别出此包为非法包,是不是就可以丢掉这些无用包,解决问题呢。
需要实现这些功能,需要扩展一下tcp包头。增加时间戳字段。发送者在每次发送的时候。在tcp包头里面带上发送时候的时间戳。当接收者接收的时候,在ACK应答中除了TCP包头中带自己此时发送的时间戳,并且把收到的时间戳附加在后面。也就是说ACK包中有两个时间戳字段。结构如下:
那我们接下来一个个分析tcp_tw_reuse是如何解决TIME_WAIT的两个问题的
4、tcp_tw_recycle
tcp_tw_recycle也是借助 timestamp机制。顾名思义, tcp_tw_reuse是复用端口,并不会减少 TIME-WAIT数量。你去查询机器上TIME-WAIT数量,还是几千几万个,这点对有强迫症的同学感觉很不舒服。tcp_tw_recycle是提前回收 TIME-WAIT资源。会减少机器上 TIME-WAIT数量。
tcp_tw_recycle工作原理是。
Linux TCP -SYN cookies的一个问题分析
最近,我们团队内遇到一个令人困惑的TCP问题,这里与大家分享一下。在Linux实现的TCP中,特别是与SYN cookie相关的功能,存在一个不为人知的缺陷。当客户端连续并发发送两个数据包,而服务端的TCP堆栈仅将第二个数据包中的信息传给应用程序,却未意识到这并非数据流中的首个数据包。这究竟是如何发生的呢?
当以下条件同时满足时,此问题就会出现:客户端发送两个数据包,服务端未接收到首个数据包,同时接收到并处理了第二个数据包。结果是,客户端发送了"dog"和"cat",而服务端仅接收到了"cat"。我们发现这个问题时,通常属于随机发生的事件。使用的纯TCP协议偶尔会导致程序崩溃,经过分析,发现服务器未接收到前两个字符。
为了解决这一问题,首先需要理解TCP的基本原理。TCP协议保证了发送端的所有字节按照相同的顺序被接收端接收。每个数据包包含序列号和确认号,这些信息用于识别重复、丢失或无序的数据。序列号由发送端在连接开始时选择的任意值开始,随着每个数据包发送,序列号递增。确认号则指示接收端已经接收到序列号之前的数据。
在建立TCP连接时,涉及到三次握手、序列号和确认号的作用。MSS(最大段大小)是另一个关键概念,指定了主机为每个TCP数据包准备接收的最大数据字节数,通常默认为536字节。
为了进一步了解,我们讨论了SYN cookie的原理和作用。SYN cookie是服务器选择的初始序列号,用于对连接建立过程中的信息进行编码,防止部分连接的记录丢失。然而,Linux中实现的SYN cookie计算方式存在一个“额外的黑客”,即在计算过程中压缩了数据与客户端的初始序列号,导致了问题发生。
当服务端接收到客户端的第一个ACK(确认)包时,它需要根据ACK中的信息重建连接状态。然而,在ACK到达之前,服务端无任何连接记录。如果在服务端接收到ACK之前,客户端再次发送数据包,ACK包可能会丢失,导致服务端误认为接收到的数据是第一个数据包,而非后续数据。
在Linux中,secure_tcp_syn_cookie函数用于计算SYN cookie,而check_tcp_syn_cookie函数用于验证客户端发送的ACK是否有效。问题出在处理ACK序列号和MSS索引值的逻辑中,当计算结果与预期不符时,服务端错误地接受了连接,导致丢失了部分数据。
为了解决这个问题,关键在于避免将数据与客户端的初始序列号一起压缩到SYN cookie中。这可以通过修改SYN cookie的计算方式来实现,确保服务器能够正确识别数据包的顺序,从而避免数据丢失。
对于这一问题的复现方式,感兴趣的读者可以尝试模拟相关场景,并通过代码分析或调试工具来进一步验证问题的发生。当然,解决这一问题的方法需要深入理解TCP协议、SYN cookie的实现细节以及Linux内核源码。
linux查看是否有ack flood
ACK Flood攻击。在TCP连接建立之后,所有的数据传输TCP报文都是带有ACK标志位的,主机在接收到一个带有ACK标志位的数据包的时候,需要检查该数据包所表示的连接四元组是否存在,如果存在则检查该数据包所表示的状态是否合法,然后再向应用层传递该数据包。如果在检查中发现该数据包不合法,例如该数据包所指向的目的端口在本机并未开放,则主机操作系统协议栈会回应RST包告诉对方此端口不存在。通常状态检测防火墙所做的事情与此类似,只不过防火墙只拦截非法的数据包,而不主动回应。