扫描与Java接口的最快方法(Fastest way to scan ports with Java

2019-06-17 11:21发布

我做了很简单的端口扫描器,但它运行速度太慢,所以我在寻找方法,使之更快地扫描。 这里是我的代码:

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

这里的代码测试,如果特定端口上的特定IP开放。 对于超时我用的200最小值,因为当我去降低它没有足够的时间来测试该端口。 那么它运作良好,但需要太多的扫描从0到65535是否有也许可以从0到65535不到5分钟扫描任何其他方式?

Answer 1:

如果你需要200毫秒为每个65536个端口(在最坏的情况下,防火墙阻止了一切,从而使你打你的每一个端口超时),在数学很简单:你需要13K秒,或者约3小时一半。

你有2个(非独家)选项,使其更快:

  • 减少你的超时
  • paralellize代码

由于该操作是I /界O(对比势必CPU -也就是说,你花时间等待I / O,而不是为一些巨大的计算来完成), 您可以用很多很多的线程 。 尝试用20起他们将分成3个半小时当中, 所以预期的最大时间约为10分钟 。 请记住,这将施压的另一面,即扫描主机会看到“不合理”或“奇怪”的模式庞大的网络活动,使得扫描非常容易察觉。

最简单的方法(即以最小的变化)是使用ExecutorService的和未来的API:

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

然后,你可以这样做:

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

如果您需要知道哪些端口是开放的 (而不是有多少 ,如上面的例子),你需要改变功能的返回类型Future<SomethingElse>其中SomethingElse将持有端口和结果扫描的,是这样的:

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

然后,更改BooleanScanResult在第一个片段,并返回new ScanResult(port, true)new ScanResult(port, false) ,而不是仅仅的truefalse

编辑:其实,我只注意到:在这种特殊情况下,你不需要ScanResult类来保存结果+端口,并且还知道哪些端口是开放的。 既然你添加期货清单 ,该清单有序的 ,并且,以后,你在你加入他们的相同顺序处理它们 ,你可以有你想要增加在每次迭代知道你正在处理哪个端口计数器。 但是,嘿,这只是为了完整和明确。 千万不要尝试这样做,这太可怕了,我主要是惭愧,我想过这个... 使用ScanResult对象是干净多了 ,代码的方式更容易阅读和维护,并允许你,以后,例如,使用CompletionService来提高扫描仪。



Answer 2:

除了并行扫描时,可以使用更先进的端口扫描技术,像的那些(TCP SYN和TCP FIN扫描)这里解释: http://nmap.org/nmap_doc.html 。 实现的VB代码可以在这里找到: http://h.ackack.net/spoon-worlds-fastest-port-scanner.html

为了使用这些技术,但是,您需要使用原始TCP / IP套接字。 您应该使用RockSaw库这一点。



Answer 3:

代码示例由“布鲁诺雷斯”的启发

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

}
}


Answer 4:

为Android试试这个真棒图书馆

https://github.com/stealthcopter/AndroidNetworkTools



Answer 5:

如果你决定使用Nmap的选项,并希望继续使用Java,你应该看看Nmap4j SourceForge.net上(http://nmap4j.sourceforge.net)。 这是一个简单的API,可以让你的Nmap集成到Java应用程序。

--Jon



Answer 6:

我写我自己的异步端口扫描工具Java服务,可以通过TCP-SYN扫描扫描端口像Nmap的一样。 它还支持IMCP平的扫描,并且可以具有非常高的吞吐量工作(这取决于网络能够维持):

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

内部它使用Java绑定PCAP并通过JMS / AMQP公开其服务。 虽然你也可以在你的应用程序直接使用它,如果你不介意它具有root权限。



文章来源: Fastest way to scan ports with Java