Fermer manuellement un port depuis la ligne de commande

112

Je souhaite fermer un port ouvert en mode d'écoute entre mon application cliente et serveur.

Existe-t-il une option de ligne de commande manuelle sous Linux pour fermer un port?

REMARQUE: j'ai appris que "seule l'application à laquelle appartient la prise connectée doit la fermer, ce qui se produira à la fin de l'application".

Je ne comprends pas pourquoi ce n'est possible que par l'application qui l'ouvre ... Mais je suis toujours impatient de savoir s'il existe un autre moyen de le faire.

Glorfindel
la source
5
Non, les ports ouverts appartiennent au processus qui les a ouverts, il n'y a pas de contrôle possible de l'extérieur. Ce qui est une bonne chose, sinon toutes les applications devraient anticiper que leurs ports ouverts (et leurs fichiers) sont gâchés. Cependant, vous pouvez bloquer le trafic sur un port en utilisant un pare-feu (iptables), mais cela ne fermera pas et n'abandonnera pas le port pour une autre utilisation.
Jürgen Strobel
10
Beaucoup de répondants ont mal compris le sens de cette question. Il est absurde de déclarer que seule l'application propriétaire du port peut le déconnecter. Je peux le déconnecter en allant dans la boîte et en tirant le câble Ethernet de la prise, ou en supprimant l'application à l'autre bout de la connexion! L'application doit être écrite pour gérer cela. Alors, comment vérifier que l’application est correctement écrite sans intervention physique et / ou le contrôle de l’autre ordinateur?
Dale Wilson
"... il n'y a pas de contrôle possible de l'extérieur." C'est une remarque importante, cela m'a conduit à la question suivante: comment puis-je être la partie du processus de l'extérieur? GDB.
Dankó Dávid
@ JürgenStrobel Il existe en effet un contrôle possible de l'extérieur - tcpkill et ss peuvent faire exactement ce qui est demandé. Parce que les ports ouverts n'appartiennent pas vraiment à un processus; ce sont des ressources du noyau, avec certains droits attribués à un processus, mais n'existant toujours que pour le plaisir du noyau.
Tom Anderson
@ tom-anderson DaleW: tcpkill est un outil de pare-feu, et j'ai mentionné cette option. Vous pouvez empêcher le trafic sur un port, ce qui est différent de la fermeture d'un port (socket).
Jürgen Strobel

Réponses:

134

J'ai eu le même problème, le processus doit rester en vie mais le socket doit se fermer. Fermer un socket dans un processus en cours n'est pas impossible mais difficile:

  1. localiser le processus:

    netstat -np
    

    Vous obtenez une source/destination ip:port portstate pid/processnamecarte

  2. localisez le descripteur de fichier du socket dans le processus

    lsof -np $pid
    

    Vous obtenez une liste: nom du processus, pid, utilisateur, descripteur de fichier, ... une chaîne de connexion.

    Localisez le numéro de fichier descripteur correspondant pour la connexion. Ce sera quelque chose comme "97u" qui signifie "97".

  3. Maintenant connectez le processus:

    gdb -p $pid
    
  4. Maintenant fermez la prise:

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

    exemple:

    call close(97)
    

    Puis détachez gdb:

    quit
    

    Et la prise est fermée.

Dankó Dávid
la source
1
sudo lsof -np $pidme donne environ 200 lignes et je suis confus sur la façon de trouver FD souhaité. Dans mon cas, il y a un onglet Chrome et j'essaie de fermer les Websockets ouverts ...
SET
2
Une rangée ressemble généralement: 14812 firefox szupervigyor 97u IPv4 32814564 0T0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) en tant que: process_name utilisateur pid Fd [opened_for] Dispositif protocole inode protocol_data_toString
Dankó Dávid
2
* Une ligne se présente généralement comme suit: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) comme suit: nom_processus pid utilisateur fd [Open_for] périphérique de protocole inode protocole_data_toString adresse et trouver sur le dernier col. Dans mon exemple, le 97 est le FileDescriptor. La recherche est difficile si vous avez ouvert plusieurs connexions à l'hôte cible.
Dankó Dávid
7
c'est une solution brillante
marcorossi
8
Si vous souhaitez simuler la prise étant fermée par l'extrémité distante (par exemple , la sortie par les pairs) , il est préférable d'utiliser shutdown: call shutdown($fileDescriptor, 0).
ecatmur
75

Vous êtes en quelque sorte de poser la mauvaise question ici. Il n'est pas vraiment possible de simplement "fermer un port" de l'extérieur de l'application qui a ouvert le socket en l'écoutant. La seule façon de procéder consiste à supprimer complètement le processus propriétaire du port. Ensuite, dans environ une minute ou deux, le port redeviendra disponible. Voici ce qui se passe (si vous ne vous en souciez pas, passez à la fin où je vous montrerai comment arrêter le processus possédant un port particulier):

Les ports sont des ressources allouées par le système d'exploitation à différents processus. Ceci est similaire à demander au système d'exploitation un pointeur de fichier. Cependant, contrairement aux pointeurs de fichier, un seul processus à la fois peut posséder un port. Grâce à l'interface de socket BSD, les processus peuvent demander à écouter sur un port, ce que le système d'exploitation accorde ensuite. Le système d'exploitation s'assurera également qu'aucun autre processus n'obtient le même port. À tout moment, le processus peut libérer le port en fermant le socket. Le système d'exploitation récupérera alors le port. Alternativement, si le processus se termine sans libérer le port, le système d'exploitation le récupérera éventuellement (bien que cela ne se produise pas immédiatement: cela prendra quelques minutes).

Maintenant, ce que vous voulez faire (fermer simplement le port à partir de la ligne de commande) n'est pas possible pour deux raisons. Premièrement, si cela était possible, cela signifierait qu'un processus pourrait tout simplement dérober la ressource d'un autre processus (le port). Ce serait une mauvaise politique, sauf si elle est limitée aux processus privilégiés. La deuxième raison est que nous ne savons pas ce qui arriverait au processus qui appartenait au port si nous le laissions continuer à fonctionner. Le code du processus est écrit en supposant qu'il possède cette ressource. Si nous l'enlevions simplement, le système s'écraserait tout seul. Les systèmes d'exploitation ne vous le permettent pas, même si vous êtes un processus privilégié. Au lieu de cela, vous devez simplement les tuer.

Quoi qu'il en soit, voici comment supprimer un processus possédant un port particulier:

sudo netstat -ap | grep :<port_number>

Cela affichera la ligne correspondant au port de traitement du processus, par exemple:

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

Dans ce cas, procHoldingPort est le nom du processus qui a ouvert le port, 4683 est son pid et 8000 (notez qu'il s'agit de TCP) est le numéro de port qu'il détient.

Ensuite, regardez dans la dernière colonne, vous verrez /. Ensuite, exécutez ceci:

kill  <pid>

Si cela ne fonctionne pas (vous pouvez vérifier en réexécutant la commande netstat). Faire ceci:

kill -9 <pid>

En général, il vaut mieux éviter d'envoyer SIGKILL si vous le pouvez. C'est pourquoi je vous dis d'essayer killavant kill -9. Simplement utiliser killenvoie le SIGTERM plus doux.

Comme je l'ai dit, la réouverture du port prendra encore quelques minutes si vous procédez ainsi. Je ne sais pas comment accélérer cela. Si quelqu'un d'autre le fait, j'aimerais l'entendre.

Guy Avraham
la source
@smehmood - Merci pour l'explication détaillée. Un petit doute. Comment le noyau récupère-t-il un port ouvert par un processus brutalement tué? .. la solution fournie semble tuer le processus qui tient le port ...
3
@codingfreak Le noyau sait que le processus est parti. Il sait qu'il peut récupérer le port. Il existe en fait des règles sur le moment de la fermeture du port, pour s'assurer qu'il n'y a pas de paquets parasites flottant sur le réseau. Comment sait-il qu'il dispose de ces ressources? c'est ce que le noyau fait, garde la trace des choses.
Rich Homolka
Jusqu'à ce que quelqu'un poste quelque chose de sensé, comme unix.tools.port.close(<my port number>)je le ferais init 6.
Snowcrash 10/02/2017
C'est une excellente réponse à une question différente. Cette question concerne l'attachement d'un débogueur et la modification d'un programme en cours afin que ce programme appelle une fonction sur un descripteur de fichier.
Arthur Ulfeldt
19

Le four peut également être utilisé

fuser -k -n *protocol portno*

Ici le protocole est tcp / udp et portno est le numéro que vous souhaitez fermer. Par exemple

fuser -k -n tcp 37

Plus d'informations sur la page de manuel de fusion

Baron Rouge
la source
Tuer un processus de possession ne fonctionnait pas pour moi, mais fuser fonctionnait. Merci!
Webwurst
J'ai eu des résultats mitigés avec, même après l'utilisation de fuser, j'ai eu "socket déjà utilisé" en essayant de réutiliser le port de l'application tuée, même en tant que root. D'autre part, le temps nécessaire pour libérer la prise semblait être plus court qu'avant, alors merci quand même.
Jan Vlcinsky
@JanVlcinsky Peut-être qu'il y a un processus "gardien" qui redémarre le processus tué quelques instants après fuserson exécution?
RedBaron
@RedBaron: selon le commentaire superuser.com/a/415236/153413, mon problème provient d'une application mal écrite, qui ne nettoie / ferme pas le socket en cours de terminaison. Donc, fusertrouve le processus en utilisant le port et le tue, mais ne résout pas le fait, que le socket n'est pas fermé. 60 secondes et le noyau le fait pour moi.
Jan Vlcinsky
6

Vous pouvez aussi utiliser iptables:

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

Fondamentalement, il accomplit ce que vous voulez. Cela abandonnera tout le trafic TCP sur le port 80.

supercheetah
la source
4
Non, cela maintiendra la socket ouverte jusqu'à ce que tous les délais d'attente les ferment. (Cela cachera tout le trafic du processus propriétaire qui n'aura alors aucun moyen de savoir qu'il devrait le fermer.) Vous pouvez utiliser -j REJECTpour renvoyer l'indicateur de réinitialisation TCP, qui sera ensuite vu par le processus propriétaire (mais seulement lorsque l'autre partie essaiera envoyer quelque chose).
Marki555
3
netstat -anp | grep 80

Il devrait vous dire, si vous utilisez apache, "httpd" (ceci est juste un exemple, utilisez le port que votre application utilise au lieu de 80)

pkill -9 httpd 

ou

killall -9 httpd
Ben
la source
4
essayez une mise à mort normale avant de recourir à -9
Thilo
@omfgroflmao - Mais cela va tuer le processus qui a ouvert le port ??
@codingfreak Le processus qui détient le port, oui, il va le tuer.
2

Vous pourriez probablement simplement savoir quel processus a ouvert le socket auquel le port est associé et tuer ce processus.

Mais vous devez réaliser que si ce processus n’a pas de gestionnaire qui désinitialise tout ce qu’il utilisait (fichiers ouverts, sockets, fourchettes, choses pouvant persister s’il n’est pas fermé correctement à la fin), vous auriez créé ce fichier. faites glisser la performance du système. De plus, le socket restera ouvert jusqu'à ce que le noyau réalise que le processus a été tué. Cela prend généralement environ une minute.

Je suppose que la meilleure question serait: quel port (appartenant à quel processus) voulez-vous arrêter?

Si vous essayez de mettre fin à une porte dérobée ou à un virus que vous avez trouvé, vous devez au moins connaître les données échangées avant de les supprimer. (Wireshark est bon pour cela) (et le nom de l'exécutable du processus afin que vous puissiez le supprimer et l'empêcher de revenir au redémarrage) ou, s'il s'agit de quelque chose que vous avez installé (comme HTTPD ou FTPD, le processus lui-même.

Habituellement, il y aura un programme de contrôle (HTTPD stop | start ou quelque chose). Ou, si c'est une affaire de système, vous ne devriez probablement pas jouer avec. Quoi qu'il en soit, je pensais que puisque tout le monde vous donnait l'angle de la marche à suivre, je devrais vous donner les mises en garde.

Jackenheimer
la source
Très bon commentaire. J'ai un programme qui, en cas de terminaison, ne ferme pas le socket, ce qui entraîne le comportement décrit - le socket est inutilisable pendant environ 60 secondes. Lorsque j'arrête et démarre ce processus, il se plaint pendant environ une minute que l'adresse et le port sont déjà utilisés. La meilleure solution consiste à corriger le processus mal conduit pour fermer correctement, mais parfois ce n'est pas une option. Existe-t-il un moyen de demander au noyau de vérifier cette socket bloquée plus tôt qu'en 60 secondes?
Jan Vlcinsky
2

J'ai d'abord cherché les processus de mongo et de noeud, puis j'ai fait ce qui suit:

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

Une fois identifié, il suffit de tuer les processus avec la commande kill.

kill -9 10418
kill -9 10490

Enfin, tapez meteoret il devrait fonctionner à nouveau.

abautista
la source
1

Vous pouvez écrire un script qui modifie les iptables et les redémarre. Un script pour ajouter une règle supprimant tous les paquets sur le port, un autre script pour supprimer ladite règle.

Les autres réponses vous ont montré comment tuer le processus lié au port - ce n'est peut-être pas ce que vous voulez. Si vous souhaitez que le serveur continue à fonctionner, tout en empêchant les connexions des clients, vous souhaitez bloquer le port, pas arrêter le processus.

Michael Shimmins
la source
@Michael Shimmins ... hmm semble intéressant car nous pouvons bloquer le port côté serveur afin que le client n'envoie aucun message.
Eh bien, le client peut envoyer des messages à sa
1

Un autre problème: le noyau possède parfois des ports eux-mêmes. Je sais que le routage NAT maintient certains ports ouverts pour une utilisation NAT. Vous ne pouvez pas tuer un processus pour cela, il s’agit d’un noyau et une reconfiguration et un redémarrage sont nécessaires.

Rich Homolka
la source
1

Si vous souhaitez que votre port soit libéré plus tôt, vous devez définir la valeur suivante:

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

pour le régler de 60 secondes (par défaut) à 1 seconde

Daniel
la source
1

Vous pouvez utiliser la commande nommée killcx pour fermer une connexion sans qu'aucun processus ne soit tué.

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

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • exemple:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0
shuaiming
la source
//, La plupart des machines Linux ont-elles killcx? Aucun de ceux que j'ai essayés ne dispose de cette commande killcx sans installer des packages indisponibles avec la configuration de référentiel actuelle.
Nathan Basanese
non, vous pouvez trouver l'outil ici: killcx.sourceforge.net
shuaiming
//, je sais que je peux trouver l'outil, c'est un peu pénible de l'installer sur des milliers de serveurs.
Nathan Basanese
Utilisez Puppet @NathanBasanese :)
SHOUBHIK BOSE
1

Je suis conscient que cette réponse ne répond pas à la question elle-même, à proprement parler, mais en y lisant cette information pourrait être pertinente:

Le comportement par défaut de la liaison d'un socket à un port (et à une adresse) est le suivant: lorsque le socket est fermé par un arrêt brutal du processus, le socket reste dans TIME_WAIT pendant un certain temps. Cela signifie que vous ne pouvez pas immédiatement renouer avec cette adresse / ce port. Si vous développez le système lui-même via l'interface de socket BSD standard, vous pouvez (au moins dans une certaine mesure) contrôler ce comportement avec l'option de socket SO_REUSEADDR. Cela vous permettra fondamentalement de vous connecter à la même adresse / au même port si le socket est à l'état TIME_WAIT. Encore une prise par port si!

Toutefois, ces informations ne doivent être utilisées que dans le cadre de l'aide au développement, car TIME_WAIT a une raison d'exister, ce qui a déjà été expliqué dans les autres réponses.

Tommi Tuura
la source
// , Droite. Bien sûr, tuer les processus n’est pas le meilleur moyen de libérer des ports. J'ai remarqué que lorsque je tue le processus Vagrant s'il se bloque, je ne peux plus vagabonder pendant un moment. Je parie que cette chose TIME_WAIT a quelque chose à voir avec cela.
Nathan Basanese
0

Si vous ne voulez pas de trafic sur le socket mais que vous voulez garder en vie le processus: tcpkill .

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

Lance un démon de détection qui intercepte et supprime tout le trafic sur ce port. Très pratique pour tester vos applications pour les scissions de réseau.

RickyA
la source
0

Vous pouvez fermer une socket d’écoute à l’aide de ss :

sudo ss --kill state listening src :1234

Où 1234 est votre numéro de port.

ss fait partie du paquet iproute2, il y a donc un changement important: il est déjà installé sur un Linux moderne.

J'ai appris à ce sujet d' une réponse à une question connexe .

Tom Anderson
la source