【问题标题】:Jnetpcap, preparing UDP/TCP/IP/ICMP packetJnetpcap,准备UDP/TCP/IP/ICMP包
【发布时间】:2011-11-15 18:19:15
【问题描述】:

最近,我正在使用 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!

【问题讨论】:

    标签: java jnetpcap


    【解决方案1】:

    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 之后,可以检索以太网实例并使用setter

    Ethernet ethernet = packet.getHeader( new Ethernet() );  
    ethernet.destination(...);
    ...
    

    IP4 header 需要位置 14 的版本 (0x04) 和大小 (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)可以一次写入所有必要的字节以避免对扫描方法的如此多的调用。

    【讨论】:

    • 完美! packetSize 怎么样?如何预测合适的尺寸?
    • @MasoudM。协议头长度和数据大小的总和。 System.out.print(packet.toString())System.out.print(packet.toHexdump()) 对于查看缓冲区和数据包很有用。
    【解决方案2】:

    您是否面临how to write subheders on jNetPcap 的问题?是的,JNetPcap 以字节为单位进行发送,但在我提供的帮助下,内容可以用子标题填充。如果您想在数据包内发送一些数据,许多 Java 类型都有toBytes() 函数或类似函数。

    编辑:
    该特定 Icmp 类的 API 是 here。对给定链接上的其他类也可以这样做。只需打开 Google 并提供“Icmp 类参考 jnetpcap”或其他标头类型。

    edit2:
    创建 ICMP 数据包的更简单方法是通过ICMPPacket class,它有一个简单的 ICMP 数据包构造函数,其中在单个构造函数调用中创建标头。根据类参考,它做了以下内容:

    扩展 IP 数据包,添加 ICMP 标头和 ICMP 数据负载。

    【讨论】:

    • 感谢您的回答。但是,您写的链接是关于测试文件,而不是填充它们。
    • 主要思想是找出用于测试的Icmp 对象,并表明这不仅仅是手动设置位。当然,这方面的教程必须在其他地方找到。
    • 我修改了答案。它现在是否回答了正确的问题/是否足够完整?
    • 这个有问题,不能new简单填写。如果你能用,请给我指路。
    • 我进行了第二次编辑。这会创建一个构造函数,但您不能影响自己在其中写入的内容。你需要一个可以 100% 由构造函数配置的,还是这样就可以了?
    猜你喜欢
    • 2017-08-25
    • 1970-01-01
    • 2016-06-10
    • 2018-01-16
    • 1970-01-01
    • 2014-04-26
    • 2018-03-18
    • 2012-01-02
    • 1970-01-01
    相关资源
    最近更新 更多