Pcap_open_live wrapper fails

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

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

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.

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.

1 Like

Thank you!!
That did solve the problem!

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