前言
这篇文章时在吾之理解的基础上,加以翻译,其中肯定包含很多个人理解的东西,
如有不对之处,请赐教!
信道机制 Channel Mechanism
所有的终端会话,转发连接等等都是信道。
任何一方都可以打开一个信道。多个信道是复用同一个连接。
通信双方是根据编号来识别信道的。通信双方所涉及到的同一个信道的编号可能是不一样的(因为其用的是各自本机的编号)。打开信道的请求应该包含发送方的信道编号。其他信道有关的消息应该包含接收方的信道编号。
信道是通过流来控制的。在没有明确的指示窗口空间为可用之前,都不可以向信道发送数据。如何明确指示呢?就是通过发送一个消息,来告诉对方,这个信道可用!
打开一个信道 Opening a Channel
当任何一方希望打开一个新的信道,其会为该信道分配一个本地编号。
接着发送以下消息到另一方,并且在消息中要包含本地信道编号和初始化窗口大小。
byte SSH_MSG_CHANNEL_OPEN
string channel type in US-ASCII only
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
.... channel type specific data follows
channel type
是个名称,其在【SSH-ARCH】和【SSH-NUMBERS】中有描述,其具有类似的扩展机制。
sender channel
是本消息的发送方用于识别信道的一个本地标识。
initial window size
在没有调整窗口大小的情况下,可以通过信道发送多少字节数据给本消息的发送方。
maximum packet size
指定可以发送给本消息的发送方的单个最大数据包的大小。
例如:可能希望在交互式连接中使用较小的数据包,使得在慢连接中获得更好的交互响应。
然后,远程端(另一方)决定是否打开这个信道,并且响应SSH_MSG_CHANNEL_OPEN_CONFIRMATION
或者SSH_MSG_CHANNEL_OPEN_FAILURE
。
byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION
uint32 recipient channel
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
.... channel type specific data follows
recipient channel
是 原打开信道请求中给出的信道编号,并且sender channel
是另一方分配的信道编号。
byte SSH_MSG_CHANNEL_OPEN_FAILURE
uint32 recipient channel
uint32 reason code
string description in ISO-10646 UTF-8 encoding [RFC3629]
string language tag [RFC3066]
如果SSH_MSG_CHANNEL_OPEN
消息的接收方不支持指定的channel type
,其只需要简单的响应SSH_MSG_CHANNEL_OPEN_FAILURE
。
客户端可将description
字符串信息显示给使用者。如果这样做了,客户端软件应该采取在SSH-ARCH中讨论的预防措施。
SSH_MSG_CHANNEL_OPEN_FAILURE
消息中的reason code
的值早已定义好了如下表。注意,下面的reason code
的值为了可读性给出的是十进制,但是它们实际是uint32
。
Symbolic name | reason code |
---|---|
SSH_OPEN_ADMINISTRATIVELY_PROHIBITED | 1 |
SSH_OPEN_CONNECT_FAILED | 2 |
SSH_OPEN_UNKNOWN_CHANNEL_TYPE | 3 |
SSH_OPEN_RESOURCE_SHORTAGE | 4 |
要请求为SSH_MSG_CHANNEL_OPEN
分配新的范围在0x00000005
到0xFDFFFFFF
之间的reason_code
值(及相关的description
文本),必须使用IETF CONSENSUS
方法,见[RFC2434]。信道连接失败时,在0xFE000000
和0xFFFFFFFF
范围的值,IANA
不会分配给reason code
。
该范围内的信道连接失败的reason code
值留给PRIVATE USE
。见【RFC2434】。
虽然IANA
不会控制0xFE000000
到0xFFFFFFFF
这个范围的值,但是,这个范围的值,会被分割成两个部分,并通过以下的约定来管理。
0xFE000000
和0xFEFFFFFF
将与本地分配的信道一起使用。例如,如果提议打开一个channel type
为example_session@example.com
的信道,但是失败了,接着响应将包含一个IANA分配的reason code
,其范围为0x00000001
到0xFDFFFFFF
,或者是本地分配的值,其范围是在0xFE000000
到0xFEFFFFFF
。自然的,如果服务器不理解提议的channel type
,那么如果发送reason code
,则必须为0x00000003
。如果服务器理解channel type
,但是该信道仍然打开失败,接着服务器应响应一个本地分配的和提议中相一致的reason code
。
假设系统实现人员首先尝试使用IANA
分配的reason code
的值,然后再使用他们本地分配的reason code
的值。- 对于从
0xFF
开始的范围没有任何限制,其一般用于测试。
数据传输
窗口大小规定在对方必须等待窗口调整之前,可以发送多少字节。
双方使用下面消息格式来调整窗口。
byte SSH_MSG_CHANNEL_WINDOW_ADJUST
uint32 recipient channel
uint32 bytes to add
在收到这个消息之后,接收方可能发送给定的字节数要多于以前允许的字节数(感觉是句废话);窗口大小是增量。系统实现必须正确的处理2^32-1
字节的窗口大小。窗口大小的增加不能超过2^32-1
字节。
数据传输时通过下面类型的消息实现的:
byte SSH_MSG_CHANNEL_DATA
uint32 recipient channel
string data
数据的最大长度是由信道中最大包的大小与当前窗口大小中最小者来决定的。窗口大小会根据已发送的数据进行递减。双方都可以忽略掉当可用的窗口空间耗尽后,发送的所有额外数据。
系统实现预计会对SSH
传输层数据包的大小会有限制(对于接收包的任何限制必须大于等于32768
字节,见SSH-TRANS)
SSH连接层实现:
- 决不能公布数据包的最大大小,否则可能会产生比传输层可接收大的数据包。
- 决不能生成比传输层可发送的还要大的数据包,即使远程端可以接收非常大的包。
此外,有些信道可以传输几种类型的数据。例如:来自交互式会话的stderr
数据。这种数据可以通过SSH_MSG_CHANNEL_EXTENDED_DATA
消息格式传送,其使用一个整数来指定数据类型。可用的类型和他们的解释依赖于信道类型。
byte SSH_MSG_CHANNEL_EXTENDED_DATA
uint32 recipient channel
uint32 data_type_code
string data
通过该消息发送的数据,和普通消息消耗的窗口空间相同。
目前,只定义了以下类型。注意,为了可读性,data_type_code
显示是十进制,其实实际是uint32
。
Symbolic name data_type_code
------------- --------------
SSH_EXTENDED_DATA_STDERR 1
扩展信道数据传输中的data_type_code
的值,必须按顺序分配。
请求分配新的扩展信道数据传输的data_type_code
的值的范围0x00000002
到0xFDFFFFFF
,data_type_code
和相关的data
都是通过IETF CONSENSUS
方法,详情见RFC2434。IANA
不会分配0xFE000000
到0xFFFFFFFF
的值给data_type_code
。该范围内的扩展信道数据传输中的data_type_code
的值是留给PRIVATE USE
,见RFC2434。如上所述,关于IANA
的说明,见SSH-NUMBERS。
关闭一个信道
当一方不打算再发送更多的数据给信道时,其应该发送SSH_MSG_CHANNEL_EOF
。
byte SSH_MSG_CHANNEL_EOF
uint32 recipient channel
对本消息不发送明确响应。但是,应用软件可以给信道的另一端发送EOF
。
注意,在发送本消息之后,信道依然是保持打开,并且对方依然可以发送更多数据。本消息不会消耗窗口空间,也就是即使没有可利用的窗口空间,依然可以发送本消息。
当任何一方希望终止信道时,其应该发送SSH_MSG_CHANNEL_CLOSE
。
一方收到本消息后,另一方必须也发送SSH_MSG_CHANNEL_CLOSE
,除非其之前已经发送过了。信道 在 一方 发送并接收到SSH_MSG_CHANNEL_CLOSE
时视为关闭,这时,该方可以重用该信道编号。任何一方可以在没有发送或者接收到SSH_MSG_CHANNEL_EOF
时,发送SSH_MSG_CHANNEL_CLOSE
。
byte SSH_MSG_CHANNEL_CLOSE
uint32 recipient channel
本消息不会消耗窗口空间,也就是即使没有可利用的窗口空间,依然可以发送本消息。
推荐如果可以的话,应该把在本消息发送之前的所有数据都递送到目的地。
特定信道的请求
许多channel type
都有特定于channel type
的扩展。例如,为交互式会话请求一个pty
(伪终端)。
所有的 特定信道的请求 都使用下面的形式:
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string request type in US-ASCII characters only
boolean want reply
.... type-specific data follows
如果want reply
是false
,将不会对本请求发送响应。否则,接收方响应给另一方为SSH_MSG_CHANNEL_SUCCESS
、SSH_MSG_CHANNEL_FAILURE
或者特定请求的延续消息。
如果请求不被识别或者是该信道不支持,返回SSH_MSG_CHANNEL_FAILURE
。
本消息不会消耗窗口空间,也就是即使没有可利用的窗口空间,依然可以发送本消息。request type
的值对于每个channel type
是局部的。
客户端可以继续发送消息,而不需要等待该请求的响应。
request type 名称遵循DNS
扩展命名惯例,详见SSH-ARCH和SSH-NUMBERS。
byte SSH_MSG_CHANNEL_SUCCESS
uint32 recipient channel
byte SSH_MSG_CHANNEL_FAILURE
uint32 recipient channel
本消息不会消耗窗口空间,也就是即使没有可利用的窗口空间,依然可以发送本消息。
交互式 会话
会话是远程执行一个程序。程序可能是一个shell
,一个应用程序,一个系统命令或者某些内置的子系统。它可以有也可以没有tty
,可以涉及也可以不涉及X11
转发。多个会话可以同时活动。
打开一个会话
通过发送以下消息开启一个会话。
byte SSH_MSG_CHANNEL_OPEN
string "session"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
客户端系统实现应该拒绝任何打开会话信道
的请求,来加大通过已被攻破的服务器 攻击客户端的难度。
通俗的说:会话信道只能是客户端请求服务端,而不能服务端请求客户端。
请求一个伪终端
通过发送下面消息来为会话
分配一个伪终端
。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "pty-req"
boolean want_reply
string TERM environment variable value (e.g., vt100)
uint32 terminal width, characters (e.g., 80)
uint32 terminal height, rows (e.g., 24)
uint32 terminal width, pixels (e.g., 640)
uint32 terminal height, pixels (e.g., 480)
string encoded terminal modes
encoded terminal modes 在 第8节有描述。尺寸参数为0
的必须忽略。character或者row
尺寸覆盖pixel
尺寸(当不为0
)。Pixel
尺寸指窗口可绘制区域。
尺寸参数只为提示。
客户端应该忽视掉pty
请求
X11 转发
请求X11转发
会话
通过发送一个SSH_MSG_CHANNEL_REQUEST
消息来请求X11
转发。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "x11-req"
boolean want reply
boolean single connection
string x11 authentication protocol
string x11 authentication cookie
uint32 x11 screen number
推荐发送的x11 authentication cookie
是一个假的、随机的cookie
,当连接请求被接收时,检查该cookie
并替换真的cookie
。
当会话信道关闭时,X11
连接转发应该关闭。但是当会话信道关闭时,已经打开的转发不应该自动关闭。
如果single connection
是true
,只应转发单个连接。在第一个连接之后,或者会话信道关闭之后,均不会转发更多的连接。
x11 authentication protocol
是所使用X11
验证方法的名称。如:MIT-MAGIC-COOKIE-1
。
x11 authentication cookie
必须是十六进制编码。
X 协议文档 详见 SCHEIFLER
X11 信道
X11
信道通过打开信道请求来打开。所打开的信道独立于会话,关闭会话信道不会关闭X11
转发信道。
byte SSH_MSG_CHANNEL_OPEN
string "x11"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string originator address (e.g., "192.168.7.38")
uint32 originator port
接收方应该响应SSH_MSG_CHANNEL_OPEN_CONFIRMATION
或者SSH_MSG_CHANNEL_OPEN_FAILURE
。
如果系统没有实现X11
信道转发请求,那么其得拒绝任何打开X11
信道请求。
环境变量传递
环境变量可以被传递给后续将启动的shell/command
。
在一个享有特权的进程中设置不被控制的环境变量是安全风险的。
推荐系统实现维持一个允许的变量名称列表或者只在没有特权的服务器进程中进行环境变量的设置。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "env"
boolean want reply
string variable name
string variable value
启动一个Shell 或者一个 Command
一旦会话被设定,远程端将启动一个程序。这个程序可以是一个shell
、一个应用程序或者一个与主机名称无关的子系统。
每个信道只会有一个请求会成功。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "shell"
boolean want reply
该消息将会请求启动远程端用户默认的shell
(通常是在UNIX
系统中的/etc/passwd
)。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exec"
boolean want reply
string command
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exec"
boolean want reply
string command
这个消息将请求服务器开始执行给定的命令。command
字串可包含一个路径。必须采取一般性措施来防止执行未经授权的命令。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "subsystem"
boolean want reply
string subsystem name
最后这个消息时用于执行一个预定义的子系统。可预计该行为将包含一个通用的文件传输机制,和可能的其他功能。系统实现也可需要设置更多的机制。由于通常是用户的shell
来执行子系统,建议子系统协议在协议在传输开始包含一个magic cookie
,来区别shell
初始化脚本等生成的任意输出。这些shell
的伪输出可以在服务器或者客户端中过滤掉。
当启动一个shell
或者一个程序时,服务器不应该停止执行协议栈。所有的输入和输出都应该重定向到信道或者加密隧道。
推荐对这些消息进行回复并且其进行检查。客户端应该忽略掉这些消息。
也就是说 上面的三个消息,都应该是客户端请求服务器端,反之不行。
子系统名称遵循DNS
扩展名称约定 见SSH-NUMBERS
会话数据传输
会话数据传输使用SSH_MSG_CHANNEL_DATA
和SSH_MSG_CHANNEL_EXTENDED_DATA
数据包和窗口机制来完成的。
为stderr
数据 定义了 扩展数据类型SSH_EXTENDED_DATA_STDERR
。
窗口大小变化消息
当客户端窗口(terminal
)大小变化时,客户端可向另一方发送一个消息通知其新的大小。
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "window-change"
boolean FALSE
uint32 terminal width, columns
uint32 terminal height, rows
uint32 terminal width, pixels
uint32 terminal height, pixels
对该消息不应发送响应。
总结
暂时就翻译这些
参考地址: