Test efficiente se una porta è aperta su Linux?


197

Da uno script bash come posso scoprire rapidamente se una porta 445è aperta / in ascolto su un server.

Ho provato un paio di opzioni, ma voglio qualcosa di veloce:
1. lsof -i :445 (Richiede secondi)
2. netstat -an |grep 445 |grep LISTEN(Richiede secondi)
3. telnet(Non restituisce)
4. nmap, netcatnon sono disponibili sul server

Sarà bello conoscere un modo che non enumera prima e poi si insinua.


1
Netcat è disponibile? Ha un percorso di errore rapido IIRC. netcat.sourceforge.net
JimR

5
netstat -lnt(con -te senza -a) limiterà l'output solo alle connessioni TCP in ascolto. Potrebbe accelerare un po '. È possibile aggiungere -4per IPv4 solo se non è necessario IPv6.
Bartosz Moczulski

lsof -i è un preferito personale.
Matt Joyce,

14
netstat -an | grep PORTNUMBER | grep -i listenSe l'output è vuoto, la porta non è in uso.
automatix,

Non so perché lsofsia lento per te, ma normalmente è la migliore delle soluzioni che hai elencato. La tua netstatsoluzione non è molto affidabile (puoi indovinarla ogni volta che la usi grep; comunque ritorna vera se qualcuno sta ascoltando ad es. 4450). telnete in netcatrealtà tentare di creare una connessione, che potrebbe non essere sempre quella desiderata.
petersohn,

Risposte:


155

Una sorpresa che ho scoperto di recente è che Bash supporta nativamente le connessioni tcp come descrittori di file . Usare:

exec 6<>/dev/tcp/ip.addr.of.server/445
echo -e "GET / HTTP/1.0\n" >&6
cat <&6

Sto usando 6 come descrittore di file perché 0,1,2 sono stdin, stdout e stderr. 5 è talvolta usato da Bash per processi figlio , quindi 3,4,6,7,8 e 9 dovrebbero essere sicuri.

Come da commento di seguito, per testare l'ascolto su un server locale in uno script:

exec 6<>/dev/tcp/127.0.0.1/445 || echo "No one is listening!"
exec 6>&- # close output connection
exec 6<&- # close input connection

Per determinare se qualcuno sta ascoltando, prova a connetterti tramite loopback. In caso contrario, la porta viene chiusa o non è consentito l'accesso. Successivamente, chiudere la connessione.

Modificalo per il tuo caso d'uso, come l'invio di un'e-mail, l'uscita dallo script in caso di errore o l'avvio del servizio richiesto.


2
Questo mi ha appena impiccato.
Aman Jain,

Il gatto @AmanJain attende la chiusura di EOF o Ctrl-C. Dovrai modificarlo per il tuo protocollo. A proposito, lo stai eseguendo su un server remoto?
Spencer Rathbun

Voglio incorporare il codice di controllo della porta in uno script sul server, in /etc/init.d/
Aman Jain

@AmanJain L'ho aggiornato per un sistema locale. Vuoi solo verificare se l'ascolto è corretto? Non c'è alcun controllo del protocollo, come richiedere una pagina tramite http?
Spencer Rathbun l'

1
Questo non è un metodo affidabile poiché non tutti i sistemi operativi (ad esempio Ubuntu 16, come ho scoperto oggi) sono spediti con bash compilato per la costruzione /dev/tcp/IP/PORTdell'albero
dyasny,

107

C'è molto breve con "risposta rapida" qui: Come verificare se la porta TCP remota è aperta dallo script Shell?

nc -z <host> <port>; echo $?

Lo uso con 127.0.0.1 come indirizzo "remoto".

questo restituisce "0" se la porta è aperta e "1" se la porta è chiusa

per esempio

nc -z 127.0.0.1 80; echo $?

-z Specifica che nc deve semplicemente cercare i demoni in ascolto, senza inviare alcun dato. È un errore usare questa opzione insieme all'opzione -l.


2
Questo sembra essere il modo più semplice, grazie. Il link di script di esempio non funziona più, tuttavia si spiega comunque da solo.
derFunk,

Bello! Questo è molto più veloce delle altre risposte su un server con molte porte aperte. Ritorna in <0,01 secondi per me mentre netstat / lsof prende 1s +
Tim

2
Il flag -z non è disponibile nel ncat basato su nmap con cui vengono distribuite le distribuzioni più recenti: Fedora, Centos, ecc. (Nmap-ncat-6.01-9.fc18.x86_64)
Zack

9
Contro-intuitivamente, questo restituisce "0" se la porta è aperta e "1" se la porta è chiusa.
Sean,

3
I comandi @Sean unix in genere restituiscono '0' per indicare l'esito positivo e diverso da zero in caso di errore. Quindi '0' indica che si è connesso correttamente e diverso da zero che non si è connesso per qualche motivo. Si noti, tuttavia, che alcune versioni di 'nc' non supportano l'argomento '-z', quindi stackoverflow.com/a/25793128/6773916 è probabilmente una soluzione migliore.
Rich Sedman,

89

Puoi usare netstat in questo modo per risultati molto più veloci:

Su Linux:

netstat -lnt | awk '$6 == "LISTEN" && $4 ~ /\.445$/'

Su Mac:

netstat -anp tcp | awk '$6 == "LISTEN" && $4 ~ /\.445$/'

Questo produrrà un elenco di processi in ascolto sulla porta (445 in questo esempio) o non produrrà nulla se la porta è libera.


1
la sintassi di netstat non è corretta. netstat -ln --tcp funziona, ma è ancora lento
Aman Jain

6
In realtà è la sintassi corretta ma probabilmente stai usando Linux e io sono su Mac. Per Linux usa questo:netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".445"'
anubhava il

21
questo non ha prodotto nulla.
Jürgen Paul,

1
La domanda era su Linux, quindi forse il commento dovrebbe essere nella risposta.
UpTheCreek,

1
Per verificare la porta 80 avevo bisogno di usare awk '$6 == "LISTEN" && $4 ~ "80$"'. Invece di controllare il punto prima del numero di porta con \.80, ho usato 80$. Altrimenti, questo corrispondeva anche agli indirizzi IP contenenti .80e alle porte che iniziano con 80come 8000.
Patrick Oscity,

37

Puoi usare netcat per questo.

nc ip port < /dev/null

si connette al server e chiude di nuovo direttamente la connessione. Se netcat non è in grado di connettersi, restituisce un codice di uscita diverso da zero. Il codice di uscita è memorizzato nella variabile $ ?. Come esempio,

nc ip port < /dev/null; echo $?

restituirà 0 se e solo se netcat potrebbe connettersi correttamente alla porta.


1
Questa risposta richiede più voti. nc funziona perfettamente per questo caso. il trucco / dev / tcp è intelligente, ma sembra difficile implementare uno script con interruzioni del segnale.
Avindra Goolcharan,

5
ncha il -zflag per questo scopo, che non richiede di ricevere input da /dev/null. C'è già una risposta usando la -zbandiera qui sopra.
Abe Voelker,

2
@AbeVoelker Non tutte le versioni di nc supportano il flag -z. Sono su CentOS 7 e ho trovato la soluzione di Tony come quella di cui avevo bisogno.
Shadoninja,

@Shadoninja Buono a sapersi! Se potessi modificare il carattere irriverente dal mio commento del 2014, lo farei.
Abe Voelker,

'nc' non supporta più '-z' e quindi questa risposta sembra essere la soluzione migliore.
Rich Sedman,

18

Basato sulla risposta di Spencer Rathbun, usando bash:

true &>/dev/null </dev/tcp/127.0.0.1/$PORT && echo open || echo closed

Bene, sopprimerà il messaggio "Connessione rifiutata". Esce automaticamente se il servizio accetta la connessione senza attendere per sempre.
Seff,

La migliore soluzione per i servizi che non inviano dati dopo una nuova connessione. Circa 20 volte più veloce di chiamare netcat. Può essere ridotto a: &>/dev/null </dev/tcp/127.0.0.1/$PORT
ens

16

sono elencati in / proc / net / tcp.

è la seconda colonna, dopo il ":", in esadecimale:

> cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 10863 1 ffff88020c785400 99 0 0 10 -1                     
   1: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7983 1 ffff88020eb7b3c0 99 0 0 10 -1                      
   2: 0500010A:948F 0900010A:2328 01 00000000:00000000 02:00000576 00000000  1000        0 10562454 2 ffff88010040f7c0 22 3 30 5 3                   
   3: 0500010A:E077 5F2F7D4A:0050 01 00000000:00000000 02:00000176 00000000  1000        0 10701021 2 ffff880100474080 41 3 22 10 -1                 
   4: 0500010A:8773 16EC97D1:0050 01 00000000:00000000 02:00000BDC 00000000  1000        0 10700849 2 ffff880104335440 57 3 18 10 -1                 
   5: 0500010A:8772 16EC97D1:0050 01 00000000:00000000 02:00000BF5 00000000  1000        0 10698952 2 ffff88010040e440 46 3 0 10 -1                  
   6: 0500010A:DD2C 0900010A:0016 01 00000000:00000000 02:0006E764 00000000  1000        0 9562907 2 ffff880104334740 22 3 30 5 4                    
   7: 0500010A:AAA4 6A717D4A:0050 08 00000000:00000001 02:00000929 00000000  1000        0 10696677 2 ffff880106cc77c0 45 3 0 10 -1  

quindi immagino uno di quelli :50 nella terza colonna debba essere stackoverflow: o)

cerca man 5 procper maggiori dettagli. e scegliere che a parte sed ecc è lasciato come esercizio per il lettore gentile ...


10
ss -tl4 '( sport = :22 )'

2ms è abbastanza veloce?

Aggiungi i due punti e questo funziona su Linux


2
Grande, ssè anche leggermente più veloce di nc. lè per l' ascolto , 4è per IPv4; sportsta per (ovviamente) porta sorgente . Il comando sopra presuppone una porta TCP in ascolto ( topzione): utilizzare l' uopzione per UDP o nessuna di esse per entrambi i protocolli. Maggiori informazioni sscome sempre su Nixcraft . NOTA: i ssfiltri non funzionano qui, non so perché (bash 4.3.11, ss utility, iproute2-ss131122), devono andare con grep .
Campa,

Peccato che quel sscomando non restituisca un codice di uscita che rifletta la sua ricerca; restituisce sempre 0 codice di uscita.
John Greene,

| grep LISTEN?
leucos,

Capisco State Recv-Q Send-Q Local Address:Port Peer Address:Porte adesso? Cosa significa questo?
Black

6

Eccone uno che funziona sia per Mac che per Linux:

netstat -aln | awk '$6 == "LISTEN" && $4 ~ "[\\.\:]445$"'

Penso che puoi rimuovere in sicurezza il file [\\.\:].
Patrick Oscity,

6
nc -l 8000

Dove 8000 è il numero di porta. Se la porta è libera, avvierà un server che puoi chiudere facilmente. In caso contrario genererà un errore:

nc: Address already in use

5

Volevo verificare se una porta è aperta su uno dei nostri server di test Linux. Sono stato in grado di farlo provando a connettermi con telnet dalla mia macchina di sviluppo al server di prova. Sulla tua macchina sviluppatore prova a eseguire:

$ telnet test2.host.com 8080
Trying 05.066.137.184...
Connected to test2.host.com

In questo esempio, voglio verificare se la porta 8080 è aperta sull'host test2.host.com


1

tcping è un ottimo strumento con un sovraccarico molto basso e ha anche un argomento di timeout per renderlo più veloce:

[root@centos_f831dfb3 ~]# tcping 10.86.151.175 22 -t 1
10.86.151.175 port 22 open.
[root@centos_f831dfb3 ~]# tcping 10.86.150.194 22 -t 1
10.86.150.194 port 22 user timeout.
[root@centos_f831dfb3 ~]# tcping 1.1.1.1 22 -t 1
1.1.1.1 port 22 closed.

1
Non sono sicuro che valga la pena installare tcping quando la soluzione di Spencer non richiede installazioni extra, ma questa è sicuramente la soluzione più pulita e leggibile dall'uomo.
bdombro,

1

Puoi anche usare il comando netcat

[location of netcat]/netcat -zv [ip] [port]

o

nc -zv [ip] [port]

-z - imposta nc in modo che esegua semplicemente la ricerca dei demoni in ascolto, senza in realtà inviare alcun dato.
-v - abilita la modalità dettagliata.


-2

nmapè lo strumento giusto. Basta usarenmap example.com -p 80

Puoi usarlo dal server locale o remoto. Ti aiuta anche a identificare se un firewall sta bloccando l'accesso.


-4

Se stai usando iptables prova:

iptables -nL

o

iptables -nL | grep 445

che elenca solo le regole di iptables ... che potrebbero non avere alcuna correlazione con le porte aperte.
David Goodwin,
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.