rust-pcap / pcap

Rust language pcap library
Apache License 2.0
610 stars 138 forks source link

question; `cap` was mutably borrowed here in the previous iteration of the loop #193

Closed thejjw closed 2 years ago

thejjw commented 2 years ago

Hello, I'd like to ask some help on using pcap crate. I'm using pcap = "0.9.1" crate under fedora 34 x86_64 environment with rust stable-x86_64-unknown-linux-gnu - Up to date : 1.56.1 (59eed8a2a 2021-11-01) and edition 2021 configuration. The problem is that I can't seem to be able to call Capture\<Active>.next() repeatedly. I have looked at the documentation https://docs.rs/pcap/0.9.1/pcap/#capturing-packets for sample code. Following the sample code, my function looks somewhat like below:

pub fn capture_and_process () {
    let mut condition = true;

    let mut packets = Vec::new();

    let mut cap = pcap::Capture::from_device(pcap::Device::lookup().unwrap())
        .unwrap()
        .immediate_mode(true)
        .promisc(true)
        .open()
        .unwrap();

    cap.filter("tcp src port 80", false)
        .unwrap();
    while let Ok(packet) = cap.next() {
        packets.push(packet);

        condition = test_and_reset_condition();

        if condition == false {
            break;
        }
    }
    process_packets(packets);
}

fn process_packets(packets: Vec<pcap::Packet>) {
    todo!()
}

fn test_and_reset_condition() -> bool {
    todo!()
}

...and cargo build fails with below error:

 |     while let Ok(packet) = cap.next() {
 |                            ^^^ `cap` was mutably borrowed here in the previous iteration of the loop

I have searched for general suggestions dealing with "... was mutably borrowed here in the previous iteration of the loop" error but suggestions like avoid such situation altogether doesn't help me much in this case since obviously cap in cap.next() does require mutable borrow and it needs to be called repeatedly for my use.

I do confess that my rust (and network programming) experience is poor. Maybe I'm missing something obvious hopefully since I haven't even got to start processing packets yet. Could someone help me understand (and fix) the situation better?

Thanks.

gmacon commented 2 years ago

The pcap::Packet contains a slice of the buffer allocated by libpcap to hold the packet data. That buffer is reused each time you call next, so you have to copy the data if you want to keep it beyond the current iteration of the loop. So, instead of

packets.push(packet);

You need something like

packets.push((*packet.header, packet.data.to_vec()));

though it would be cleaner to create a struct to represent an owned packet instead of just using a tuple. (Note that PacketHeader implements Copy, so it's copied by the dereference.)

Edit: I messed up the copy, but this should actually work. I haven't tried this code, though.

thejjw commented 2 years ago

@gmacon Thank you for the suggestion. I tried putting the tuple to the vector as you suggested, and the error went away. I did not realize that problem from the compiler error I got but I do see how trying to keep packet data without copying it first would be problematic as you explained. Thanks again for the help.