Can't get TUN_SET_IFF ioctl to execute properly

Hi all, I am trying to follow this TUN/TAP tutorial. While I was able to get the C code to run just fine. Something weird happens when I translate the code to Rust.

Here is my attempt at writing the code to allocate the tuntap interface.. After executing the TUN_SET_IFF ioctl on this line I get an EBADFD error.

I have no idea what's going wrong with the code. The struct passed to the TUN_SET_IFF ioctl is identical as far as I can see :confused:

e: There is nothing wrong with the permissions on the persistent tap device "my_premade_tap". I tested it with C and it works.

I can't spot the error, but I suggest using strace to see what system calls are actually being performed, and comparing to the C version.

You are right. I need to use ioctl!(write_int tun_set_iff with TUN_MAGIC, TUN_SET_IFF); to get the proper ioctl for TUNSETIFF.

However, the kernel defines TUNSETIFF as taking an int when in reality it takes the address of the struct. How can I solve that? Casting the pointer to an int doesn't work since it's not the same size.

Looking at the nix documentation, you may want to use this functionality:

As mentioned earlier, there are many old ioctls that do not use the newer method of generating ioctl numbers and instead use hardcoded values. These can be used with the bad * variants of the ioctl! macro. This naming comes from the Linux kernel which refers to these ioctls as "bad". These are a different variant as they bypass calling the macro that generates the ioctl number and instead use the defined value directly.

(source: nix::sys::ioctl - Rust)

…In this case, the C definition doesn't actually use "hardcoded values", but rather "the newer method" with the wrong type. Still, by allowing you to specify the ioctl number directly, the 'bad' variant should serve the purpose. See also the source code defining the macro - it's quite straightforward.

You should be able to specify the number as iow!(TUN_MAGIC, TUN_SET_IFF, size_of::<c_int>()).

3 Likes

Thanks. That works :slight_smile:

For future reference I changed the ioctl! line to:

ioctl!(bad write_ptr tun_set_iff with iow!(TUN_MAGIC, TUN_SET_IFF, mem::size_of::<c_int>()); InterfaceRequest);