java - 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)
解决方案
推荐阅读
- opencv - 标准化照明条件以进行图像识别
- javascript - 如何创建一些导出的 Axios 实例的多个实例?
- android - 将元素(尤其是右上角)修复到 chrome mobile 中的可视视口,内容非常广泛?
- sql-server - 如何修复 Azure 分析服务器的 Active Directory 身份验证中的“无法获取身份验证令牌”
- swift - DispatchQueue.global.async 中的代码是串行执行的吗?
- azure - 删除原始 Azure SQL Server 后通过 Portal 恢复 Azure SQL Database LTR 备份
- javascript - 如何根据数组隐藏/显示元素?
- powershell - 尝试在 Powershell 中动态连接到最近的 Exchange Server
- android - 导航组件 - onSupportNavigateUp()
- javascript - 在包装器中设置样式组件的样式