2024/02/15 Telnetを実装する
Telnetは、オプションという仕組みの上にある
TCP/IPのうえにNVTの仕組みさえ提供できれば、自由にメッセージを送り合える
⇒ TCP/IPサーバを立てて、ターミナルの機能に必要なオプションを一つ一つ実装していこう
✅ TCP/IPサーバを実装する
BSDソケットで書いた
✅ コマンドのパーサを作ろう
t6o_o6t.icon
1バイトずつ読んでいくことにする
whileで固定長読みだすようにしていたが・・
Subnegotiationを実装するなら、必要なバイト数だけ読みだすほうが良さそう
たとえば、0xffが来たら2バイト(または1バイト2回)読みだすと良さそう?
IaC(0xff)が来たら、次はコマンドをexpectする
input = IaC (DO | WILL | DONT | WONT) Option | IaC SB Option Any SE | ...
✅ Negotiationシステムを実装しよう(すべて拒否する)
まずは、クライアントからのすべてのDO要求にWONTを返却してみよう
今後は、オプションが実装できたら、WILLを返すようにしていく
https://scrapbox.io/files/65cddad2a471230023322828.png
PuTTYのWindow枠を右クリックしてメニューから開ける
今はリモートエコーの実装をしていないので、「Force off」にすると、入力しても反応がありません
裏でBufferには入力内容がたまっているので、Enterを押すとサーバ側から入力内容を確認できるはずです。
✅ terminal_speed オプションを実装しよう
WILLとDOは排反なコマンドではないことに気づいたt6o_o6t.icon
RFC854だけでは、コマンドの意味が分かりにくいt6o_o6t.icon
実際に、各オプションのRFCにある「Command meanings」を読んでみると分かってくる
WILLは、主に情報を「送信したい」という意志をホストが表明するときに使われる。
DOは、情報を「受信したい」(相手の情報を受け入れたい)という意志をホストが表明するときに使われる。
例
WILLのterminal_speedは、コマンド送信元のホストがterminal_speedの送信を希望することを表す。
DOのnawsは、コマンド送信元のホストが、相手のホストからのnawsの受信を希望することを表す。
WILLに対する応答がDO/DONTで、DOに対する応答がWILL/WONTなのも、上のように理解すれば妥当と感じられる。
相手ホストは、送信するかしないかを表明することでこれに応答する。
⇒ 「送信したい」意志の表明にはWILL/WONTを用いる。
terminal_speedを要求するのは基本的にクライアント
RFC1079からは、クライアントが、自分のターミナルの表示速度を知らせることで表示に役立てることを目的にしていると読み取れる ⇒ とりあえず、terminal_speedを受け取れるようにしてみる
RFC1079にあるように、IAC SB TERMINAL-SPEED SEND IAC SEでこちらから要求する必要がある 受信の実装は、NVT ASCIIで表現される文字列を取得する
terminal_speedやterminal_typeは、受け付けるように実装するだけでは意味がない?
実際にそれを必要とするターミナルアプリケーションに渡すところまでがセットではないだろうか
どのようにアプリケーションにこれを伝えれば良いのかが分からない
□ terminal_type オプションを実装しよう
✅ window_size オプションを実装しよう
何かを間違っているらしく、terminal_speedをDO応答したつもりが、nawsが送られてきているt6o_o6t.icon
Wiresharkで確認したところ、Negotiationの応答が誤っていることが分かった nawsの値を解釈する実装はできた
Negotiationの実装ミス
なぜか、パケット受信前のbuf[1]の値をresponseに使用していたので修正
一度は違和感を持っていたが、誤りに気づけなかったt6o_o6t.icon
修正によって、正しく
□ echo オプションを実装しよう
echoは、単に入出力を渡せば良い
RFC857によれば、echoオプションを設定するだけでは意味がない □ bashを使えるようにしよう
方法が思いつかない.
必要なこと
サーバーは相手からの入力を受け取るので、/bin/bashにその内容を渡す
ここで、/bin/bashは都度実行されるのではなく、別プロセスで実行されていなければならない
/bin/bashの出力を受け取って、サーバーから相手に出力する
a. パイプを使う案
$ ./server | /bin/bash | ./
?
□ RFC854の記述を100%カバーしよう
✅ 7ビットのUSASCIIに関しては、入力をunsigned charで扱えば十分。
□ サーバー側の処理が完了 ⇒ 入力待機状態に切り替わったとき、GAコマンドを送信しよう
□ 割り込みプロセスを実装しよう
□ Ctrl+Cで中止できることを確認しよう
□ AYT信号を実装しよう
□ 「THE NVT PRINTER AND KEYBOARD」セクションで示されているコードが動作することを確認しよう
書かれていないコードが動作しないことも確認しましょう