telnet 命令详解与参数实测(Ubuntu 22.04)
telnet 命令逐参数实测详解:telnet host port 手打 HTTP 全流程逐段解读、Connection refused 与超时两种失败形态、-4/-6 协议族、-l/-a 登录选项、-E 关闭转义字符与 ^] 逃逸机制,含 telnet 与 nc 选型对比及明文风险提示,全部回显在 Ubuntu 22.04 实测通过。
telnet 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 telnet 的每一个常用参数——
telnet host port基本连接与手打 HTTP 全流程、连接拒绝与连接超时两种失败形态、无参数交互命令模式(?/status/quit)、-4/-6协议族选择、-l/-a登录选项、-E关闭转义字符与^]逃逸机制,并附 telnet 与 nc 的选型对比及明文传输风险提示,全部命令与回显已在 Ubuntu 22.04 实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- telnet 实现:netkit-telnet 客户端(
/usr/bin/telnet经 alternatives 指向/usr/bin/telnet.netkit,见 2.3) - telnet 包版本:0.17-44build1(
dpkg -l telnet实测) - 演示服务端:Python 3.10.12 自带
python3 -m http.server(本地 8801 端口 IPv4、8802 端口 IPv6 双栈各起一个) - 演示目录:
/root/demo/telnet/www(内含一个index.html) - 系统时区:UTC(回显中的 GMT 时间即 UTC)
- telnet 属明文协议客户端,本篇所有实测均为本机回环(127.0.0.1 / ::1),不经过公网
Ubuntu 22.04 默认不带 telnet 命令,需先安装。安装过程实测(节选):
$ apt-get install -y telnet
Setting up telnet (0.17-44build1) ...
update-alternatives: using /usr/bin/telnet.netkit to provide /usr/bin/telnet (telnet) in auto mode
注意 update-alternatives 这一行:/usr/bin/telnet 是一个 alternatives 管理的软链接,真实程序是 /usr/bin/telnet.netkit。若后续安装了 inetutils-telnet 等其他实现,alternatives 会自动切换 /usr/bin/telnet 的指向,因此确认真实来源要像 2.3 那样用 readlink -f 穿透软链接。
二、命令概览
2.1 语法与参数总览
telnet 的角色是「通用的 TCP 客户端」:它向远端主机的指定端口发起 TCP 连接,把本机键盘输入原样发过去、把对方返回的字节原样显示出来。正因为「原样」,它既能当远程终端(连 23 端口的 telnetd),也能用来手工探测/调试任意 TCP 明文服务。参数总览(实测 Ubuntu 22.04 的 netkit-telnet,man telnet 汇总):
| 参数 | 作用 | 本篇实测节 |
|---|---|---|
host port | 连接远端主机与端口;port 缺省为 23 | 3.1 / 3.3 |
| (无参数) | 进入交互命令模式(telnet> 提示符) | 3.2 |
-4 | 强制使用 IPv4 地址族 | 3.4 |
-6 | 强制使用 IPv6 地址族 | 3.5 |
-l user | 连接时向远端发送指定登录用户名(供 telnetd 等使用) | 3.6 |
-a | 尝试自动登录(env 里带 USER 并请求远端跳过登录流程) | 3.7 |
-E | 禁用转义字符(Escape character 为 off) | 3.8 |
-e char | 自定义转义字符(本文仅在说明中提及,与 -E 同族) | — |
完整语法形态(man telnet 摘录):
telnet [-4] [-6] [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile] [host-name [port]]
💡 技术拓展:同为「在命令行连 TCP 端口」,telnet 并非唯一选择,常见同类工具对比——
工具 特点 适用场景 telnet 交互式终端体验,可手动输入协议内容,输出友好 明文协议调试、教学演示 nc(netcat) 「TCP/UDP 瑞士军刀」,支持 -z端口扫描、监听、脚本化脚本化探测、管道传输 ncat nmap 家族的 nc 增强版,支持 SSL/TLS 加密连接 需要加密通道的调试 /dev/tcp bash 内建伪设备,零依赖不装包 最小环境下的端口探测 curl/wget 面向 HTTP(S) 的应用层客户端 只关心 Web 服务时 本文主角是 telnet:它的「所见即所发」让它成为理解 TCP 明文协议(HTTP/SMTP/POP3 等)最直观的工具;脚本化场景见 4.3 的 /dev/tcp 对照。
2.2 帮助形态:交互命令列表实测(? 命令)
netkit-telnet 没有 --help 长选项(传入 --help 会按 usage 报错),它的「帮助」是交互命令模式下的 ? 命令。先用无参数形态进入交互模式,再用管道喂入 ?、status、quit 三个命令,实测回显逐行照抄:
$ telnet < /dev/null
telnet>
$ printf "?\nstatus\nquit\n" | telnet
telnet> Commands may be abbreviated. Commands are:
close close current connection
logout forcibly logout remote user and close the connection
display display operating parameters
mode try to enter line or character mode ('mode ?' for more)
open connect to a site
quit exit telnet
send transmit special characters ('send ?' for more)
set set operating parameters ('set ?' for more)
unset unset operating parameters ('unset ?' for more)
status print status information
toggle toggle operating parameters ('toggle ?' for more)
slc set treatment of special characters
z suspend telnet
environ change environment variables ('environ ?' for more)
telnet> No connection.
Escape character is '^]'.
telnet>
首行 Commands may be abbreviated. 说明命令可缩写(如 o 代表 open)。status 在未连接时回显 No connection.,并再次提示转义字符为 ^]。这份列表就是本实现的完整命令族:open/close/quit 管连接生命周期,set/unset/toggle/display 调运行参数,z 把 telnet 挂到后台。
💡 说明:无参数直接运行
telnet(上例第一段)立即出现telnet>提示符,这就是交互命令模式;quit或 Ctrl-D 退出。
2.3 来源与版本确认
先穿透 alternatives 软链接确认真实程序与所属包,再查版本号:
$ which telnet; readlink -f $(which telnet)
/usr/bin/telnet
/usr/bin/telnet.netkit
$ dpkg -S $(readlink -f $(which telnet))
telnet: /usr/bin/telnet.netkit
$ dpkg -l telnet | tail -1
ii telnet 0.17-44build1 amd64 basic telnet client
$ apt policy telnet 2>/dev/null | head -3
telnet:
Installed: 0.17-44build1
Candidate: 0.17-44build1
/usr/bin/telnet → /usr/bin/telnet.netkit,属于 telnet 包,版本 0.17-44build1(netkit-telnet 系实现)。telnet 自身没有 --version 选项,版本号以包管理器查询为准。
三、参数逐项实测
本章演示服务端的准备:在 /root/demo/telnet/www 下放一个演示页,分别起 8801(IPv4)与 8802(IPv6 双栈)两个 HTTP 服务:
$ mkdir -p /root/demo/telnet/www
$ printf '<html><head><title>telnet demo</title></head>\n<body><h1>Hello from telnet demo</h1></body></html>\n' > /root/demo/telnet/www/index.html
$ (cd /root/demo/telnet/www && nohup python3 -m http.server 8801 >/tmp/http8801.log 2>&1 &)
$ (cd /root/demo/telnet/www && nohup python3 -m http.server 8802 --bind :: >/tmp/http8802.log 2>&1 &)
$ ss -tln | grep -E ':(8801|8802) '
LISTEN 0 5 0.0.0.0:8801 0.0.0.0:*
LISTEN 0 5 *:8802 *:*
ss 确认 8801 监听在 0.0.0.0(IPv4),8802 监听在 *(IPv6,且为双栈)。以下实测均围绕这两个端口展开;演示结束用 pkill -f 'http.server 880' 清理。
3.1 基本形态:telnet host port——手打一次完整 HTTP 会话
本节演示 telnet 最经典的调试用法:连上本地 HTTP 服务,手工敲一个 HTTP 请求,逐段解读整个会话。命令通过管道把两行输入喂给 telnet(GET / HTTP/1.0 请求行 + 空行表示请求头结束),sleep 2 留出服务端响应时间:
$ { echo "GET / HTTP/1.0"; echo; sleep 2; } | telnet 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Fri, 16 Oct 2026 00:25:30 GMT
Content-type: text/html
Content-Length: 98
Last-Modified: Fri, 16 Oct 2026 00:25:29 GMT
<html><head><title>telnet demo</title></head>
<body><h1>Hello from telnet demo</h1></body></html>
Connection closed by foreign host.
逐段解读这份完整回显:
Trying 127.0.0.1...——telnet 正在对该地址发起 TCP 连接(DNS 解析与 connect 阶段)。Connected to 127.0.0.1.——TCP 三次握手完成,连接建立。Escape character is '^]'.——提示逃逸字符为 Ctrl-],随时可从会话跳回telnet>命令模式(见 3.9)。HTTP/1.0 200 OK起的响应头与随后的 HTML 正文——服务端对我们手敲的请求返回的原始字节流,没有任何中间层加工。Connection closed by foreign host.——HTTP/1.0 为短连接,服务端发完响应即关闭连接,telnet 检测到对端 FIN 后提示「对端关闭」并退出。
💡 要点:telnet 把「请求 → 响应 → 断开」的每个字节都摊在你眼前,这正是它做协议调试的价值——curl 会隐藏的部分,telnet 全部可见。
3.2 无参数:交互命令模式
不带参数运行 telnet(stdin 给 /dev/null,即打开后立即 EOF):
$ telnet < /dev/null
telnet>
仅出现 telnet> 提示符。在该模式下可用 2.2 列出的全部命令:open host port 建立连接、close 断开当前连接、status 查看状态、quit 退出。真实交互场景下,这个模式还承担「半途逃逸」职责——连接建立后按 Ctrl-] 也会回到这个 telnet> 提示符(见 3.9)。
💡 要点:无参数进入的
telnet>模式是「会话控制台」——连接挂死时按 Ctrl-] 回到这里再quit,是唯一不杀进程的体面退出。脚本检验客户端可用性用echo "quit" | telnet,无需交互。
3.3 连接被拒绝的形态(rc=1)
对没有服务监听的端口发起连接,观察失败形态与退出码:
$ telnet 127.0.0.1 9999; echo rc=$?
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
rc=1
两个要点:
Connection refused说明目标主机可达、但目标端口没有进程监听(内核直接回 RST)。排障时这是「服务没起 / 端口不对」的典型信号,与防火墙 DROP 导致的「长时间无响应」截然不同。Unable to connect走 stderr,Trying 127.0.0.1...走 stdout,重定向到同一终端时因缓冲顺序可能出现如上「错误先出现」的显示顺序,属正常现象。退出码 rc=1,脚本中可直接用$?判断端口连通性。
💡 要点:端口排障三分法——refused(端口没进程监听)、timeout(防火墙 DROP/网络不通)、秒连成功(有服务)。telnet 探端口本质是验证「TCP 三次握手能否完成」,与端口上跑什么协议无关,这正是它至今仍是巡检标配的原因。
💡 要点:记住端口排障三分法——refused(端口没进程听)、timeout(防火墙 DROP/网络不通)、秒连成功(有服务)。telnet 探端口的本质是「TCP 三次握手成功与否」,与端口上跑什么协议无关,这也是它至今仍是巡检标配的原因。
3.4 -4:强制 IPv4 地址族
$ { echo "GET / HTTP/1.0"; echo; sleep 2; } | telnet -4 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Fri, 16 Oct 2026 00:25:32 GMT
Content-type: text/html
Content-Length: 98
Last-Modified: Fri, 16 Oct 2026 00:25:29 GMT
<html><head><title>telnet demo</title></head>
<body><h1>Hello from telnet demo</h1></body></html>
Connection closed by foreign host.
-4 限定只尝试 IPv4 地址。当目标主机名同时解析出 A/AAAA 记录、而其中某族链路有问题时,用它排除另一族的干扰。
💡 要点:
-4/-6的日常价值在 DNS 双栈故障排查——AAAA 记录存在但 IPv6 链路不通时,连接会先卡在 IPv6 超时才回退;加-4一步锁定 IPv4 路径。机房内网多为纯 IPv4,巡检脚本固定带-4可避免无谓的 6 秒级等待。
3.5 -6:强制 IPv6 地址族
IPv6 双栈服务监听在 8802,用 -6 显式走 IPv6 回环:
$ { echo "GET / HTTP/1.0"; echo; sleep 2; } | telnet -6 ::1 8802
Trying ::1...
Connected to ::1.
Escape character is '^]'.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Fri, 16 Oct 2026 00:25:34 GMT
Content-type: text/html
Content-Length: 98
Last-Modified: Fri, 16 Oct 2026 00:25:29 GMT
<html><head><title>telnet demo</title></head>
<body><h1>Hello from telnet demo</h1></body></html>
Connection closed by foreign host.
Trying ::1... → Connected to ::1. 证明走了 IPv6 回环地址。若目标端口只有 IPv4 监听,telnet -6 会得到与 3.3 相同的 Connection refused——排障时可用 -4/-6 快速定位「服务只绑了一个协议族」的问题。
💡 要点:
-4/-6是排查「双栈主机上 v4 通 v6 不通(或反之)」的第一把扳手,比改 /etc/hosts 或卸载 IPv6 干净得多。
3.6 -l user:指定登录用户名
$ { echo "GET / HTTP/1.0"; echo; sleep 2; } | telnet -l root 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Fri, 16 Oct 2026 00:25:36 GMT
Content-type: text/html
Content-Length: 98
Last-Modified: Fri, 16 Oct 2026 00:25:29 GMT
<html><head><title>telnet demo</title></head>
<body><h1>Hello from telnet demo</h1></body></html>
Connection closed by foreign host.
-l root 的语义是:连接建立后在 telnet 协议层向远端递交用户名 root(ENV/NEW-ENVIRON 与登录协商),供真正的 telnetd 类服务完成免输入登录。本文的演示对象是 HTTP 服务,它不消费 telnet 协议协商,因此连接与响应不受影响——这也说明 -l 只对「懂 telnet 协议」的远端有意义。
💡 要点:
-l只在远端跑 telnetd 类服务时生效;对 HTTP/SMTP 等纯 TCP 服务完全无感。现代网络中 telnet 明文协议已被 SSH 取代,-l实用场景极少,理解其「协议层递交用户名」的语义即可,不建议在任何生产环境开放 telnetd。
3.7 -a:尝试自动登录
$ { echo "GET / HTTP/1.0"; echo; sleep 2; } | telnet -a 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Fri, 16 Oct 2026 00:25:38 GMT
Content-type: text/html
Content-Length: 98
Last-Modified: Fri, 16 Oct 2026 00:25:29 GMT
<html><head><title>telnet demo</title></head>
<body><h1>Hello from telnet demo</h1></body></html>
Connection closed by foreign host.
-a 请求远端「自动登录」:把本机 USER 环境变量通过 telnet 协议递给远端,并声明跳过登录流程。与 -l 一样,效果取决于远端是否是 telnetd 类服务;对 HTTP 服务无感知。一句话记忆:-l 指定「用谁登录」,-a 表示「自动用当前用户登录」。
💡 要点:
-a与-l是同一协商的两种入口——-a自动带$USER,-l 名字显式指定。两者都依赖远端 telnetd 接受免密登录(现代系统默认拒绝),所以对探端口场景无实际影响;安全审计时看到 telnet 协商中的登录名传递,应直接判高危。
3.8 -E:禁用转义字符
$ { echo "GET / HTTP/1.0"; echo; sleep 2; } | telnet -E 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is 'off'.
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Fri, 16 Oct 2026 00:25:40 GMT
Content-type: text/html
Content-Length: 98
Last-Modified: Fri, 16 Oct 2026 00:25:29 GMT
<html><head><title>telnet demo</title></head>
<body><h1>Hello from telnet demo</h1></body></html>
Connection closed by foreign host.
对比 3.1 的第 3 行:这里变成了 Escape character is 'off'.——-E 生效。禁用后连接期间无法再用 Ctrl-] 逃逸回命令模式,只能等到连接结束或按 Ctrl-C 强杀进程。适合把 telnet 塞进脚本跑固定任务、避免输入数据中恰好出现转义字节造成「中途跳回命令模式」的意外。
💡 要点:
-E的典型场景是管道喂脚本——数据流里可能出现\x1d(Ctrl-] 字节)时,禁用转义可防「中途跳回命令模式」的假死。脚本标准写法:telnet -E host port < 输入文件 > 输出 2>&1,配timeout兜底。
3.9 转义字符 ^] 与交互模式:一次「中途逃逸」的原理
连接建立后的横幅 Escape character is '^]'. 是telnet 交互体验的核心:在交互终端里按 Ctrl-](ASCII 0x1D),telnet 会暂停数据转发、回到 telnet> 命令提示符,此时可以 status 看状态、send 发特殊字符,最后 quit 或回车继续会话。当对端服务「假死」(连上了但迟迟不响应)时,这是唯一的体面退出方式——连接不会被关闭,回到 shell 后还能再进入或 close 掉。
但要注意一个实测出的边界:转义字符只在交互终端模式下被 telnet 识别。用管道把 0x1D 字节喂给非交互的 telnet,它不会触发逃逸,而是把该字节当普通数据原样发给对端——下面的实测同时暴露了 \r\n 在 telnet 线路上的 CR-NUL 展开现象:
$ { printf "GET / HTTP/1.0\r\n\r\n"; sleep 1; printf "\035"; sleep 1; printf "quit\r"; sleep 1; } | telnet 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code: 400</p>
<p>Message: Bad request version ('\x00').</p>
<p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
</body>
</html>
Connection closed by foreign host.
解读:请求头之后又混入了 \035(0x1D)与 quit 两段「数据」,telnet 原样转发且未进入逃逸模式(全程没有出现 telnet>);HTTP 服务端把多出来的字节当成新请求解析,报了 400。两点结论:
- 非交互(管道/重定向)场景下 telnet 不处理转义字符,想退出只能靠 stdin 结束(EOF)或杀进程;
- 管道喂
\r\n时,telnet 线路层会把裸 CR 展开为 CR-NUL(telnet 协议要求 CR 后必须跟 NUL 或 LF),多出的 NUL 字节被 HTTP 服务端解析成乱码请求(Bad request version ('\x00'))。所以管道手打 HTTP 请用echo(LF 结尾)让 telnet 自己做换行翻译,如 3.1 的写法。
💡 要点:交互终端里 Ctrl-] 是「逃生舱」;脚本里 EOF 是「熄火开关」。两者别混用。
3.10 连接超时形态:对不存在(被过滤)的地址发起连接
Connection refused 是「主机可达但端口没人听」;另一种更磨人的失败是「主机不可达/防火墙静默丢包」,此时 connect 会长时间挂起。用 timeout 包一层观察(对内网黑洞地址 10.255.255.1 的 80 端口):
$ timeout 6 telnet 10.255.255.1 80; echo rc=$?
rc=124
6 秒后 timeout 以 SIGTERM 杀掉 telnet,rc=124 是 timeout 的「超时」约定退出码。值得注意的实测细节:这段输出里连 Trying 10.255.255.1... 都没出现——telnet 的 stdout 接到管道/非终端时是块缓冲的,进程被杀时缓冲区来不及刷出。在真实交互终端上执行同一条命令,会先看到 Trying 10.255.255.1... 然后无限期停在那里。
💡 要点:判别「端口不通」的三种形态——立刻 refused(服务没起)、短暂 Trying 后 refused(路由可达端口关)、永远 Trying(被防火墙丢包)。第三种在交互终端下可按 Ctrl-] 逃逸后 quit 退出,脚本下必须用 timeout 兜底。
3.11 技术拓展:端口连通性检查工具对比
「测一台服务器的某端口通不通」有多种工具,横向对比——
| 工具 | 原理 | 能否交互 | 适用场景 |
|---|---|---|---|
| telnet | 完整 TCP 连接 + 协议协商 | 可(可手敲协议) | 快速探端口 + 人工看服务横幅(本文主线) |
| nc (netcat) | 裸 TCP/UDP 连接 | 半(-e 可挂进程) | 脚本化探端口、端口监听模拟 |
| curl/openssl s_client | 应用层协议请求 | - | 验证 HTTP/TLS 服务真正可用 |
| nmap | 多种扫描技术 | - | 批量端口扫描与指纹识别 |
| ss / netstat | 读本地 socket 表 | - | 查「本机」监听(非远程探测) |
💡 关键差异一句话:telnet 与 nc 都是 TCP 握手级探测,telnet 胜在 ubiquitous(老系统必有)与可交互,nc 胜在协议中立(支持 UDP)。本文以 telnet 为主线(Ubuntu 22.04 需
apt install telnet,inetutils 包);探端口写脚本优先 nc,人工验证服务横幅 telnet 最直观,涉及 TLS 必须上 openssl s_client 才能看清证书。
四、实战示例
4.1 探测远端 TCP 端口是否开放(运维惯用法)
排障最常用的一招:连上就说明端口通,refused 说明服务没起。连接成功后立即 Ctrl-] 逃逸再 quit(脚本里用 EOF 短路),避免停留在会话里:
$ telnet 127.0.0.1 8801
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
^]
telnet> quit
(交互演示形态:Connected to 127.0.0.1. 即为「端口开放」的判据;随后 Ctrl-] 回到 telnet>,quit 退出。)
4.2 调试明文协议:手打 SMTP/HTTP 请求
任何明文协议都能这样「人肉客户端」。除 3.1 的 HTTP 外,同法可测 SMTP(telnet mail.example.com 25 后敲 EHLO/QUIT)、Redis(telnet 127.0.0.1 6379 后敲 PING)、Memcached 等。判读方法一致:把 telnet 输出当作服务端原始响应阅读。
4.3 零依赖替代:bash 内建 /dev/tcp 对照
不能装 telnet 的最小环境里,bash 的 /dev/tcp 伪设备可以做纯连通性判断(只判「通/不通」,不能交互):
$ timeout 3 bash -c "echo > /dev/tcp/127.0.0.1/8801" && echo port-open; echo rc=$?
port-open
rc=0
$ timeout 3 bash -c "echo > /dev/tcp/127.0.0.1/9999"; echo rc=$?
bash: connect: Connection refused
bash: line 1: /dev/tcp/127.0.0.1/9999: Connection refused
rc=1
对照结论:判端口用 /dev/rc 足够且零依赖;要「看得见协议字节」就必须 telnet(或 nc)。
五、注意事项与常见问题
Q1:telnet 连上后一直「卡住」不退出,怎么退?
交互终端按 Ctrl-] 回到 telnet>,再输入 quit 回车;或直接 Ctrl-C 强杀(连接随即断开)。脚本/管道场景下靠 stdin EOF 结束,或外层用 timeout N telnet ... 兜底(见 3.10)。
Q2:telnet 为什么被认为不安全?替代方案是什么?
telnet 协议(RFC 854)全程明文,账号、密码、命令在链路上可直接被抓包还原,远程登录场景早已被 SSH 取代(ssh user@host,加密 + 主机指纹校验)。今天 telnet 的合理定位只剩「内网明文服务调试」与「端口连通性快速验证」。运维侧建议:生产网关/防火墙直接封 23 端口,登录一律走 SSH。
Q3:脚本里喂给 telnet 的 \r\n 为什么会让 HTTP 服务报 400?
telnet 的线路层遵循 NVT(网络虚拟终端)规则,裸 CR 发送时会补成 CR-NUL。HTTP 服务端把多出的 NUL 当成下一请求行,于是出现 Bad request version ('\x00')。解法是管道里用 echo(LF 结尾),让 telnet 自行完成换行翻译,参见 3.9 的对照实测。
Q4:timeout 包裹的超时实测里,为什么连 Trying ... 都没打印?
telnet 检测到 stdout 不是终端时使用块缓冲,被 SIGTERM 杀死时缓冲未刷出。这只是显示层现象,不代表 connect 没有发生;交互终端下即可看到 Trying 行(见 3.10 解读)。
Q5:-l/-a 连 HTTP 服务没任何效果,是不是参数坏了?
不是。这两个参数只在 telnet 协议协商层递交用户名,只有 telnetd 类远端会消费;HTTP 服务把它当空气是预期行为(见 3.6/3.7 解读)。
六、参考链接
- Ubuntu 手册页(netkit-telnet,与本环境同版本系):https://manpages.ubuntu.com/manpages/jammy/en/man1/telnet.1.html
- TELNET 协议规范 RFC 854:https://www.rfc-editor.org/rfc/rfc854
- TELNET 选项:_linemode 与 NVT 说明 RFC 1184:https://www.rfc-editor.org/rfc/rfc1184
- GNU inetutils telnet 手册(另一常见实现,便于对照):https://www.gnu.org/software/inetutils/manual/html_node/telnet-invocation.html
- bash /dev/tcp 用法(bash 手册 REDIRECTION 节):https://www.gnu.org/software/bash/manual/html_node/Redirections.html