内核连接表本身
ss 与 netstat 的数据都来自 /proc/net/tcp:工具被替换或不可用时,直接读内核连接表同样能拿到连接信息。代价是地址与端口都是十六进制,地址还是小端序,需要转换才能阅读。
三个文件都要看
/proc/net/tcp、tcp6 与 udp 三个文件分别对应 IPv4 TCP、IPv6 TCP 与 UDP。只看第一个会漏掉 IPv6 与 UDP 外联,而这两者常被用来绕过监控。
基本信息
| 文件 | /proc/net/tcp,以及 tcp6 与 udp |
|---|---|
| 地址格式 | 十六进制小端序:0100007F 即 127.0.0.1 |
| 端口格式 | 十六进制:1F90 即 8080 |
| 状态字段 | 0A 监听、01 已建立、06 等待关闭 |
| 字段顺序 | 本地地址:端口、对端地址:端口、状态、inode |
| 权限要求 | 读取连接表普通用户即可 |
典型使用场景
- 工具被替换时获取可信的连接信息
- 排查 IPv6 与 UDP 外联
- 与 ss 输出交叉验证结果
- 分析内核视角的连接状态
- 容器内外的连接归属对齐
读取并转换
读取并转换
cat /proc/net/tcp | head -n 20
awk 'NR>1{print $2, $3, $4}' /proc/net/tcp | head -n 20
printf '%d\n' 0x1F90 # 十六进制端口转十进制
awk 'NR>1{print $4}' /proc/net/tcp | sort | uniq -c # 状态分布
cat /proc/net/udp | head -n 10
cat /proc/net/tcp6 | head -n 10逐列读法
| 列 | 含义 | 注意点 |
|---|---|---|
| sl | 行号 | 仅表示序号,无业务含义 |
| local_address | 本地地址:端口(十六进制) | 0100007F:1F90 即 127.0.0.1:8080 |
| rem_address | 对端地址:端口 | 全 0 表示未连接,常见于监听套接字 |
| st | 连接状态码 | 0A 监听、01 已建立、06 等待关闭 |
地址字段是 8 位小端十六进制:需要按字节倒序再转十进制,直接当明文 IP 读是常见误解。
直接读 /proc/net/tcp 得不到进程归属:必须结合 socket inode 反查 /proc/*/fd 才能定位持有连接的进程。
按 inode 反查进程
按 inode 反查进程
INODE=$(awk 'NR>1{print $10}' /proc/net/tcp | head -n 1)
for p in /proc/[0-9]*; do ls -l $p/fd 2>/dev/null | grep -q "socket:\[$INODE\]" && echo "$p"; done
tr '\0' ' ' < /proc/1234/cmdline; echo与其他数据源对照
- 与 ss 输出比对连接数量与状态分布
- 与 /proc/PID/fd 反查确认进程归属
- 与抓包结果比对确认连接是否真正建立
- 与防火墙日志比对确认是否被阻断
容器与网络命名空间各自持有一份连接表:宿主机读到的内容与容器内视角不同,跨命名空间排查要先进入对应 netns 再读取。
读懂连接表的步骤
- 先按状态聚合,看清监听与已建立连接的数量级
- 过滤掉对端全 0 的条目,锁定真正的外部连接
- 把十六进制地址与端口转换后与业务清单核对
- 用 inode 反查进程,确认发起方身份
状态码速记
- 01 ESTABLISHED:已建立连接
- 02 SYN_SENT:正在尝试连接
- 06 TIME_WAIT:连接刚结束等待回收
- 08 CLOSE_WAIT:对端已关闭,本端未关
- 0A LISTEN:监听状态