web-dev-qa-db-ja.com

UDPを介したnetcatの問題

ここ に記載されている問題のトラブルシューティング中に、私は本当に基本的なものを試しました:UDP経由で非常に基本的なnetcat接続をセットアップしようとしましたが、期待どおりに機能していないことに気付きました。

以下のTCPの図のように、UDPの場合はウィンドウ2に入力したときと同じ出力がウィンドウ1にエコーされると予想しました。代わりに、UDPの場合はウィンドウ1に出力がありません。 。

私は私のラップトップでDebian Jessieを実行しており、次のキャプチャフィルターを使用してWiresharkを実行しています。

udp and not (port 123 or port 5353 or port 1900)

1つのターミナルウィンドウで、次のコマンドを実行してTCPテストを開始しました。

$ nc -l 6900

2番目のターミナルウィンドウで、次のコマンドを実行しました。

$ nc localhost 6900

ウィンドウ2で、「1」と入力してEnterキーを押し、次に「2」と入力してEnterキーを押し、最後にCtrl + Dを押して終了しました。

「one」でEnterキーを押すと、ウィンドウ1に「one」がエコーされます。「two」でEnterキーを押すと、ウィンドウ1に「two」がエコーされます。Ctrl+ Dを押すと、両方のnetcatインスタンスが終了し、戻りました。プロンプトに。

これは、TCP接続を問題なく実行できることを示しています。次に、UDPを試しました。

ウィンドウ1:

$ nc -l -u 6900

ウィンドウ2:

$ nc -u localhost 6900

それはおかしいです。 「1」と入力してEnterキーを押し、次に「2」キーを押してEnterキーを押すと、ウィンドウ2のプロンプトに自動的に戻ります。

ウィンドウ1に、出力が表示されません。

ウィンドウ1で-vを使用して再試行しました。

$ nc -v -l -u 6900
Listening on [0.0.0.0] (family 0, port 6900)

ウィンドウ2で-vを使用して再試行したときはおかしいです。

$ nc -v -u localhost 6900
$

Netcatが実行されなかったようなものです。私はすぐにプロンプ​​トに戻りました。

更新:localhost127.0.0.1に置き換えると、進捗があります。

ウィンドウ1でリッスンする「サーバー」を使用します。

$ nc -v -l -u 6900
one
two
three

「1」、「2」、「3」と入力すると、ウィンドウ2からエコーされた出力を取得できました。

$ nc -u 127.0.0.1 6900
one
two
three
^C

-vは、上記と同じであるため、まだ不可解です。

3
jia103

MacOSを使用して、私は別の結論に達しました。キーはIPv6です。 localhostはIPv6とIPv4の両方に解決されます。ただし、次のコマンドラインでは、ncがIPv4でリッスンします。

nc -l -u 6900

結果:

$ lsof -n -i:6900
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
nc      63923 fuzzy    3u  IPv4 0xad7f669b928a178b      0t0  UDP *:6900

これを使用して「接続」すると、次のようになります。

nc -u localhost 6900

...実際にはIPv6に接続します。 127.0.0.1を使用する場合、使用しません。

ただし、UDPはコネクションレスであるため、接続しません。そのため、接続のリモートエンドが実際に存在するかどうかを知る方法はありません。そのため、IPv4にフォールバックする必要があることを検出できません。メッセージは送信されますが、それらのメッセージをリッスンするものはありません。

送信すると、次のことが確認できます。

$ tcpdump -i lo0 udp port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:46:37.543273 IP6 localhost.54473 > localhost.6900: UDP, length 6

TCPを使用すると、IPv6で接続を試み、これが機能していないと判断して、IPv4で再試行します。

$ tcpdump -i lo0 port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:50:21.495107 IP6 localhost.64306 > localhost.6900: Flags [SEW], seq 1432891337, win 65535, options [mss 16324,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495136 IP6 localhost.6900 > localhost.64306: Flags [R.], seq 0, ack 1432891338, win 0, length 0
00:50:21.495231 IP localhost.64307 > localhost.6900: Flags [S], seq 307818799, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495283 IP localhost.6900 > localhost.64307: Flags [S.], seq 4254625238, ack 307818800, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 766376063,sackOK,eol], length 0
00:50:21.495295 IP localhost.64307 > localhost.6900: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0
00:50:21.495306 IP localhost.6900 > localhost.64307: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0

ncにIPv4の使用を強制できます。

nc -4u localhost 6900
5
Daniel B

tl; dr

最後の結論を参照してください。


前文

結果を説明できます。私はDebianではなくKubuntuを使用していますが、それでも要点は共通していると思います。何が起こるかを完全に理解するには、TCPケースを分析してから、UDPと比較することをお勧めします。

私の研究を再現したい場合は、私がそう言ったり、それ自体で終了したりしない限り、ncを終了したり殺したりしないでください。私が言うとき、ncsを殺します。それは非常に重要です。完全な答えを読んだ後、あなたはこれのポイントを理解するでしょう。

この分析には、複数の端末(またはtmux、またはscreen)が必要です。


TCPケース

最初に、以前のすべてのncプロセスを取り除きます。

killall nc

リスニングプロセスを実行します。

nc -l 6900

lsof -i :6900の出力を調べます。あなたのncはそこでリスニングプロセスとしてリストされています。

接続プロセスを実行します。

nc localhost 6900

lsof -i :6900の出力を調べます。 2つのncsは、established接続の終わりです。

最初のncはもうリッスンしていないので、secondリッスンプロセスを実行できます。

nc -l 6900

および接続プロセス:

nc localhost 6900

ncが実行されているすべてのコンソールに何かを入力します(ヒットすることを忘れないでください) Enter 毎回)。 2つの別々の接続があることがわかります。必要に応じて、3番目のものを確立できます。

lsof -i :6900をもう一度確認してください。 2つの(以前の)リスニングncsは同じポート6900を使用しますが、もう一方の端のncsは異なるため、2つの接続は混在しませんポート。パケットが6900ポートに到着すると、カーネルはこの他のポートをチェックし、(以前の)リスニングncsのどれがそれを受信するかを決定します。

追加の(ペアになっていない)接続ncを実行できます。

nc localhost 6900 || echo fail

そしてそれはすぐに失敗します。

まだ2つの別々の接続が確立されています。すべてのペアの1つのncをで終了します CtrlC または CtrlD また、対応する両端も終了します。これは、TCPがコネクション型であるためです。接続がいずれかの端から正常に終了すると、それに応じて反応できるように、もう一方の端に通知されます。この場合はncただ終了します。


UDPケース

重要:

killall nc

次のコマンドを順番に実行し、それぞれを個別のコンソールで実行します。また、それぞれの後にlsof -i :6900をチェックして、何が起こるかを確認してください。コマンドは次のとおりです。

nc -ul 6900
nc -u localhost 6900

最初に何かを入力します(「リスニング」)nc(ヒット Enter);チェックlsof -i :6900; 2番目のncに何かを入力します(ヒット Enter); lsof -i :6900をもう一度確認して、変更を記録します。

次に、別のペアを(別々のコンソールで)準備します。

nc -ul 6900
nc -u localhost 6900

いくつかの文字列をやり取りして、機能するかどうかを確認します。 1つのncをで終了します CtrlC ((CtrlD 動作しません)、他のnc(対応する端)がまだ実行されていることに注意してください。 「接続」の反対側は、「接続」がいつ「終了」したかを知りません。 lsofで確認できるように、データが流れ始めるまで、「接続」が「確立」されていることがわかりません。

UDPはコネクションレス型であり、これが主な違いであるため、ここでいくつかの単語を引用します。


何が複雑になる可能性がありますか?

これまでのところ、すべてが機能しているはずです。物事がうまくいかなかったときに、以前の結果を説明し始める時が来ました。

重要:

killall nc

「リスニング」を準備するnc

nc -ul 6900

lsof -i :6900を確認してください。出力は次のようになります。

… UDP *:6900

「接続」を準備するnc

nc -u localhost 6900

lsof -i :6900を確認してください。出力例(54766は異なる場合があります):

… UDP *:6900
… UDP localhost:54766->localhost:6900

2番目のncから最初のncにデータを渡します。 lsof -i :6900を確認してください:

… UDP localhost:6900->localhost:54766
… UDP localhost:54766->localhost:6900

2番目のncを CtrlC。もう一度lsof -i :6900

… UDP localhost:6900->localhost:54766

つまり、最初のncは、「接続」の反対側のポート54766にのみ「通信」します。 3番目のncに接続しようとすると:

nc -u localhost 6900

おそらく、その側で別のランダムなポートを選択します。それを試してみてください。このncが終了する前に、質問で行ったのと同じように、(約)2行を「渡す」ことができます。

(注:このwiresharkはICMPパケットが原因で終了します。 this を参照してください。lsofでパケットをキャプチャすることができます。)

ただし、適切なポートを強制することができます(nc出力に合わせて54766を変更してください)。

nc -up 54766 localhost 6900

そして、この4番目のncはデータを渡すことができます!最初のncでは違いはわかりません。 2番目のncが決して終了されなかったかのようになります。

続行する前に、4番目のncを終了します。最初のものを実行したままにします。


-vオプション

最後の謎は、なぜnc -v -u localhost 6900がすぐに終了したのか?

上記の例では、4つのXsがありました。

  1. 最初の–「聞く」もの;
  2. 2番目–正常に接続され、その後終了しました。
  3. 3番目–間違ったローカルポートのために接続できません。
  4. 4番目–正しい(強制)ローカルポートのおかげで接続できます。

私のKubuntunc -uv …では、2番目の場合、おそらく接続をプローブするために、いくつかのnc文字を送信します。このため、それが3番目の場合、(約)2行の外部入力が失敗する必要はなく、すぐに失敗します。 最初のncがまだ実行されている場合は、次を試してください:

nc -uv localhost 6900

失敗するはずです。繰り返しますが、適切なポートを強制することができ、上記の例の4番目Xのように機能します。

nc -uvp 54766 localhost 6900

これを呼び出すと、最初のncのコンソールにnc- sが出力されているのがわかります。


クリーニング

killall nc

結論

あなたが持っていたように見えます( "listening")ncこれはすでに「接続」の反対側の特定のポートに関連付けられていました。 else)少なくとも1つのパケットを正常に送信した。他のncsが、他のポートを使用しようとしたため、この最初のポートと通信できませんでした。

localhost127.0.0.1に置き換えると、進捗があります

無関係です。この場合、killall ncの後で行ったように、クリーンに始めたばかりだと思います。

4