Manuelles Schließen eines Ports über die Befehlszeile


112

Ich möchte einen offenen Port schließen, der sich im Empfangsmodus zwischen meiner Client- und Serveranwendung befindet.

Gibt es eine manuelle Befehlszeilenoption in Linux, um einen Port zu schließen?

HINWEIS: Ich habe erfahren, dass "nur die Anwendung, die den verbundenen Socket besitzt, diesen schließen sollte, was passieren wird, wenn die Anwendung beendet wird."

Ich verstehe nicht, warum es nur durch die Anwendung möglich ist, die es öffnet ... Aber ich bin immer noch gespannt, ob es eine andere Möglichkeit gibt, dies zu tun.


5
Nein, geöffnete Ports gehören zu dem Prozess, der sie geöffnet hat, eine Kontrolle von außen ist nicht möglich. Was eine gute Sache ist, oder alle Anwendungen müssten damit rechnen, dass ihre offenen Ports (und Dateien) durcheinander gebracht werden. Sie können jedoch den Datenverkehr zu einem Port durch Firewalling (iptables) blockieren. Dadurch wird der Port jedoch nicht geschlossen und für andere Zwecke freigegeben.
Jürgen Strobel

10
Viele Antwortende haben den Punkt dieser Frage verpasst. Es ist Unsinn zu erklären, dass nur die Anwendung, die den Port besitzt, die Verbindung trennen kann. Ich kann die Verbindung trennen, indem ich zur Box gehe und das Ethernet-Kabel aus der Steckdose ziehe oder die Anwendung am anderen Ende der Verbindung beende! Die Anwendung muss dafür geschrieben werden. Wie können Sie also testen, ob die Anwendung ordnungsgemäß geschrieben ist, ohne dass ein physischer Eingriff und / oder die Steuerung des anderen Computers erforderlich ist?
Dale Wilson

"... von außen ist keine Kontrolle möglich." Das ist eine wichtige Bemerkung, die mich zur nächsten Frage geführt hat: Wie kann ich von außen Teil des Prozesses sein? GDB.
Dankó Dávid

@ JürgenStrobel Es ist zwar eine Kontrolle von außen möglich - sowohl tcpkill als auch ss können genau das tun, was gewünscht wird. Weil geöffnete Ports nicht wirklich zu einem Prozess gehören. Es handelt sich um Kernelressourcen, denen einige Rechte für einen Prozess zugewiesen wurden, die jedoch nur nach Belieben des Kernels vorhanden sind.
Tom Anderson

@ tom-anderson DaleW: tcpkill ist ein Firewall-Tool, und ich habe diese Option erwähnt. Sie können den Datenverkehr zu einem Port verhindern, der sich vom Schließen eines Ports (Sockets) unterscheidet.
Jürgen Strobel

Antworten:


134

Ich hatte das gleiche Problem, der Prozess muss am Leben bleiben, aber der Socket muss schließen. Das Schließen eines Sockets in einem laufenden Prozess ist nicht unmöglich, aber schwierig:

  1. Suchen Sie den Prozess:

    netstat -np
    

    Sie erhalten eine source/destination ip:port portstate pid/processnameKarte

  2. Suchen Sie dabei den Dateideskriptor des Sockets

    lsof -np $pid
    

    Sie erhalten eine Liste: Prozessname, PID, Benutzer, FileDescriptor, ... eine Verbindungszeichenfolge.

    Suchen Sie die passende fileDescriptor-Nummer für die Verbindung. Es wird so etwas wie "97u" sein, was "97" bedeutet.

  3. Verbinden Sie nun den Prozess:

    gdb -p $pid
    
  4. Schließen Sie nun die Steckdose:

    call close($fileDescriptor) //does not need ; at end.
    

    Beispiel:

    call close(97)
    

    Dann trennen Sie gdb:

    quit
    

    Und die Steckdose ist geschlossen.


1
sudo lsof -np $pidGibt mir ungefähr 200 Zeilen und ich bin verwirrt darüber, wie ich den gewünschten FD finde. In meinem Fall handelt es sich um einen Chrome-Tab, und ich versuche, geöffnete Websockets zu schließen ...
SET

2
Eine Reihe sieht typischerweise wie: firefox 14812 szupervigyor 97U IPv4 32.814.564 0T0 TCP 192.168.2.4:40385->173.194.39.65:https (gegründet) als: process_name pid Benutzer fd [opened_for] Protokolleinrichtung inode protocol_data_toString
Dankó Dávid

2
* Eine Zeile sieht normalerweise so aus: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) als: process_name pid user fd [opens_for] protocol device inode protocol_data_toString Sie müssen den remote-ipode kennen Adresse und finden Sie auf der letzten Spalte. In meinem Beispiel ist die 97 der FileDescriptor. Das Suchen ist schwierig, wenn Sie mehrere Verbindungen zum Zielhost hergestellt haben.
Dankó Dávid

7
Dies ist eine brillante Lösung
Marcorossi

8
Wenn Sie mit dem entfernten Ende simulieren wollen geschlossen , um die Buchse wird (zB Peer Verlassen) , ist es besser zu nutzen shutdown: call shutdown($fileDescriptor, 0).
Ecatmur

75

Sie stellen hier die falsche Frage. Es ist nicht wirklich möglich, einen Port einfach von außerhalb der Anwendung zu "schließen", die den Socket geöffnet hat, der ihn abhört. Die einzige Möglichkeit, dies zu tun, besteht darin, den Prozess, dem der Port gehört, vollständig zu beenden. In ein oder zwei Minuten ist der Port dann wieder verfügbar. Hier ist, was los ist (wenn es Ihnen egal ist, fahren Sie mit dem Ende fort, wo ich Ihnen zeige, wie Sie den Prozess beenden, der einen bestimmten Port besitzt):

Ports sind Ressourcen, die vom Betriebssystem verschiedenen Prozessen zugewiesen werden. Dies ähnelt dem Auffordern des Betriebssystems nach einem Dateizeiger. Im Gegensatz zu Dateizeigern kann jedoch immer nur EIN Prozess einen Port besitzen. Über die BSD-Socket-Schnittstelle können Prozesse anfordern, einen Port abzuhören, den das Betriebssystem dann gewährt. Das Betriebssystem stellt außerdem sicher, dass kein anderer Prozess denselben Port erhält. Zu jedem Zeitpunkt kann der Prozess den Port freigeben, indem der Socket geschlossen wird. Das Betriebssystem fordert dann den Port zurück. Wenn der Vorgang beendet wird, ohne den Port freizugeben, wird das Betriebssystem den Port schließlich zurückfordern (obwohl dies nicht sofort geschieht: es dauert einige Minuten).

Was Sie jetzt tun möchten (einfach den Port von der Kommandozeile aus schließen), ist aus zwei Gründen nicht möglich. Erstens, wenn es möglich wäre, würde dies bedeuten, dass ein Prozess einfach die Ressource eines anderen Prozesses (den Port) stehlen könnte. Dies wäre eine schlechte Richtlinie, sofern sie nicht auf privilegierte Prozesse beschränkt ist. Der zweite Grund ist, dass unklar ist, was mit dem Prozess geschehen würde, dem der Port gehört, wenn wir ihn weiter laufen lassen. Der Code des Prozesses wird unter der Annahme geschrieben, dass er Eigentümer dieser Ressource ist. Wenn wir es einfach wegnehmen würden, würde es von alleine abstürzen, daher lassen die Betriebssysteme Sie dies nicht zu, selbst wenn Sie ein privilegierter Prozess sind. Stattdessen musst du sie einfach töten.

Wie auch immer, hier erfahren Sie, wie Sie einen Prozess beenden, der einen bestimmten Port besitzt:

sudo netstat -ap | grep :<port_number>

Das wird die Zeile ausgeben, die dem Prozesshalteport entspricht, zum Beispiel:

tcp  0  0 *:8000   *:* LISTEN  4683/procHoldingPort

In diesem Fall ist procHoldingPort der Name des Prozesses, der den Port geöffnet hat, 4683 die PID und 8000 (beachten Sie, dass es sich um TCP handelt) die Portnummer, die er enthält.

Dann schauen Sie in die letzte Spalte und Sie werden / sehen. Führen Sie dann Folgendes aus:

kill  <pid>

Wenn dies nicht funktioniert (Sie können dies überprüfen, indem Sie den Befehl netstat erneut ausführen). Mach das:

kill -9 <pid>

Im Allgemeinen ist es besser, das Senden von SIGKILL zu vermeiden, wenn Sie können. Deshalb sage ich dir, dass du es killvorher versuchen sollst kill -9. Nur mit killSendet der schonendere SIGTERM.

Wie gesagt, es wird noch einige Minuten dauern, bis der Hafen wieder geöffnet ist, wenn Sie dies tun. Ich weiß nicht, wie ich das beschleunigen kann. Wenn es jemand anderes tut, würde ich es gerne hören.


@smehmood - Danke für die ausführliche Erklärung. Ein kleiner Zweifel. Wie kann der Kernel einen offenen Port durch einen abrupt getöteten Prozess zurückerobern? .. die Lösung, die Sie zur Verfügung gestellt haben, scheint den Prozess zu

3
@codingfreak Der Kernel weiß, dass der Prozess beendet ist. Es weiß, dass es den Hafen zurückfordern kann. Es gibt tatsächlich Regeln zum Zeitpunkt des Schließens des Ports, um sicherzustellen, dass keine Streupakete im Netz schweben. Woher weiß es, dass es über diese Ressourcen verfügt? Das ist es, was der Kernel tut, der die Dinge im Auge behält.
Rich Homolka

Bis jemand etwas sinnvolles posten würde, wie unix.tools.port.close(<my port number>)ich es nutzen würde init 6.
Snowcrash

Dies ist eine hervorragende Antwort auf eine andere Frage. In dieser Frage geht es darum, einen Debugger anzuhängen und ein laufendes Programm so zu ändern, dass dieses Programm eine Funktion in einem Dateideskriptor aufruft.
Arthur Ulfeldt

19

Fixiereinheit kann auch verwendet werden

fuser -k -n *protocol portno*

Hier ist das Protokoll tcp / udp und portno ist die Nummer, die Sie schließen möchten. Z.B

fuser -k -n tcp 37

Weitere Informationen finden Sie auf der Manpage von fuser


Nur den Prozess des Besitzens zu töten, hat bei mir nicht funktioniert, aber bei fuser. Vielen Dank!
Webwurst

Ich habe damit gemischte Ergebnisse erzielt, auch nachdem ich die Fixiereinheit verwendet habe, wurde der Socket bereits verwendet, als ich versuchte, den Port der getöteten App wiederzuverwenden, selbst wenn ich dies als Root tat. Andererseits schien die Zeit, um die Steckdose freizugeben, kürzer zu sein als zuvor, also trotzdem danke.
Jan Vlcinsky

@JanVlcinsky Vielleicht gibt es einen "Wächter" -Prozess, der den getöteten Prozess unmittelbar nach seiner fuserAusführung neu startet ?
RedBaron

@RedBaron: nach Kommentar superuser.com/a/415236/153413 mein Problem entsteht in schlecht geschriebene Anwendung, die nicht / schließt sich aufzuräumen die Steckdose unter Terminierung. So fuserfindet der Prozess den Port und tötet sie, aber nicht die Tatsache beheben, dass die Steckdose nicht geschlossen ist. 60 Sekunden und der Kernel erledigt das für mich.
Jan Vlcinsky

6

Alternativ können Sie auch iptables verwenden:

iptables -I INPUT -p tcp --dport 80 -j DROP

Im Grunde erreicht es, was Sie wollen. Dadurch wird der gesamte TCP-Verkehr auf Port 80 unterbrochen.


4
Nein, dadurch bleibt die Steckdose geöffnet, bis alle Timeouts sie schließen. (Es wird den gesamten Datenverkehr vor dem Besitzprozess verbergen, der dann keine Möglichkeit hat, zu wissen, dass er geschlossen werden sollte.) Sie können das -j REJECTTCP-Rücksetzflag zurückgeben, das dann beim Besitzprozess angezeigt wird (aber nur, wenn die andere Seite es versucht etwas senden).
Marki555,

3
netstat -anp | grep 80

Es sollte Ihnen sagen, wenn Sie Apache ausführen, "httpd" (dies ist nur ein Beispiel, verwenden Sie den Port, den Ihre Anwendung verwendet, anstelle von 80).

pkill -9 httpd 

oder

killall -9 httpd

4
Versuchen Sie einen normalen Kill, bevor Sie auf -9
Thilo

@omfgroflmao - Aber es wird den Prozess, der den Hafen geöffnet hat, töten?

@codingfreak Der Prozess, der den Port hält, ja, er wird ihn töten.

2

Sie könnten wahrscheinlich nur herausfinden, welcher Prozess den Socket geöffnet hat, dem der Port zugeordnet ist, und diesen Prozess beenden.

Aber Sie müssten sich darüber im Klaren sein, dass Sie das erstellt haben, wenn dieser Prozess keinen Handler hat, der alle von ihm verwendeten Daten (offene Dateien, Sockets, Forks, Daten, die nach dem Beenden nicht ordnungsgemäß geschlossen werden) deminitialisiert die Systemleistung beeinträchtigen. Außerdem bleibt der Socket offen, bis der Kernel feststellt, dass der Prozess abgebrochen wurde. Das dauert normalerweise nur ungefähr eine Minute.

Ich nehme an, die bessere Frage wäre: Welchen (zu welchem ​​Prozess gehörenden) Port möchten Sie anhalten?

Wenn Sie versuchen, eine von Ihnen gefundene Hintertür oder einen Virus zu beenden, sollten Sie zumindest wissen, welche Daten hin und her gehen, bevor Sie sie beenden. (wireshark ist dafür gut geeignet) (und der Name der ausführbaren Datei des Prozesses, so dass Sie ihn löschen und verhindern können, dass er beim Neustart wieder angezeigt wird) oder, falls Sie etwas installiert haben (wie HTTPD oder FTPD oder etwas anderes), sollten Sie bereits Zugriff darauf haben der Prozess selbst.

Normalerweise wird es ein Steuerungsprogramm haben (HTTPD stop | start oder so). Oder, wenn es sich um ein System handelt, sollten Sie sich wahrscheinlich nicht damit anlegen. Wie auch immer, ich dachte, da alle anderen dir den "How-to" -Winkel geben, sollte ich dir die Vorbehalte geben.


Sehr guter Kommentar. Ich habe ein Programm, das beim Beenden den Socket nicht schließt, was zu dem beschriebenen Verhalten führt - der Socket ist für ca. 60 Sekunden unbrauchbar. Wenn ich diesen Prozess stoppe und starte, klagt es ungefähr eine Minute lang, dass die Adresse und der Port bereits belegt sind. Die beste Lösung besteht darin, fehlerhafte Vorgänge zu korrigieren, um sie ordnungsgemäß zu schließen. Manchmal ist dies jedoch keine Option. Gibt es eine Möglichkeit, den Kernel zu fragen, ob er den blockierten Socket früher als in 60 Sekunden überprüft?
Jan Vlcinsky

2

Ich habe zuerst nach den Prozessen mongo und node gesucht und dann Folgendes ausgeführt:

ps -A | grep node

10418 pts/23   00:00:05 node

10551 pts/23   00:00:00 node

ps -A | grep mongo

10490 pts/23   00:00:00 mongod

Sobald Sie identifiziert sind, beenden Sie die Prozesse einfach mit dem Befehl kill.

kill -9 10418
kill -9 10490

Zuletzt tippen meteorund es sollte wieder funktionieren.


1

Sie könnten ein Skript schreiben, das die iptables modifiziert und neu startet. Ein Skript zum Hinzufügen einer Regel zum Löschen aller Pakete auf dem Port, ein anderes Skript zum Entfernen der Regel.

Die anderen Antworten haben Ihnen gezeigt, wie Sie den an den Port gebundenen Prozess beenden können - dies ist möglicherweise nicht das, was Sie möchten. Wenn Sie möchten, dass der Server weiterhin ausgeführt wird, aber keine Verbindungen von Clients hergestellt werden, möchten Sie den Port blockieren und den Prozess nicht anhalten.


@Michael Shimmins ... hmm klingt interessant, da wir den Port auf der Serverseite blockieren können, damit der Client keine Nachrichten sendet.

Nun, der Kunde kann Nachrichten senden, so

1

Ein weiteres Problem: Manchmal besitzt der Kernel selbst Ports. Ich weiß, dass NAT-Routing einige Ports für die Verwendung durch NAT offen hält. Sie können einen Prozess dafür nicht beenden, dies ist ein Kernel, und eine Neukonfiguration und ein Neustart sind erforderlich.


1

Wenn Sie möchten, dass Ihr Port früher freigegeben wird, müssen Sie den folgenden Wert festlegen:

echo 1 > /proc/sys/net/ipv4/tcp_fin_timeout

Zum Einstellen von 60 Sekunden (Standard) auf 1 Sekunde


1

Sie können den Befehl killcx verwenden, um eine Verbindung zu schließen, ohne dass ein Prozess beendet werden muss.

  • Syntax:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • Beispiel:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0

//, Haben die meisten Linux-Rechner killcx? Keiner von denen, die ich ausprobiert habe, hat diesen Befehl killcx zur Verfügung gestellt, ohne Pakete zu installieren, die für sie mit ihrer aktuellen Repository-Konfiguration nicht verfügbar sind.
Nathan Basanese

Nein, das Tool finden Sie hier: killcx.sourceforge.net
shuaiming

// Ich weiß, dass ich das Tool finden kann, es ist nur ein Schmerz, das auf Tausenden von Servern zu installieren.
Nathan Basanese

Verwenden Sie Puppet @ NathanBasanese :)
SHOUBHIK BOSE

1

Mir ist bewusst, dass diese Antwort nicht die eigentliche Frage beantwortet, aber in sie hineinzulesen, könnte eine relevante Information sein:

Das Standardverhalten beim Binden eines Sockets an einen Port (und eine Adresse) besteht darin, dass der Socket eine Weile in TIME_WAIT verbleibt, wenn der Socket durch abrupte Beendigung des Prozesses geschlossen wird. Dies bedeutet, dass Sie sich nicht sofort wieder an diese Adresse / diesen Port binden können. Wenn Sie das System selbst über die Standard-BSD-Socket-Schnittstelle entwickeln, können Sie dieses Verhalten (zumindest teilweise) mit der Socket-Option SO_REUSEADDR steuern. Auf diese Weise können Sie sich grundsätzlich wieder an dieselbe Adresse / denselben Port binden, wenn sich der Socket im Status TIME_WAIT befindet. Trotzdem noch eine Steckdose pro Port!

Diese Informationen sollten jedoch nur als Entwicklungshilfe verwendet werden, da es einen Grund dafür gibt, dass TIME_WAIT an erster Stelle steht, der bereits in den anderen Antworten erläutert wurde.


// , Richtig. Das Beenden von Prozessen ist natürlich nicht der beste Weg, um Ports freizugeben. Mir ist aufgefallen, dass ich, wenn ich den Vagrant-Prozess stoppe, wenn er hängt, für eine Weile nicht mehr auftauchen kann. Ich wette, diese TIME_WAIT-Sache hat etwas damit zu tun.
Nathan Basanese

0

Wenn Sie keinen Datenverkehr über den Socket möchten, aber den Prozess am Leben erhalten möchten: tcpkill .

tcpkill -i eth0 host xxx.xxx.xxx.xxx and port yyyy

Startet einen Sniffing-Daemon, der den gesamten Datenverkehr auf diesem Port abfängt und zerstört. Sehr praktisch zum Testen Ihrer Anwendungen auf Netzwerksplits.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.