libpnet / libpnet/libpnet

Reassembling fragmented packets

Open
#507 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
2.6k
Forks
329
PR merge metrics
No merged PRs in 30d

Description

Hi I would like to reassemble packets that have undergone IPV4 fragmentation. I searched around and couldn't find anything. Is this something that libpnet would be interested in having?

For example, some code may look like this janky first attempt:

use pnet::packet::{
    ethernet::{EtherTypes, EthernetPacket},
    ip::IpNextHeaderProtocols,
    ipv4::Ipv4Packet,
    udp::UdpPacket,
    Packet,
};

struct Ipv4Reassembler {
    cap: pcap::Capture<pcap::Offline>,
}

impl Iterator for Ipv4Reassembler {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut payload = Vec::<u8>::new();
        while let Some(packet) = self.cap.next().ok() {
            let ethernet = EthernetPacket::new(packet.data).unwrap();
            match ethernet.get_ethertype() {
                EtherTypes::Ipv4 => {
                    let ipv4_packet = Ipv4Packet::new(ethernet.payload()).unwrap();
                    // dbg!(&ipv4_packet);
                    // todo: discard incomplete packets, construct header for reassembled packet, check id, etc
                    let off: usize = 8 * ipv4_packet.get_fragment_offset() as usize;
                    let end = off + ipv4_packet.payload().len();
                    if payload.len() < end {
                        payload.resize(end, 0);
                    }
                    payload[off..end].clone_from_slice(ipv4_packet.payload());
                    if ipv4_packet.get_flags() & 1 == 0 {
                        return Some(payload);
                    }
                }
                _ => {}
            }
        }
        None
    }
}

fn main() {
    let pcap_path = "os-992114000702.pcap";

    let reass = Ipv4Reassembler {
        cap: pcap::Capture::from_file(&pcap_path).unwrap(),
    };

    for payload in reass {
        let udp_packet = UdpPacket::new(&payload).unwrap();
        dbg!(&udp_packet);
        dbg!(&udp_packet.payload().len());
    }
}

For reference, for C++'s libtins library it is pretty painless:

#include <tins/ip_reassembler.h>
#include <tins/packet.h>
#include <tins/rawpdu.h>
#include <tins/sniffer.h>
#include <tins/tins.h>
#include <tins/udp.h>

#include <iostream>
#include <string>

void read_packets(const std::string &pcap_filename) {
    Tins::IPv4Reassembler reassembler;
    Tins::FileSniffer sniffer(pcap_filename);

    while (Tins::Packet packet = sniffer.next_packet()) {
        auto &pdu = *packet.pdu();
        const Tins::Timestamp &timestamp = packet.timestamp();
        if (reassembler.process(pdu) != Tins::IPv4Reassembler::FRAGMENTED) {
            const Tins::UDP *udp = pdu.find_pdu<Tins::UDP>();
            if (!udp) {
                continue;
            }
            const Tins::RawPDU *raw = pdu.find_pdu<Tins::RawPDU>();
            if (!raw) {
                continue;
            }
            const Tins::RawPDU::payload_type &payload = raw->payload();
            std::cout << "Packet: " << payload.size() << std::endl;
        }
    }
}

int main() {
    const std::string pcap_path = "os-992114000702.pcap";
    read_packets(pcap_path);
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No target file, entry point, or test is named. Start by reviewing the existing IPv4 packet implementation and tests, then compare the requested behavior with the IPv4 fragmentation fields used in the example. Define how incomplete fragments, packet identity, headers, and completed payloads should be represented before determining what tests would demonstrate a finished reassembler.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.