2030 Engineer

JnetPcap 본문

카테고리 없음

JnetPcap

Hard_Try 2021. 5. 20. 00:48

JnetPcap

  • C에서 사용하는 libpcap 라이브러리의 JAVA 확장판 라이브러리이다.
  • 캡처 한 패킷을 실시간으로 디코딩 가능
  • 네트워크 프로토콜의 대규모 라이브러리를 제공한다.
  • 사용자는 JAVA SDK를 사용하의 자신의 포로토콜 정의를 쉽게 추가할 수 있다.

package main;

import java.util.ArrayList;

import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;

public class Main {

  public static void main(String[] args) {
    // 네트워크 어댑터들을 저장할 수 있는 배열생성
    ArrayList<PcapIf> allDevs = new ArrayList<PcapIf>();
    // 오류 메시지를 담을 수 있는 변수 생성
    StringBuilder errbuf = new StringBuilder();
    // 오류 발생시 errbuf안에 오류들을 담게 된다.
    int r = Pcap.findAllDevs(allDevs, errbuf);
    // Pcap이 -1이거나 비어있으면 오류 발생 메시지 출력
    if (r == Pcap.NOT_OK || allDevs.isEmpty()) {
      System.out.println("네트워크 장치를 찾을 수 없습니다." + errbuf.toString());
      return;
    }
    System.out.println("네트워크 장비 탐색 성공!!");
    int i = 0;
    // 장치에 존재하는 네트워크들을 모두 탐색하여 null이 아니면 현재장치 설명담는 변수
    for (PcapIf device : allDevs) {
      String description = (device.getDescription() != null) ? device.getDescription() : "장비에 대한 설명이 없습니다.";
      System.out.printf("[%d]번 : %s [%s]n\n", i++, device.getName(), description);
    }
  }

}

패킷 가져오기

package main;

import java.util.ArrayList;
import java.util.Date;

import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;
import org.jnetpcap.packet.PcapPacket;
import org.jnetpcap.packet.PcapPacketHandler;

public class Main {

  public static void main(String[] args) {
    // 네트워크 어댑터들을 저장할 수 있는 배열생성
    ArrayList<PcapIf> allDevs = new ArrayList<PcapIf>();
    // 오류 메시지를 담을 수 있는 변수 생성
    StringBuilder errbuf = new StringBuilder();
    // 오류 발생시 errbuf안에 오류들을 담게 된다.
    int r = Pcap.findAllDevs(allDevs, errbuf);
    // Pcap이 -1이거나 비어있으면 오류 발생 메시지 출력
    if (r == Pcap.NOT_OK || allDevs.isEmpty()) {
      System.out.println("네트워크 장치를 찾을 수 없습니다." + errbuf.toString());
      return;
    }
    System.out.println("네트워크 장비 탐색 성공!!");
    int i = 0;
    // 장치에 존재하는 네트워크들을 모두 탐색하여 null이 아니면 현재장치 설명담는 변수
    for (PcapIf device : allDevs) {
      String description = (device.getDescription() != null) ? device.getDescription() : "장비에 대한 설명이 없습니다.";
      System.out.printf("[%d]번 : %s [%s]n\n", i++, device.getName(), description);
    }

    // 실제 사용할 네트워크를 지정하기 (나 같은 경우는 [Intel(R) I211 Gigabit Network Connection]
    PcapIf device = allDevs.get(1);
    System.out.printf("선택한 장치 : %s\n", (device.getDescription() != null) ? device.getDescription() : device.getName());

    int snaplen = 64 * 1024; // 패킷을 얼마나 캡쳐할 것인지에 대한 옵션
    int flags = Pcap.MODE_NON_PROMISCUOUS; // 패킷검열 없이 받아들이는 옵션
    int timeout = 10 * 1000; // 10000ms 만큼 timeout 설정
    Pcap pcap = Pcap.openLive(device.getName(), snaplen, flags, timeout, errbuf);
    // 에러 발생시 에러메시지 출력
    if (pcap == null) {
      System.out.printf("패킷 캡처를 위해 네트워크 장치를 여는 데 실패했습니다. 오류 : " + errbuf.toString());
      return;
    }
    // pcap에서 제공하는 함수임으로 Override를 해야하고 형식도 맞춰야한다.
    PcapPacketHandler<String> jPacketHandler = new PcapPacketHandler<String>() {
      @Override
      public void nextPacket(PcapPacket packet, String user) {
        System.out.printf("캡처 시작: %s\n 패킷의 길이: %-4d\n", new Date(packet.getCaptureHeader().timestampInMillis()),
            packet.getCaptureHeader().caplen());
      }
    };
		// loop를 통해 10개만 출력하게 했다.
    pcap.loop(10, jPacketHandler, "jNetPcap");
    pcap.close();
  }

}

네트워크 장비 탐색 성공!! [0]번 : {3408094B-9742-48B2-A4B0-E3AED8FF409D} [Microsoft]n [1]번 : {FB235D64-60DD-48C5-ABFB-26741A365F55} [Intel(R) I211 Gigabit Network Connection]n [2]번 : {49E7D5AD-8DB7-4962-9D59-D30CB71B0DBC} [Microsoft]n [3]번 : {A45A01EF-57C0-43FE-9760-0DB8FF20496E} [Microsoft]n [4]번 : {1C24F5B5-155C-47AE-83A6-2B737B8210D1} [Microsoft]n [5]번 : {0C0ABFFB-1641-4D17-8588-092161B5C18A} [TunnelBear Adapter V9]n 선택한 장치 : Intel(R) I211 Gigabit Network Connection 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 1529 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 60 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 1514 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 1514 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 60 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 54 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 1514 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 54 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 1514 캡처 시작: Mon Apr 05 14:26:36 KST 2021 패킷의 길이: 1514

MAC 주소 나타내기

package main;

import java.util.ArrayList;

import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;

public class Main {

  public static void main(String[] args) {
    // 네트워크 어댑터들을 저장할 수 있는 배열생성
    ArrayList<PcapIf> allDevs = new ArrayList<PcapIf>();
    // 오류 메시지를 담을 수 있는 변수 생성
    StringBuilder errbuf = new StringBuilder();
    // 오류 발생시 errbuf안에 오류들을 담게 된다.
    int r = Pcap.findAllDevs(allDevs, errbuf);
    // Pcap이 -1이거나 비어있으면 오류 발생 메시지 출력
    if (r == Pcap.NOT_OK || allDevs.isEmpty()) {
      System.out.println("네트워크 장치를 찾을 수 없습니다." + errbuf.toString());
      return;
    }
    System.out.println("네트워크 장비 탐색 성공!!");

    try {
      for (final PcapIf i : allDevs) {
        final byte[] mac = i.getHardwareAddress();
        if (mac == null) {
          continue;
        }
        System.out.printf("장치 주소 : %s\n맥주소 : %s\n", i.getName(), asString(mac));
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  // mac주소를 문자열형태로 나타내기 위함
  public static String asString(final byte[] mac) {
    final StringBuilder buf = new StringBuilder();
    for (byte b : mac) {
      if (buf.length() != 0) {
        buf.append(":");
      }
      if (b >= 0 && b < 16) {
        buf.append('0');
      }
      buf.append(Integer.toHexString((b < 0) ? b + 256 : b).toUpperCase());
    }
    return buf.toString();
  }
}

장치 주소 : {FB235D64-60DD-48C5-ABFB-26741A365F55} 맥주소 : 00:D8:61:A8:75:F6 장치 주소 : {49E7D5AD-8DB7-4962-9D59-D30CB71B0DBC} 맥주소 : 5C:87:9C:1D:12:3E 장치 주소 : {A45A01EF-57C0-43FE-9760-0DB8FF20496E} 맥주소 : 5C:87:9C:1D:12:3B 장치 주소 : {1C24F5B5-155C-47AE-83A6-2B737B8210D1} 맥주소 : 5E:87:9C:1D:12:3A 장치 주소 : {0C0ABFFB-1641-4D17-8588-092161B5C18A} 맥주소 : 00:FF:0C:0A:BF:FB

패킷 감청

package main;

import java.util.ArrayList;

import org.jnetpcap.Pcap;
import org.jnetpcap.PcapHeader;
import org.jnetpcap.PcapIf;
import org.jnetpcap.nio.JBuffer;
import org.jnetpcap.nio.JMemory;
import org.jnetpcap.packet.JRegistry;
import org.jnetpcap.packet.Payload;
import org.jnetpcap.packet.PcapPacket;
import org.jnetpcap.packet.format.FormatUtils;
import org.jnetpcap.protocol.lan.Ethernet;
import org.jnetpcap.protocol.network.Ip4;
import org.jnetpcap.protocol.tcpip.Tcp;



public class Main {


  public static void main(String[] args) {
    // 네트워크 어댑터들을 저장할 수 있는 배열생성
    ArrayList<PcapIf> allDevs = new ArrayList<PcapIf>();
    // 오류 메시지를 담을 수 있는 변수 생성
    StringBuilder errbuf = new StringBuilder();
    // 오류 발생시 errbuf안에 오류들을 담게 된다.
    int r = Pcap.findAllDevs(allDevs, errbuf);
    // Pcap이 -1이거나 비어있으면 오류 발생 메시지 출력
    if (r == Pcap.NOT_OK || allDevs.isEmpty()) {
      System.out.println("네트워크 장치를 찾을 수 없습니다." + errbuf.toString());
      return;
    }
    System.out.println("네트워크 장비 탐색 성공!!");
    int i = 0;
    // 장치에 존재하는 네트워크들을 모두 탐색하여 null이 아니면 현재장치 설명담는 변수
    for (PcapIf device : allDevs) {
      String description = (device.getDescription() != null) ? device.getDescription() : "장비에 대한 설명이 없습니다.";
      System.out.printf("[%d]번 : %s [%s]n\n", i++, device.getName(), description);
    }

    // 실제 사용할 네트워크를 지정하기 (나 같은 경우는 [Intel(R) I211 Gigabit Network Connection]
    PcapIf device = allDevs.get(1);
    System.out.printf("선택한 장치 : %s\n", (device.getDescription() != null) ? device.getDescription() : device.getName());

    int snaplen = 64 * 1024; // 패킷을 얼마나 캡쳐할 것인지에 대한 옵션
    int flags = Pcap.MODE_NON_PROMISCUOUS; // 패킷검열 없이 받아들이는 옵션
    int timeout = 10 * 1000; // 10000ms 만큼 timeout 설정
    Pcap pcap = Pcap.openLive(device.getName(), snaplen, flags, timeout, errbuf);
    // 에러 발생시 에러메시지 출력
    if (pcap == null) {
      System.out.printf("패킷 캡처를 위해 네트워크 장치를 여는 데 실패했습니다. 오류 : " + errbuf.toString());
      return;
    }
    // 네트워크 2계층 정보를 담는다
    Ethernet eth = new Ethernet();
    // 네트워크 3계층 정보를 담는다
    Ip4 ip = new Ip4();
    // 네트워크 4계층 정보를 담는다
    Tcp tcp = new Tcp();
    // 서버와 통신해서 데이터를 주고 받을 때 데이터가 들어가는 공간(ex. 로그인)
    Payload payload = new Payload();
    // 패킷 헤더
    PcapHeader header = new PcapHeader(JMemory.POINTER);
    // 패킷 버퍼
    JBuffer buf = new JBuffer(JMemory.POINTER);
    // 패킷 캡처시 필요한 id값
    int id = JRegistry.mapDLTToId(pcap.datalink());

    // 오류가 발생하지 않는 한 계속해서 패킷을 캡처할 수 있도록 하는 While 구문
    while (pcap.nextEx(header, buf) != Pcap.NEXT_EX_NOT_OK) {
      PcapPacket packet = new PcapPacket(header, buf);
      packet.scan(id);
      System.out.printf("[ #%d ]\n", packet.getFrameNumber());
      if (packet.hasHeader(eth)) {
        System.out.printf("출발지 MAC 주소 = %s\n도착지 MAC 주소 = %s\n", FormatUtils.mac(eth.source()),
        		FormatUtils.mac(eth.destination()));
      }
      if (packet.hasHeader(ip)) {
        System.out.printf("출발지 IP 주소 = %s\n도착지 IP 주소 = %s\n",
        		FormatUtils.ip(ip.source()), FormatUtils.ip(ip.destination()));
      }
      if (packet.hasHeader(tcp)) {
        System.out.printf("출발지 TCP 주소 = %d\n도착지 TCP 주소 = %d\n",
        		tcp.source(), tcp.destination());
      }
      if(packet.hasHeader(payload)) {
        System.out.printf("페이로드의 길이 = %d\n", payload.getLength());
        System.out.print(payload.toHexdump());
      }
    }
    pcap.close();
  }
}

패킷 감청 일부분

[ #31 ] 출발지 MAC 주소 = 70:5D:CC:7E:67:1C 도착지 MAC 주소 = 00:D8:61:A8:75:F6 출발지 IP 주소 = 162.254.195.71 도착지 IP 주소 = 192.168.0.26 페이로드의 길이 = 404 0000: 56 53 30 31 70 01 06 02 ba 65 2f 00 02 00 00 00 VS01p....e/..... 0010: 5f 02 00 00 08 04 00 00 01 00 00 00 5f 02 00 00 _..........._... 0020: 70 01 00 00 e0 ac a5 c7 b5 02 89 b1 8c 66 78 76 p............fxv 0030: 4d 52 bb 2b d7 37 37 35 37 df 71 0b 00 c9 aa 55 MR.+.7757.q....U 0040: f4 91 c3 cd 6e 1f a7 51 2b 1a b2 1f 93 98 85 f6 ....n.Q+...... 0050: 84 5f bd 89 68 2c a0 14 d2 ca 50 94 7c 0c 0f c8 ._..h,....P.|... 0060: 8c 40 7c af 24 9b 8e d9 53 19 45 0a 65 7b 62 ea .@|.$...S.E.e{b. 0070: 7b 52 19 50 bb 1f 20 0d 67 0d 10 45 03 16 78 aa {R.P. .g..E..x. 0080: 51 1b 46 6e 28 cb f6 de d6 70 8c 3c 44 f1 07 bb Q.Fn(....p.<D... 0090: e8 1d 15 53 6c 87 b0 a6 72 58 12 c1 70 f5 10 89 ...Sl...rX..p... 00a0: 11 17 1c f7 2b f9 fc 2a a8 24 0e ab 9d 1e 37 df ....+..*.$....7. 00b0: 22 e7 83 64 ea 83 cf 1f 97 e0 eb 56 80 9e fe fe "..d......V.... 00c0: 96 24 a9 87 39 16 06 f1 9f ed aa 95 14 08 13 f9 .$..9........... 00d0: b4 68 66 6f 95 a8 ae e4 e9 6e 25 ef d8 dc ed 5f .hfo.....n%...._ 00e0: 67 f2 9d 62 eb a2 f0 dc fa 9e 0c bd 7f 61 00 cf g..b.........a.. 00f0: d5 4c f2 2f 44 4d c9 f0 49 b6 f4 26 83 0c c3 c8 .L./DM..I..&.... 0100: 90 66 29 24 ea c2 fb 9a 79 6b 85 b5 e7 02 e1 ef .f)$....yk...... 0110: c2 4a 5a 8c 20 da 83 1c 33 95 65 71 9a b6 a8 bc .JZ. ...3.eq.... 0120: 34 2c d1 a1 a8 fc 34 22 7a ce 6b 91 97 33 2e 73 4,....4"z.k..3.s 0130: ed 8d 46 a5 e0 14 8c a6 78 b9 aa ed 45 e1 a7 4d ..F.....x...E..M 0140: fe 1c 58 46 12 b1 04 7c 8a 43 3d 01 84 05 4f 4a ..XF...|.C=...OJ 0150: 66 ae c6 35 eb 18 ca 9d 56 ce 29 ae 80 d6 c4 51 f..5....V.)....Q 0160: 47 91 e7 41 c3 a3 cd a3 e9 d2 e8 53 37 58 83 09 G..A.......S7X.. 0170: 9a d3 68 74 af 56 21 43 6a 59 8f e4 75 d0 35 12 ..ht.V!CjY..u.5. 0180: 1c 12 b4 3a 40 77 38 b0 4b b7 f0 3a e9 51 f1 43 ...:@w8.K..:.Q.C 0190: 3c d2 2c 23 <.,#

패킷전송하기

package main;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;

import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;

public class Main {

  public static void main(String[] args) {
    // 네트워크 어댑터들을 저장할 수 있는 배열생성
    ArrayList<PcapIf> allDevs = new ArrayList<PcapIf>();
    // 오류 메시지를 담을 수 있는 변수 생성
    StringBuilder errbuf = new StringBuilder();
    // 오류 발생시 errbuf안에 오류들을 담게 된다.
    int r = Pcap.findAllDevs(allDevs, errbuf);
    // Pcap이 -1이거나 비어있으면 오류 발생 메시지 출력
    if (r == Pcap.NOT_OK || allDevs.isEmpty()) {
      System.out.println("네트워크 장치를 찾을 수 없습니다." + errbuf.toString());
      return;
    }
    System.out.println("네트워크 장비 탐색 성공!!");
    int i = 0;
    // 장치에 존재하는 네트워크들을 모두 탐색하여 null이 아니면 현재장치 설명담는 변수
    for (PcapIf device : allDevs) {
      String description = (device.getDescription() != null) ? device.getDescription() : "장비에 대한 설명이 없습니다.";
      System.out.printf("[%d]번 : %s [%s]n\n", i++, device.getName(), description);
    }

    // 실제 사용할 네트워크를 지정하기 (나 같은 경우는 [Intel(R) I211 Gigabit Network Connection]
    PcapIf device = allDevs.get(1);
    System.out.printf("선택한 장치 : %s\n", (device.getDescription() != null) ? device.getDescription() : device.getName());

    int snaplen = 64 * 1024; // 패킷을 얼마나 캡쳐할 것인지에 대한 옵션
    int flags = Pcap.MODE_NON_PROMISCUOUS; // 패킷검열 없이 받아들이는 옵션
    int timeout = 10 * 1000; // 10000ms 만큼 timeout 설정
    Pcap pcap = Pcap.openLive(device.getName(), snaplen, flags, timeout, errbuf);

    byte[] bytes = new byte[14];
    Arrays.fill(bytes, (byte) 0xff);
    // 전송을 하기 위한 기본 변수 설정
    ByteBuffer buffer = ByteBuffer.wrap(bytes);
    // 전송 실패시
    if (pcap.sendPacket(buffer) != Pcap.OK) {
      System.out.println(pcap.getErr());
    }
    // 어떠한 메시지를 실질적으로 보냈는지 확인하는 부분
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
      // 0xff 와 AND연산해서 1인 부분만 true 연산
      sb.append(String.format("%02x ", b & 0xff));
    }
    System.out.println("전송한 패킷 : " + sb.toString());

    pcap.close();
  }
}

선택한 장치 : Intel(R) I211 Gigabit Network Connection 전송한 패킷 : ff ff ff ff ff ff ff ff ff ff ff ff ff ff

실제로 wireshark에서도 패킷이 전송되었다는 부분을 볼 수 있다.

Comments