Pcap_open_live wrapper fails


#1

Hi! Does anyone know why pcap_open_live in simple C works fine, but when wrapped in rust extern "C" - returns “SIOCGIFHWADDR: No such device” ?

#[link(name = "pcap")]
extern "C" {
    pub fn pcap_open_live(
        device: *const c_char,
        snaplen: c_int,
        promisc: c_int,
        to_ms: c_int,
        errbuf: *mut c_char,
    ) -> Pcap_;

    pub fn pcap_close(pcap: Pcap_);
}

The code is from https://github.com/jedisct1/iptrap project


#2

Can you show how you call it from C and Rust?


#3

The C code i have found somewhere:

#include <stdio.h>
#include <pcap.h>

#define UNUSED(x) ((void)(x))

static void callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char*
        packet) {
  static int count = 1;

  printf("\nPacket number [%d], length of this packet is: %d\n", count++, pkthdr->len);
  printf("%s\n", packet);
}

int main(int argc, char * argv[]) {

    if (argc != 2) {
        fprintf(stderr, "ERROR: Device not specified.\n");
        return 1;
    }

    char error[PCAP_ERRBUF_SIZE];

    char * device_name = argv[1];
    pcap_t * device_handle = pcap_open_live(device_name, BUFSIZ, 1, 100, error);

    if (device_handle == NULL) {
        fprintf(stderr, "ERROR: %s\n", error);
        return 2;
    }

    pcap_loop(device_handle, 100, callback, (void *)device_handle);

    pcap_close(device_handle);

    return 0;
}

It does work.

The Rust code:

extern crate libc;

use libc::{c_char, c_int, c_void};
use std::ffi;
use std::str;

pub const PCAP_ERRBUF_SIZE: usize = 256;

pub type Pcap_ = *mut c_void;

#[link(name = "pcap")]
extern {
    pub fn pcap_open_live(
        device: *const c_char,
        snaplen: c_int,
        promisc: c_int,
        to_ms: c_int,
        errbuf: *mut c_char,
    ) -> Pcap_;

    pub fn pcap_close(pcap: Pcap_);
}

fn runtest() {
    let errbuf = [0; PCAP_ERRBUF_SIZE].as_mut_ptr();
    let device_name = "eth0";
    let device = ffi::CString::new(device_name.as_bytes()).unwrap().as_ptr();

    let pcap = unsafe {
        pcap_open_live(device, 8192, 1, 100, errbuf)
    };

    if pcap.is_null() {
        let err = unsafe {
                str::from_utf8(ffi::CStr::from_ptr(errbuf).to_bytes()).unwrap()
            }.to_owned();

        println!("{}", err);
    }

    unsafe { pcap_close(pcap) };
}

fn main() {
    runtest();
}

Returns “: No such device exists (SIOCGIFHWADDR: No such device)”
(under sudo)

I’ve also tried https://github.com/ebfull/pcap library.
In it, pcap::Device::list() doesn’t return any devices. It is as if Rust doesn’t see any devices at all.

All this is on Ubuntu 16.04 vagrant vm.


#4

This is exactly one of the misuses of CString, and it’s documented in the rustdoc for the as_ptr method :slight_smile:. You need to keep the CString alive while using a ptr to it:

let cstr = ffi::CString::new(device_name.as_bytes()).unwrap();
let ptr = unsafe { pcap_open_live(cstr.as_ptr()) };

Not sure if that’s the problem, but it’s definitely a problem.


#5

Thank you!!
That did solve the problem!

(well, at least the one i faced so far) :slight_smile: