Implement TAP interface support.
parent
77225b77a9
commit
e7d6237279
|
@ -1,11 +1,13 @@
|
|||
#![feature(range_contains, associated_consts)]
|
||||
#![no_std]
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate byteorder;
|
||||
|
||||
#[cfg(any(test, feature = "std"))]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
extern crate byteorder;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate libc;
|
||||
|
||||
pub mod phy;
|
||||
pub mod wire;
|
||||
|
|
|
@ -2,13 +2,21 @@
|
|||
//!
|
||||
//! The `phy` module provides an interface for sending and receiving frames
|
||||
//! through a physical (or perhaps virtualized) network device, [Device](trait.Device.html),
|
||||
//! as well as some useful implementations of that trait.
|
||||
//!
|
||||
//! Currently the only implementation, [RawSocket](struct.RawSocket.html), is based on
|
||||
//! Unix raw sockets, and only works on Linux.
|
||||
//! as well as an implementations of that trait that uses the host OS,
|
||||
//! [OsDevice](struct.OsDevice.html).
|
||||
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
#[cfg(feature = "std")]
|
||||
mod sys;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod raw_socket;
|
||||
#[cfg(all(feature = "std", target_os = "linux"))]
|
||||
mod tap_interface;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::raw_socket::RawSocket;
|
||||
#[cfg(all(feature = "std", target_os = "linux"))]
|
||||
pub use self::tap_interface::TapInterface;
|
||||
|
||||
/// An interface for sending and receiving raw network frames.
|
||||
///
|
||||
|
@ -32,13 +40,10 @@ pub trait Device {
|
|||
/// Transmits a frame.
|
||||
///
|
||||
/// It is expected that a `send` implementation would gain ownership of a buffer with
|
||||
/// the requested size, provide it for emission, and then schedule it to be read from
|
||||
/// the requested length, provide it for emission, and then schedule it to be read from
|
||||
/// memory by the network device.
|
||||
///
|
||||
/// # Panics
|
||||
/// This function may panic if `size` is larger than `MTU`.
|
||||
fn send<F: FnOnce(&mut [u8])>(&mut self, size: usize, handler: F);
|
||||
/// This function may panic if `len` is larger than `MTU`.
|
||||
fn send<F: FnOnce(&mut [u8])>(&mut self, len: usize, handler: F);
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
pub use self::raw_socket::RawSocket;
|
||||
|
|
|
@ -1,112 +1,41 @@
|
|||
extern crate std;
|
||||
extern crate libc;
|
||||
use std::{vec, io};
|
||||
use super::{sys, Device};
|
||||
|
||||
use self::std::{mem, vec, io};
|
||||
|
||||
#[repr(C)]
|
||||
struct ifreq {
|
||||
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
|
||||
ifr_data: libc::c_int /* ifr_ifindex or ifr_mtu */
|
||||
}
|
||||
|
||||
const SIOCGIFMTU: libc::c_ulong = 0x8921;
|
||||
const SIOCGIFINDEX: libc::c_ulong = 0x8933;
|
||||
|
||||
const ETH_P_ALL: libc::c_short = 0x0003;
|
||||
|
||||
/// A raw socket: a socket that captures the entire packet, up to and including
|
||||
/// the link layer header.
|
||||
/// A socket that captures or transmits the complete frame.
|
||||
#[derive(Debug)]
|
||||
pub struct RawSocket {
|
||||
sockfd: libc::c_int,
|
||||
lower: sys::RawSocketDesc,
|
||||
buffer: vec::Vec<u8>
|
||||
}
|
||||
|
||||
impl RawSocket {
|
||||
/// Creates and returns a raw socket, bound to the interface called `name`.
|
||||
/// Creates a raw socket, bound to the interface called `name`.
|
||||
///
|
||||
/// This requires superuser privileges or a corresponding capability bit
|
||||
/// set on the executable.
|
||||
pub fn new(name: &str) -> io::Result<RawSocket> {
|
||||
unsafe {
|
||||
let sockfd = libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32);
|
||||
if sockfd == -1 {
|
||||
return Err(io::Error::last_os_error())
|
||||
}
|
||||
let mut lower = try!(sys::RawSocketDesc::new(name));
|
||||
try!(lower.bind_interface());
|
||||
|
||||
let mut ifreq = ifreq {
|
||||
ifr_name: [0; libc::IF_NAMESIZE],
|
||||
ifr_data: 0
|
||||
};
|
||||
for (i, byte) in name.as_bytes().iter().enumerate() {
|
||||
ifreq.ifr_name[i] = *byte as libc::c_char
|
||||
}
|
||||
|
||||
let res = libc::ioctl(sockfd, SIOCGIFINDEX, &mut ifreq as *mut ifreq);
|
||||
if res == -1 {
|
||||
libc::close(sockfd);
|
||||
return Err(io::Error::last_os_error())
|
||||
}
|
||||
let if_index = ifreq.ifr_data;
|
||||
|
||||
let res = libc::ioctl(sockfd, SIOCGIFMTU, &mut ifreq as *mut ifreq);
|
||||
if res == -1 {
|
||||
libc::close(sockfd);
|
||||
return Err(io::Error::last_os_error())
|
||||
}
|
||||
let if_mtu = ifreq.ifr_data;
|
||||
|
||||
let sockaddr = libc::sockaddr_ll {
|
||||
sll_family: libc::AF_PACKET as u16,
|
||||
sll_protocol: ETH_P_ALL.to_be() as u16,
|
||||
sll_ifindex: if_index as i32,
|
||||
sll_hatype: 1,
|
||||
sll_pkttype: 0,
|
||||
sll_halen: 6,
|
||||
sll_addr: [0; 8]
|
||||
};
|
||||
libc::bind(sockfd,
|
||||
&sockaddr as *const libc::sockaddr_ll as *const libc::sockaddr,
|
||||
mem::size_of::<libc::sockaddr_ll>() as u32);
|
||||
if res == -1 {
|
||||
libc::close(sockfd);
|
||||
return Err(io::Error::last_os_error())
|
||||
}
|
||||
|
||||
let mut buffer = vec::Vec::new();
|
||||
buffer.resize(if_mtu as usize, 0);
|
||||
Ok(RawSocket {
|
||||
sockfd: sockfd,
|
||||
buffer: buffer
|
||||
})
|
||||
}
|
||||
let mut buffer = vec::Vec::new();
|
||||
buffer.resize(try!(lower.interface_mtu()), 0);
|
||||
Ok(RawSocket {
|
||||
lower: lower,
|
||||
buffer: buffer
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawSocket {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::close(self.sockfd); }
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Device for RawSocket {
|
||||
impl Device for RawSocket {
|
||||
const MTU: usize = 1536;
|
||||
|
||||
fn recv<F: FnOnce(&[u8])>(&mut self, handler: F) {
|
||||
let len = unsafe {
|
||||
let len = libc::recv(self.sockfd, self.buffer.as_mut_ptr() as *mut libc::c_void,
|
||||
self.buffer.len(), 0);
|
||||
if len == -1 { Err(io::Error::last_os_error()).unwrap() }
|
||||
len
|
||||
};
|
||||
|
||||
handler(&self.buffer[..len as usize])
|
||||
let len = self.lower.recv(&mut self.buffer[..]).unwrap();
|
||||
handler(&self.buffer[..len])
|
||||
}
|
||||
|
||||
fn send<F: FnOnce(&mut [u8])>(&mut self, size: usize, handler: F) {
|
||||
handler(&mut self.buffer[..size]);
|
||||
|
||||
unsafe {
|
||||
let len = libc::send(self.sockfd, self.buffer.as_ptr() as *const libc::c_void,
|
||||
size, 0);
|
||||
if len == -1 { Err(io::Error::last_os_error()).unwrap() }
|
||||
}
|
||||
fn send<F: FnOnce(&mut [u8])>(&mut self, len: usize, handler: F) {
|
||||
handler(&mut self.buffer[..len]);
|
||||
self.lower.send(&self.buffer[..len]).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
use libc;
|
||||
|
||||
pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
|
||||
pub const SIOCGIFINDEX: libc::c_ulong = 0x8933;
|
||||
|
||||
pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
|
||||
|
||||
pub const IFF_TAP: libc::c_int = 0x0002;
|
||||
pub const IFF_NO_PI: libc::c_int = 0x1000;
|
||||
|
||||
pub const ETH_P_ALL: libc::c_short = 0x0003;
|
|
@ -0,0 +1,42 @@
|
|||
use libc;
|
||||
use std::io;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "linux.rs"]
|
||||
mod imp;
|
||||
|
||||
pub mod raw_socket;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod tap_interface;
|
||||
|
||||
pub use self::raw_socket::RawSocketDesc;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use self::tap_interface::TapInterfaceDesc;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct ifreq {
|
||||
ifr_name: [libc::c_char; libc::IF_NAMESIZE],
|
||||
ifr_data: libc::c_int /* ifr_ifindex or ifr_mtu */
|
||||
}
|
||||
|
||||
fn ifreq_for(name: &str) -> ifreq {
|
||||
let mut ifreq = ifreq {
|
||||
ifr_name: [0; libc::IF_NAMESIZE],
|
||||
ifr_data: 0
|
||||
};
|
||||
for (i, byte) in name.as_bytes().iter().enumerate() {
|
||||
ifreq.ifr_name[i] = *byte as libc::c_char
|
||||
}
|
||||
ifreq
|
||||
}
|
||||
|
||||
fn ifreq_ioctl(lower: libc::c_int, ifreq: &mut ifreq,
|
||||
cmd: libc::c_ulong) -> io::Result<libc::c_int> {
|
||||
unsafe {
|
||||
let res = libc::ioctl(lower, cmd, ifreq as *mut ifreq);
|
||||
if res == -1 { return Err(io::Error::last_os_error()) }
|
||||
}
|
||||
|
||||
Ok(ifreq.ifr_data)
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
use libc;
|
||||
use std::{mem, io};
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawSocketDesc {
|
||||
lower: libc::c_int,
|
||||
ifreq: ifreq
|
||||
}
|
||||
|
||||
impl RawSocketDesc {
|
||||
pub fn new(name: &str) -> io::Result<RawSocketDesc> {
|
||||
let lower = unsafe {
|
||||
let lower = libc::socket(libc::AF_PACKET, libc::SOCK_RAW,
|
||||
imp::ETH_P_ALL.to_be() as i32);
|
||||
if lower == -1 { return Err(io::Error::last_os_error()) }
|
||||
lower
|
||||
};
|
||||
|
||||
Ok(RawSocketDesc {
|
||||
lower: lower,
|
||||
ifreq: ifreq_for(name)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn interface_mtu(&mut self) -> io::Result<usize> {
|
||||
ifreq_ioctl(self.lower, &mut self.ifreq, imp::SIOCGIFMTU).map(|mtu| mtu as usize)
|
||||
}
|
||||
|
||||
pub fn bind_interface(&mut self) -> io::Result<()> {
|
||||
let sockaddr = libc::sockaddr_ll {
|
||||
sll_family: libc::AF_PACKET as u16,
|
||||
sll_protocol: imp::ETH_P_ALL.to_be() as u16,
|
||||
sll_ifindex: try!(ifreq_ioctl(self.lower, &mut self.ifreq, imp::SIOCGIFINDEX)),
|
||||
sll_hatype: 1,
|
||||
sll_pkttype: 0,
|
||||
sll_halen: 6,
|
||||
sll_addr: [0; 8]
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let res = libc::bind(self.lower,
|
||||
&sockaddr as *const libc::sockaddr_ll as *const libc::sockaddr,
|
||||
mem::size_of::<libc::sockaddr_ll>() as u32);
|
||||
if res == -1 { return Err(io::Error::last_os_error()) }
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let len = libc::recv(self.lower, buffer.as_mut_ptr() as *mut libc::c_void,
|
||||
buffer.len(), 0);
|
||||
if len == -1 { return Err(io::Error::last_os_error()) }
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let len = libc::send(self.lower, buffer.as_ptr() as *const libc::c_void,
|
||||
buffer.len(), 0);
|
||||
if len == -1 { Err(io::Error::last_os_error()).unwrap() }
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawSocketDesc {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::close(self.lower); }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
use libc;
|
||||
use std::io;
|
||||
use super::*;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[derive(Debug)]
|
||||
pub struct TapInterfaceDesc {
|
||||
lower: libc::c_int,
|
||||
ifreq: ifreq
|
||||
}
|
||||
|
||||
impl TapInterfaceDesc {
|
||||
pub fn new(name: &str) -> io::Result<TapInterfaceDesc> {
|
||||
let lower = unsafe {
|
||||
let lower = libc::open("/dev/net/tun".as_ptr() as *const libc::c_char,
|
||||
libc::O_RDWR);
|
||||
if lower == -1 { return Err(io::Error::last_os_error()) }
|
||||
lower
|
||||
};
|
||||
|
||||
Ok(TapInterfaceDesc {
|
||||
lower: lower,
|
||||
ifreq: ifreq_for(name)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attach_interface(&mut self) -> io::Result<()> {
|
||||
self.ifreq.ifr_data = imp::IFF_TAP | imp::IFF_NO_PI;
|
||||
ifreq_ioctl(self.lower, &mut self.ifreq, imp::TUNSETIFF).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn recv(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let len = libc::read(self.lower, buffer.as_mut_ptr() as *mut libc::c_void,
|
||||
buffer.len());
|
||||
if len == -1 { return Err(io::Error::last_os_error()) }
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&mut self, buffer: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let len = libc::write(self.lower, buffer.as_ptr() as *const libc::c_void,
|
||||
buffer.len());
|
||||
if len == -1 { Err(io::Error::last_os_error()).unwrap() }
|
||||
Ok(len as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TapInterfaceDesc {
|
||||
fn drop(&mut self) {
|
||||
unsafe { libc::close(self.lower); }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
use std::{vec, io};
|
||||
use super::{sys, Device};
|
||||
|
||||
/// A virtual Ethernet interface.
|
||||
#[derive(Debug)]
|
||||
pub struct TapInterface {
|
||||
lower: sys::TapInterfaceDesc,
|
||||
buffer: vec::Vec<u8>
|
||||
}
|
||||
|
||||
impl TapInterface {
|
||||
/// Attaches to a TAP interface called `name`, or creates it if it does not exist.
|
||||
///
|
||||
/// If `name` is a persistent interface configured with UID of the current user,
|
||||
/// no special privileges are needed. Otherwise, this requires superuser privileges
|
||||
/// or a corresponding capability set on the executable.
|
||||
pub fn new(name: &str) -> io::Result<TapInterface> {
|
||||
let mut lower = try!(sys::TapInterfaceDesc::new(name));
|
||||
try!(lower.attach_interface());
|
||||
|
||||
let mut buffer = vec::Vec::new();
|
||||
buffer.resize(Self::MTU, 0);
|
||||
Ok(TapInterface {
|
||||
lower: lower,
|
||||
buffer: buffer
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for TapInterface {
|
||||
const MTU: usize = 1536;
|
||||
|
||||
fn recv<F: FnOnce(&[u8])>(&mut self, handler: F) {
|
||||
let len = self.lower.recv(&mut self.buffer[..]).unwrap();
|
||||
handler(&self.buffer[..len])
|
||||
}
|
||||
|
||||
fn send<F: FnOnce(&mut [u8])>(&mut self, len: usize, handler: F) {
|
||||
handler(&mut self.buffer[..len]);
|
||||
self.lower.send(&self.buffer[..len]).unwrap();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue