Probleme mit netcat über UDP

2211
jia103

Bei der Fehlerbehebung für das hier beschriebene Problem habe ich etwas wirklich grundlegendes ausprobiert: Ich habe versucht, eine sehr einfache Netcat-Verbindung über UDP einzurichten, und ich habe festgestellt, dass es nicht wie erwartet funktioniert.

Wie bei der TCP-Abbildung unten erwartete ich, dass der UDP-Fall dieselbe Ausgabe in Fenster 1 wiedergibt, wie ich sie in Fenster 2 eingebe. Stattdessen bekomme ich im UDP-Fall keine Ausgabe in Fenster 1.

Ich verwende Debian Jessie auf meinem Laptop, und ich habe Wireshark mit dem folgenden Erfassungsfilter ausgeführt:

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

In einem Terminalfenster begann ich mit einem TCP-Test, indem ich den folgenden Befehl ausführte:

$ nc -l 6900 

In einem zweiten Terminalfenster habe ich Folgendes ausgeführt:

$ nc localhost 6900 

In Fenster 2 habe ich "Eins" eingegeben und die Eingabetaste gedrückt, dann habe ich "Zwei" eingegeben und die Eingabetaste gedrückt, und schließlich habe ich zum Verlassen Strg + D gedrückt.

Nachdem Sie auf "Eins" die Eingabetaste gedrückt hatten, sah ich in Fenster 1 "Eins". Nachdem Sie auf "Zwei" die Eingabetaste gedrückt hatte, sah ich in Fenster 1 "Zwei". Wenn ich Strg + D drückte, wurden beide Netcat-Instanzen beendet und ich kehrte zurück auf die Aufforderung.

Dies zeigt, dass ich eine TCP-Verbindung ohne Probleme herstellen konnte. Als nächstes versuchte ich UDP.

Fenster 1:

$ nc -l -u 6900 

Fenster 2:

$ nc -u localhost 6900 

Es ist lustig. Ich glaube, ich könnte nur "Eins" eingeben, die Eingabetaste drücken, dann "Zwei" und dann die Eingabetaste. Ich kehrte automatisch zur Eingabeaufforderung in Fenster 2 zurück.

In Fenster 1 sehe ich keine Ausgabe.

Ich habe es erneut -vin Fenster 1 versucht :

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

Komisch, wenn ich -vin Fenster 2 einen erneuten Versuch unternahm :

$ nc -v -u localhost 6900 $ 

Es ist, als ob Netcat nie gelaufen ist. Ich kehrte sofort zur Aufforderung zurück.

Aktualisieren: Wenn ich ersetzen localhostmit 127.0.0.1, es läuft.

Wenn der "Server" in Fenster 1 überwacht wird:

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

Bei Eingabe von "eins", "zwei" und "drei" konnte ich eine Ausgabe von Fenster 2 erhalten:

$ nc -u 127.0.0.1 6900 one two three ^C 

Das -vist immer noch rätselhaft, weil es das gleiche wie oben ist.

2

2 Antworten auf die Frage

4
Kamil Maciorowski

tl; dr

Siehe Schlussfolgerungen ganz am Ende.


Präambel

Ich kann deine Ergebnisse erklären. Ich benutze Kubuntu, nicht Debian, dennoch glaube ich, dass die Hauptpunkte allgemein sind. Um zu verstehen, was passiert, ist es gut, den TCP-Fall zu analysieren und dann mit UDP zu vergleichen.

Wenn Sie meine Forschung replizieren möchten, beenden Sie den Vorgang nicht, oder töten Sie ihn ncnicht, es sei denn, ich sage das oder es endet von selbst. Töte ncs, wenn ich sage. Es ist sehr wichtig. Nachdem Sie die vollständige Antwort gelesen haben, werden Sie den Punkt verstehen.

Diese Analyse erfordert mehrere Terminals (oder tmux, oder screen).


TCP-Fall

Beseitigen Sie zunächst alle bisherigen ncProzesse.

killall nc 

Einen Abhörprozess ausführen:

nc -l 6900 

Untersuchen Sie die Ausgabe von lsof -i :6900. Ihr ncwird dort als Abhörvorgang aufgeführt.

Führen Sie einen Verbindungsprozess aus:

nc localhost 6900 

Untersuchen Sie die Ausgabe von lsof -i :6900. Die beiden ncs sind die Enden der aufgebauten Verbindung.

Da Ihr erster ncnicht mehr hört, können Sie einen zweiten Hörprozess ausführen :

nc -l 6900 

und ein zweiter Verbindungsprozess:

nc localhost 6900 

Geben Sie etwas in jede Konsole ein, auf der es ncläuft (vergessen Sie nicht, Enterjedes Mal einen Treffer zu treffen ). Sie werden feststellen, dass es zwei getrennte Verbindungen gibt. Sie können eine dritte einrichten, wenn Sie möchten.

Überprüfen Sie noch lsof -i :6900einmal. Obwohl die beiden (früher) zuhörenden ncs denselben Port verwenden 6900, mischen sich die beiden Verbindungen nicht, da ncs an den anderen Enden unterschiedliche Ports verwenden. Wenn ein Paket an den 6900Port kommt, überprüft der Kernel diesen anderen Port und entscheidet, welche der (früher) hörenden ncs es empfangen sollen.

Sie können zusätzliche (ungepaarte) Verbindungen herstellen nc:

nc localhost 6900 || echo fail 

und es wird sofort scheitern.

Sie haben noch zwei getrennte Verbindungen. Beenden Sie eines ncvon jedem Paar mit Ctrl+ Coder Ctrl+ Dund Sie werden feststellen, dass die entsprechenden Enden ebenfalls enden. Dies liegt daran, dass TCP verbindungsorientiert ist. Wenn eine Verbindung von einem ihrer Enden aus ordnungsgemäß beendet wird, wird das andere Ende benachrichtigt, damit es entsprechend reagieren kann - in diesem Fall wird es nceinfach beendet.


UDP-Fall

Wichtig:

killall nc 

Führen Sie die folgenden Befehle nacheinander aus, und zwar jeweils in einer separaten Konsole. Überprüfen Sie auch lsof -i :6900nach jedem, was passiert. Die Befehle sind:

nc -ul 6900 nc -u localhost 6900 

Geben Sie etwas in das erste ein ("Hören") nc(Treffer Enter); überprüfen lsof -i :6900; tippe etwas in den zweiten nc(hit Enter); überprüfen Sie noch lsof -i :6900einmal und beachten Sie die Änderung.

Bereiten Sie dann ein anderes Paar vor (in separaten Konsolen):

nc -ul 6900 nc -u localhost 6900 

Führen Sie einige Zeichenketten hin und her, um zu sehen, ob es funktioniert. Beenden Sie einen ncmit Ctrl+ C( Ctrl+ Dfunktioniert nicht) und beachten Sie, dass der andere nc(am entsprechenden Ende) noch läuft. Die andere Seite der "Verbindung" weiß nicht, wann die "Verbindung" "beendet" ist. Wie Sie sehen konnten lsof, weiß es nicht, dass die "Verbindung" "hergestellt" ist, bis die Daten zu fließen beginnen.

Ich zitiere hier einige Worte, weil UDP verbindungslos ist und das der Hauptunterschied ist.


Was kann kompliziert werden?

Bisher sollte alles geklappt haben. Es ist an der Zeit, Ihre vorherigen Ergebnisse zu erklären, wenn die Dinge nicht funktionierten.

Wichtig:

killall nc 

Bereiten Sie ein "Hören" vor nc:

nc -ul 6900 

Überprüfen lsof -i :6900. Die Ausgabe wird wie folgt aussehen:

… UDP *:6900 

Bereiten Sie eine "Verbindung" vor nc:

nc -u localhost 6900 

Überprüfen lsof -i :6900. Beispielausgabe (Sie 54766können variieren):

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

Übergeben Sie einige Daten von der zweiten nczur ersten. Überprüfen lsof -i :6900:

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

Beenden Sie die Sekunde ncmit Ctrl+ C. Wieder lsof -i :6900:

… UDP localhost:6900->localhost:54766 

Dies bedeutet, dass die ersten nc"Gespräche" nur mit dem Port 54766am anderen Ende der "Verbindung" erfolgen. Wenn Sie versuchen, sich mit einem Dritten zu verbinden nc:

nc -u localhost 6900 

Es würde höchstwahrscheinlich einen anderen zufälligen Port auf seiner Seite wählen. Versuch es. Sie können (ungefähr) zwei Zeilen "übergeben", genau wie Sie es in Ihrer Frage getan haben, bevor diese ncbeendet wird.

(Hinweis: Dieser ncVorgang wird aufgrund eines ICMP-Pakets abgebrochen, siehe hierzu ; Sie können das Paket so aufnehmen wiresharkwie ich.)

Sie können jedoch den richtigen Port erzwingen (ändern 54766, um sich an Ihre lsofAusgabe anzupassen):

nc -up 54766 localhost 6900 

und dieser vierte ncwird in der Lage sein, Daten zu übergeben! Der erste ncwird den Unterschied nicht sehen. Es wird so sein, als ob der zweite ncnie beendet wurde.

Beenden Sie die vierte, ncbevor Sie fortfahren. Lass den ersten laufen.


Die -vOption

Das letzte Rätsel ist: Warum wurde es nc -v -u localhost 6900sofort beendet?

Im obigen Beispiel hatten wir vier ncs:

  1. der erste - "Zuhören";
  2. der zweite - erfolgreich verbunden, dann beendet;
  3. der dritte - kann aufgrund eines falschen lokalen Ports keine Verbindung herstellen;
  4. der vierte - kann dank rechtem (erzwungenem) lokalem Port eine Verbindung herstellen.

In meinem Kubuntu überträgt nc -uv …, wenn es der zweite ist, nur wenige XZeichen, wahrscheinlich um die Verbindung zu prüfen. Wenn es sich um die dritte handelt, müssen nicht (ungefähr) zwei Zeilen externer Eingänge ausfallen, sondern sofort. Wenn die erste nc noch läuft, versuchen Sie Folgendes:

nc -uv localhost 6900 

Es sollte scheitern Sie können auch hier den richtigen Port erzwingen, und er funktioniert genauso wie der vierte nc im obigen Beispiel.

nc -uvp 54766 localhost 6900 

Wenn ich das anrufe, sehe ich X-s in der Konsole der ersten nc .


Reinigung

killall nc 

Schlussfolgerungen

Mir scheint, Sie hatten (das "Hören"), ncdas bereits mit einem bestimmten Port auf der anderen Seite der "Verbindung" verbunden war, ganz sicher, weil ein anderer nc(oder etwas anderes) mindestens ein Paket erfolgreich übertragen hatte. Ihre anderen ncs haben versucht, andere Ports auf ihrer Seite zu verwenden und konnten nicht mit diesem ersten kommunizieren.

Wenn ich ersetzen localhostmit 127.0.0.1, gibt es Fortschritte

Irrelevant. Ich denke, in diesem Fall haben Sie gerade mit dem Saubermachen begonnen, wie wir es später getan haben killall nc.

Diese Antwort liefert ausgezeichnete Details, und ich konnte sie den ganzen Weg verfolgen. Ich musste jedoch viele der 'nc'-Befehle ändern, um zusätzlich' -4 'pro Antwort von Daniel anzugeben. jia103 vor 7 Jahren 0
3
Daniel B

Mit macOS komme ich zu einer anderen Schlussfolgerung. Der Schlüssel ist IPv6. localhostwird sowohl in IPv6 als auch in IPv4 aufgelöst. Die folgende Befehlszeile führt jedoch dazu nc, dass IPv4 überwacht wird:

nc -l -u 6900 

Das Ergebnis:

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

Wenn Sie dies jetzt zum Verbinden verwenden:

nc -u localhost 6900 

... verbindet sich tatsächlich mit IPv6. Wenn Sie 127.0.0.1es nicht verwenden.

Es wird jedoch keine Verbindung hergestellt, da UDP verbindungslos ist. Daher gibt es keine Möglichkeit zu wissen, ob das entfernte Ende der Verbindung wirklich existiert. Daher kann es nicht erkennen, dass es auf IPv4 zurückgreifen sollte. Ihre Nachrichten werden gesendet, aber diese Nachrichten werden nicht abgehört.

Beim Senden ist folgendes zu beachten:

$ 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 

Bei TCP wird versucht, eine Verbindung mit IPv6 herzustellen, festzustellen, dass dies nicht funktioniert, und mit IPv4 erneut zu versuchen:

$ 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 

Sie können ncdie Verwendung von IPv4 erzwingen :

nc -4u localhost 6900