作者:threedayman
内容提要
什么是TCP?
在OSI模型中,TCP属于哪一层?
TCP得头格式
怎样唯一确认一个TCP连接
一台服务器下,某应用 TCP最大连接数是多少?
TCP连接怎样建立
- SYN Flood攻击
TCP连接断开
TCP
传输控制协议(英语:Transmission Control Protocol,缩写:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。在简化的计算机网络 OSI 模型中,它完成第四层传输层所指定的功能。
TCP 报文头
源端口: 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设置,另外受到机器内存 限制。
三次握手
- 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打开
从抓包结果上看发送syn报文后,没有收到syn+ack报文,发送端会重试发送syn报文。重试次数可以在 /proc/sys/net/ipv4/tcp_syn_retries 中设置。
查看当时得tcp连接状态
SYN Flood 攻击
正常流程
- 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表示始终启用。