Telnet 協議詳解
一、概述
============================================================
Telnet 協議是 TCP/IP 協議族中應用最廣泛的協議。
它允許用戶(Telnet 客戶端)通過一個協商過程來與一個遠程設備進行通信。
Telnet 協議是基於網絡虛擬終端 NVT(Network Virtual Termina1)的實現,
NVT 是虛擬設備,連接雙方(客戶機和服務器)都必須把它們的物理終端和 NVT 進行相互轉換。
============================================================
Telnet 協議具有如下的特點:
__(1) 適應異構__
為了使多個操作系統間的 Telnet 交互操作成為可能,就必須詳細了解異構計算機和操作系統。比如,一些操作系統需要每行文本用 ASCII 回車控制符(CR)結束,另一些系統則需要使用 ASCII 換行符(LF),還有一些系統需要用兩個字符的序列回車-換行(CR-LF);再比如,大多數操作系統為用戶提供了一個中斷程序運行的快捷鍵,但這個快捷鍵在各個系統中有可能不同(一些系統使用 CTRL+C,而另一些系統使用 ESCAPE)。如果不考慮系統間的異構性,那么在本地發出的字符或命令,傳送到遠地並被遠地系統解釋后很可能會不准確或者出現錯誤。因此,Telnet 協議必須解決這個問題。
為了適應異構環境,Telnet 協議定義了數據和命令在 Internet 上的傳輸方式,此定義被稱作網絡虛擬終端 NVT(Net Virtual Terminal)。它的應用過程如下:
-
對於發送的數據:客戶機軟件把來自用戶終端的按鍵和命令序列轉換為 NVT 格式,並發送到服務器,服務器軟件將收到的數據和命令,從 NVT 格式轉換為遠地系統需要的格式;
-
對於返回的數據:遠地服務器將數據從遠地機器的格式轉換為 NVT 格式,而本地客戶機將將接收到的 NVT 格式數據再轉換為本地的格式。
__(2) 傳送遠地命令__
我們知道絕大多數操作系統都提供各種快捷鍵來實現相應的控制命令,當用戶在本地終端鍵入這些快捷鍵的時候,本地系統將執行相應的控制命令,而不把這些快捷鍵作為輸入。那么對於 Telnet 來說,它是用什么來實現控制命令的遠地傳送呢?
Telnet 同樣使用 NVT 來定義如何從客戶機將控制功能傳送到服務器。我們知道 USASCII 字符集包括 95 個可打印字符和 33 個控制碼。當用戶從本地鍵入普通字符時,NVT 將按照其原始含義傳送;當用戶鍵入快捷鍵(組合鍵)時,NVT 將把它轉化為特殊的 ASCII 字符在網絡上傳送,並在其到達遠地機器后轉化為相應的控制命令。將正常 ASCII 字符集與控制命令區分主要有兩個原因:
-
這種區分意味着 Telnet 具有更大的靈活性:它可在客戶機與服務器間傳送所有可能的 ASCII 字符以及所有控制功能;
-
這種區分使得客戶機可以無二義性的指定信令,而不會產生控制功能與普通字符的混亂。
__(3) 數據流向__
將 Telnet 設計為應用級軟件有一個缺點,那就是:效率不高。這是為什么呢?下面給出 Telnet 中的數據流向:
數據信息被用戶從本地鍵盤鍵入並通過操作系統傳到客戶機程序,客戶機程序將其處理后返回操作系統,並由操作系統經過網絡傳送到遠地機器,遠地操作系統將所接收數據傳給服務器程序,並經服務器程序再次處理后返回到操作系統上的偽終端入口點,最后,遠地操作系統將數據傳送到用戶正在運行的應用程序,這便是一次完整的輸入過程;輸出將按照同一通路從服務器傳送到客戶機。
因為每一次的輸入和輸出,計算機將切換進程環境好幾次,這個開銷是很昂貴的。還好用戶的鍵入速率並不算高,這個缺點我們仍然能夠接受。
__(4) 強制命令__
我們應該考慮到這樣一種情況:假設本地用戶運行了遠地機器的一個無休止循環的錯誤命令或程序,且此命令或程序已經停止讀取輸入,那么操作系統的緩沖區可能因此而被占滿,如果這樣,遠地服務器也無法再將數據寫入偽終端,並且最終導致停止從 TCP 連接讀取數據,TCP 連接的緩沖區最終也會被占滿,從而導致阻止數據流流入此連接。如果以上事情真的發生了,那么本地用戶將失去對遠地機器的控制。
為了解決此問題,Telnet 協議必須使用外帶信令以便強制服務器讀取一個控制命令。我們知道 TCP 用緊急數據機制實現外帶數據信令,那么 Telnet 只要再附加一個被稱為數據標記(date mark)的保留八位組,並通過讓 TCP 發送已設置緊急數據比特的報文段通知服務器便可以了,攜帶緊急數據的報文段將繞過流量控制直接到達服務器。作為對緊急信令的相應,服務器將讀取並拋棄所有數據,直到找到了一個數據標記。服務器在遇到了數據標記后將返回正常的處理過程。
__(5) 選項協商__
由於 Telnet 兩端的機器和操作系統的異構性,使得 Telnet 不可能也不應該嚴格規定每一個 telnet 連接的詳細配置,否則將大大影響 Telnet 的適應異構性。因此,Telnet 采用選項協商機制來解決這一問題。
Telnet 選項的范圍很廣:一些選項擴充了大方向的功能,而一些選項制涉及一些微小細節。例如:有一個選項可以控制 Telnet 是在半雙工還是全雙工模式下工作(大方向);還有一個選項允許遠地機器上的服務器決定用戶終端類型(小細節)。
Telnet 選項的協商方式也很有意思,它對於每個選項的處理都是對稱的,即任何一端都可以發出協商申請;任何一端都可以接受或拒絕這個申請。另外,如果一端試圖協商另一端不了解的選項,接受請求的一端可簡單的拒絕協商。因此,有可能將更新,更復雜的 Telnet 客戶機服務器版本與較老的,不太復雜的版本進行交互操作。如果客戶機和服務器都理解新的選項,可能會對交互有所改善。否則,它們將一起轉到效率較低但可工作的方式下運行。所有的這些設計,都是為了增強適應異構性,可見 Telnet 的適應異構性對其的應用和發展是多么重要。
二、原理
Telnet 協議的主體由三個部分組成:
-
網絡虛擬終端(NVT,Network Virtual Terminal)的定義;
-
操作協商定義;
-
協商有限自動機;
2.1 網絡虛擬終端(NVT)
2.1.1. NVT 工作原理
顧名思義,網絡虛擬終端(NVT)是一種虛擬的終端設備,它被客戶和服務器所采用,用來建立數據表示和解釋的一致性。
2.1.2. NVT 的定義
(1) NVT 的組成
網絡虛擬終端 NVT 包括兩個部分:
-
輸出設備:輸出遠程數據,一般為顯示器
-
輸入設備:本地數據輸入
(2) 在 NVT 上傳輸的數據格式
在網絡虛擬終端 NVT 上傳輸的數據采用 8bit 字節數據,其中 最高位為 0 的字節用於一般數據,最高位為 1 的字節用於 NVT 命令。
(3) NVT 在 TELNET 中的使用
TELNET 使用了一種對稱的數據表示,當每個客戶機發送數據時,把它的本地終端的字符表示影射到 NVT 的字符表示上,當接收數據時,又把 NVT 的表示映射到本地字符集合上。
在通信開始時,通信雙方都支持一個基本的 NVT 終端特性子集(只能區分何為數據,何為命令),以便在最低層次上通信,在這個基礎上,雙方通過 NVT 命令協商確定NVT的更高層次上的特性,實現對 NVT 功能的擴展。
在 TELNET 中存在大量的子協議用於協商擴展基本的網絡虛擬終端 NVT 的功能,由於終端類型的多樣化,使得 TELNET 協議族變得龐大起來。
2.2. 操作協商
2.2.1. 為什么要協商操作選項
當定義了網絡虛擬終端設備后,通信的雙方就可以在一個較低的層次上實現數據通信,但基本的 NVT 設備所具有的特性是十分有限的,它只能接收和顯示 7 位的 ASCII 碼,沒有最基本的編輯能力,所以簡單的 NVT 設備是沒有實際應用意義的;為此 TELNET 協議定義了一族協議用於擴展基本 NVT 的功能,目的是使 NVT 能夠最大限度地達到用戶終端所具有的功能。
為了實現對多種終端特性的支持,TELNET協議規定在擴展NVT功能時采用協商的機制,只有通信雙方通過協商后達成一致的特性才能使用,才能賦予NVT該項特性,這樣就可以支持具有不同終端特性的終端設備可以互連,保證他們是工作在他們自己的能力以內。
2.2.2. 操作協商命令格式
TELNET 的操作協商使用 NVT 命令,即最高位為 1 的字節流,每條 NVT 命令以字節 IAC(0xFF)開始。原理如下:
只要客戶機或服務器要發送命令序列而不是數據流,它就在數據流中插入一個特殊的保留字符,該保留字符叫做“解釋為命令”(IAC ,Interpret As Command) 字符。當接收方在一個入數據流中發現 IAC 字符時,它就把后繼的字節處理為一個命令序列。
下面列出了所有的 Telnet NVT 命令。
表1 TELNET 命令
| 名稱 | 編碼 | 說明 |
|---|---|---|
| EOF | 236 | 文件結束符 |
| SUSP | 237 | 掛起當前進程 |
| ABORT | 238 | 中止進程 |
| EOR | 239 | 記錄結束符 |
| SE | 240 | 子選項結束 |
| NOP | 241 | 空操作 |
| DM | 242 | 數據標記 |
| BRK | 243 | 終止符(break) |
| IP | 244 | 終止進程 |
| AO | 245 | 終止輸出 |
| AYT | 246 | 請求應答 |
| EC | 247 | 終止符 |
| EL | 248 | 擦除一行 |
| GA | 249 | 繼續 |
| SB | 250 | 子選項開始 |
| WILL | 251 | 選項協商 |
| WONT | 252 | 選項協商 |
| DO | 253 | 選項協商 |
| DONT | 254 | 選項協商 |
| IAC | 255 | 字符0XFF |
其中常用的TELNET選項協商如下:
- WILL (option code) 251 指示希望開始執行,或者確認現在正在操作指示的選項。
- WON'T (option code) 252 指出拒絕執行或繼續招待所指示的選項。
- DO (option code) 253 指出要求對方執行,或者確認希望對方執行指示的選項。
- DON'T (option code) 254 指出要求對方停止執行,或者確診要求對方停止執行指示的選項。
那么對於接收方和發送方有以下幾種組合:
表2 TELNET 選項協商的六種情況
| 發送者 | 接收者 | 說明 |
|---|---|---|
| WILL | DO | 發送者想激活某選項,接受者接收該選項請求 |
| WILL | DONT | 發送者想激活某選項,接受者拒絕該選項請求 |
| DO | WILL | 發送者希望接收者激活某選項,接受者接受該請求 |
| DO | DONT | 發送者希望接收者激活某選項,接受者拒絕該請求 |
| WONT | DONT | 發送者希望使某選項無效,接受者必須接受該請求 |
| DONT | WONT | 發送者希望對方使某選項無效,接受者必須接受該請求 |
選項協商需要 3 個字節:IAC,然后是 WILL、DO、WONT 或 DONT;最后一個標識字節用來指明操作的選項。常用的選項代碼如下:
表3 TELNET 選項代碼
| 選項標識 | 名稱 | RFC |
|---|---|---|
| 1 | 回應(echo) | 857 |
| 3 | 禁止繼續 | 858 |
| 5 | 狀態 | 859 |
| 6 | 時鍾標識 | 860 |
| 24 | 終端類型 | 1,091 |
| 31 | 窗口大小 | 1,073 |
| 32 | 終端速率 | 1,079 |
| 33 | 遠端流量控制 | 1,372 |
| 34 | 行模式 | 1,184 |
| 36 | 環境變量 | 1,408 |
通常情況下,客戶機向服務器發送字符而服務器將其回顯到用戶的終端上,但是,如果網絡的時延回引起回顯速度太慢,用戶可能更願意讓本地系統回顯字符。在客戶機允許本地系統回顯前,它要向服務器發送以下序列:
IAC DONT ECHO
服務器收到請求后,發出 3 個字符的響應:
IAC WONT ECHO
表示服務器已經按請求同意關閉回顯。
2.3. 子選項協商
除了“打開”或“關閉”以外,有些選項還需要更多的信息,例如對於指明終端類型來說,客戶必須發送一個字符串來標識終端類型,所以要定義子選項協商。
RFC 1091 定義了終端類型的子選項協商。舉個例子:
客戶發送字節序列來請求打開選項:
<IAC, WILL, 24>
24 是終端類型的選項標識符。如果服務器同意該請求,響應為:
<IAC, DO, 24 >
接着服務器發送請求,要客戶給出其終端類型。
<IAC, SB, 24, 1, IAC, SE>
SB 是子選項開始命令,下一個字節24表示該子選項為終端類型選項。下一個字節1表示:發送你的終端類型。客戶的響應為:
<IAC, SB, 24, 0, 'I', 'B', 'M', 'P', 'C', IAC, SE>
第四個字節 0 的含義是“我的終端類型為”。
3. 實現
整個協議軟件分為三個模塊,各模塊的功能如下:
-
與本地用戶的輸入/輸出模塊:處理用戶輸入/輸出;
-
與遠地系統的輸入/輸出模塊:處理與遠程系統輸入/輸出;
-
TELNET 協議模塊:實現 TELNET 協議,維護協議狀態機。
telnet 客戶機要做兩件事:
讀取用戶在鍵盤上鍵入的字符,並通過 tcp 連接把他們發送到遠程服務器上
讀取從 tcp 連接上收到的字符,並顯示在用戶的終端上
參考:
-
《Telnet 協議詳解》:https://www.cnblogs.com/spinsoft/archive/2012/06/27/2566069.html
-
《RFC1073-Telnet窗口尺寸選項中文版》:https://blog.csdn.net/ghj1976/article/details/3438
-
《Java 實現 Telnet》:https://github.com/binarylei/netty/tree/master/netty04
每天用心記錄一點點。內容也許不重要,但習慣很重要!
