Jnetpcap, подготовка пакета UDP/TCP/IP/ICMP

Недавно я использую 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!

2 ответа

Решение

1) Код генерирует исключение, потому что классы-оболочки работают только с использованием ранее выделенных буферов, потому что основная цель библиотеки - анализировать буферы захваченных пакетов. Итак, перед их использованием необходимо выделить буфер.

2) Пакеты должны быть собраны с предоставлением всех необходимых байтов. Но код может быть написан так, что только несколько байтов действительно необходимы (см. Выше).

3) sendPacket ожидает целый пакет, полный кадр Ethernet. Таким образом, заголовки Ethernet, IP, TCP и полезная нагрузка должны быть записаны в буфер.

4) Основная идея, позволяющая вам использовать классы-обертки, состоит в том, чтобы выделить буфер и затем покинуть библиотеку, сканируя его для обнаружения заголовков, но необходимо предоставить минимум информации (байты).

JMemoryPacket packet = new JMemoryPacket(packetSize);
packet.order(ByteOrder.BIG_ENDIAN); 

Для фрейма Ethernet требуется тип протокола (0x0800) в позиции 12:

packet.setUShort(12, 0x0800);
packet.scan(JProtocol.ETHERNET_ID); 

После scanможно получить экземпляр Ethernet и использовать установщики:

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

Заголовок IP4 требует версии (0x04) и размера (0x05) в позиции 14:

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 (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) Все необходимые байты могут быть записаны за один раз, чтобы избежать большого количества вызовов метода сканирования.

Вы сталкиваетесь с проблемой, как писать подхедеры на jNetPcap? Да, JNetPcap принимает байты для отправки, но содержимое может быть заполнено подзаголовками с помощью, которую я оказал. Если затем вы хотите отправить некоторые данные внутри пакета, многие типы Java имеют toBytes() функция или подобное.

редактировать:
API этого конкретного класса Icmp здесь. Аналогичным образом можно сделать другие классы по данной ссылке. Просто откройте Google и дайте "Ссылка на класс Icmp jnetpcap" или что-то еще для других типов заголовков.

edit2:
Более простой способ создания пакета ICMP - через класс ICMPPacket, который имеет простой конструктор для пакета ICMP, в котором заголовки создаются в одном вызове конструктора. В соответствии со ссылкой на класс это делает следующее:

Расширяет пакет IP, добавляя заголовок ICMP и полезную нагрузку данных ICMP.

Другие вопросы по тегам