バックグラウンド
Java自体はネットワーク層と次のプロトコルの処理をサポートしていません(私はjava8を使用していますが、ほとんど知らないかもしれませんが、このように見えます)。関連するネットワークスニッフィング開発にJavaを使用する場合は、jpcapやJNetPcapなどのいくつかのライブラリを使用する必要があります。jpcapはあまり早く維持されておらず、jNetPcapほど機能的ではないため、JNetPcapをお勧めします。
この記事では、WindowsでのjNetPcap開発環境の構成を紹介します。Linuxの場合は、いくつかの問題点を説明する記事を書きます。
jNetPcapの紹介
jNetPcapは、libcapまたはWinPcapのJavaカプセル化であり、JNIを介して呼び出されます。jNetPcapはこれを見ることができます:https://sourceforge.net/projects/jnetpcap/
libpcap / winpcapに慣れていない場合は、いくつかの関連情報を見つけることができます。
ここでは、libpcap / winpcapの使用法を簡単に紹介します。コンピューターでは、トラフィックはネットワーク駆動型デバイスを通過します。開発者がオペレーティングシステムでパケットをキャプチャする場合は、関連するインターフェイスを調整してから、自然に調整します。研究所はlibpcapを開発し、関連するインターフェースを提供しました。これにより、開発者はC言語を使用して、トラフィックキャプチャやその他の操作のためにlibpcapの関連するインターフェースを呼び出すことができます。
winpcapとは何ですか?libpcapはLinuxシステムにインストールされるライブラリであり、winpcapはWindowsにインストールされます。したがって、たとえば、wiresharkなどのパケットキャプチャツールをWindowsにインストールする場合は、winpcapをインストールする必要があります。もちろん、古いwiresharkはwinpcapを使用します。しばらく前に最新バージョンをインストールしました。インストールしたものは別のものです。これは互換性を置き換えてサポートすることができます。winpcapのライブラリは、呼び出すのを忘れていました。pcapのようです。Linuxにtcpdumpをインストールするようなものであれば、libpcapをインストールすることを意味します。これは同じ理由です。Elasticsearchスタックのコンポーネントであるpacketbeatを理解し、この軽量ネットワークデータコレクターを使用したことがある場合は、その下部で使用されるトラフィックキャプチャツールもlibpcapである可能性があり、そうである必要はないことも理解する必要があります。また、他のものを使用することもできます。
もちろん、Linuxでのパケットキャプチャの基盤となる依存関係ライブラリは必ずしもlibpcapである必要はありません。以前、関連する論文でより優れたライブラリをいくつか見ました。
次に、JavajNetPcapでlibpcap / winpcapを呼び出す方法について説明します。jNetPcapはJava言語でカプセル化されたライブラリですが、libpcap / winpcapを直接呼び出すことはありません。代わりに、ダイナミックリンクライブラリが提供されます。Windowsではjnetpcap.dll、Linuxではlibjnetpcap.soです。jNetPcapはjniを介してjnetpcap.dllのインターフェースを呼び出し、次にjnetpcap.dllの実現はwinpcapのインターフェースを呼び出します。これはおそらく同じ理由です。Linuxは同じです。
Windowsでの構成
1. winpcapをインストールします。理由は上記のとおりです。インストール方法は、インターネットで検索してみましょう。
2.jnetpcap.dllを構成します。このダイナミックリンクライブラリを見つける方法を説明します。最初にjNetPcap.jarをダウンロードし、次にjarを解凍して、次のディレクトリに配置します。
LinuxとWindowsの両方で。インターネットでダウンロードせず、jarパッケージを解凍するだけです。mavenを使用してこのjarパッケージをダウンロードします。
このjnetpcap.dllを配置する場所は、jvmシステム変数「java.library.path」の下に配置します。場所がわからない場合は、コードを記述して印刷します。
public static void main(String[] args) {
System.out.println(System.getProperty("java.library.path"));
}
上に表示されているディレクトリはすべてOKであり、必ずしも赤い線でマークされているわけではありません。jdkのbinディレクトリ(%JAVA_HOME%\ bin)に配置します。
次に、コードを記述します。
サンプルコード
私はMavenを使用しているので、最初にpomでこのjar依存関係を構成します。幸い、このjarパッケージには追加の依存関係がなく、Mavenでなければ簡単です。
<dependency>
<groupId>jnetpcap</groupId>
<artifactId>jnetpcap</artifactId>
<version>1.4.r1425-1g</version>
</dependency>
これは、中央ウェアハウスで見つけた最新の安定バージョンです(Linuxでは問題ありません)。もちろん、現在表示されている最新のソースコードは2.0以降のようです。
キャプチャしたパッケージをコーディングし、印刷し、可能な限りコメントします。これは単なるデモです。
package com.xuxd.jnetpcap;
import org.jnetpcap.Pcap;
import org.jnetpcap.PcapDLT;
import org.jnetpcap.PcapIf;
import org.jnetpcap.packet.PcapPacket;
import java.util.ArrayList;
import java.util.List;
/**
* Created by 许晓东 on 2020-05-17.
*/
public class JNetPcapDemo {
public static void main(String[] args) {
start();
}
private static final String DEV_NAME = "\\Device\\NPF_{4F039C40-B2B8-4531-9C75-E6C79FCA3CB9}";
private static void start() {
StringBuilder errbuf = new StringBuilder();
// 获得所有网卡
List<PcapIf> ifs = new ArrayList<PcapIf>();
if (Pcap.findAllDevs(ifs, errbuf) != 0) {
System.err.println("No interfaces found");
return;
}
Pcap pcap = null;
//查找要监听的网卡进行流量嗅探
for (PcapIf i : ifs) {
//System.out.println(i);
errbuf.setLength(0);
if ((pcap = Pcap.openLive(i.getName(), 64, Pcap.MODE_NON_PROMISCUOUS,
1000, errbuf)) == null) {
System.err.printf("Capture open %s: %s\n", i.getName(), errbuf
.toString());
}
// 混杂模式,看源码注释可能被忽略设置.其实我觉得现在也多用不到,实际中用Java写这个流量嗅探还得是混杂模式的应该不多吧
// 况且说真的,在生活中,交换机现在这么智能,混杂模式不好用呀。
// 本地环回:NULL,
// 通用的话如以太网卡什么的推荐EN10MB,
// 但是可能出现多网卡情况,所以过滤条件写复杂点比如指定ip呀mac地址什么
// 这只是个demo写的简单了
// 所以实际开发此处需要注意考虑监听网上配置,或者尝试启用混杂模式
// 我这与这个代码的时候用的无限网卡,我看下值是30,这里就写这个30写死了,仅供参考
if (pcap.datalink() == PcapDLT.EN10MB.getValue() && i.getFlags() == 30) {
System.out.printf("Opened interface\n\t%s\n\t%s\n", i.getName(), i
.getDescription());
System.out.printf("Warnings='%s'\n", errbuf.toString());
break;
} else {
pcap.close();
pcap = null;
}
}
if (pcap == null) {
System.err.println("Unable to find interface");
return;
}
pcap.loop(Pcap.LOOP_INFINATE, (PcapPacket packet, String userObject) -> {
System.out.println(userObject);
// 打印报文
System.out.println(packet);
}, "xuxd");
System.out.println("start capture...");
}
}
次に、csdnを更新し、以下のスクリーンショットを撮って、印刷されたメッセージ情報を確認します。
トランスポート層以下から。
これはほとんど役に立たないかもしれません。メッセージ情報を分析する必要がある場合があります。例としてHttpメッセージをキャプチャします。
コードを変更し、メッセージを処理し、HTTPリクエストメッセージを取得して出力します。
pcap.loop(Pcap.LOOP_INFINATE, (PcapPacket packet, String userObject) -> {
//System.out.println(userObject);
// 打印报文
//System.out.println(packet);
// 打印http报文
if (packet.hasHeader(Http.ID)) {
Http http = new Http();
packet.getHeader(http);
// 打印请求头
System.out.println(http);
// 打印请求体
System.out.println(new String(http.getPayload()));
}
}, "xuxd");
印刷メッセージは次のとおりです。http応答メッセージです。
もちろん、私が書いたこれは単なるデモであり、参照用としては比較的低く見えます