1. 개요
Java를 사용한 포트 스캔은 대상 시스템의 열린 포트 또는 활성 포트를 열거하는 방법입니다. 목표는 주로 현재 실행 중인 응용 프로그램 및 서비스를 알기 위해 열린 포트를 나열하는 것입니다.
이 사용방법(예제)에서는 호스트에서 열린 포트를 검색하는 데 사용할 수 있는 Java로 포트 검색을 위한 간단한 애플리케이션을 개발하는 방법을 설명합니다 .
2. 컴퓨터 포트란 무엇입니까?
컴퓨터 포트는 특정 서비스를 연결과 연결할 수 있게 해주는 논리적 엔터티입니다. 또한 포트는 1에서 65535까지의 정수로 식별됩니다. 규칙에 따라 처음 1024개는 다음과 같은 표준 서비스용으로 예약되어 있습니다.
- 포트 20: FTP
- 포트 23: 텔넷
- 포트 25: SMTP
- 포트 80: HTTP
포트 스캐너의 아이디어는 TCP 소켓 을 만들고 특정 포트에 연결을 시도하는 것입니다. 연결이 성공적으로 설정되면 이 포트를 열린 것으로 표시하고 그렇지 않은 경우 닫힌 것으로 표시합니다.
그러나 각 65535 포트에서 연결을 설정하는 데는 포트당 최대 200ms가 소요될 수 있습니다. 이것은 짧은 시간처럼 들릴 수 있지만 전체적으로 단일 호스트의 모든 포트를 하나씩 스캔하는 데 상당한 시간이 걸립니다 .
성능 문제를 해결하기 위해 다중 스레드 방식 을 사용합니다 . 이렇게 하면 각 포트에 순차적으로 연결을 시도하는 것과 비교하여 프로세스 속도를 크게 높일 수 있습니다.
3. 시행
프로그램을 구현하기 위해 두 개의 매개변수를 입력으로 사용하여 portScan() 함수를 만듭니다 .
- ip : 스캔 할 IP 주소. localhost의 경우 127.0.0.1과 동일합니다.
- nbrPortMaxToScan : 스캔할 최대 포트 수. 모든 포트를 스캔하려는 경우 이 숫자는 65535와 같습니다.
3.1 구현
portScan() 메서드가 어떻게 생겼는지 봅시다 :
public void runPortScan(String ip, int nbrPortMaxToScan) throws IOException {
ConcurrentLinkedQueue openPorts = new ConcurrentLinkedQueue<>();
ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
AtomicInteger port = new AtomicInteger(0);
while (port.get() < nbrPortMaxToScan) {
final int currentPort = port.getAndIncrement();
executorService.submit(() -> {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, currentPort), timeOut);
socket.close();
openPorts.add(currentPort);
System.out.println(ip + " ,port open: " + currentPort);
} catch (IOException e) {
System.err.println(e);
}
});
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
List openPortList = new ArrayList<>();
System.out.println("openPortsQueue: " + openPorts.size());
while (!openPorts.isEmpty()) {
openPortList.add(openPorts.poll());
}
openPortList.forEach(p -> System.out.println("port " + p + " is open"));
}
우리의 메서드는 열려 있는 모든 포트 가 있는 List 을 반환합니다. 이를 위해 두 호스트 간의 커넥터로 사용할 새 소켓 개체를 만듭니다. 연결이 성공적으로 설정되면 포트가 열려 있다고 가정하고 이 경우 다음 줄로 계속 진행합니다. 반면에 연결이 실패하면 포트가 닫히고 SocketTimeoutException 이 발생하며 예외 catch 블록으로 넘어간다고 가정합니다.
3.2 멀티스레딩
대상 머신의 모든 65535개 포트를 스캔하는 데 필요한 시간을 최적화하기 위해 방법을 동시에 실행합니다. 우리는 실행할 스레드 풀과 작업 Queue을 캡슐화하는 ExecutorService 를 사용합니다. 풀의 모든 스레드가 계속 실행 중입니다.
서비스는 Queue에서 작업을 처리해야 하는지 확인하고 처리해야 하는 경우 작업을 철회하고 실행합니다. 작업이 실행되면 스레드는 서비스가 Queue에서 새 작업을 할당할 때까지 다시 기다립니다.
또한 우리는 10개의 스레드 가 있는 FixedThreadPool 을 사용하는데 , 이는 프로그램이 최대 10개의 스레드를 병렬로 실행한다는 것을 의미합니다. 시스템 구성 및 용량에 따라 이 풀 크기를 조정할 수 있습니다.
4. 결론
이 빠른 사용방법(예제)에서는 Socket 및 다중 스레드 접근 방식을 사용하여 Java로 포트 스캔을 위한 간단한 응용 프로그램을 개발하는 방법을 설명했습니다.
항상 그렇듯이 코드 스니펫은 GitHub 에서 사용할 수 있습니다 .