这就是TCP?

Posted 恒生Light云社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了这就是TCP?相关的知识,希望对你有一定的参考价值。

作者:threedayman

来源:恒生LIGHT云社区

内容提要

  • 什么是TCP?

  • 在OSI模型中,TCP属于哪一层?

  • TCP得头格式

  • 怎样唯一确认一个TCP连接

  • 一台服务器下,某应用 TCP最大连接数是多少?

  • TCP连接怎样建立

    • SYN Flood攻击

  • TCP连接断开

TCP

传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。在简化的计算机网络 OSI 模型中,它完成第四层传输层所指定的功能。

TCP 报文头

640.png

  • 源端口: 2 字节 发送端口

  • 目标端口:2 字节 接收端口

    TCP 协议中没有源 ip 和目标 ip,那是 ip 层相关信息。源 ip、源端口、目标 ip、目标端口构成了 TCP 连接的四元组 。一个四元组可以唯一标识一个 TCP 连接。

  • 序列号: 4 字节 TCP 是面向字节流的协议,通过 TCP 传输的字节流的每个字节都分配了序列号,序列号指的是本报文段第一个字节的序列号

  • 确认号:期望接收下一个序列号,小于此确认号的所有字节都已经收到。

  • 头部长度:

  • 保留: 占 6bits 保留为今后使用,但目前应置为 0

  • TCP Flags

  • NS: 1bit ECN-nonce 隐藏保护

  • CWR: 1bit 减少拥塞窗口(CWR)标志由发送主机设置,以指示它收到了设置了 ECE 标志的 TCP 段并在拥塞控制机制中作出了响应

  • ECE: 如果设置了 SYN 标志(1),则 TCP 对等点可以使用 ECN;如果 SYN 标志为 clear(0),则说明 IP 报头中具有拥塞经历标志的包在正常传输过程中收到(ECN=11)。这可以作为 TCP 发送方网络拥塞(或即将发生拥塞)的指示。

  • URG: 紧急比特

  • ACK: 确认数据包

  • PSH:告知对方数据包收到以后应马上交给上层应用,不能缓存。

  • RST: 用来强制断开连接,之前建立的连接已经不在了、包不合法、或者无法处理。

  • SYN: 发起连接数据包同步双方的初始序列号。

  • FIN: 准备断开连接,不会再发数据包。

  • 窗口大小: 标识窗口大小。

  • 校验和: 检查数据是否被篡改或损坏。

  • 紧急指针: 当 URG=1 时,标识紧急数据所在的位置。

  • 选项、填充:常用的选项有 MSS、SACK、Window Scale 等,填充为了补齐数据到 32 位。

    通过四元组(源 ip、源端口、目标 ip、目标端口)可以唯一确认一个TCP连接。假设某应用得ip和端口 都固定,客户端得ip和端口是可变得,理论上 最大TCP连接数 = 客户端IP数 * 客端端口数。IPv4,客户端ip数最多为2^32,端口数最多2^16,那理论最大单机TCP为2^48。当然tcp连接数还受其他因素得限制,比如在linux操作系统中,受文件描述符限制 ,可以通过ulimit设置,另外受到机器内存 限制。

三次握手

640 (1).png

  • Sender 发送 SYN(seq = x);

  • Reciver 接收到 SYN 后 返回 SYN+ACK(seq=y,ack = x+1);

  • Sender 接收到 SYN 和 ACK 之后 返回给 Reciver 一个 ACK(seq=x+1,ack=y+1);

三次握手优点

  • 防止旧得连接重复初始化。

  • 同步双方序列号。(序列号用于数据去重,按序接收处理数据,标识哪些数据已经被处理)

  • 避免资源浪费。(每收到一个SYN就会创建一个连接)

SYN_SENT 状态模拟

packetdrill简介 (https://github.com/google/packetdrill

  • 执行系统调用(system call),对比返回值是否符合预期

  • 把数据包(packet)注入到内核协议栈,模拟协议栈收到包

  • 比较内核协议栈发出的包与预期是否相符

  • shell 命令

  • python 命令

SYN_SENT状态模拟脚本

//0s 创建一个 socket
+0 socket(...,SOCK_STREAM,IPPROTO_TCP)=3
//连接
+0 connect(3,...,...)= -1

tcpdump 抓包导出syn_sent.pcap 文件。通过wireshark打开

640 (2).png

从抓包结果上看发送syn报文后,没有收到syn+ack报文,发送端会重试发送syn报文。重试次数可以在 /proc/sys/net/ipv4/tcp_syn_retries 中设置。

查看当时得tcp连接状态

640 (3).png

SYN Flood 攻击

640 (4).png

正常流程

  • Receiver接收到Sender的SYN 报文时,会将其加入到SYN队列

  • 发送 SYN + ACK 给Sender,等待Sender回应 ACK 报文;

  • Receiver接收到 ACK 报文后,从SYN队列 移除放入到Accept队列

  • 应用调用 accpet()接口,从Accept队列 取出的连接

异常流程

  • 受到SYN攻击得时候,Receive将收不到Sender发送得ACK报文,将导致SYN队列 中的数据不能转移到Accept队列

  • SYN队列 满之后,将会影响正常得连接请求

SYN Flood攻击防御

  • 通过增加SYN 队列 长度,长度受到net.ipv4.tcp_max_syn_backlog、net.core.somaxconn、backlog 参数影响。再长得队列,面对恶意攻击也有被填满得时刻。

  • 减少SNY+ACK 重试次数,重试时间指数级避退(1s、2s、4s、8s、16s),重试完成之后才会将SYN-RECV连接关闭 通过/proc/sys/net/ipv4/tcp_synack_retries 设置。该选项对于误传SYN能有一点作用,面对恶意SYN请求,也顶不住。

  • SYN-Cookie 机制

    • SYN 队列 满之后,后续Receiver收到 SYN 包,不进入SYN 队列

    • 计算出一个 cookie 值,再以 SYN + ACK 中的序列号 返回Sender,

    • Receiver接收到Sender的应答报文时,Receiver会检查这个 ACK 包的合法性。如果合法,直接放入到Accept 队列

    • SYN-Cookie 通过/proc/sys/net/ipv4/tcp_syncookies设置 默认1表示队列满时启用,0表示禁用,2表示始终启用。

四次挥手

 

以上是关于这就是TCP?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Sublime Text中添加代码片段

使用 Pygments 检测代码片段的编程语言

如何在 Javadoc 中使用 @ 和 符号格式化代码片段?

如何在 Django Summernote 中显示编程片段的代码块?

这两个代码片段有啥区别?

为啥这段代码会泄露? (简单的代码片段)