Added support for strange BSD tun header

This commit is contained in:
Dennis Schwerdel 2016-07-02 14:05:24 +02:00
parent 883049986b
commit 91722f4270
4 changed files with 64 additions and 13 deletions

View File

@ -48,12 +48,15 @@ The tests can be run via ``cargo test``.
##### Debian / Ubuntu
Deb packages for each release can be found in the [releases](https://github.com/dswd/vpncloud.rs/releases) section.
Currently only packages for amd64 are available (I am accepting help on building and packaging for other platforms).
Deb packages for each release can be found in the
[releases](https://github.com/dswd/vpncloud.rs/releases) section. Currently only
packages for amd64 are available (I am accepting help on building and packaging
for other platforms).
##### Arch Linux (AUR)
There is a [VpnCloud package for Arch Linux](https://aur.archlinux.org/packages/vpncloud/) thanks to Oscar Rainford (fourbytes).
There is a [VpnCloud package for Arch Linux](https://aur.archlinux.org/packages/vpncloud/)
thanks to Oscar Rainford (fourbytes).
### Contributions welcome

View File

@ -7,7 +7,6 @@ use test::Bencher;
use std::str::FromStr;
use std::net::{UdpSocket, ToSocketAddrs, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::os::unix::io::AsRawFd;
use std::mem;
use super::cloud::GenericCloud;
use super::device::{Device, Type};

View File

@ -500,7 +500,7 @@ impl<P: Protocol> GenericCloud<P> {
Message::Data(payload, start, end) => {
let (src, _dst) = try!(P::parse(&payload[start..end]));
debug!("Writing data to device: {} bytes", end-start);
match self.device.write(&payload[start..end]) {
match self.device.write(&mut payload[..end], start) {
Ok(()) => (),
Err(e) => {
error!("Failed to send via device: {}", e);
@ -592,7 +592,7 @@ impl<P: Protocol> GenericCloud<P> {
},
fd if (fd == device_fd) => {
let start = 64;
let size = try_fail!(self.device.read(&mut buffer[start..]), "Failed to read from tap device: {}");
let (start, size) = try_fail!(self.device.read(&mut buffer[start..]), "Failed to read from tap device: {}");
if let Err(e) = self.handle_interface_data(&mut buffer, start, start+size) {
error!("Error: {}", e);
}

View File

@ -126,31 +126,80 @@ impl Device {
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
/// packet/frame will be split.
/// The method will block until a packet/frame is ready to be read.
/// On success, the method will return the amount of bytes read into the buffer (starting at
/// position 0).
/// On success, the method will return the starting position and the amount of bytes read into
/// the buffer.
///
/// # Errors
/// This method will return an error if the underlying read call fails.
#[inline]
pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, Error> {
self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read error"))
pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<(usize, usize), Error> {
let read = try!(self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read error")));
let (start, read) = self.correct_data_after_read(&mut buffer, 0, read);
Ok((start, read))
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
fn correct_data_after_read(&mut self, _buffer: &mut [u8], start: usize, read: usize) -> (usize, usize) {
(start, read)
}
#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
target_os = "freebsd", target_os = "ios", target_os = "macos",
target_os = "netbsd", target_os = "openbsd"))]
#[inline]
fn correct_data_after_read(&mut self, buffer: &mut [u8], start: usize, read: usize) -> (usize, usize) {
if self.type_ == Type::Tun {
// BSD-based systems add a 4-byte header containing the Ethertype for TUN
assert!(read>=4);
(start+4, read-4)
} else {
(start, read)
}
}
/// Writes a packet/frame to the device
///
/// This method writes one packet or frame (depending on the device type) from `data` to the
/// device.
/// device. The data starts at the position `start` in the buffer. The buffer should have at
/// least 4 bytes of space before the start of the packet.
/// The method will block until the packet/frame has been written.
///
/// # Errors
/// This method will return an error if the underlying read call fails.
#[inline]
pub fn write(&mut self, data: &[u8]) -> Result<(), Error> {
match self.fd.write_all(data) {
pub fn write(&mut self, mut data: &mut [u8], start: usize) -> Result<(), Error> {
let start = self.correct_data_before_write(&mut data, start);
match self.fd.write_all(&data[start..]) {
Ok(_) => self.fd.flush().map_err(|_| Error::TunTapDevError("Flush error")),
Err(_) => Err(Error::TunTapDevError("Write error"))
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
fn correct_data_before_write(&mut self, _buffer: &mut [u8], start: usize) -> usize {
start
}
#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
target_os = "freebsd", target_os = "ios", target_os = "macos",
target_os = "netbsd", target_os = "openbsd"))]
#[inline]
fn correct_data_before_write(&mut self, buffer: &mut [u8], start: usize) -> usize {
if self.type_ == Type::Tun {
// BSD-based systems add a 4-byte header containing the Ethertype for TUN
assert!(start>=4);
match buffer[start] >> 4 { // IP version
4 => buffer[start-4..start].clone_from_slice(&[0x00, 0x00, 0x08, 0x00]),
6 => buffer[start-4..start].clone_from_slice(&[0x00, 0x00, 0x86, 0xdd]),
_ => unreachable!()
}
start-4
} else {
start
}
}
}
impl AsRawFd for Device {