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에서도 패킷이 전송되었다는 부분을 볼 수 있다.
Uploaded by Notion2Tistory v1.1.0