首页 > 解决方案 > udp 标头行中的空指针异常:“Udp udp = packet.getHeader(new Udp());” 为什么 JNETPCAP 无法初始化 Udp 对象

问题描述

我正在尝试使用 jnetpcap jar 文件创建一个原始套接字,以使用 UDP 协议在 java 中进行 IP 欺骗。当我尝试下面的代码时,在为 udp 标头创建对象时出现空指针异常。我反编译了 jar 文件中的类文件以了解问题,但最终在我的回溯中调用了本机方法。帮我找出这个错误的原因。

只需要在cmd中以管理员模式执行。

cmd中的编译命令:

javac -cp .;"C:\Users\kabilan-pt2837\eclipse-workspace\Study\jnetpcap\jnetpcap.jar" -Xlint RawUdpPacketSender.java

cmd中的执行命令:

java -cp .;"C:\Users\kabilan-pt2837\eclipse-workspace\Study\jnetpcap\jnetpcap.jar" -Djava.library.path=%JNETPCAP_HOME% RawUdpPacketSender

其中 %JNETPCAP_HOME% 是一个环境变量,指向 JNETPCAP 的 jar 和 dll 文件的位置

JAVA中的代码:

RawUdpPacketSender.java

import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jnetpcap.Pcap;
import org.jnetpcap.PcapIf;
import org.jnetpcap.packet.JMemoryPacket;
import org.jnetpcap.packet.JPacket;
import org.jnetpcap.protocol.JProtocol;
import org.jnetpcap.protocol.lan.Ethernet;
import org.jnetpcap.protocol.network.Ip4;
import org.jnetpcap.protocol.tcpip.Udp;

public class RawUdpPacketSender {
    private static Logger logger = Logger.getLogger(RawUdpPacketSender.class.getName());

    private Pcap pcap = null;
    private int headerLength = getHeaderLength();
    private int UDP_SOURCE_PORT = 9091;
    private byte[] sourceMacAddress;
    private byte[] destinationMacAddress;

    public RawUdpPacketSender() {
        String macAddress = System.getProperty("gateway_mac_address", "");
        //Destination MAC address needs to be configured. This can be retrieved using ARP, but it's not easy
        destinationMacAddress = hexStringToByteArray(macAddress);
        try {
            pcap = createPcap();
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Failed to start pcap library.", e);
        }
    }

    public void sendPacket(URI destination, byte[] packet)
            throws IOException {
        int port = destination.getPort();
        InetAddress address = InetAddress.getByName(destination.getHost());
        byte[] destinationAddress = address.getAddress();
        System.out.println(port+"   "+address.getHostAddress());
        sendPacket(destinationAddress, port, packet);
    }

    private Pcap createPcap() throws IOException {
        PcapIf device = getPcapDevice();
        if (device == null) {
            return null;
        }
        sourceMacAddress = device.getHardwareAddress();  //Use device's MAC address as the source address
        StringBuilder errorBuffer = new StringBuilder();
        int snapLen = 64 * 1024;
        int flags = Pcap.MODE_NON_PROMISCUOUS;
        int timeout = 10 * 1000;
        Pcap pcap = Pcap.openLive(device.getName(), snapLen, flags, timeout,
                errorBuffer);
        if (logger.isLoggable(Level.INFO)) {
            logger.info(String.format("Pcap starts for device %s successfully.", device));
        }
        return pcap;
    }

    private PcapIf getPcapDevice() {
        List<PcapIf> allDevs = new ArrayList<PcapIf>();
        StringBuilder errorBuffer = new StringBuilder();
        int r = Pcap.findAllDevs(allDevs, errorBuffer);
        if (r == Pcap.NOT_OK || allDevs.isEmpty()) {
            logger.log(Level.SEVERE, String.format("Can't read list of devices, error is %s",
                    errorBuffer.toString()));
            return null;
        }
        String deviceName = System.getProperty("raw_packet_network_interface", "eth0");
        for (PcapIf device : allDevs) {
            if (deviceName.equals(device.getName())) {
                return device;
            }
        }
        return allDevs.get(0);
    }

    private int getHeaderLength() {
        return 14 + 20 + 8; //Ethernet header + IP v4 header + UDP header
    }

    private void sendPacket(byte[] destinationAddress, int port, byte[] data) throws IOException {
        int dataLength = data.length;
        int packetSize = headerLength + dataLength;
        JPacket packet = new JMemoryPacket(packetSize);
        packet.order(ByteOrder.BIG_ENDIAN);
        packet.setUShort(12, 0x0800);
        packet.scan(JProtocol.ETHERNET_ID);
        Ethernet ethernet = packet.getHeader(new Ethernet());
        ethernet.source(sourceMacAddress);
        ethernet.destination(destinationMacAddress);
        ethernet.checksum(ethernet.calculateChecksum());

        //IP v4 packet
        packet.setUByte(14, 0x40 | 0x05);
        packet.scan(JProtocol.ETHERNET_ID);
        Ip4 ip4 = packet.getHeader(new Ip4());

        ip4.type(Ip4.Ip4Type.UDP);
        ip4.length(packetSize - ethernet.size());
        byte[] sourceAddress = InetAddress.getLocalHost().getAddress();
        ip4.source(sourceAddress);
        ip4.destination(destinationAddress);
        ip4.ttl(32);
        ip4.flags(0);
        ip4.offset(0);
        ip4.checksum(ip4.calculateChecksum());
        //UDP packet
        packet.scan(JProtocol.IP4_ID);
        Udp udp = packet.getHeader(new Udp());
                    // This is where I'm getting the null pointer exception
        System.out.println(udp);
        udp.source(UDP_SOURCE_PORT);
        udp.destination(port);
        udp.length(packetSize - ethernet.size() - ip4.size());
        udp.checksum(udp.calculateChecksum());
        packet.setByteArray(headerLength, data);
        packet.scan(Ethernet.ID);
        if (pcap.sendPacket(packet) != Pcap.OK) {
            throw new IOException(String.format(
                    "Failed to send UDP packet with error: %s", pcap.getErr()));
        }
    }

    private byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
                    .digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public static void main(String[] args) throws IOException {
        RawUdpPacketSender sender = new RawUdpPacketSender();
        byte[] packet = "Hello".getBytes();
        URI destination = URI.create("udp://192.168.159.192:9090");
        System.out.println(destination+"   "+packet);
        sender.sendPacket(destination, packet);
    }
}

管理员模式下在cmd中执行about程序得到的结果:

Apr 08, 2019 12:15:41 PM RawUdpPacketSender createPcap
INFO: Pcap starts for device <flags=0, addresses=[[addr=[INET6:FE80:0000:0000:0000:B825:ACBF:F18D:9FE9], mask=[0], broadcast=[0], dstaddr=null], [addr=[INET6:FE80:0000:0000:0000:B825:ACBF:F18D:9FE9], mask=[0], broadcast=[0], dstaddr=null]], name=\Device\NPF_{E7240CA2-66F1-42D6-9ECE-AE7BF28010E4}, desc=Microsoft> successfully.
udp://192.168.159.192:9090   [B@27bc2616
9090   192.168.159.192
null
Exception in thread "main" java.lang.NullPointerException
        at RawUdpPacketSender.sendPacket(RawUdpPacketSender.java:118)
        at RawUdpPacketSender.sendPacket(RawUdpPacketSender.java:44)
        at RawUdpPacketSender.main(RawUdpPacketSender.java:145)

标签: javaipraw-socketsspoofingjnetpcap

解决方案


推荐阅读