🚧 Routing!
This commit is contained in:
parent
e643d9dd41
commit
337425446b
6 changed files with 288 additions and 2 deletions
|
|
@ -9,6 +9,7 @@ mod imp;
|
|||
pub(crate) mod imp;
|
||||
|
||||
mod options;
|
||||
pub mod routing;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[cfg(feature = "tokio")]
|
||||
|
|
|
|||
148
tun/src/routing.rs
Normal file
148
tun/src/routing.rs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
use std::{io, mem};
|
||||
use crate::TunInterface;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::process::Command;
|
||||
use fehler::throws;
|
||||
// use rtnetlink;
|
||||
use std::io::{Error, Write};
|
||||
use libc::{rt_msghdr, c_uchar, rt_metrics, sockaddr_dl};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use socket2::SockAddr;
|
||||
|
||||
struct Handle {
|
||||
pub inner: socket2::Socket,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
#[throws]
|
||||
pub fn new() -> Self {
|
||||
let inner = socket2::Socket::new(socket2::Domain::from(libc::PF_ROUTE), socket2::Type::RAW, None)?;
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Route<'a> {
|
||||
pub destination: IpAddr, // Default: 0.0.0.0
|
||||
pub destination_prefix: u8,
|
||||
|
||||
pub interface: &'a TunInterface,
|
||||
|
||||
// #[cfg(target_os = "linux")]
|
||||
// pub ifindex: Option<u32>,
|
||||
//
|
||||
// #[cfg(target_os = "linux")]
|
||||
// pub table: u8,
|
||||
}
|
||||
|
||||
impl<'a> Route<'a> {
|
||||
#[throws]
|
||||
pub fn new(destination: IpAddr, destination_prefix: u8, interface: &'a TunInterface) -> Self {
|
||||
let mut handle = Handle::new()?;
|
||||
|
||||
let mut hdr: rt_msghdr = unsafe { mem::zeroed() };
|
||||
hdr.rtm_version = libc::RTM_VERSION as c_uchar;
|
||||
hdr.rtm_type = libc::RTM_ADD as c_uchar;
|
||||
hdr.rtm_flags = libc::RTF_STATIC | libc::RTF_UP;
|
||||
hdr.rtm_addrs = libc::RTA_DST | libc::RTA_NETMASK | libc::RTA_GATEWAY | libc::RTA_IFP;
|
||||
hdr.rtm_seq = 1;
|
||||
|
||||
let destination_addr = SockAddr::from(SocketAddr::new(destination, 0));
|
||||
let gateway_addr = SockAddr::from(SocketAddrV4::new(interface.ipv4_addr()?, 0));
|
||||
|
||||
let index = interface.index()?;
|
||||
let (_, if_addr) = unsafe {
|
||||
SockAddr::init(|storage, len| {
|
||||
*len = mem::size_of::<libc::sockaddr_dl>() as u32;
|
||||
|
||||
let mut addr: &mut libc::sockaddr_dl = &mut *storage.cast();
|
||||
addr.sdl_len = *len as u8;
|
||||
addr.sdl_family = libc::AF_LINK as u8;
|
||||
addr.sdl_index = index as u16;
|
||||
Ok(())
|
||||
})?
|
||||
};
|
||||
let mask_addr = SockAddr::from(SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), 0));
|
||||
|
||||
hdr.rtm_msglen = (
|
||||
(mem::size_of::<rt_msghdr>() as u32) + destination_addr.len() + gateway_addr.len() + if_addr.len() + mask_addr.len()
|
||||
) as u16;
|
||||
|
||||
println!("0z {:#?}", if_addr.len());
|
||||
let buffer = vec![];
|
||||
let mut cursor = std::io::Cursor::new(buffer);
|
||||
cursor.write_all(unsafe {
|
||||
std::slice::from_raw_parts(&hdr as *const _ as *const _, mem::size_of::<rt_msghdr>())
|
||||
})?;
|
||||
|
||||
println!("one");
|
||||
write_addr(&mut cursor, destination_addr)?;
|
||||
println!("two");
|
||||
write_addr(&mut cursor, gateway_addr)?;
|
||||
println!("three");
|
||||
write_addr(&mut cursor, if_addr)?;
|
||||
println!("4");
|
||||
write_addr(&mut cursor, mask_addr)?;
|
||||
println!("five");
|
||||
|
||||
let buf = cursor.into_inner();
|
||||
println!("cbuf len: {:#?}, calcsize: {:#?}", buf.len(), hdr.rtm_msglen);
|
||||
|
||||
handle.inner.write_all(&buf)?;
|
||||
|
||||
// Create handle
|
||||
Self {
|
||||
destination,
|
||||
destination_prefix,
|
||||
interface
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn through_interface(&self, iface: TunInterface) {
|
||||
// High-level overview:
|
||||
// 1. Create a socket
|
||||
iface.socket.bind(iface.addr);
|
||||
|
||||
// 2. Bind the socket to the interface
|
||||
// 3. Add the route
|
||||
// 4. Close the socket
|
||||
// 5. Return the result
|
||||
}
|
||||
}
|
||||
|
||||
#[throws]
|
||||
#[cfg(target_platform = "linux")]
|
||||
pub async fn add_route(route: Route) {
|
||||
let conn = rtnetlink::new_connection()?;
|
||||
|
||||
let handle = conn.route();
|
||||
let route_add_request = handle
|
||||
.add()
|
||||
.v4()
|
||||
.destination_prefix(route.destination, route.destination_prefix)
|
||||
.output_interface(route.interface.index()?)
|
||||
.execute().await?;
|
||||
}
|
||||
|
||||
#[throws]
|
||||
#[cfg(target_vendor="apple")]
|
||||
pub fn add_route(route: Route) {
|
||||
// Construct
|
||||
// Construct RT message
|
||||
Command::new("route")
|
||||
.arg("add")
|
||||
.arg("-host")
|
||||
.arg(route.destination.to_string())
|
||||
.arg("-interface")
|
||||
.arg(route.interface.name().expect("the interface's name"))
|
||||
.spawn()
|
||||
.expect("failed to execute add route process");
|
||||
}
|
||||
|
||||
#[throws]
|
||||
fn write_addr<T: Write>(sock: &mut T, addr: socket2::SockAddr) {
|
||||
let len = addr.len() as usize;
|
||||
let ptr = addr.as_ptr() as *const _;
|
||||
sock.write_all(unsafe { std::slice::from_raw_parts(ptr, len) })?;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use fehler::throws;
|
||||
use fehler::{throw, throws};
|
||||
use libc::{c_char, iovec, writev, AF_INET, AF_INET6};
|
||||
use tracing::info;
|
||||
use socket2::{Domain, SockAddr, Socket, Type};
|
||||
|
|
@ -9,6 +9,7 @@ use std::os::fd::{AsRawFd, RawFd};
|
|||
use std::{io::Error, mem};
|
||||
use tracing::instrument;
|
||||
|
||||
|
||||
mod kern_control;
|
||||
mod sys;
|
||||
|
||||
|
|
@ -54,6 +55,11 @@ impl TunInterface {
|
|||
#[throws]
|
||||
#[instrument]
|
||||
pub fn name(&self) -> String {
|
||||
ifname_to_string(self.ifname()?)
|
||||
}
|
||||
|
||||
#[throws]
|
||||
fn ifname(&self) -> [libc::c_char; libc::IFNAMSIZ] {
|
||||
let mut buf = [0 as c_char; sys::IFNAMSIZ];
|
||||
let mut len = buf.len() as sys::socklen_t;
|
||||
sys::syscall!(getsockopt(
|
||||
|
|
@ -63,7 +69,20 @@ impl TunInterface {
|
|||
buf.as_mut_ptr() as *mut sys::c_void,
|
||||
&mut len,
|
||||
))?;
|
||||
ifname_to_string(buf)
|
||||
buf
|
||||
}
|
||||
|
||||
|
||||
#[throws]
|
||||
#[instrument]
|
||||
pub fn index(&self) -> usize {
|
||||
let ifname = self.ifname()?;
|
||||
let index = unsafe { libc::if_nametoindex(ifname.as_ptr()) };
|
||||
if index == 0 {
|
||||
throw!(Error::last_os_error())
|
||||
}
|
||||
|
||||
index as usize
|
||||
}
|
||||
|
||||
#[throws]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue