使用Pcap4j库发送TCP SYN包时出现NullPointerException问题
使用Pcap4j构建TCP SYN包时触发NullPointerException(提示builder.srcAddr/dstAddr为null)
问题详情
尝试使用Pcap4j库发送TCP SYN数据包,执行ipv4Builder.build();时触发NullPointerException。调试确认sourceIp与destIp均不为空,但错误日志提示builder.srcAddr: null builder.dstAddr: null。
相关代码
import org.pcap4j.core.*; import org.pcap4j.packet.*; import org.pcap4j.packet.namednumber.TcpPort; import org.pcap4j.util.MacAddress; import org.pcap4j.packet.namednumber.EtherType; import org.pcap4j.packet.namednumber.IpNumber; import org.pcap4j.packet.namednumber.IpVersion; import java.net.Inet4Address; import java.net.InetAddress; import java.util.Collections; import java.util.List; public class SYN { public static void send() { String targetIp = "8.8.8.8"; int targetPort = 80; try { List<PcapNetworkInterface> allDevs = Pcaps.findAllDevs(); Collections.shuffle(allDevs); PcapNetworkInterface nif = null; Inet4Address sourceIp = null; for (PcapNetworkInterface dev : allDevs) { System.out.println("Interface: " + dev.getName() + " (" + dev.getDescription() + ")"); for (PcapAddress pcapAddress : dev.getAddresses()) { InetAddress addr = pcapAddress.getAddress(); if (addr instanceof Inet4Address) { System.out.println("Found IPv4 Address: " + addr.getHostAddress()); if (nif == null) { nif = dev; sourceIp = (Inet4Address) addr; break; } } } if (nif != null) { break; } } if (nif == null || sourceIp == null) { System.out.println("No suitable network interface found."); return; } System.out.println("Selected Interface: " + nif.getName()); System.out.println("Source IP: " + sourceIp.getHostAddress()); PcapHandle handle = nif.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10); TcpPacket.Builder tcpBuilder = new TcpPacket.Builder(); tcpBuilder .srcPort(TcpPort.getInstance((short) 80)) .dstPort(TcpPort.getInstance((short) targetPort)) .sequenceNumber(100) .acknowledgmentNumber(0) .dataOffset((byte) 5) .syn(true) .window((short) 65535) .correctChecksumAtBuild(true) .correctLengthAtBuild(true); Inet4Address destIp = (Inet4Address) InetAddress.getByName(targetIp); IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder(); ipv4Builder .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .ttl((byte) 64) .protocol(IpNumber.TCP) .srcAddr(sourceIp) .dstAddr(destIp) .payloadBuilder(tcpBuilder) .correctChecksumAtBuild(true) .correctLengthAtBuild(true); System.out.println(sourceIp == null); System.out.println(destIp == null); Packet p1 = ipv4Builder.build(); // 触发错误的行 handle.close(); } catch (Exception e) { e.printStackTrace(); } } }
错误信息
false // sourceIp is not null false // destIp is not null java.lang.NullPointerException: builder.srcAddr: null builder.dstAddr: null at org.pcap4j.packet.TcpPacket.<init>(TcpPacket.java:100) at org.pcap4j.packet.TcpPacket.<init>(TcpPacket.java:33) at org.pcap4j.packet.TcpPacket$Builder.build(TcpPacket.java:432) at org.pcap4j.packet.TcpPacket$Builder.build(TcpPacket.java:169) at org.pcap4j.packet.IpV4Packet.<init>(IpV4Packet.java:121) at org.pcap4j.packet.IpV4Packet.<init>(IpV4Packet.java:32) at org.pcap4j.packet.IpV4Packet$Builder.build(IpV4Packet.java:370)
解决方案
错误的核心原因是:TCP校验和的计算依赖IP层的源地址和目的地址,但TcpPacket.Builder未获取到这些信息。当开启correctChecksumAtBuild(true)时,Pcap4j需要这些地址来生成正确的TCP校验和,而IPv4 Builder不会自动将IP地址传递给下层的TCP Builder,必须手动设置。
修改代码,在构建TcpPacket.Builder后添加一行,设置外层IPv4地址:
tcpBuilder.outerIpv4Address(sourceIp, destIp);
修改后的关键代码片段
TcpPacket.Builder tcpBuilder = new TcpPacket.Builder(); tcpBuilder .srcPort(TcpPort.getInstance((short) 80)) .dstPort(TcpPort.getInstance((short) targetPort)) .sequenceNumber(100) .acknowledgmentNumber(0) .dataOffset((byte) 5) .syn(true) .window((short) 65535) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .outerIpv4Address(sourceIp, destIp); // 新增这一行,传递IP地址给TCP Builder
说明
outerIpv4Address方法会将IP层的源和目的地址传递给TCP Builder,这样TCP包在计算校验和时就能获取到所需的地址信息,避免NullPointerException。
内容的提问来源于stack exchange,提问作者Metalowy Robot
相关产品推荐
相关产品推荐

