Il modo più veloce per scansionare le porte con Java

Ho realizzato uno scanner di porte molto semplice, ma funziona troppo lentamente, quindi sto cercando un modo per farlo scansionare più velocemente. Ecco il mio codice:

public boolean portIsOpen(String ip, int port, int timeout) { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress(ip, port), timeout); socket.close(); return true; } catch (Exception ex) { return false; } } 

questo codice qui verifica se porta specifica è aperta su IP specifico. Per timeout uso il valore minimo di 200 perché quando vado in basso non ha abbastanza tempo per testare la porta. Bene Funziona bene, ma richiede troppo tempo per scansionare da 0 a 65535. Esiste un altro modo che potrebbe eseguire la scansione da 0 a 65535 in meno di 5 minuti?

Se hai bisogno di 200ms per ognuna delle 65536 porte (nel peggiore dei casi, un firewall sta bloccando tutto, facendo così scadere il tuo timeout per ogni singola porta), la matematica è piuttosto semplice: hai bisogno di 13k secondi, o circa 3 ore e metà.

Hai 2 opzioni (non esclusive) per renderlo più veloce:

  • ridurre il timeout
  • paralellizza il tuo codice

Dato che l’operazione è vincasting all’I / O (al contrario del limite della CPU, ovvero, si trascorre del tempo in attesa di I / O, e non per completare un enorme calcolo), è ansible utilizzare molti, molti thread . Prova a partire da 20. Divideranno le 3 ore e mezza tra di loro, quindi il tempo massimo previsto è di circa 10 minuti . Basta ricordare che questo farà pressione sull’altro lato, cioè, l’host scansionato vedrà un’enorme attività di rete con pattern “irragionevoli” o “strani”, rendendo la scansione estremamente facile da rilevare.

Il modo più semplice (cioè con modifiche minime) è utilizzare le API ExecutorService e Future:

 public static Future portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) { return es.submit(new Callable() { @Override public Boolean call() { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress(ip, port), timeout); socket.close(); return true; } catch (Exception ex) { return false; } } }); } 

Quindi, puoi fare qualcosa come:

 public static void main(final String... args) { final ExecutorService es = Executors.newFixedThreadPool(20); final String ip = "127.0.0.1"; final int timeout = 200; final List> futures = new ArrayList<>(); for (int port = 1; port <= 65535; port++) { futures.add(portIsOpen(es, ip, port, timeout)); } es.shutdown(); int openPorts = 0; for (final Future f : futures) { if (f.get()) { openPorts++; } } System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)"); } 

Se hai bisogno di sapere quali porte sono aperte (e non solo quante , come nell’esempio sopra), dovresti cambiare il tipo di ritorno della funzione in Future , dove SomethingElse manterrà la porta e il risultato della scansione, qualcosa come:

 public final class ScanResult { private final int port; private final boolean isOpen; // constructor // getters } 

Quindi, modificare Boolean in ScanResult nel primo frammento e restituire new ScanResult(port, true) o new ScanResult(port, false) anziché solo true o false

EDIT: In realtà, ho appena notato: in questo caso particolare, non è necessario che la class ScanResult conservi la porta risultato + e sappia ancora quale porta è aperta. Dal momento che aggiungi i futures a una lista , che è ordinata e, successivamente, li elabori nello stesso ordine in cui li hai aggiunti , potresti avere un contatore che incrementeresti a ogni iterazione per sapere quale porta hai a che fare con . Ma, hey, questo è solo per essere completo e preciso. Non provo mai a farlo , è orribile, mi vergogno per lo più di aver pensato a questo … Usare l’object ScanResult è molto più pulito , il codice è molto più facile da leggere e mantenere e ti permette, in seguito, di ad esempio, utilizzare un CompletionService per migliorare lo scanner.

Oltre a parallelizzare la scansione, è ansible utilizzare tecniche di scansione delle porte più avanzate come quelle (TCP SYN e TCP FIN scanning) spiegate qui: http://nmap.org/nmap_doc.html . Il codice VB di un’implementazione può essere trovato qui: http://h.ackack.net/spoon-worlds-fastest-port-scanner.html

Per utilizzare queste tecniche, tuttavia, è necessario utilizzare socket TCP / IP non elaborati. Dovresti usare la libreria RockSaw per questo.

Esempio di codice ispirato a “Bruno Reis”

 class PortScanner { public static void main(final String... args) throws InterruptedException, ExecutionException { final ExecutorService es = Executors.newFixedThreadPool(20); final String ip = "127.0.0.1"; final int timeout = 200; final List> futures = new ArrayList<>(); for (int port = 1; port <= 65535; port++) { // for (int port = 1; port <= 80; port++) { futures.add(portIsOpen(es, ip, port, timeout)); } es.awaitTermination(200L, TimeUnit.MILLISECONDS); int openPorts = 0; for (final Future f : futures) { if (f.get().isOpen()) { openPorts++; System.out.println(f.get().getPort()); } } System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)"); } public static Future portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) { return es.submit(new Callable() { @Override public ScanResult call() { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress(ip, port), timeout); socket.close(); return new ScanResult(port, true); } catch (Exception ex) { return new ScanResult(port, false); } } }); } public static class ScanResult { private int port; private boolean isOpen; public ScanResult(int port, boolean isOpen) { super(); this.port = port; this.isOpen = isOpen; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public boolean isOpen() { return isOpen; } public void setOpen(boolean isOpen) { this.isOpen = isOpen; } } } 

Per Android prova questa impressionante libreria

https://github.com/stealthcopter/AndroidNetworkTools

Se decidi di usare l’opzione Nmap e vuoi continuare con Java, dovresti guardare Nmap4j su SourceForge.net (http://nmap4j.sourceforge.net). È una semplice API che ti consente di integrare Nmap in un’app java.

–Jon

Ho scritto il mio servizio java asincrono di portscanner che può scansionare le porte tramite TCP-SYN-Scan come fa Nmap. Supporta inoltre le scansioni ping di IMCP e può funzionare con un throughput molto elevato (a seconda di ciò che la rete può sostenere):

https://github.com/subes/invesdwin-webproxy

Internamente utilizza un pcap di java binding e espone i suoi servizi tramite JMS / AMQP. Sebbene tu possa anche usarlo direttamente nella tua applicazione se non ti dispiace avere i permessi di root.