如果你想知道当前系统(运行Linux内核)中处在SYN RECV状态的TCP半连接数量的大小,最朴素的方法莫过如下:

netstat -antp|grep SYN_RECV|wc -l
ss -ant|grep SYN-RECV|wc -l

有什么问题吗?

方法朴素归朴素,但只能应对日常需求,如果遇到SYN Flood攻击,执行netstat/ss -ant命令需要 扫描遍历系统中所有的连接 ,然后再grep出半连接,在系统已经遭受攻击时,遍历操作无疑是雪上加霜!

你想如果上百万的半连接到达你的系统,会怎样?

然而,令人遗憾的是,系统中没有这样的关于SYN RECV状态的连接总量的之际统计值,至少我是没有找到,无论从ss -s还是从netstat -s,或者说snmp中,都没有找到这样的统计值。

那么如何在系统在面临攻击已经扛不住的情况下,快速统计半连接的数量,这无疑是一个很有意思的工作。

也许你会想到tcp_diag模块,但是它依然是遍历,只不过是采用更加复杂的netlink接口(研究的不多)。当我看inet_diag_dump_icsk函数时,我失望至极!所以,激动的心瞬间又沉了下去。


2020年第一个雷雨天,开了一下午会,饭也没吃一口,写下这篇文章。


在系统压力很大时,遍历所有的socket不现实, 但是LISTEN socket的数量是固定的 ,你见过系统的Listener超过1万的吗?不超过1万,遍历开销就不是事儿。

系统的Listener不会随着系统压力的增加而增加,它们分布在INET_LHTABLE_SIZE个hash桶中,每一个Listener都保存着自己的半连接计数,用其listen_sock的qlen字段计数,我们只需要把这些加起来就是结果了。

看来只有自己动手了。下面是代码:

#include <linux/module.h>
#include <net/tcp.h>static unsigned int dump_syn_recv(void)
{unsigned int num = 0;int i;struct inet_hashinfo *hashinfo = &tcp_hashinfo;for (i = 0; i < INET_LHTABLE_SIZE; i++) {struct sock *sk;struct hlist_nulls_node *node;struct inet_listen_hashbucket *ilb;ilb = &hashinfo->listening_hash[i];spin_lock_bh(&ilb->lock);sk_nulls_for_each(sk, node, &ilb->head) {struct inet_connection_sock *icsk = inet_csk(sk);struct listen_sock *lopt;read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);lopt = icsk->icsk_accept_queue.listen_opt;if (lopt && lopt->qlen)num += lopt->qlen;read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);}spin_unlock_bh(&ilb->lock);}return num;
}static ssize_t dump_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos)
{unsigned int num = dump_syn_recv(), n;char kbuf[16] = {0};if (*ppos != 0) {return 0;}n = snprintf(kbuf, 16, "%d\n", num);memcpy(ubuf, kbuf, n);*ppos += n;return n;
}static struct file_operations dump_ops = {.owner = THIS_MODULE,.read = dump_read,
};static struct proc_dir_entry *ent;
static int __init dumpstat_init(void)
{ent = proc_create("syn-recv-cnt", 0660, NULL, &dump_ops);if (!ent)return -1;return 0;
}static void __exit dumpstat_exit(void)
{proc_remove(ent);
}module_init(dumpstat_init);
module_exit(dumpstat_exit);
MODULE_LICENSE("GPL");

下面是一个模拟攻击时的测试结果:

# cat /proc/syn-recv-cnt
82719

也许有人会质疑这里面的两把锁,其实这种质疑是徒劳的:

  • ilb->lock是hash冲突桶的锁,对于Listener而言,冲突桶并不会很大。
  • icsk_accept_queue.syn_wait_lock是队列锁,它和热点函数互斥,但是互斥区间非常小。

由于这个dump操作基本上是一个oneshot的低频操作,且在Listener固定的情况下,它的时间复杂度是O(1)的,所以我觉得是OK的,这主要要感谢的是,内核自己做了lopt->qlen计数统计,我们只需要将每一个Listener的该字段累加起来就是了。

没有必要看见有锁操作就dis,这是一种因噎废食的偏见。

我不明白为什么tcp diag没有提供一个轻量级的如此这般的dump机制,也许是我没有注意到,不过随他去吧,反正我这个已经够轻量了。


netstat/ss工具好不好?当然好,但是它是常规意义上的好。同样的案例还有延伸到iptables/nftables,ebpf/xdp,如果精准化特定场景,还是需要自己动手来搞非通用方案。

为什么Linux内核为什么直到现在都没有一个计数器来统计半连接的数量?因为那是针对TCP的专有需求,Linux内核显然不是偏向于TCP的。无论如何,我觉得为其增加一些percpu的无锁计数器,是优雅的做法,你至少可以应对别人说你引入原子变量锁总线的开销,是吧,哈哈。

当然,这些话并不是对经理说的。


浙江温州皮鞋湿,下雨进水不会胖。

Linux快速统计TCP半连接的数量相关推荐

  1. linux快速统计目录大小,linux下统计文件夹、文件的大小--du

    Linux下统计文件夹大小 du -sh ./ 统计文件夹占用的空间 find ./ -type f xargs ls -l awk 'BEGIN { size=0;}{size+=$5};END{p ...

  2. 5-5array统计tcp连接状态数量

    #vim count_tcpconn_status.sh 名字和数组最好有一个区分 如果要持续实时查看执行结果,可以使用watch命令 转载于:https://blog.51cto.com/54509 ...

  3. 请使用命令行统计各tcp状态的数量_TCP 连接状态及相关命令学习

    在平时的开发工作中,我们都使用被封装完好的 TCP/HTTP 库去完成需求开发,很少关心底层 TCP 的连接状态,但是一旦遇到较难定位的线上事故,往往都是因为 TCP 连接参数或者使用姿势不对导致的, ...

  4. 转帖:对linux中半增加半连接数量和防止服务器被dos***

    1.增大队列SYN最大半连接数 在Linux中执行命令"sysctl -a|grep net.ipv4.tcp_max_syn_backlog",在返回的"net.ipv ...

  5. 转帖:对linux中半增加半连接数量和防止服务器被dos攻击

    .增大队列SYN最大半连接数 在Linux中执行命令"sysctl -a|grep net.ipv4.tcp_max_syn_backlog",在返回的"net.ipv4 ...

  6. linux 全连接队列,TCP半连接队列和全连接队列的可能和出现问题和解决方案

    问题描述 监控系统发现电商网站主页及其它页面间歇性的无法访问: 查看安全防护和网络流量.应用系统负载均正常: 系统重启后,能够暂时解决,但持续一段时间后间歇性问题再次出现. 此时问题已影响到整个网站的 ...

  7. Linux查询压缩文件行数,linux命令行快速统计文件(压缩文件)的行数

    统计(文件|压缩文件)的行数 zcat file.gz | sed -n '$='                                         #迅速.直接打印出多少行.-n 取消 ...

  8. Linux ss 日志,linux ss命令统计tcp连接数

    ss命令ss -s -t: tcp -a: all -l: listening 列出所有已打开的网络连接. -s: summary   显示Sockets摘要. -p: progress -n: nu ...

  9. [计算机网络] - TCP半连接队列和全连接队列

    转载自:https://blog.csdn.net/qq_34827674/article/details/106448326 1. 概念 在 TCP 三次握手的时候,Linux 内核会维护两个队列, ...

最新文章

  1. 集合框架一:Collection集合
  2. linux机器启动pg数据库命令,Linux下创建Postgresql数据库的方法步骤
  3. mysql完整字段包括_MySQL字段类型最全解析
  4. sony z2 android 5.0,索尼Xperia Z2 5.0 root教程_索尼Z2获取5.0系统的root
  5. typeahead有什么作用_typeahead使用配置参数。
  6. java线程的创建与执行_Java多线程的创建和运行
  7. nginx+php使用open_basedir限制站点目录防止跨站
  8. LeetCode简单题目(#53 #58 #66 #67 #69 #70 #83 #88)-8道
  9. 开榨油店的失败教训_开榨油坊风险大吗?该如何投资
  10. 关于sql语句拼接字符串变量的操作
  11. java 判断浏览器_Java怎么判断访问者使用的是360浏览器
  12. 我的框架——MyBean
  13. Kotlin教程,从入门到精通
  14. 帝国cms html广告,帝国cms加入JS广告代码不显示的解决办法
  15. 最短路径算法 | Bellman-Ford Algorithm
  16. GWAS研究和多基因评分
  17. 数睿数据的四域模型(软件=数据+形式)源何引发强烈关注?
  18. mysql好友关系数据表设计_即时通讯数据库好友关系(一对多)应该怎样设计?...
  19. Beef加载msf插件---metasploit对IE浏览器的极光漏洞进行渗透利用
  20. DLNA UPnP协议简介

热门文章

  1. 使用gpio_direction_output()无法设置GPIO原因分析
  2. 增大SwipeRefreshLayout容差
  3. 彭光哲:8.14黄金走势分析技术面反弹美元指数支撑金价走高看涨千八
  4. 1. emqx docker安装以及持久化配置
  5. TCP拥塞控制算法纵横谈-Illinois和YeAH
  6. 担忧民众隐私 欧委会要求美国澄清雅虎电邮扫描
  7. 格式工厂:视频无法加入 srt 字幕
  8. 长沙现象-互联网教育行业
  9. 电子书下载:人一生要看的60部电影
  10. 什么事DDoS?什么事ADS?看ADS如何治愈DDoS伤痛