操作系统对 TCP 和 UDP 协议的发送方的机制不同,也就是问题原因在发送方
:用户消息通过 UDP 协议传输时,操作系统不会对消息进行拆分。也就是每个 UDP 报文就是一个用户消息的边界。
操作系统在收到 UDP 报文后,会将其插入到队列里,队列里的每一个元素就是一个 UDP 报文
:用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个的 TCP 报文。一个完整的用户消息被拆分成多个 TCP 报文进行传输。
不能认为一个用户消息对应一个 TCP 报文,正因为这样,所以 TCP 是面向字节流的协议
为了很大程度上防止历史报文被下一个相同四元组的连接接收。又引入时间戳的机制,从而完全避免了历史报文被接收的问题。
开启 tcp_tw_recycle 参数,两个的客户端都在同一个NAT环境下,造成 SYN 报文被丢弃
TCP 两个队列满了(半连接队列和全连接队列),造成 SYN 报文被丢弃
处于 Established 状态的服务端,如果收到了客户端的 SYN 报文(注意此时的 SYN 报文其实是乱序的,因为 SYN 报文的初始化序列号其实是一个随机数),会回复一个携带了正确序列号和确认号的 ACK 报文,这个 ACK 被称之为 Challenge ACK。
接着,客户端收到这个 Challenge ACK,发现确认号(ack num)并不是自己期望收到的,于是就会回 RST 报文,服务端收到后,就会释放掉该连接
要伪造一个能关闭 TCP 连接的 RST 报文,必须同时满足「四元组相同」和「序列号是对方期望的」这两个条件。(两种关闭 TCP 连接的工具:tcpkill 和 killcx 工具)
tcpkill 工具只能用来关闭活跃的 TCP 连接,无法关闭非活跃的 TCP 连接,因为 tcpkill 工具是等双方进行 TCP 通信后,才去获取正确的序列号,如果这条 TCP 连接一直没有任何数据传输,则就永远获取不到正确的序列号。
killcx 工具可以用来关闭活跃和非活跃的 TCP 连接,因为 killcx 工具是主动发送 SYN 报文,这时对方就会回复 Challenge ACK ,然后 killcx 工具就能从这个 ACK 获取到正确的序列号。
?