【原创】源码分析 TCP 协议中的 SYN queue 和 accept queue 处理

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介:

若要理解本文意图说明的问题,可能需要以下知识背景: 
  • listen 系统调用的 backlog 参数含义,以及与 net.core.somaxconn 参数的关系;
  • SYN flood 攻击与防护;
  • SYN queue 和 accept queue 的用途,以及在不同 linux 版本中的实现差异;

---- 

在 SYN queue 未满的情况下,在收到 SYN 包后,TCP 协议栈自动回复 SYN,ACK 包,之后在收到 ACK 时,根据 accept queue 状态进行后续处理; 
若 SYN queue 已满,在收到 SYN 时 
      若设置 net.ipv4.tcp_syncookies = 0 ,则直接丢弃当前 SYN 包;
      若设置 net.ipv4.tcp_syncookies = 1 ,则令 want_cookie = 1 继续后面的处理;
            若 accept queue 已满,并且 qlen_young 的值大于 1 ,则直接丢弃当前 SYN 包; 
            若 accept queue 未满或者 qlen_young 的值未大于 1 ,则输出 "possible SYN flooding on port %d. Sending cookies.\n",生成 syncookie 并在 SYN,ACK 中带上; 

---
   以下源码取自 linux-2.6.32 版本 --- 
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
    ...
#ifdef CONFIG_SYN_COOKIES
	int want_cookie = 0;
#else
#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
#endif
    ...
	/* TW buckets are converted to open requests without
	 * limitations, they conserve resources and peer is
	 * evidently real one.
	 */
	// 判定 SYN queue 是否已满
	if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
#ifdef CONFIG_SYN_COOKIES
		if (sysctl_tcp_syncookies) {  // SYN queue 已满,并且设置了 net.ipv4.tcp_syncookies = 1 ,则设置 want_cookie = 1 以便后续处理
			want_cookie = 1;
		} else
#endif
		goto drop;    // 否则,直接丢弃当前 SYN 包
	}

	/* Accept backlog is full. If we have already queued enough
	 * of warm entries in syn queue, drop request. It is better than
	 * clogging syn queue with openreqs with exponentially increasing
	 * timeout.
	 */
	// 若此时 accept queue 也已满,并且 qlen_young 的值大于 1(即保存在 SYN queue 中未进行 SYN,ACK 重传的连接超过 1 个)
	// 则直接丢弃当前 SYN 包(相当于针对 SYN 进行了速率限制)
	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
		goto drop;
...
	// 若 accept queue 未满,或者 qlen_young 的值未大于 1
	if (want_cookie) {
#ifdef CONFIG_SYN_COOKIES
		syn_flood_warning(skb);  // 输出 "possible SYN flooding on port %d. Sending cookies.\n"
		req->cookie_ts = tmp_opt.tstamp_ok;  // 为当前 socket 设置启用 cookie 标识
#endif
		// 生成 syncookie
		isn = cookie_v4_init_sequence(sk, skb, &req->mss);
	} else if (!isn) {
	    ...
	}
	// 保存 syncookie 值
	tcp_rsk(req)->snt_isn = isn;

	// 回复 SYN,ACK ,若之前设置了 net.ipv4.tcp_syncookies = 1 则会释放对应的 socket 结构
	if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
		goto drop_and_free;
		
	// 启动 SYN,ACK 重传定时器
	inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
	return 0;

drop_and_release:
	dst_release(dst);
drop_and_free:
	reqsk_free(req);
drop:
	return 0;
}
--- 

若 accept queue 已满,在收到三次握手最后的 ACK 时 
      若设置 tcp_abort_on_overflow = 1 ,则 TCP 协议栈回复 RST 包,并直接从 SYN queue 中删除该连接信息; 
      若设置 tcp_abort_on_overflow = 0 ,则 TCP 协议栈将该连接标记为 acked ,但仍保留在 SYN queue 中,并启动 timer 以便重发 SYN,ACK 包;当 SYN,ACK 的重传次数超过 net.ipv4.tcp_synack_retries 设置的值时,再将该连接从 SYN queue 中删除; 
--- 
/*
 *	Process an incoming packet for SYN_RECV sockets represented
 *	as a request_sock.
 */
struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        struct request_sock *req,
        struct request_sock **prev)
{
    ...
	/* OK, ACK is valid, create big socket and
	 * feed this segment to it. It will repeat all
	 * the tests. THIS SEGMENT MUST MOVE SOCKET TO
	 * ESTABLISHED STATE. If it will be dropped after
	 * socket is created, wait for troubles.
	 */
	// 调用 net/ipv4/tcp_ipv4.c 中的 tcp_v4_syn_recv_sock 函数
	// 判定 accept queue 是否已经满,若已满,则返回的 child 为 NULL
	child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
	if (child == NULL)
		goto listen_overflow;

	// 在 accept queue 未满的情况下,将 ESTABLISHED 连接从 SYN queue 搬移到 accept queue 中
	inet_csk_reqsk_queue_unlink(sk, req, prev);
	inet_csk_reqsk_queue_removed(sk, req);

	inet_csk_reqsk_queue_add(sk, req, child);
	return child;

listen_overflow:
	// 若 accept queue 已满,但设置的是 net.ipv4.tcp_abort_on_overflow = 0
	if (!sysctl_tcp_abort_on_overflow) {
		inet_rsk(req)->acked = 1;    // 则只标记为 acked ,直接返回,相当于忽略当前 ACK
		return NULL;
	}

embryonic_reset:
	// 若 accept queue 已满,但设置的是 net.ipv4.tcp_abort_on_overflow = 1
	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);   // 变更统计信息
	if (!(flg & TCP_FLAG_RST))
		req->rsk_ops->send_reset(sk, skb);   // 发送 RST

	inet_csk_reqsk_queue_drop(sk, req, prev);    // 直接从 SYN queue 中删除该连接信息
    return NULL;
}

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
8月前
|
缓存 网络协议 Linux
手把手实现tcp/ip用户态协议栈,帮你实践网络知识(网络必备,面试项目)
手把手实现tcp/ip用户态协议栈,帮你实践网络知识(网络必备,面试项目)
|
9月前
|
XML 存储 JSON
【面试题精讲】序列化协议对应于 TCP/IP 4 层模型的哪一层?
【面试题精讲】序列化协议对应于 TCP/IP 4 层模型的哪一层?
|
2月前
|
网络协议 安全 网络安全
网络 (TCP/IP 四层协议中常见网络协议)
网络 (TCP/IP 四层协议中常见网络协议)
53 7
|
1月前
|
网络协议 网络架构
计算机网络——计算机网络体系结构(1/4)-常见的计算机网络体系结构(OSI体系、TCP/IP体系、原理体系五层协议)
计算机网络——计算机网络体系结构(1/4)-常见的计算机网络体系结构(OSI体系、TCP/IP体系、原理体系五层协议)
47 0
|
2月前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
11月前
|
网络协议 网络架构 数据格式
协议分层与OSI参考模型【图解TCP/IP(笔记三)】
协议分层与OSI参考模型【图解TCP/IP(笔记三)】
协议分层与OSI参考模型【图解TCP/IP(笔记三)】
|
9月前
|
网络协议
百度搜索:蓝易云【四层协议:TCP/IP详解!】
现了互联网上的可靠数据传输和网络通信。每个层次都有特定的功能和协议,相互配合以实现端到端的通信。
86 0
|
11月前
|
网络协议 Unix 网络性能优化
两种传输层协议TCP和UDP【图解TCP/IP(笔记十二)】
两种传输层协议TCP和UDP【图解TCP/IP(笔记十二)】
123 0
|
11月前
|
监控 网络协议 网络架构
IP协议【图解TCP/IP(笔记九)】
IP协议【图解TCP/IP(笔记九)】
|
域名解析 网络协议 安全
网络:网络分层与协议/OSI七层模型/(TCP/IP模型)
网络:网络分层与协议/OSI七层模型/(TCP/IP模型)
201 0