tcp的半连接与完全连接队列(三)源码分析
TCP 协议中的 SYN queue 和 accept queue 处理
若要理解本文意图说明的问题,可能需要以下知识背景:
- 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;
}
tcp的半连接与完全连接队列(三)源码分析的更多相关文章
- 分布式缓存技术之Redis_Redis集群连接及底层源码分析
目录 1. Jedis 单点连接 2. Jedis 基于sentinel连接 基本使用 源码分析 本次源码分析基于: jedis-3.0.1 1. Jedis 单点连接 当是单点服务时,Java ...
- tcp的半连接与完全连接队列
队列及参数 https://segmentfault.com/a/1190000008224853 server端的半连接队列(syn队列) 在三次握手协议中,服务器维护一个半连接队列,该队列为每个客 ...
- (转)tcp的半连接与完全连接队列
队列及参数 tcp-sync-queue-and-accept-queue-small.jpg server端的半连接队列(syn队列) 在三次握手协议中,服务器维护一个半连接队列,该队列为每个客 ...
- tcp的半连接与完全连接队列(二)
队列及参数 server端的半连接队列(syn队列) 在三次握手协议中,服务器维护一个半连接队列,该队列为每个客户端的SYN包开设一个条目(服务端在接收到SYN包的时候,就已经创建了request_s ...
- 多线程高并发编程(11) -- 非阻塞队列ConcurrentLinkedQueue源码分析
一.背景 要实现对队列的安全访问,有两种方式:阻塞算法和非阻塞算法.阻塞算法的实现是使用一把锁(出队和入队同一把锁ArrayBlockingQueue)和两把锁(出队和入队各一把锁LinkedBloc ...
- 学习JUC源码(1)——AQS同步队列(源码分析结合图文理解)
前言 最近结合书籍<Java并发编程艺术>一直在看AQS的源码,发现AQS核心就是:利用内置的FIFO双向队列结构来实现线程排队获取int变量的同步状态,以此奠定了很多并发包中大部分实现基 ...
- AbstractQueuedSynchronizer 队列同步器源码分析
AbstractQueuedSynchronizer 队列同步器(AQS) 队列同步器 (AQS), 是用来构建锁或其他同步组件的基础框架,它通过使用 int 变量表示同步状态,通过内置的 FIFO ...
- Http请求连接池-HttpClient的AbstractConnPool源码分析
在做服务化拆分的时候,若不是性能要求特别高的场景,我们一般对外暴露Http服务.Spring里提供了一个模板类RestTemplate,通过配置RestTemplate,我们可以快速地访问外部的Htt ...
- tomcat源码分析(三)一次http请求的旅行-从Socket说起
p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...
随机推荐
- js教程--从入门到精通 第一篇 js的前世今生以及js中基本数据类型和引入方式
1.Javascript前世今生 1.1.什么是Javascript Javascript运行于Javascript [解释器/引擎]中的解释性脚本语言 Javascript ...
- 多线程学习-基础(六)分析wait()-notify()-notifyAll()
一.理解wait()-notify()-notifyAll()obj.wait()与obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,notify是针对已经获 ...
- 关于UI Automation框架
微软提供的UI Automation框架给开发windows平台的自动化测试带来了很大的便利,这里就总结一下相关的代码. 首先,直接使用UI Automation框架,完成一个NotePad的abou ...
- 与HDFS交互-By shell命令
Shell命令的开头有三种: hadoop fs hadoop dfs hdfs dfs 关于具体命令之前写过 可查看:https://www.cnblogs.com/floakss/p/970344 ...
- linux内核中的##__VA_ARGS__有什么作用?
答: 1.__VA_ARGS__是一个可变参数宏: 2. 当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错: 3. 示例 3.1 #defin ...
- 【转】windows server 2012 R2搭建IIS服务器
源地址:http://blog.csdn.net/microsoft_wu/article/details/46521017
- hdu1845(a^b的因子和%p)
题目链接:http://poj.org/problem?id=1845 思路: 1.整数唯一分解定理: 任意正整数都有且只有一种方式写出其素因子的乘积表达式. a=(p1^k1)*(p2^k2)*(p ...
- [USACO09FEB]改造路Revamping Trails 分层最短路 Dijkstra BZOJ 1579
题意翻译 约翰一共有N)个牧场.由M条布满尘埃的小径连接.小径可 以双向通行.每天早上约翰从牧场1出发到牧场N去给奶牛检查身体. 通过每条小径都需要消耗一定的时间.约翰打算升级其中K条小径,使之成为高 ...
- .net mvc 框架实现后台管理系统 3
左侧菜单实现 默认html <div class="layui-side layui-bg-black h-slide"> <div class="la ...
- Git的安装使用
1.什么是Git Git是一个自由和开源的分布式版本管理工具,用于有效.高速的处理任何或大或小的项目.最初由Linux Torvalds编写,用于帮助管理Linux内核开发而开发的一个开放源码的版本管 ...