Подтвердить что ты не робот

Самый быстрый способ сканирования портов с помощью Java

Я сделал очень простой сканер портов, но он работает слишком медленно, поэтому я ищу способ ускорить его сканирование. Вот мой код:

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 минут?

4b9b3361

Ответ 1

Если вам нужен 200 мс для каждого из портов 65536 (в худшем случае брандмауэр блокирует все, что заставляет вас ударить ваш тайм-аут для каждого отдельного порта), математика довольно проста: вам нужно 13 тыс. секунд или около 3 часа с половиной.

У вас есть 2 (неисключительных) варианта, чтобы сделать это быстрее:

  • уменьшить время ожидания
  • paralellize ваш код

Поскольку операция связана с вводом-выводом (в отличие от привязки к ЦП, т.е. вы тратите время, ожидая ввода-вывода, а не для завершения какого-либо огромного вычисления), вы можете использовать многие, многие темы. Попробуйте начать с 20. Они разделили бы 3 часа с половиной среди них, , поэтому максимальное ожидаемое время составляет около 10 минут. Просто помните, что это будет оказывать давление на другую сторону, то есть сканированный хост увидит огромную сетевую активность с "необоснованными" или "странными" шаблонами, что сделает сканирование чрезвычайно простым для обнаружения.

Самый простой способ (т.е. с минимальными изменениями) - использовать API-интерфейс ExecutorService и Future:

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
}

Затем измените Boolean на ScanResult в первом фрагменте и верните new ScanResult(port, true) или new ScanResult(port, false) вместо просто true или false

EDIT: На самом деле, я просто заметил: в этом конкретном случае вам не нужен класс ScanResult для хранения порта результата + и все еще известно, какой порт открыт. Поскольку вы добавляете фьючерсы в Список, который упорядочен, а затем вы обрабатываете их в том же порядке, в котором вы добавили их, у вас может быть счетчик, который вы увеличивали бы на каждой итерации, чтобы узнать, с каким портом вы имеете дело. Но, эй, это просто быть полным и точным. Никогда не пытайтесь делать это, это ужасно, мне в основном стыдно, что я думал об этом... Использование объекта ScanResult намного чище, код проще читать и обслуживать, а также позволяет, например, использовать CompletionService для улучшения сканера.

Ответ 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.

Ответ 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;
    }

}
}

Ответ 5

Если вы решили использовать опцию Nmap и хотите продолжить работу с Java, вам следует взглянуть на Nmap4j на SourceForge.net.

Это простой API, который позволяет интегрировать Nmap в Java-приложение.

Ответ 6

Я написал свой собственный асинхронный Java-сервис portscanner, который может сканировать порты через TCP-SYN-Scan, как это делает Nmap. Он также поддерживает сканирование ping IMCP и может работать с очень высокой пропускной способностью (в зависимости от того, что может поддерживать сеть):

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

Внутри он использует java binding pcap и предоставляет свои услуги через JMS/AMQP. Хотя вы также можете использовать его непосредственно в своем приложении, если не возражаете, если у вас есть права root.

Ответ 7

Нет, самый быстрый способ здесь - использовать метод динамически создаваемого потока

Executors.newCachedThreadPool();

Таким образом, он использует потоки до тех пор, пока все они не будут приняты, затем, когда все они будут заняты, и появится новое задание, он откроет новый поток и выполнит перед ним новое задание.

Вот мой фрагмент кода (Кредиты из-за Джека и Бруно Рейса)

Я также добавил функцию для поиска любого IP-адреса, который вы вводите, для получения дополнительной функциональности и простоты использования.

    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;

    class PortScanner {

    public static void main(final String... args) throws InterruptedException, ExecutionException 
    {
        final ExecutorService es = Executors.newCachedThreadPool();
        System.out.print("Please input the ip address you would like to scan for open ports: ");
        Scanner inputScanner = new Scanner(System.in);
        final String ip = inputScanner.nextLine();
        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;
}

    }
    }

Ответ 8

я не знаю, как использовать? simle yyyyyyyyyyyyyyyy