1. 윈도우에서 Pcap을 테스트 하기 위해서는 Pcap이 설치 되어 있어야 한다.

  • 설치파일 : https://www.winpcap.org/install/ 에서 인스톨파일 다운로드(WinPcap_4_1_3.exe)
  • 다운로드한 WinPcap을 관리자권한으로 설치

2. Centos, Rocky Linux에서 pcap을 사용하려면 libpcap 설치

libpcap-1.10.4.tar.gz 수동 설치 할 경우 (Root 권한으로 진행)

1. 파일 다운로드
wget http://www.tcpdump.org/release/libpcap-1.10.1.tar.gz

2. 압축해제
tar -xzf libpcap-1.10.1.tar.gz

3. 압축해제된 폴더로 이동해서 설치 (configure 시 설치경로 /usr 지정)
./configure --prefix=/usr
make
make install

4. 설치 완료 후 설치 경로에 라이브러리 있는지 확인
ls /usr/include/pcap.h
ls /usr/lib64/libpcap.so

5. /usr/include/pcap.h에 없고 /usr/local/include/pcap.h에 있으면 심볼 생성
ln -s /usr/local/include/pcap.h /usr/include/pcap.h

6. usr/lib64 path 설정 (다른 방법으로도 전역으로 생성하면 됨)
echo 'export LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

 

  • pcap 설치 확인 및 테스트
간단하게 C로 인터페이스 출력하는 코드로 설치가 정상적으로 됐는지 확인

1. vi로 테스트 코드 작성
vi pcaptest.c

2. pcaptest.c 내용
#include <pcap.h>
#include <stdio.h>

int main() {
    pcap_if_t *alldevs, *dev;
    char errbuf[PCAP_ERRBUF_SIZE];

    // 모든 네트워크 장치 목록을 가져옴
    if (pcap_findalldevs(&alldevs, errbuf) == -1) {
        printf("Error finding devices: %s\n", errbuf);
        return 1;
    }

    // 첫 번째 장치를 선택 (기본 장치)
    dev = alldevs;
    if (dev == NULL) {
        printf("No devices found.\n");
        pcap_freealldevs(alldevs); // 메모리 해제
        return 1;
    }

    printf("Interface: %s\n", dev->name);

    // 장치 목록에서 사용한 메모리 해제
    pcap_freealldevs(alldevs);

    return 0;
}

3. pcaptest.c 컴파일
gcc -o pcaptest pcaptest.c -lpcap

4. pcaptest.c 컴파일을 하면 pcaptest 파일이 생성되면 실행이 정상적으로 되는지 확인
./pcaptest

5. ./pcaptest 실행하면 나오는 경과
Interface: eth0   <---eth0은 서버 환경에 따라서 다를 수 있음

 

3. Java Spring 구현

  • pom.xml에 pcap4j 라이브러리 Maven Dependency 추가
<dependency>
        <groupId>org.pcap4j</groupId>
         <artifactId>pcap4j-core</artifactId>
         <version>1.7.4</version>
</dependency>
<dependency>
         <groupId>org.pcap4j</groupId>
         <artifactId>pcap4j-packetfactory-static</artifactId>
         <version>1.7.4</version>
</dependency>

 

  • PcapHandleWrapper.class 작성
import org.pcap4j.core.PcapHandle;

public
class PcapHandleWrapper {

         private PcapHandle handle;
         public PcapHandleWrapper(PcapHandle handle) {
                  this.handle = handle;
         }
          public PcapHandle getHandle() {
                    return handle;
          }
          public void setHandle(PcapHandle handle) {
                    this.handle = handle;
          }
}

 

  • 테스트 샘플
import java.net.InetAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.pcap4j.core.BpfProgram;
import org.pcap4j.core.PcapHandle;
import org.pcap4j.core.PcapNetworkInterface;
import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode;
import org.pcap4j.core.Pcaps;
import org.pcap4j.packet.EthernetPacket;
import org.pcap4j.packet.IpV4Packet;
import org.pcap4j.packet.Packet;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import egovframework.example.utils.PcapHandleWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Controller
@RequestMapping("/mactest")
@RequiredArgsConstructor
@Log4j2
public class MacAddrSampleController {

    private static PcapHandleWrapper handleWrapper;



     @ResponseBody
     @GetMapping(value = {"/pcap4j"})
     public String pcap4j5(HttpServletRequest req ,HttpServletResponse rep,
          //client IP
          @RequestParam(name = "targetIP", defaultValue = "192.168.35.224") String targetIP) throws Exception {

          //Was가 동작하고 있는 server IP
          String serverIP = "192.168.35.28";

          ExecutorService executor = Executors.newSingleThreadExecutor();

         
try {


               //Was가 동작하고 있는 server IP
               InetAddress addr = InetAddress.getByName(serverIP);
               PcapNetworkInterface device = Pcaps.getDevByAddress(addr);

               if (device == null) {
                    System.out.println("네트워크 인터페이스를 선택하지 않았습니다.");
                     return "네트워크 인터페이스를 선택하지 않았습니다.";
               }

              
// 캡처 설정

               int snaplen = 65536; // 최대 캡처할 패킷 크기
               PromiscuousMode mode = PromiscuousMode.PROMISCUOUS; // Promiscuous 모드
               int timeout = 50; // 타임아웃 (단위: ms)
               PcapHandle handle = device.openLive(snaplen, mode, timeout);

               handleWrapper = new PcapHandleWrapper(handle);

               String filter = "ip host " + targetIP;

               handle.setFilter(filter, BpfProgram.BpfCompileMode.OPTIMIZE);

               executor.submit(() -> {

                    try {

                             
while (true) { // 무한 루프


                                   Packet
packet = handleWrapper.getHandle().getNextPacket();


                                       
if (packet != null) {


                                                     EthernetPacket
ethernetPacket = packet.get(EthernetPacket.class);

                                                       if (ethernetPacket != null) {

                                                            // IP 패킷으로 변환
                                                            IpV4Packet ipV4Packet = packet.get(IpV4Packet.class);

                                                           
if (ipV4Packet != null) {


                                                                
// 목적지 MAC 주소 추출

                                                                 String dstAddr = ipV4Packet.getHeader().getDstAddr().getHostAddress();
                                                                 String dstMacAddrIp = ethernetPacket.getHeader().getDstAddr().toString();

                                                                      if(dstAddr != null && targetIP.equals(dstAddr)) {
                                                                           System.out.println("Destination IP Address: " + dstAddr);
                                                                           System.out.println("Destination MAC Address: " + dstMacAddrIp);
                                                                       }

                                                             }

                                                       }

                                         }
                                  }

                    } catch (Exception e) {
                         e.printStackTrace();
                    } finally {
                         handleWrapper.getHandle().close();
                    }
               });


          // ExecutorService 종료 대기
          Runtime.getRuntime().addShutdownHook(new Thread(() -> {

               try {

                    executor.shutdown();

                    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                         executor.shutdownNow();
                    }

               } catch (InterruptedException e) {
                    executor.shutdownNow();
               }

          }));


         } catch (Exception e) {
               e.printStackTrace();
         }

          return "pcap 스레드 동작 중";

     }


}

웹 프로젝트에서 테스트를 진행 했기 대문에 웹 호출로 스레드를 구동하고 나면 모니터링이 시작되고

웹페이지에 접속하는 클라이언트의 정보를 pcap으로 통해 가져 올 수 있다.

 

* 같은 망에서만 mac 정보를 가져올 수 있고 망이 다르면 가져올 수 없다.

https://kkubi-story.tistory.com/21

 

pcap 동작 원리

pcap(Packet Capture) 도구를 사용해도 망이 다르면 MAC 주소 정보를 가져올 수 없다. 이는 네트워크의 기본적인 동작 원리에 따른 것이다. 이유 설명 1. MAC 주소의 역할과 ARP 프로토콜

kkubi-story.tistory.com

 

+ Recent posts