renet/src/interface/raw_socket.rs

102 lines
3.1 KiB
Rust

extern crate std;
extern crate libc;
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.
#[derive(Debug)]
pub struct RawSocket {
sockfd: libc::c_int,
buffer: vec::Vec<u8>
}
impl RawSocket {
/// Creates and returns a raw socket, bound to the interface called `name`.
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 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
})
}
}
/// Captures a packet into the internal buffer, which is sized appropriately
/// for the interface MTU.
pub fn capture(&mut self) -> io::Result<&[u8]> {
unsafe {
let len = libc::recv(self.sockfd, self.buffer.as_mut_ptr() as *mut libc::c_void,
self.buffer.len(), 0);
if len == -1 {
return Err(io::Error::last_os_error())
}
Ok(&self.buffer[..len as usize])
}
}
}
impl Drop for RawSocket {
fn drop(&mut self) {
unsafe { libc::close(self.sockfd); }
}
}