0

シリアル デバイス サーバー上の組み込み Linux システム用の C のアプリケーションに取り組んでいます。Telnetで接続できるシステム独自のシェルにアクセスする必要があり、シェルプロンプトで実行できるカスタムコマンドラインインターフェイスコマンドがたくさんあります。

デバイスのメーカーで働くエンジニアは、これらのコマンド ライン インターフェイス コマンドをプログラムで発行する唯一の方法は、シェルにログインする telnet クライアントを経由することだと述べました。

したがって、アプリケーション内で、デバイス サーバー telnet を自分自身に接続して、シェル経由で自分自身にいくつかのコマンドを発行できるようにしたいと考えています。C の実装を行う前に、まず IRB 経由でソケットを開き、コマンドをそのように機能させることを試みることにしました。実際の telnet セッションは次のようになります。

login: admin
password: password

prompt# set watchdog off
prompt# save
Save config to flash ROM y/n
y    

以下は、IRB で実行している単純なスクリプトで、TCP ソケットを介して上記の telnet セッションをエミュレートできるかどうかを確認します。これは、Linux の C で実装する方法だからです。

require 'socket'
@ip = 'xxx.xxx.xxx.xxx'
@enter = "\n"
@sock = TCPSocket.open(@ip,23)
@ret = @sock.write("admin" + @enter)
puts @ret.to_s
sleep(1)      
@ret = @sock.write("password" + @enter)
puts @ret.to_s
puts @sock.read(1)
sleep(2)
@ret = @sock.write("set watchdog off" + @enter)
puts @ret.to_s
puts @sock.read(1)
sleep(1)
@ret = @sock.write("save" + @enter)
puts @ret.to_s
puts @sock.read(1)
sleep(1)
@ret = @sock.write("y")
puts @ret.to_s
puts @sock.read(1)
sleep(1)

@sock.close

C でのソケットのオープン、ソケットへの書き込み、およびソケットからの読み取りは、私にとっては問題ありません。アプリケーションですでに多くのことを行っているため、これらのことを実行するための簡単な機能が既に用意されています。私の質問は、エミュレートするためにソケットにどの文字列を書き込む必要があるかということです。たとえば、プロンプトで何かを入力した後にエンターキーを押すとしますか? 「\n」または「\x0a」が機能していませんでした。または、この方法を簡単にするLinux Cライブラリを使用できますか?

4

2 に答える 2

3

もちろん、telnet プロトコルを読むこともできますが、以下のリンクの下部にある回答を確認してください。これには、WireShark を使用して実際に何がやり取りされているかを確認することが含まれます。

http://www.codeproject.com/Questions/147555/Telnet-client-using-TCP

パケット スニファを使用したことがない場合は、非常に啓発的です (私にとってはそうでした)。TCP ソケット接続を介して telnet を実行するための手順は次のとおりです。

(1) 上記のリンクの指示に従って、ネットワーク上のトラフィックをキャプチャし、目的のアプリケーション/スクリプトで最終的に実行するコマンドを正確に実行し、telnet 接続の作成から開始して終了します。

(2) セッションのキャプチャを停止した後、ネットワーク上で同時に発生していた他の多くのトラフィックがキャプチャに表示される場合があるため、ip.addr == xxx.xxx.xxx.xxx でそれを除外します。もちろん、リモートコンピューターのIPアドレスを使用します

(3) 自分のコンピューターとリモート コンピューターの間を行き来するすべてのものを見ると、アプリケーションがメッセージごとに通信のさまざまなレイヤーをどのように分離しているかがわかります。プロトコル「Telnet」を使用したメッセージに特に注意を払う必要があります。これは、それが最上位層であることを意味します。WireShark ウィンドウの一番上のペインでメッセージを強調表示すると、下の 2 番目のペインに、そのメッセージがどのように異なるレイヤーに分割されているかが表示されます。その 2 番目のペインで、たとえば Telnet レイヤーを強調表示すると、下の 3 番目のペインで、telnet プロトコルを実装するメッセージのバイトがどのように強調表示されるかがわかります。時間をかけて、やり取りされるメッセージを分析してください。より直接的に見ることができ、

(4) あとは、アプリケーションで Wireshark で確認できる通信を基本的にエミュレートするだけです。アプリケーションで TCP ソケットを開いているので、アプリケーションがすべての TCP およびダウン通信を舞台裏で処理していることを思い出してください。そのため、TCP ソケットへの telnet バイト/データ/コマンドの読み取り/書き込みについてのみ心配する必要があります。 .

この方法はまったく時間がかからず、システムに余分なものを必要としません。これは、システム リソースが限られているデバイス、非常に単純な OS のデバイス、または OS がまったくないデバイスを扱っている場合に最適です。たとえば、私のデバイスのミニ Linux システムには、Expect がまだインストールされておらず、一般的なものを簡単にインストールする方法もありません。私はそれができることを意味しますが、私たちはここで本当に厄介なことを話している. また、ボックスに物をインストールするのにそれほどクレイジーではない方法があったとしても、私はすでに50個のこれらをフィールドに持っており、サーバーに置いた新しいバイナリに自動更新するように設定していますが、彼らは期待していませんサーバーからスクリプトもダウンロードする必要があります。また、そのスクリプトを実行できる OS がインストールされていません。したがって、ここでは比較的低レベルのことを話しているので、シンプルに保つことはオプションではなく要件です。シリアル デバイス サーバーを自分自身に telnet させ (独自のコマンド ライン インターフェイスにアクセスする唯一の方法です。これはメーカーの選択です)、必要なコマンドを自分自身に発行させる最終的な C 関数は次のようになります。

turnoff_watchdog
{
  // telnetsock, TCP socket to 127.0.0.1 at port 23, has already been set previously

  char negotiation_1[] = {0xFF,0xFC,0X18,0xFF,0xFC,0x20,0xFF,0xFC,0x23,0xFF,0xFC,0x27,0xFF,0xFD,0x03};
  char negotiation_2[] = {0xFF,0xFC,0x01,0xFF,0xFC,0x1F,0xFF,0xFE,0x05,0xFF,0xFB,0x21};
  char telnet_login_name[] = "admin\r\n";
  char telnet_login_password[] = "password\r\n";
  char set_command[] = "set watchdog off\r\n";
  char save_command[] = "save\r\n";
  char confirm[] = "y\n";
  char escape[] = {0x5E,0x5D,0x0A}; // ^]
  char quit[] = "quit\n";

  sleep(2);
  write(telnetsock,&negotiation_1[0],15);
  sleep(2);
  write(telnetsock,&negotiation_2[0],12);
  sleep(2);
  write(telnetsock,&telnet_login_name[0],7);
  sleep(2);
  write(telnetsock,&telnet_login_password[0],10);
  sleep(2);
  write(telnetsock,&set_command[0],18);
  sleep(2);
  write(telnetsock,&save_command[0],6);
  sleep(2);
  write(telnetsock,&confirm[0],2);
  sleep(2);
  write(telnetsock,&escape[0],3);
  sleep(2);
  write(telnetsock,&quit[0],5);
  sleep(2);

  return(0);
}

そのような単純な。これの最も困難な部分は、元の (Wireshark を使用してキャプチャしたもの) telnet ネゴシエーションがかなり長かったことですが、ネゴシエーションされていたオプションを見た後、ほとんど必要ないことに気付きました。それが大幅にダウン。ところで、バイトを見て怖がっている方は、気にしないでください。大したことじゃないよ。あなたはどのようにnegotiation_1そしてnegotiation_2上記では、0xFF が 3 バイトごとにポップアップし続けますか? これら 2 つのネゴシエーションはすべて、0xFF で始まる長さ 3 バイトのコマンド/ネゴシエーションの文字列であり、telnet セッション中に何を実行し、何を実行しないかを通信しようとします。そして、3 バイトの各チャンクの 2 番目のバイト (0xFB、0xFC、0xFD、または 0xFE のいずれか) は、自分が何かを行うか行わないか、または相手に何かを行うか行わないかを伝えるだけです。最後のバイトは、それぞれがやりたいかやりたくないか、やるかやらないかのオプションです。すべてがどのように分解されるかは、Wireshark で確認できます。それは実際にはかなり面白い言語です。私はしませんでした ネゴシエーションへの応答を確認するためにソケットを読んでいた最初の行を含めます (irb で非常に簡単に実行できたので、Ruby ですべてのテストと作業を行いました) が、それを行う必要があります。基本的には、ログイン プロンプトが表示されるまで交渉をできるだけ少なくするだけです。ソケットに書き込む最初のネゴシエーションを決定するためのテストでは、ソケットを開くときに、最初に送信された telnet 制御シーケンスを読み込むことを確認してください。次に、それらのシーケンスにのみ応答する必要があります。ほとんどの場合、ネゴシエーションの量を減らすために否定的です。楽しむ!ソケットに書き込む最初のネゴシエーションを決定するためのテストでは、ソケットを開くときに、最初に送信された telnet 制御シーケンスを読み込むことを確認してください。次に、それらのシーケンスにのみ応答する必要があります。ほとんどの場合、ネゴシエーションの量を減らすために否定的です。楽しむ!ソケットに書き込む最初のネゴシエーションを決定するためのテストでは、ソケットを開くときに、最初に送信された telnet 制御シーケンスを読み込むことを確認してください。次に、それらのシーケンスにのみ応答する必要があります。ほとんどの場合、ネゴシエーションの量を減らすために否定的です。楽しむ!

于 2012-10-02T14:28:10.723 に答える
0

Cの質問をしますが、スクリプトを投稿します。telnetがどのように機能するかを知りたい場合は、RFCを読んでください。この場合854

https://www.rfc-editor.org/rfc/rfc854

于 2012-10-02T03:05:34.577 に答える