最近,我正在使用Jnetpcap通过网络发送/接收原始数据包。
Jnetpcap提供Pcap.sendPacket()
发送数据包。此方法获取要发送的原始缓冲区或字节。
另一方面,有org.jnetpcap.protocol.*
个类包装协议头,我们可以使用它们来解码捕获的数据包。
当我使用下面的代码制作Ip4
数据包时,会导致NullPointerException:
import org.jnetpcap.protocol.network.Ip4;
public class Test {
public static void main(String[] args) {
Ip4 ip4 = new Ip4();
ip4.ttl(10);
}
}
错误:
Exception in thread "main" java.lang.NullPointerException
at org.jnetpcap.nio.JBuffer.check(Unknown Source)
at org.jnetpcap.nio.JBuffer.setUByte(Unknown Source)
at org.jnetpcap.protocol.network.Ip4.ttl(Unknown Source)
at jaeger.Test.main(Test.java:17)
如何构建该数据包然后通过Pcap.sendPacket()
发送?
注意:我真的对逐字节准备数据包不感兴趣... C / C ++ libpcap和Jpcap有工作功能,但我想使用Jnetpcap!
答案 0 :(得分:8)
1)代码抛出异常,因为包装类仅使用先前分配的缓冲区,因为库的主要目的是分析捕获的数据包的缓冲区。因此,在使用它们之前必须分配一个缓冲区。
2)必须构建数据包,提供所有必需的字节。但是可以编写代码,以便只需要几个字节(参见上文)。
3) sendPacket
需要一个完整的数据包,一个完整的以太网帧。因此,必须将以太网,IP,TCP标头和Payload写入缓冲区。
4)允许你使用包装类的主要思想是分配一个缓冲区,然后让库扫描它以发现标题,但最少的信息(字节)必须是提供。
JMemoryPacket packet = new JMemoryPacket(packetSize);
packet.order(ByteOrder.BIG_ENDIAN);
Ethernet frame在位置12需要协议类型(0x0800):
packet.setUShort(12, 0x0800);
packet.scan(JProtocol.ETHERNET_ID);
在scan
之后,可以检索以太网实例并使用 setters :
Ethernet ethernet = packet.getHeader( new Ethernet() );
ethernet.destination(...);
...
IP4 header需要版本(0x04)和位置14的大小(0x05):
packet.setUByte(14, 0x40 | 0x05);
packet.scan(JProtocol.ETHERNET_ID);
Ip4 ip4 = packet.getHeader( new Ip4() );
ip4.type(0x06); //TCP
ip4.length( packetSize - ethernet.size() );
ip4.ttl(...);
...
TCP header需要大小(0x50):
packet.setUByte(46, 0x50);
packet.scan(JProtocol.ETHERNET_ID);
Tcp tcp = packet.getHeader( new Tcp() );
tcp.seq(...);
...
所以,有效负载:
Payload payload = packet.getHeader( new Payload() );
payload.set...(...);
...
最后:
pcap.sendPacket( ByteBuffer.wrap( packet.getByteArray(0, packet.size() ) );
5)可以一次写入所有必需的字节,以避免对扫描方法进行如此多的调用。
答案 1 :(得分:1)
您是否遇到how to write subheders on jNetPcap的问题?是的,JNetPcap以字节为单位进行发送,但内容可以通过我给出的帮助填充子标题。如果您希望在数据包内发送一些数据,则许多Java类型具有toBytes()
函数或类似功能。
修改强>
该特定Icmp类的API为here。同样可以对给定链接上的其他类进行操作。只需打开Google并为其他标题类型提供“Icmp类引用jnetpcap”。
<强> EDIT2:强>
更简单的创建ICMP数据包的方法是通过ICMPPacket class,它有一个简单的ICMP数据包构造函数,其中标头是在单个Constructor调用中创建的。根据课程参考,它做了以下内容:
扩展IP数据包,添加ICMP头和ICMP数据有效负载。