ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

macOS telnet被移除:nc、ncat、socat替代与端口调试

macOS telnet被移除:nc、ncat、socat替代与端口调试 1. macOS 上的 telnet 去哪了先把这件事说透如果你在两台机器之间调试过 TCP 服务或者要确认某台网络设备的 23 端口是不是通的你大概率敲过telnet。但在 macOS 上敲这个命令十有八九会得到一句zsh: command not found: telnet。很多人第一反应是系统坏了或者路径没配好其实都不是——macOS 从 High Sierra 开始就不再预装 telnet 客户端了这是有意为之不是 bug。这个变化影响的其实是三类人一类是做后端和运维的平时用 telnet 探端口、手工发 HTTP 或 SMTP 报文一类是搞嵌入式、做网络设备调试的需要和串口服务器、打印服务器、交换机这类设备做文本交互还有一类就是纯好奇、想复现教程里命令的普通用户。这篇内容就是给这三类人写的我会把 macOS 上 telnet 的可用替代方案一条条拆开讲清楚每个工具适合什么场景、参数怎么填、有哪些坑最后给出可以直接抄的脚本。先建立一个认知telnet 这个命令本身能做的事情其实被拆到了好几个工具里。它不只是连 23 端口这么简单老一代工程师用它做了很多事——探测任意 TCP 端口是否开放、手工构造应用层协议报文、做收发测试、给设备做半交互式调试。理解了这一点你才能明白为什么替代方案不是一个工具而是一组工具。2. 为什么会被移除理解背后的取舍2.1 明文协议这件事绕不过去telnet 从设计之初就是明文传输。你输入的账号、口令、敲下的每一个字符在网络链路上都是公开可见的中间任何一跳的抓包都能还原出完整会话。它诞生的年代网络还局限在实验室内安全问题不是优先项。但当这套协议被用在跨网络环境里风险就变得不可接受。相比之下SSH 在同一场景下提供了加密通道、主机指纹校验、密钥认证。所以整个行业的方向很明确能上 SSH 就上 SSHtelnet 只在隔离的、可信的本地网络里用于那些根本没有 SSH 支持的哑设备。2.2 苹果的做法不删协议只是不预装需要注意一个细节macOS 并没有从系统里拔掉 telnet 的能力它只是不再把客户端二进制放进/usr/bin。telnet 所依赖的 TCP 栈、解析库都还在系统里。这意味着你完全可以通过包管理器把客户端装回来只是苹果把这个选择权交还给了用户——想要就自己装装了之后风险自负。这个思路其实挺合理。系统预装一个默认就会发明文口令的工具对普通用户来说是不必要的风险面而对确实需要的专业用户一条安装命令的成本可以忽略不计。2.3 你真正需要的其实不是 telnet这是我想强调的核心观点。大多数人喊我要 telnet实际需求可以归成下面几类确认某个 IP 的某个 TCP 端口是不是通的手工往一个 TCP 服务里发几行文本看看它回什么做 HTTP、SMTP、Redis 这类文本协议的手工调试和一台老设备保持一个半交互式的命令行会话。这四类需求对应的是不同的最佳工具。硬要用一个 telnet 全包反而是效率最低的做法。下面我把替代方案按接近 telnet 的程度从高到低排开。3. 替代方案全景五个工具各自的位置3.1 ncnetcat手感最接近的那个netcat 通常被称为TCP/IP 的瑞士军刀它最基础的能力就是建立一条到目标 IP 和端口的 TCP 连接然后把标准输入送过去、把收到的数据打出来。这跟 telnet 的核心行为几乎一样。macOS 自带的nc是 Apple 定制版本位于/usr/bin/nc不需要额外安装开箱即用。这一点非常关键——当你只想快速验证一下端口不需要装任何东西。最简单的用法nc -v 192.168.1.1 80-v打开详细输出会告诉你连接成功还是失败。连上之后你敲的字会被发到对端对端返回的内容会直接显示在终端里。如果只想判断端口通不通、不想进入交互用-znc -vz 192.168.1.1 443-z是零 I/O 模式只做连接建立和关闭不发送任何数据。这个用法是我日常用得最多的比 telnet 那种还要手动退出的方式干净得多。3.2 用 Apple nc 的正确姿势-G 和 -w 别搞混这里有个真实的坑很多教程写错。Apple 版本的 nc 里连接超时用的是-G会话空闲超时用的是-w。-G timeout控制 TCP 连接建立的超时秒数。目标主机不可达、被防火墙丢包时如果不设这个你可能要等系统默认的几十秒才返回。-w timeout连接建立之后空闲多少秒自动断开。所以在做批量扫描时写法应该是nc -vz -G 2 192.168.1.1 22而不是只写-w 2。我见过太多次有人只加-w结果遇到不通的 IP 时脚本卡住不动就是因为-w在 Apple nc 里对正在建立连接这个阶段不生效。注意如果你用的是通过 Homebrew 安装的 GNU netcat包名netcat超时参数就变成了-w语义跟 Apple 版不同。两个 nc 混用是排查问题时最容易被绕进去的地方先用which nc和nc -h确认版本。3.3 ncatNmap 家的增强版ncat 是 Nmap 项目维护的 netcat 重写版特点是支持 SSL/TLS、支持代理、支持连接代理链行为比传统 nc 更规范。安装方式brew install nmap装完之后 ncat 是一个独立命令。它最实用的两个场景一是带 TLS 的连接。传统 nc 无法直接对 TLS 服务做手工交互ncat 可以ncat --ssl example.com 443它会自动完成 TLS 握手你之后输入的内容就是加密通道里的明文极大方便调试 HTTPS 服务。二是稳定的监听与转发行为。nc 各家实现对于监听端断开后是否继续等待处理不一致ncat 默认行为更可预测做临时中转服务时更省心。3.4 socat把任意两种数据流对接起来socat 的定位比 nc 更进一步它把两个数据端点抽象出来然后做双向转发。用它替代 telnet 的最简写法socat - TCP:192.168.1.1:23前面的-表示标准输入输出。连上之后你的键盘输入进 TCPTCP 返回的数据打到屏幕上体验和 telnet 基本一致。socat 真正的价值在于复杂场景比如把本地某个端口转发到远端设备、把串口数据转到 TCP、给一条连接加上日志记录。举个日志的例子socat -v - TCP:192.168.1.1:23 2 session.log-v会把双向数据流都打上方向标记写进日志事后回看会话过程非常方便。这是 telnet 完全给不了的能力。3.5 真要把 telnet 装回来两种方式如果你就是习惯 telnet 的交互或者要复现某篇文档里的命令装回来是最省事的。第一种Homebrew 单独装brew install telnet第二种装一整套传统网络工具brew install inetutilsinetutils会把 telnet、ftp、tftp、rsh 等一批经典工具一起装上。装完后命令在 Homebrew 的bin目录里直接在终端调用即可。注意装回来的 telnet 依然是明文协议版。如果你的使用场景涉及账号口令请在受控的、隔离的本地网络里使用或者改用 SSH。这一点没有折中余地。3.6 场景专用工具别忘了几位专科医生有些调试任务其实根本不需要通用 TCP 工具HTTP 调试curl -v http://host:port/path比手工敲报文高效得多curl -v telnet://host:port甚至可以直接用 telnet 协议连一个端口只用来看握手和响应。TLS 服务openssl s_client -connect host:443 -servername host能看到证书链、协商的加密套件这是任何 nc 都做不到的。SSH 服务直接ssh -p 2222 userhost比先 telnet 试探再切 SSH 少一步。把这些工具和 nc 组合起来日常九成以上的调试需求都能覆盖。4. 实操把常见 telnet 用法逐个换掉4.1 端口连通性检测三种写法对比这是最高频的需求。给一个直观的对比需求推荐命令说明单端口快速探测nc -vz -G 2 host 443自带无需安装输出清晰不想看详细输出nc -z host 443; echo $?返回码 0 表示通非 0 表示不通带 TLS 的端口探测ncat --ssl host 443需要 nmap能验证 TLS 层用返回码判断这一点特别值得展开。nc -z在连接成功时退出码是 0失败是非 0这意味着你可以把它直接塞进 shell 的条件判断if nc -z -G 2 192.168.1.1 6379; then echo redis 端口可达 else echo redis 端口不可达 fi这段逻辑在写巡检脚本时几乎是必备的。相比 telnet 那种连上要看输出、不通要等超时的体验nc -z配合-G把整个过程压缩到了秒级。4.2 手工发送应用层报文以 Redis 为例Redis 用的是文本协议非常适合手工敲。假设你要确认一个 Redis 实例能不能正常响应nc 192.168.1.1 6379连上之后输入PING如果服务正常会返回PONG再试一条INFO server会返回一大段服务器信息。这一整套流程和当年用 telnet 完全一样换成 nc 之后没有任何学习成本。需要注意一点Redis 6 之后可能需要先认证输入AUTH yourpassword即可。但如果你只是想确认端口和基本响应PING通常就够。4.3 手工发 HTTP 请求用 nc 走一遍原始报文虽然 curl 更方便但用 nc 手工发 HTTP 请求能帮你真正理解协议长什么样排查一些诡异的响应问题时特别有用。nc -v example.com 80连上后输入注意 HTTP/1.1 必须带 Host 头否则很多服务器会直接返回 400GET / HTTP/1.1 Host: example.com Connection: close最后那个空行不能少它是请求头和请求体的分隔符。输入完成后按回车服务器就会返回响应头加响应体。Connection: close的作用是让服务器在响应结束后主动关闭连接这样 nc 会自动退出不用你手动断。提示在 nc 里输入时如果终端没有回显是正常的——nc 的默认行为是把输入直接送走不回显。如果你需要看到自己敲的内容可以配合rlwrap来包一层后面会讲。4.4 邮件服务调试SMTP 手工会话SMTP 交互是 telnet 的经典用途之一。用 nc 替换nc -v mail.example.com 25连接成功后依次输入EHLO myhost.local服务器返回支持的扩展列表。然后MAIL FROM:senderexample.com RCPT TO:recipientexample.com DATA输入DATA之后可以开始写正文以单独一行的一个点.结束。整个过程中每一步服务器都会回一个三位数字的状态码看到250就是成功5xx就是被拒绝。这个流程在排查为什么邮件发不出去时非常有用因为你绕过了所有客户端封装看到的是服务器最原始的反应。4.5 与网络设备做文本交互的注意事项有一类设备只提供基于文本的命令行接口比如某些打印服务器、串口服务器、老的交换设备。这类交互用 nc 或 socat 都能做socat -,raw,echo0 TCP:192.168.1.50:23raw关掉了终端的行缓冲和特殊字符处理echo0关掉本地回显让设备的回显成为唯一的显示来源。这两个参数是关键——不加的话你敲一个字符可能被本地终端和远端设备各回显一次看起来就是一片乱码。需要明确的是只应对你有管理权限的设备做这类连接。生产环境里的设备调试应该走厂商提供的正规管理通道和凭据体系而不是试图绕过认证。这一点不是技术建议是职业底线。4.6 批量端口巡检脚本把前面的东西拼起来就是一个能直接用的巡检脚本。它会遍历一份主机列表和端口列表输出哪些通、哪些不通并且用颜色区分。脚本用 bash 写兼容 macOS 自带版本#!/bin/bash # 用法: ./portcheck.sh hosts.txt ports.txt HOST_FILE${1:-hosts.txt} PORT_FILE${2:-ports.txt} while read -r host; do [ -z $host ] continue while read -r port; do [ -z $port ] continue if nc -z -G 2 $host $port 2/dev/null; then printf [OK] %s:%s\n $host $port else printf [FAIL] %s:%s\n $host $port fi done $PORT_FILE done $HOST_FILE-G 2保证单个不可达目标最多等 2 秒避免整批任务被一个坏 IP 拖死。如果要并发跑可以把内层循环改成后台执行但那样输出顺序会乱需要重定向到各自的文件再汇总。对于几十个目标的量级串行跑完全够用没必要为了快一点引入复杂度。5. 踩坑实录这些坑我都替你踩过了5.1 自带 nc 和 GNU netcat 的参数不通用这是最高频的困惑。macOS 自带的是 Apple 版 nc它不支持-c、-e这类 GNU 扩展参数超时语义也和 GNU 版不同。表现就是你从网上抄了一条命令在别人机器上跑得好好的在你这里报invalid option。排查手段很简单which -a nc nc -h 21 | head -20which -a会把 PATH 里所有的 nc 都列出来你能看到到底是/usr/bin/nc还是 Homebrew 装的版本生效了。nc -h输出的选项列表就是最权威的参考比任何博客都准。提示如果你确实需要 GNU 语义可以装完后用绝对路径调用或者把 Homebrew 的版本重命名为gnc做别名避免和系统版本打架。5.2-z加-w在 Apple nc 上可能不生效前面提过Apple nc 的连接超时是-G。但还有一个更隐蔽的问题-z模式和-w组合时某些 macOS 版本上-w对连接建立阶段没有任何作用。结果就是脚本遇到一个不存在的主机会卡住十几秒。解决办法只有两个一是始终用-G控制连接超时二是在脚本外层加timeout命令兜底。但 macOS 默认没有timeout需要brew install coreutils之后用gtimeout或者在脚本里自己实现一个基于后台进程和kill的超时函数。我现在的习惯是统一用-G简单可靠。5.3 连上之后退不出来用 nc 连上一个服务如果对面不主动断开你会发现自己敲什么都没反应CtrlC会直接杀掉整个终端里的当前进程CtrlD在某些情况下也不管用。标准做法是CtrlC其实是可以的它发 SIGINT 给 nc 进程进程退出。如果你希望更礼貌地关闭连接可以先按CtrlD关闭标准输入很多服务检测到对端关闭后会自动断开。真正的坑在于如果你在socat里没有加-t参数关闭时可能等待一段时间才退出加个-t 1能让它一秒内退出。判断当前是不是卡住了看终端光标是否还在动。如果连输入都不回显基本就是连接已经断开但进程还没回收CtrlC一次即可。5.4 输入没有回显打错字也看不见这是新用户最不适应的地方。nc 默认不回显你输入的内容因为它的设计假设是你输入的就是要发送的字节。解决方法是用rlwrap包一层它给任意命令加上行编辑能力brew install rlwrap rlwrap nc 192.168.1.1 6379这样你就有上下键翻历史、左右键改错字、CtrlA/E跳行首行尾的能力。对经常做手工协议调试的人来说这个包装几乎是刚需。5.5 常见问题速查表现象可能原因处理方式command not found: telnet系统不再预装用nc或brew install telnetnc卡住不返回连接超时未设置加-G 2输入不回显、无法编辑nc 默认行为用rlwrap nc包装中文显示乱码终端编码或 raw 模式未开检查 localesocat 加rawinvalid option参数与 nc 版本不匹配nc -h确认区分 Apple/GNU连上后无响应服务要求先发数据或认证手工发PING、EHLO等探测6. 效率层面的一些个人做法6.1 别名和小函数我终端里长期挂着一个函数叫port用来快速探端口port() { nc -vz -G 2 $1 $2; }用的时候port 192.168.1.1 443比每次敲完整命令快得多。这种小函数的价值在于把常用参数固化下来避免每次都要回忆-G还是-w。另一个常用的是tcp函数用来做半交互连接tcp() { rlwrap -q nc $1 $2; }rlwrap的-q参数用来指定引号字符避免它对某些输入做特殊处理实测下来这个细节能省掉一些奇怪的转义问题。6.2 zsh 下的 /dev/tcp 等价物网上流传的bash写法echo /dev/tcp/host/port在 macOS 上不可用因为系统自带的 bash 3.2 编译时没有开启网络重定向特性。这是一个非常容易被误导的点很多教程直接把 Linux 的写法搬过来在 macOS 上必然失败。zsh 提供了自己的实现需要先加载模块zmodload zsh/net/tcp ztcp example.com 80成功会返回一个文件描述符编号然后用print -u $fd GET / HTTP/1.0往这个 fd 写数据用sysread读响应。这套东西适合写脚本时用日常调试还是 nc 更顺手。6.3 把会话记录下来调试时最怕的是刚才那个响应到底是啥样所以我现在默认会开启记录。用script命令可以记录整个终端会话script -q session.log之后的所有终端输出都会同步写入session.log包括你敲的命令和程序的响应。调试完exit退出日志就留在那里了。对需要事后复盘或者提交问题报告的场景这个比截图专业得多。6.4 关于交互式体验的一点取舍有人会问既然 ssh 这么好用为什么还要折腾这些文本协议工具。我的答案是两者的适用面根本不同。ssh 解决的是有一台能登录的机器而 nc/socat 解决的是有一个能说话的端口。一台 Redis、一个 MQTT broker、一台老打印服务器它们没有 ssh 服务只有裸的 TCP 端口。这时候你能依靠的就是这类原始工具。理解了这一点你就不会再纠结为什么不用 ssh 代替一切这种问题——它们本来是两条平行线各管一段。我个人的习惯是只要对方有 ssh绝不碰文本协议一旦对方只有 TCP 端口立刻切到 nc 或 socat先把端口和基本响应确认清楚再决定下一步怎么深入。
返回列表