环境:macOS(Apple Silicon),无需安装任何软件即可完成 90% 的排查 场景:服务器部署了服务,想确认"端口到底通不通"“这台机器上还开了哪些端口” 读者定位:收藏当手册,用到时按目录查
一、先建立两个认知(不懂这两个,必误判)
1.1 ping 不通 ≠ 端口不通
ping 走的是 ICMP 协议,而业务端口走的是 TCP 协议,两者互不相干。
很多服务器和内网防火墙会直接丢弃 ICMP 包,造成"ping 100% 丢包但 80 端口网页开得好好的"。
结论:不要用 ping 判断服务是否存活,要用 TCP 探测。
1.2 连上没字 ≠ 不通(“谁先说话"问题)
不同协议的"开场白"方向不一样:
| 协议类型 | 代表服务 | 连接建立后 |
|---|---|---|
| 服务器先说话 | SSH(22)、MySQL(3306)、FTP(21) | 立刻推送 banner(版本信息) |
| 客户端先说话 | HTTP(80/8080…)、Redis(6379) | 一言不发,等你先发请求 |
所以用 telnet 测 HTTP 端口,连上后一片空白、光标干等——这不是不通,是正常等待。输入 GET / HTTP/1.0 再按两次回车,响应立刻就出来了。
真实案例:浏览器能打开
http://10.36.35.43:8083/login,但telnet 10.36.35.43 8083“没响应”。用 nc 验证:TCP 秒连,手动发一行 GET 请求立刻返回HTTP/1.1 200 OK——端口一直是通的,只是 HTTP 服务不主动打招呼。
二、判断单个端口是否通
方法 1:nc(macOS 自带,首选)
三种结果,语义完全不同,要能读懂:
| 输出 | 含义 |
|---|---|
Connection to ... succeeded! | ✅ 通,且有服务在监听 |
failed: Connection refused | 主机可达,但端口没服务监听(服务没起/监听别的端口) |
failed: Operation timed out | 包被防火墙丢了,或主机不可达(不是"没服务”) |
方法 2:curl(HTTP 服务最方便)
方法 3:bash 内置 /dev/tcp(零依赖应急)
| |
无需任何外部命令,是 bash 自身的特性。缺点是超时不可控(防火墙丢包场景会等很久),日常还是 nc 好用。
⚠️ 踩坑(实测):zsh 下直接跑会得到"假阴性"。
/dev/tcp是 bash 独有的伪设备,zsh 不认识——它把/dev/tcp/10.36.35.43/22当普通文件路径,重定向失败的报错又被2>/dev/null吞掉,于是端口明明是通的也输出"不通"。macOS 从 Catalina 起默认 shell 就是 zsh,所以必须套一层bash -c '...'。验证:curl -v telnet://IP:端口能拿到 banner 而 /dev/tcp 报不通时,先想想自己当前在哪个 shell 里。
方法 4:telnet(新版 macOS 需自行安装)
看到 Connected to ... 就说明 TCP 通了。后面有没有字,取决于 1.1 节说的"谁先说话"。
方法 5:nmap(装了的话)
| |
-Pn很重要:nmap 默认先 ping 探测主机死活,ping 不通直接跳过扫描。内网服务器经常禁 ping(见 1.1),不加-Pn会得出"主机 down"的错误结论。
方法 6:浏览器
HTTP/HTTPS 服务最直接:http://IP:端口 能打开页面就是通的。但注意它只对 Web 服务有效。
三、扫描整台服务器:哪些端口是开的
方法 1:nmap(标准答案)
方法 2:nc + xargs 并发(不装任何东西的应急方案)
| |
原理:nc -z 逐端口试探 TCP 握手,xargs -P 20 并发 20 个,50 个常见端口十几秒扫完。
想扫全端口就换成 seq 1 65535 | xargs -P 50 ...,慢但可行。
注意列表覆盖:上面的清单是手挑的常见端口,像 8083 这种非典型端口就不会命中——扫不到不代表没开,只代表"不在清单里"。要穷举就上 nmap
-p-。
方法 3:masscan(海量端口,需 sudo)
异步发包,全端口几十秒扫完。适合大网段,单机用 nmap 足矣。
四、识别端口上跑的是什么服务(banner grabbing)
端口通只是第一步,抓 banner 才知道上面跑的是谁:
| |
一条命令全搞定的懒人方案:nmap -Pn -sV 目标IP。
五、实战案例:扫描内网服务器 10.36.35.43
用方法三·2 的 nc 并发扫描 + 方法四的 banner 抓取,实测结果:
| 端口 | 服务 | 识别详情 |
|---|---|---|
| 22 | SSH | OpenSSH 8.8 |
| 80 | HTTP | nginx/1.13.12,首页 200 |
| 443 | 开放但未知 | TCP 通,不回应 HTTPS 握手 |
| 3306 | MySQL | 5.7.44(版本号 banner 直接暴露) |
| 6379 | Redis | 有密码(NOAUTH) |
| 8080/8081 | HTTP | 根路径 404,未暴露 Server 头 |
| 8083 | HTTP | nginx 反代的前端登录页(后补扫发现) |
顺带两个安全观察:
- MySQL 版本号在 banner 里裸奔——等于告诉攻击者该打哪些 CVE,3306 应只对需要的网段开放
- nginx 1.13.12 是 2017 年的版本,已知漏洞不少(如 CVE-2017-7529),正式服务建议升级
六、速查表
| 需求 | 命令 |
|---|---|
| 测单个端口 | nc -vz IP 端口 |
| 测 HTTP 服务 | curl -sI -m 5 http://IP:端口 |
| 任意 TCP 端口看 banner | curl -v telnet://IP:端口 或 nc -w 2 IP 端口 |
| 扫常用端口 | nmap -Pn IP(无 nmap 时用 nc+xargs 脚本) |
| 扫全端口 | nmap -Pn -p- IP |
| 识别服务版本 | nmap -Pn -sV IP |
| ping 不通还想扫 | nmap 务必加 -Pn |
合规提醒:端口扫描只用于自己的服务器或获得明确授权的目标。对陌生主机扫描在多数公司和云厂商守则里属于攻击行为。
