java使用jNetPcap嗅探网络包之windows下配置使用

背景

java本身是不支持处理网络层及以下的协议(用的java8,可能我了解的少,但好像是这个样子)。如果想用java做相关的网络嗅探开发,需要使用一些库,比如jpcap或JNetPcap。推荐JNetPcap,原因是jpcap很早不维护了,功能上也不如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上安装的。所以,比如我们在windows上安装一些抓包工具,比如wireshark,可能会需要安装winpcap,当然老的wireshark是用winpcap,我前段时间装了个最新版的,装的是另一个可以替代并支持兼容winpcap的一个库,忘了叫啥了,好像pcap什么吧。如果是像在linux安装tcpdump的话,就是装的libpcap,这都是一个道理。如果了解elasticsearch栈的一个组件packetbeat并用过这个款轻量型网络数据采集器,应该也明白它底层使用的一个流量捕获工具也可以是libpcap,不一定非得是它,也可以使用别的。

当然了,在linux下抓包底层依赖库不一定都是libpcap,之前有在相关论文看到一些更优秀的。

接下来接着说下java jNetPcap怎么调用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包就行,这个jar包我是用maven下的。

把这个jnetpcap.dll放哪呢,放到jvm系统变量 “java.library.path”下,不确定在哪,写个代码打印下:

    public static void main(String[] args) {
        System.out.println(System.getProperty("java.library.path"));
    }

这上面出现的目录下都行,不一定是标红线的,我是放到了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以后了。

代码,打印捕捉到的包,注释我尽量写详细点,这个只是demo:

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响应报文:

当然了,我写的这个只是demo,看起来比较Low,仅供参考

猜你喜欢

转载自blog.csdn.net/x763795151/article/details/106179077
今日推荐