netstat -natp | grep SYN_RECV | wc -l
半连接队列最大长度可以使用我们上述分析得到的公式计算得到
半全连接队列溢出全连接队列溢出
当请求量很大,全连接队列比较小时 , 就有可能发生全连接队列溢出的情况 。
此代码是 linux 内核用来判断全连接队列是否已满的函数,可以看到判断用的是大于号,这也就是我们用 ss 命令可能会看到 Recv-Q > Send-Q 的原因
- sk_ack_backlog 是当前全连接队列的大小
- sk_max_ack_backlog 是全连接队列的最大长度,也就是 min(listen_backlog, somaxconn)
文章插图
当全连接队列满了发生溢出时,会根据 /proc/sys/net/ipv4/tcp_abort_on_overflow 内核参数来决定怎么处理后续的 ack 请求,tcp_abort_on_overflow 默认值为 0 。
- 当 tcp_abort_on_overflow = 0 时,如果全连接队列已满 , 服务端会直接扔掉客户端发送的 ACK,此时服务端处于 SYN_RECV 状态,客户端处于 ESTABLISHED 状态,服务端的超时重传定时器会重传 SYN + ACK 包给客户端(重传次数由/proc/sys/net/ipv4/tcp_synack_retries 指定,默认值为 5 , 重试间隔为 1s、2s、4s、8s、16s,共 31s,第 5 次发出后还要等 32s 才知道第 5 次也超时了,所以总共需要 63s) 。超过 tcp_synack_retries 后 , 服务端不会在重传,这时如果客户端发送数据过来,服务端会返回 RST 包,客户端会报 connection reset by peer 异常
- 当 tcp_abort_on_overflow = 1 时,如果全连接队列已满,服务端收到客户端的 ACK 后,会发送一个 RST 包给客户端,表示结束掉这个握手过程和这个连接,客户端会报 connection reset by peer 异常
半连接队列溢出
我们知道 , 服务端收到客户端发送的 SYN 包后会将该连接放入半连接队列中,然后回复 SYN+ACK,如果客户端一直不回复 ACK 做第三次握手,这样就会使得服务端有大量处于 SYN_RECV 状态的 TCP 连接存在半连接队列里,超过设置的队列长度后就会发生溢出 。
下述代码是 linux 内核判断是否发生半连接队列溢出的函数
// 代码在 include/net/inet_connection_sock.h 中static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk){return reqsk_queue_is_full(&inet_csk(sk)->icsk_accept_queue);}// 代码在 include/net/request_sock.h 中static inline int reqsk_queue_is_full(const struct request_sock_queue *queue){/** qlen 是当前半连接队列大小* max_qlen_log 上述解释过,如果半连接队列大小 = 16 = 2^4,那么该值就是4* 非常巧妙的用了移位运行来判断半连接队列是否溢出,底层满满的都是细节*/return queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log;}
我们常说的 SYN Flood 洪水攻击 是一种典型的 DDOS 攻击,就是利用了这个点,给服务端发送一个 SYN 包后客户端就下线了 , 服务端会超时重传 SYN+ACK 包,上述也说了总共需要 63s 才停止重传,也就是说服务端需要经过 63s 后才断开该连接,这样就会导致半连接队列快速被耗?。荒艽碚5那肭?。那是怎么防止攻击的呢?
linux 提供个一个内核参数 /proc/sys/net/ipv4/tcp_syncookies 来应对该攻击,当半连接队列满了且开启 tcp_syncookies = 1 配置时,服务端在收到 SYN 并返回 SYN+ACK 后 , 不将该连接放入半连接队列,而是根据这个 SYN 包 TCP 头信息计算出一个 cookie 值 。将这个 cookie 作为第二次握手 SYN+ACK 包的初始序列号 seq 发过去,如果是攻击者 , 就不会有响应,如果是正常连接,客户端回复 ACK 包后 , 服务端根据头信息计算 cookie,与返回的确认序列号进行比对,如果相同 , 则是一个正常建立连接 。
下述代码是计算 cookie 的函数,可以看到跟这些字段有关(源 ip、源端口、目标 ip、目标端口、客户端 syn 包序列号、时间戳、mssind)
文章插图
下面看下第一次握手,收到 SYN 包后服务端的处理代码,代码太多,简化提出跟半连接队列溢出相关代码
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb){/** 如果半连接队列已满 , 且 tcp_syncookies 未开启,则直接丢弃该连接*/if (inet_csk_reqsk_queue_is_full(sk) && !isn) {want_cookie = tcp_syn_flood_action(sk, skb, "TCP");if (!want_cookie)goto drop;}/** 如果全连接队列已满,并且没有重传 SYN+ACk 包的连接数量大于1,则直接丢弃该连接* inet_csk_reqsk_queue_young 获取没有重传 SYN+ACk 包的连接数量*/if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);goto drop;}// 分配 request sock 内核对象req = inet_reqsk_alloc(&tcp_request_sock_ops);if (!req)goto drop;if (want_cookie) {// 如果开启了 tcp_syncookies 且半连接队列已满 , 则计算 cookieisn = cookie_v4_init_sequence(sk, skb, &req->mss);req->cookie_ts = tmp_opt.tstamp_ok;} else if (!isn) {/* 如果没有开启 tcp_syncookies 并且 max_syn_backlog - 半连接队列当前大小 < max_syn_backlog >> 2,则丢弃该连接 */else if (!sysctl_tcp_syncookies &&(sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <(sysctl_max_syn_backlog >> 2)) &&!tcp_peer_is_proven(req, dst, false)) {LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"),&saddr, ntohs(tcp_hdr(skb)->source));goto drop_and_release;}isn = tcp_v4_init_sequence(skb);}tcp_rsk(req)->snt_isn = isn;// 构造 syn+ack 响应包skb_synack = tcp_make_synack(sk, dst, req,fastopen_cookie_present(&valid_foc) ? &valid_foc : NULL);if (likely(!do_fastopen)) {int err;// 发送 syn+ack 响应包err = ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr,ireq->rmt_addr, ireq->opt);err = net_xmit_eval(err);if (err || want_cookie)goto drop_and_free;tcp_rsk(req)->snt_synack = tcp_time_stamp;tcp_rsk(req)->listener = NULL;// 添加到半连接队列,并且开启超时重传定时器inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);} else if (tcp_v4_conn_req_fastopen(sk, skb, skb_synack, req))goto drop_and_free;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 【算法训练营day7】LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和
- 地下城堡3:魂之诗10月9日礼包兑换码是什么
- flutter系列之:builder为构造器而生
- 王者荣耀妲己时之奇旅皮肤的台词都有什么
- 地下城堡2:黑暗觉醒图28漩涡之底怎么通关
- 阴阳师六道之门无针女5分钟怎么速刷
- 原神3.1百人一揆第二天人间之证明怎么用试用角色拿2000分
- 原神铄石之丘左上角的神瞳怎么获取
- vulnhub靶场之RED: 1
- 苍之纪元新手怎么玩