Soru Java ile bağlantı noktalarını taramanın en hızlı yolu


Çok basit bir port tarayıcı yaptım, ama çok yavaş çalışıyor, bu yüzden daha hızlı taramak için bir yol arıyorum. İşte kodum:

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;
        }
    }

Bu kod, belirli bir portun belirli bir ip üzerinde açık olup olmadığını test eder. Zaman aşımı için minimum 200 değeri kullanıyorum çünkü indirdiğimde limiti test etmek için yeterli zamanınız yok. Peki iyi çalışıyor, ancak 0'dan 65535'e kadar taramak için çok fazla zaman harcıyor. 5 dakikadan kısa sürede 0'dan 65535'e tarayabilen başka bir yolu var mı?


26
2017-07-18 17:32


Menşei


Konu denediniz mi? - elias


Cevaplar:


65536 bağlantı noktasının her biri için 200 ms'ye ihtiyacınız varsa (en kötü durumda, bir güvenlik duvarı her şeyi engeller, böylece her bir bağlantı noktası için zaman aşımınızı vurursunuz), matematik oldukça basittir: 13k saniyeye veya yaklaşık 3 saate Yarım.

Daha hızlı hale getirmek için 2 (münhasır olmayan) seçeneğiniz var:

  • zaman aşımını azalt
  • kodunuzu paralellize

İşlem G / Ç bağlı olduğundan (CPU'nun tersine, yani, G / Ç için beklemek için zaman harcarsınız, ve büyük bir hesaplama için tamamlanmaz), pek çok iş parçacığı kullanabilirsiniz. 20 ile başlamayı deneyin. Onlar aralarında 3 saat bir buçuk bölmek, bu yüzden beklenen maksimum süre yaklaşık 10 dakikadır. Sadece bunun diğer tarafa baskı uygulayacağını unutmayın, yani taranan ev sahibi, "mantıksız" veya "garip" kalıplarla büyük ağ etkinliğini görecek ve taramayı çok kolay bir şekilde algılayacaktır.

En kolay yol (örneğin, minimum değişikliklerle) ExecutorService ve Future API'lerini kullanmaktır:

public static Future<Boolean> portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) {
  return es.submit(new Callable<Boolean>() {
      @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;
        }
      }
   });
}

Sonra, şöyle bir şey yapabilirsiniz:

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<Future<Boolean>> 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<Boolean> f : futures) {
    if (f.get()) {
      openPorts++;
    }
  }
  System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)");
}

Bilmen gerekiyorsa hangi portlar açık (ve sadece kaçYukarıdaki örnekte olduğu gibi) işlevinin dönüş türünü değiştirmeniz gerekir. Future<SomethingElse>, nerede SomethingElse bağlantı noktasını ve tarama sonucunu tutardı, şöyle bir şey:

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

Sonra değiş Boolean için ScanResult ilk snippet'te ve dönüş new ScanResult(port, true) veya new ScanResult(port, false) sadece yerine true veya false

DÜZENLEME: Aslında fark ettim: Bu durumda, sonuç + bağlantı noktasını tutmak için ScanResult sınıfına ihtiyacınız yoktur ve yine de hangi bağlantı noktasının açık olduğunu bilmeniz gerekmez. Gelecekleri bir Liste, hangisi düzenlive sonra, sen bunları eklediğiniz sırayla işleyinHangi iĢlemle uğraĢtığınızı bilmek için her iterasyona katılacağınız bir sayaca sahip olabilirsiniz. Ama, hey, bu sadece tam ve kesin olmaktır. Bunu yapmaya hiç çalışmayınKorkunç, bu konuda düşündüğümden çok utanıyorum. ScanResult nesnesini kullanmak çok daha temiz, kodu okumak ve korumak için daha kolay ve daha sonra, örneğin, bir CompletionService tarayıcıyı geliştirmek.


60
2017-07-18 17:34



Kullanmadim ama bir SocketFactory olmaz (docs.oracle.com/javase/7/docs/api/javax/net/SocketFactory.html) yardım etmek mi? - WinOrWin
SocketFactory'nin bu problemi nasıl kullandığını gerçekten göremiyorum. Aklında ne olduğunu açıklamak ister misiniz? - Bruno Reis
SocketFactory'ın destekte bir SocketPool gibi bir şey olması için uygulanabileceğini düşündüm, bu da hızlanmaya neden olabilir. Bu işe yaramazsa emin değilim .. bu bir öneri değil, sadece sizin yaklaşımınıza bir sorgu. - WinOrWin
Bu bağlamda bir "SocketPool" hiç bir anlam ifade etmiyor. Bir TCP yuvası dörtlüdür (src-ip, src-port, dest-ip, dest-port) değişmez olan (yani, bağlantının ortasında ips veya portları değiştiremezsiniz); Test ettiğiniz her port farklı bir dest port olduğundan, test ettiğiniz her port için farklı bir TCP Soketine ihtiyacınız olduğunu görüyorsunuz, bu nedenle hiçbir havuzlama işe yaramıyor. - Bruno Reis
Teşekkürler, bu genellikle benim için bir karmaşadır. - WinOrWin


Taramanın paralelleştirilmesinin yanı sıra, burada açıklananlar (TCP SYN ve TCP FIN taraması) gibi daha gelişmiş bağlantı noktası tarama tekniklerini kullanabilirsiniz: http://nmap.org/nmap_doc.html. Bir uygulamanın VB kodu burada bulunabilir: http://h.ackack.net/spoon-worlds-fastest-port-scanner.html

Bununla birlikte, bu teknikleri kullanabilmek için ham TCP / IP soketlerini kullanmanız gerekir. Kullanmalısın Rocksaw bunun için kütüphane.


4
2017-07-18 17:49





Kod örneği "Bruno Reis" den esinlenilmiştir.

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<Future<ScanResult>> 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<ScanResult> 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<ScanResult> portIsOpen(final ExecutorService es, final String ip, final int port,
        final int timeout) {
    return es.submit(new Callable<ScanResult>() {
        @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;
    }

}
}

3
2018-05-20 13:51





Android için bu Harika Kitaplığı deneyin

https://github.com/stealthcopter/AndroidNetworkTools


2
2018-05-21 00:29





Nmap seçeneğini kullanmaya karar verirseniz ve Java ile devam etmek istiyorsanız, SourceForge.net üzerinde Nmap4j'ye bakmanız gerekir (http://nmap4j.sourceforge.net). Nmap'i bir java uygulamasına entegre etmenizi sağlayan basit bir API.

--Jon


1
2017-07-19 19:35





Nmap gibi TCP-SYN-Scan yoluyla portları tarayabilen kendi asenkron portscanner java servisimi yazdım. Aynı zamanda IMCP ping taramalarını destekler ve çok yüksek bir verimlilikle çalışabilir (ağın ne yapabileceğine bağlı olarak):

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

Dahili olarak java bağlayıcı bir pcap kullanır ve hizmetlerini JMS / AMQP üzerinden sunar. Kök izinlerine sahip olup olmadığını düşünmüyorsanız, doğrudan uygulamanızda da kullanabilirsiniz.


1
2018-06-09 19:17