三次握手,四次挥手
TCP是一种面向连接的单播协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务器的内存里保存的一份关于对方的信息,如ip地址、端口号等
一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号。一个TCP连接通常分为三个阶段:启动、数据传输、退出(关闭)。
当TCP接收到另一端的数据时,它会发送一个确认,但这个确认不会立即发送,一般会延迟一会儿。ACK是累积的,一个确认字节号N的ACK表示所有直到N的字节(不包括N)已经成功被接收了。这样的好处是如果一个ACK丢失,很可能后续的ACK就足以确认前面的报文段了。
一个完整的TCP连接是双向和对称的,数据可以在两个方向上平等地流动。给上层应用程序提供一种双工服务 。一旦建立了一个连接,这个连接的一个方向上的每个TCP报文段都包含了相反方向上的报文段的一个ACK。
序列号的作用是使得一个TCP接收端可丢弃重复的报文段,记录以杂乱次序到达的报文段。因为TCP使用IP来传输报文段,而IP不提供重复消除或者保证次序正确的功能。另一方面,TCP是一个字节流协议,绝不会以杂乱的次序给上层程序发送数据。因此TCP接收端会被迫先保持大序列号的数据不交给应用程序,直到缺失的小序列号的报文段被填满。
ISN
三次握手的一个重要功能是客户端和服务端交换ISN(Initial Sequence Number), 以便让对方知道接下来接收数据的时候如何按序列号组装数据。
如果ISN是固定的,攻击者很容易猜出后续的确认号。
ISN = M + F(localhost, localport, remotehost, remoteport)
M是一个计时器,每隔4毫秒加1。 F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出。
序列号回绕
因为ISN是随机的,所以序列号容易就会超过2^31-1. 而tcp对于丢包和乱序等问题的判断都是依赖于序列号大小比较的。此时就出现了所谓的tcp序列号回绕(sequence wraparound)问题。怎么解决?
static inline int before(__u32 seq1, __u32 seq2)
{
return (__s32)(seq1-seq2) < 0;
}
#define after(seq2, seq1) before(seq1, seq2)
上述代码是内核中的解决回绕问题代码。s32是有符号整型的意思,而u32则是无符号整型。序列号发生回绕后,序列号变小,相减之后,把结果变成有符号数了,因此结果成了负数。
ISN
三次握手的一个重要功能是客户端和服务端交换ISN(Initial Sequence Number), 以便让对方知道接下来接收数据的时候如何按序列号组装数据。
如果ISN是固定的,攻击者很容易猜出后续的确认号。
ISN = M + F(localhost, localport, remotehost, remoteport)
M是一个计时器,每隔4毫秒加1。 F是一个Hash算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值。要保证hash算法不能被外部轻易推算得出。
序列号回绕
因为ISN是随机的,所以序列号容易就会超过2^31-1. 而tcp对于丢包和乱序等问题的判断都是依赖于序列号大小比较的。此时就出现了所谓的tcp序列号回绕(sequence wraparound)问题。怎么解决?
static inline int before(__u32 seq1, __u32 seq2)
{
return (__s32)(seq1-seq2) < 0;
}
#define after(seq2, seq1) before(seq1, seq2)
上述代码是内核中的解决回绕问题代码。s32是有符号整型的意思,而u32则是无符号整型。序列号发生回绕后,序列号变小,相减之后,把结果变成有符号数了,因此结果成了负数。
【面试高频问题】线程、进程、协程 https://zhuanlan.zhihu.com/p/70256971
在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤? https://www.zhihu.com/question/34873227/answer/518086565
|