如何让Telnet服务器强制客户端运行在被动模式?
我用C语言编写了一个基础Telnet Server,目前正在针对多款telnet客户端进行测试。但不同客户端(例如PuTTY)默认会以Active mode运行,有没有办法让服务器强制客户端始终以被动模式运行?我想这么做的原因是,如果能强制被动模式,我就无需实现任何协议特定细节,只需处理基础逻辑,最终我的Telnet Server就只是一个简单的TCP socket。
更新1
以下是客户端连接服务器时,我接收到的数据说明:
- 启动Telnet Server
- Telnet Client建立连接(并发送telnet协议数据)
received = {ffff1fffff20ffff18ffff27ffff01ffff03ffff03}
该数据为十六进制编码,按Telnet规范解码后可知,客户端试图在交换任何数据前建立某些配置。我在Telnet Server端直接忽略以0xff(IAC code)开头的接收数据,暂时解决了问题。
3. 在客户端输入一些数据并按下回车键
4. Telnet Server接收到数据
5. 在客户端再次输入一些数据并按下回车键
6. Telnet Server接收到数据 + telnet协议数据
比如我发送“123456”时收到的数据:
received = {616263646566ffff18ffff27ffff01ffff03ffff03}
可以看到,我收到了发送的内容,但同时也收到了Telnet协议相关数据——这是因为客户端处于Active mode。我希望在步骤2和3之间,服务器能将客户端设置为Passive mode,这样步骤6就不会收到任何Telnet协议数据。
更新2
关于“Passive mode”的细节:我指的是Telnet协商模式,分为两种:
- Passive mode:Telnet客户端/服务器不会发送任何协商数据,仅传输用户数据
- Active mode:Telnet客户端/服务器会发送协商数据,以配置/握手确定要使用的功能
这个模式未在Telnet协议规范中找到定义,仅在PuTTY文档里提及,相关内容翻译如下:
在Telnet连接中,存在两种协商模式:主动模式和被动模式。在主动模式下,PuTTY会主动发送协商请求,尝试在连接建立时启用各种Telnet功能。在被动模式下,PuTTY只会响应来自服务器的协商请求,不会主动发起任何协商。
解决方法
要强制客户端进入被动模式(停止主动发送协商数据),你需要按照Telnet协议规范,对客户端的协商请求做出明确拒绝响应,告诉客户端无需启用这些功能,也不必继续发送协商数据。
具体操作步骤:
解析客户端的协商请求:
客户端发送的十六进制数据对应这些Telnet协商指令:ffff1f=IAC WILL NAWS(窗口大小协商)ffff20=IAC WILL TERMINAL-TYPE(终端类型协商)ffff18=IAC WILL NEW-ENVIRON(环境变量协商)ffff27=IAC WILL TSPEED(终端速度协商)ffff01=IAC WILL ECHO(回显协商)ffff03=IAC WILL SUPPRESS-GO-AHEAD(抑制继续协商)
发送拒绝响应:
针对每个IAC WILL <option>请求,服务器需要回复IAC DONT <option>,明确告知客户端“我不需要你启用该功能”。例如:- 收到
IAC WILL NAWS (0xff 0xfb 0x1f),回复IAC DONT NAWS (0xff 0xfe 0x1f) - 收到
IAC WILL TERMINAL-TYPE (0xff 0xfb 0x20),回复IAC DONT TERMINAL-TYPE (0xff 0xfe 0x20) - 以此类推,处理所有客户端发送的WILL类协商请求
- 收到
禁用服务器主动协商:
确保你的服务器不会主动发送任何IAC DO或IAC WILL请求,仅做被动响应。
这样处理后,包括PuTTY在内的主流客户端会收到服务器的拒绝指令,停止主动发送协商数据,进入你所说的“被动模式”,之后只会传输用户输入的数据。
注意事项:
- 不能直接忽略
IAC开头的数据,否则客户端可能会不断重试协商请求(比如步骤6中再次出现的协议数据),只有明确拒绝才能让客户端停止发送。 - 少数客户端可能不完全遵循规范,需要针对不同客户端做测试,但该方法对绝大多数主流Telnet客户端有效。
内容的提问来源于stack exchange,提问作者campescassiano

