mirror of https://github.com/dswd/vpncloud.git
Added support for strange BSD tun header
This commit is contained in:
parent
883049986b
commit
91722f4270
|
@ -48,12 +48,15 @@ The tests can be run via ``cargo test``.
|
||||||
|
|
||||||
|
|
||||||
##### Debian / Ubuntu
|
##### Debian / Ubuntu
|
||||||
Deb packages for each release can be found in the [releases](https://github.com/dswd/vpncloud.rs/releases) section.
|
Deb packages for each release can be found in the
|
||||||
Currently only packages for amd64 are available (I am accepting help on building and packaging for other platforms).
|
[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)
|
##### 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
|
### Contributions welcome
|
||||||
|
|
|
@ -7,7 +7,6 @@ use test::Bencher;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::net::{UdpSocket, ToSocketAddrs, Ipv4Addr, SocketAddr, SocketAddrV4};
|
use std::net::{UdpSocket, ToSocketAddrs, Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use super::cloud::GenericCloud;
|
use super::cloud::GenericCloud;
|
||||||
use super::device::{Device, Type};
|
use super::device::{Device, Type};
|
||||||
|
|
|
@ -500,7 +500,7 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
Message::Data(payload, start, end) => {
|
Message::Data(payload, start, end) => {
|
||||||
let (src, _dst) = try!(P::parse(&payload[start..end]));
|
let (src, _dst) = try!(P::parse(&payload[start..end]));
|
||||||
debug!("Writing data to device: {} bytes", end-start);
|
debug!("Writing data to device: {} bytes", end-start);
|
||||||
match self.device.write(&payload[start..end]) {
|
match self.device.write(&mut payload[..end], start) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to send via device: {}", e);
|
error!("Failed to send via device: {}", e);
|
||||||
|
@ -592,7 +592,7 @@ impl<P: Protocol> GenericCloud<P> {
|
||||||
},
|
},
|
||||||
fd if (fd == device_fd) => {
|
fd if (fd == device_fd) => {
|
||||||
let start = 64;
|
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) {
|
if let Err(e) = self.handle_interface_data(&mut buffer, start, start+size) {
|
||||||
error!("Error: {}", e);
|
error!("Error: {}", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,31 +126,80 @@ impl Device {
|
||||||
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
|
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
|
||||||
/// packet/frame will be split.
|
/// packet/frame will be split.
|
||||||
/// The method will block until a packet/frame is ready to be read.
|
/// 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
|
/// On success, the method will return the starting position and the amount of bytes read into
|
||||||
/// position 0).
|
/// the buffer.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// This method will return an error if the underlying read call fails.
|
/// This method will return an error if the underlying read call fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, Error> {
|
pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<(usize, usize), Error> {
|
||||||
self.fd.read(&mut buffer).map_err(|_| Error::TunTapDevError("Read 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
|
/// Writes a packet/frame to the device
|
||||||
///
|
///
|
||||||
/// This method writes one packet or frame (depending on the device type) from `data` to the
|
/// 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.
|
/// The method will block until the packet/frame has been written.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// This method will return an error if the underlying read call fails.
|
/// This method will return an error if the underlying read call fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn write(&mut self, data: &[u8]) -> Result<(), Error> {
|
pub fn write(&mut self, mut data: &mut [u8], start: usize) -> Result<(), Error> {
|
||||||
match self.fd.write_all(data) {
|
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")),
|
Ok(_) => self.fd.flush().map_err(|_| Error::TunTapDevError("Flush error")),
|
||||||
Err(_) => Err(Error::TunTapDevError("Write 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 {
|
impl AsRawFd for Device {
|
||||||
|
|
Loading…
Reference in New Issue