Chiusura manuale di una porta dalla riga di comando


112

Voglio chiudere una porta aperta che è in modalità di ascolto tra il mio client e l'applicazione server.

Esiste un'opzione di riga di comando manuale in Linux per chiudere una porta?

NOTA: sono venuto a sapere che "solo l'applicazione proprietaria del socket collegato dovrebbe chiuderlo, cosa che accadrà al termine dell'applicazione".

Non capisco perché sia ​​possibile solo dall'applicazione che lo apre ... Ma sono ancora desideroso di sapere se esiste un altro modo per farlo.


5
No, le porte aperte appartengono al processo che le ha aperte, non è possibile alcun controllo dall'esterno. Il che è positivo, altrimenti tutte le applicazioni dovrebbero anticipare che le loro porte (e file) aperte vengano incasinate. Tuttavia, è possibile bloccare il traffico verso una porta mediante firewall (iptables), ma ciò non si chiuderà e rinuncerà alla porta per altri usi.
Jürgen Strobel,

10
Molti rispondenti hanno perso il punto di questa domanda. Non ha senso dichiarare che solo l'applicazione proprietaria della porta può disconnetterla. Posso disconnetterlo camminando verso la scatola ed estraendo il cavo Ethernet dalla presa o uccidendo l'applicazione all'altra estremità della connessione! L'applicazione deve essere scritta per gestirlo. Quindi --- come test per essere sicuro che l'applicazione sia scritta correttamente senza richiedere l'intervento fisico e / o il controllo dell'altro computer?
Dale Wilson,

"... non è possibile alcun controllo dall'esterno." Questa è un'osservazione importante, mi ha guidato alla domanda successiva, come posso essere la parte del processo dall'esterno? GDB.
Dankó Dávid,

@ JürgenStrobel Esiste davvero un controllo dall'esterno: sia tcpkill che ss possono fare esattamente ciò che viene richiesto. Perché le porte aperte non appartengono veramente a un processo; sono risorse del kernel, con alcuni diritti assegnati a un processo, ma esistono ancora solo per piacere del kernel.
Tom Anderson,

@ tom-anderson DaleW: tcpkill è uno strumento di firewalling e ho menzionato questa opzione. È possibile impedire il traffico verso una porta, che è diverso dalla chiusura di una porta (socket).
Jürgen Strobel,

Risposte:


134

Ho avuto lo stesso problema, il processo deve rimanere in vita ma il socket deve chiudere. Chiudere un socket in un processo in esecuzione non è impossibile ma difficile:

  1. individuare il processo:

    netstat -np
    

    Ottieni una source/destination ip:port portstate pid/processnamemappa

  2. individuare il descrittore di file del socket nel processo

    lsof -np $pid
    

    Ottieni un elenco: nome processo, pid, utente, fileDescriptor, ... una stringa di connessione.

    Individua il numero fileDescriptor corrispondente per la connessione. Sarà qualcosa come "97u" che significa "97".

  3. Ora collega il processo:

    gdb -p $pid
    
  4. Ora chiudi il socket:

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

    esempio:

    call close(97)
    

    Quindi scollegare gdb:

    quit
    

    E la presa è chiusa.


1
sudo lsof -np $pidmi dà circa 200 righe e sono confuso su come trovare l'FD desiderato. Nel mio caso il processo è una scheda Chrome e sto cercando di chiudere i websocket aperti ...
SET

2
Una riga appare tipicamente come: firefox 14812 szupervigyor 97u IPv4 32.814.564 0T0 TCP 192.168.2.4:40385->173.194.39.65:https (STABILITO) come: nome_processo utente pid fd [opened_for] protocollo dispositivo inode protocol_data_toString
Dankó Dávid

2
* Una riga in genere assomiglia a: firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) come: process_name pid user fd [open_for] protocollo inode protocol_data_toString È necessario conoscere l'ip remoto indirizzo e trova sull'ultimo col. Nel mio esempio 97 è FileDescriptor. La ricerca è difficile se hai aperto più connessioni all'host di destinazione.
Dankó Dávid,

7
questa è una soluzione geniale
marcorossi il

8
Se si vuole simulare la presa di essere chiuso entro la fine remoto (ad esempio, il peer in uscita) è meglio usare shutdown: call shutdown($fileDescriptor, 0).
ecatmur,

75

Stai facendo una domanda sbagliata qui. Non è davvero possibile semplicemente "chiudere una porta" dall'esterno dell'applicazione che ha aperto il socket in ascolto su di essa. L'unico modo per eseguire questa operazione è interrompere completamente il processo proprietario della porta. Quindi, tra circa un minuto o due, la porta sarà di nuovo disponibile per l'uso. Ecco cosa sta succedendo (se non ti interessa, passa alla fine dove ti faccio vedere come interrompere il processo con una determinata porta):

Le porte sono risorse allocate dal sistema operativo a diversi processi. Questo è simile a chiedere al sistema operativo un puntatore a file. Tuttavia, a differenza dei puntatori di file, solo UN processo alla volta può possedere una porta. Tramite l'interfaccia socket BSD, i processi possono effettuare una richiesta di ascolto su una porta, che verrà quindi concessa dal sistema operativo. Il sistema operativo assicurerà inoltre che nessun altro processo ottenga la stessa porta. In qualsiasi momento, il processo può rilasciare la porta chiudendo il socket. Il sistema operativo recupererà quindi la porta. In alternativa, se il processo termina senza rilasciare la porta, il sistema operativo alla fine recupererà la porta (anche se non accadrà immediatamente: ci vorranno alcuni minuti).

Ora, quello che vuoi fare (semplicemente chiudere la porta dalla riga di comando), non è possibile per due motivi. Innanzitutto, se fosse possibile, significherebbe che un processo potrebbe semplicemente rubare via la risorsa di un altro processo (la porta). Questa sarebbe una cattiva politica, a meno che non fosse limitata a processi privilegiati. La seconda ragione è che non è chiaro cosa succederebbe al processo che possedeva la porta se la lasciassimo continuare a funzionare. Il codice del processo è scritto presumendo che possiede questa risorsa. Se lo togliessimo semplicemente, finirebbe per andare in crash da solo, quindi i sistemi operativi non ti consentono di farlo, anche se sei un processo privilegiato. Invece, devi semplicemente ucciderli.

Ad ogni modo, ecco come terminare un processo che possiede una determinata porta:

sudo netstat -ap | grep :<port_number>

Ciò produrrà la linea corrispondente alla porta di mantenimento del processo, ad esempio:

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

In questo caso, procHoldingPort è il nome del processo che ha aperto la porta, 4683 è il suo pid e 8000 (nota che è TCP) è il numero di porta che contiene.

Quindi, guarda nell'ultima colonna, vedrai /. Quindi eseguire questo:

kill  <pid>

Se ciò non funziona (è possibile verificare rieseguendo il comando netstat). Fai questo:

kill -9 <pid>

In generale, è meglio evitare di inviare SIGKILL se è possibile. Ecco perché ti dico di provare killprima kill -9. Solo usando killinvia il SIGTERM più gentile.

Come ho detto, ci vorranno ancora alcuni minuti per riaprire la porta se lo fai. Non conosco un modo per accelerare questo. Se lo fa qualcun altro, mi piacerebbe ascoltarlo.


@smehmood - Grazie per la spiegazione dettagliata .. Un piccolo dubbio .. Come fa il kernel a recuperare una porta aperta da un processo improvvisamente ucciso ?? .. la soluzione che hai fornito sembra uccidere il processo che tiene la porta ...

3
@codingfreak Il kernel sa che il processo è finito. Sa che può reclamare la porta. In realtà ci sono regole sui tempi di chiusura della porta, per assicurarsi che non ci siano pacchetti randagi che galleggiano sulla 'rete. Come fa a sapere che ha queste risorse? questo è ciò che fa il kernel, tiene traccia delle cose.
Rich Homolka,

Fino a quando qualcuno non pubblicherà qualcosa di sensato unix.tools.port.close(<my port number>)che userei init 6.
Snowcrash,

Questa è un'ottima risposta a una domanda diversa. Questa domanda riguarda il collegamento di un debugger e la modifica di un programma in esecuzione per far sì che quel programma chiami una funzione su un descrittore di file.
Arthur Ulfeldt

19

È anche possibile utilizzare il fusore

fuser -k -n *protocol portno*

Qui il protocollo è tcp / udp e portno è il numero che si desidera chiudere. Per esempio

fuser -k -n tcp 37

Maggiori informazioni sulla pagina man di fuser


Solo uccidere il processo di proprietà non ha funzionato per me, ma il fusore ha funzionato. Grazie!
webwurst

Ho ottenuto risultati contrastanti con esso, anche dopo aver usato il fusore, ho ottenuto "socket già in uso" quando provavo a riutilizzare la porta dall'app uccisa anche facendo come root. D'altra parte, il tempo per liberare la presa sembrava essere più breve di prima, quindi grazie comunque.
Jan Vlcinsky,

@JanVlcinsky Forse esiste un processo "guardiano" che riavvia il processo ucciso pochi istanti dopo l' fuseresecuzione?
RedBaron,

@RedBaron: secondo il commento superuser.com/a/415236/153413 il mio problema ha origine in un'applicazione scritta male, che non pulisce / chiude il socket sotto terminazione. Quindi fusertrova il processo usando la porta e la uccide, ma non risolve il fatto che il socket non è chiuso. 60 secondi e il kernel lo fa per me.
Jan Vlcinsky,

6

In alternativa puoi usare iptables:

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

Fondamentalmente realizza ciò che vuoi. Ciò eliminerà tutto il traffico TCP sulla porta 80.


4
No, questo manterrà il socket aperto fino a quando tutti i timeout non li chiuderanno. (Nasconderà tutto il traffico dal processo proprietario che quindi non ha alcun mezzo per sapere che dovrebbe chiuderlo.) Potresti usare -j REJECTper restituire il flag di ripristino TCP, che sarebbe quindi visto il mio processo proprietario (ma solo quando l'altra parte prova per inviare qualcosa).
Marki555,

3
netstat -anp | grep 80

Se si esegue apache, dovrebbe essere indicato "httpd" (questo è solo un esempio, utilizzare la porta utilizzata dall'applicazione anziché 80)

pkill -9 httpd 

o

killall -9 httpd

4
prova a uccidere normalmente prima di ricorrere a -9
Thilo

@omfgroflmao - Ma ucciderà il processo che ha aperto la porta ??

@codingfreak Il processo che tiene la porta, sì, la ucciderà.

2

Probabilmente potresti semplicemente scoprire a quale processo ha aperto il socket a cui è associata la porta e uccidere quel processo.

Ma dovresti capire che a meno che quel processo non abbia un gestore che de-inizializza tutte le cose che stava usando (file aperti, socket, forchette, cose che possono persistere a meno che non siano chiuse correttamente al termine) allora avresti creato quello trascina sulle prestazioni del sistema. Inoltre, il socket rimarrà aperto fino a quando il kernel non si renderà conto che il processo è stato interrotto. Di solito ci vuole solo un minuto.

Suppongo che la domanda migliore sarebbe: quale porta (appartenente a quale processo) vuoi fermare?

Se stai cercando di porre fine a una backdoor o un virus che hai trovato, allora dovresti almeno sapere quali dati vanno avanti e indietro prima di terminarli. (WireShark è buono per questo) (E il processo 'nome eseguibile in modo da poterlo eliminare e impedire che torni al riavvio) o, se è qualcosa che hai installato (come HTTPD o FTPD o qualcosa del genere) allora dovresti già avere accesso a il processo stesso.

Di solito avrà un programma di controllo (HTTPD stop | start o qualcosa del genere). Oppure, se è una cosa di sistema, probabilmente non dovresti scherzare. Comunque, ho pensato che dato che tutti gli altri ti stanno dando l'angolazione "how-to", dovrei darti le avvertenze.


Ottimo commento Ho un programma, che alla fine non chiude il socket ciò che risulta nel comportamento descritto - il socket è inutilizzabile per circa 60 secondi. Quando mi fermo e inizio quel processo, mi lamento per circa un minuto, che l'indirizzo e la porta sono già in uso. La soluzione migliore è quella di correggere il processo che si comporta male per chiuderlo correttamente, ma a volte questa non è un'opzione. C'è un modo per chiedere al kernel di controllare quel socket bloccato prima che in 60 secondi?
Jan Vlcinsky,

2

Ho prima cercato i processi mongo e node, quindi ho fatto quanto segue:

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

Una volta identificato, basta uccidere i processi con il comando kill.

kill -9 10418
kill -9 10490

Infine, digita meteore dovrebbe funzionare di nuovo.


1

È possibile scrivere uno script che ha modificato iptables e li riavvia. Uno script per l'aggiunta di una regola che elimina tutti i pacchetti sulla porta, un altro script per la rimozione di detta regola.

Le altre risposte ti hanno mostrato come terminare il processo associato alla porta: questo potrebbe non essere quello che desideri. Se si desidera che il server continui a funzionare, ma per impedire le connessioni dai client, si desidera bloccare la porta, non interrompere il processo.


@Michael Shimmins ... hmm sembra interessante perché possiamo bloccare la porta sul lato server in modo che il client non invii alcun messaggio.

Bene, il cliente può inviare messaggi come vuole, abbiamo appena chiuso la porta in modo che non possano entrare.

1

Un altro problema: a volte il kernel possiede le porte stesse. So che il routing NAT tiene aperte alcune porte per l'uso NAT. Non è possibile terminare un processo per questo, questo è un kernel, sono necessari una riconfigurazione e un riavvio.


1

Se vuoi che la tua porta venga rilasciata prima, devi impostare il seguente valore:

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

per impostarlo da 60 secondi (impostazione predefinita) a 1 secondo


1

È possibile utilizzare il comando denominato killcx, chiudendo una connessione senza alcun processo da eliminare.

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

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

//, la maggior parte delle macchine Linux ha killcx? Nessuno di quelli che ho provato ha questo comando killcx disponibile senza installare pacchetti non disponibili con la configurazione del repository corrente.
Nathan Basanese,

no, puoi trovare lo strumento qui: killcx.sourceforge.net
shuaiming

//, so di poter trovare lo strumento, è solo una seccatura installarlo su migliaia di server.
Nathan Basanese,

Usa Puppet @NathanBasanese :)
SHOUBHIK BOSE

1

Sono consapevole che questa risposta non risponde alla domanda stessa, a rigor di termini, ma leggendo questa potrebbe essere un'informazione rilevante:

Il comportamento predefinito di associare un socket a una porta (e indirizzo) è che quando il socket viene chiuso da una brusca interruzione del processo, il socket rimarrà in TIME_WAIT per un po '. Ciò significa che non è possibile ricollegare immediatamente a questo indirizzo / porta. Se si sta sviluppando il sistema stesso tramite l'interfaccia socket BSD standard, è possibile (almeno in una certa misura) controllare questo comportamento con l'opzione socket SO_REUSEADDR. Ciò consentirà fondamentalmente di collegarsi nuovamente allo stesso indirizzo / porta se il socket si trova nello stato TIME_WAIT. Ancora un socket per porta!

Tuttavia, queste informazioni dovrebbero essere utilizzate solo come aiuto allo sviluppo, poiché esiste un motivo per cui TIME_WAIT esiste in primo luogo, già spiegato nelle altre risposte.


// , Giusto. Naturalmente, i processi di uccisione non sono il modo migliore per liberare le porte. Ho notato che quando uccido il processo Vagrant se si blocca, non riesco a vagare di nuovo per un po '. Scommetto che questa cosa TIME_WAIT ha qualcosa a che fare con questo.
Nathan Basanese,

0

Se non si desidera traffico sul socket ma si desidera mantenere attivo il processo: tcpkill .

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

Avvierà un demone sniffing che intercetta e elimina tutto il traffico su quella porta. Molto utile per testare le applicazioni per divisioni di rete.


0

Puoi chiudere una presa di ascolto usando ss :

sudo ss --kill state listening src :1234

Dove 1234 è il numero di porta.

ss fa parte del pacchetto iproute2, quindi c'è un forte cambiamento che è già installato su un moderno Linux.

Ho imparato questo da una risposta a una domanda correlata .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.