diff options
Diffstat (limited to 'src/tunnel.rs')
-rw-r--r-- | src/tunnel.rs | 106 |
1 files changed, 89 insertions, 17 deletions
diff --git a/src/tunnel.rs b/src/tunnel.rs index 240e5fb..ac5d074 100644 --- a/src/tunnel.rs +++ b/src/tunnel.rs @@ -4,6 +4,10 @@ use std::ffi::CString; use std::io; use std::net::{Ipv4Addr, Ipv6Addr}; +use bitfield::bitfield; + +const SIOCADDTUNNEL: u64 = 0x89F0 + 1; + /// A handle to a 6in4 tunnel. The interface is automatically deleted on drop. #[derive(Debug)] pub struct Sit { @@ -18,28 +22,53 @@ impl Drop for Sit { impl Sit { pub fn new(name: &str, master: &str, laddr: Ipv4Addr, raddr: Ipv4Addr) -> Result<Self> { - let tnlname = CString::new(name)?.into_raw(); - let ifmaster = CString::new(master)?.into_raw(); + let mut vihl = VerIhl::default(); + + vihl.set_version(4); + vihl.set_ihl(5); + + let p = IpTunnelParm { + name: CString::new(name)?, + link: libc::if_nametoindex(CString::new(master)?.as_ptr()), + i_flags: 0, + o_flags: 0, + i_key: 0, + o_key: 0, + iph: IpHdr { + vihl, + tos: 0, + tot_len: 0, + id: 0, + frag_off: 0, + check: 0, + ttl: 64, + protocol: libc::IPPROTO_IPV6 as u8, + saddr: laddr, + daddr: raddr, + }, + }; - let err = unsafe { - internal::netlinkd_create_6in4( - tnlname, - ifmaster, - u32::from(laddr).to_be(), - u32::from(raddr).to_be(), - ) + if p.link == 0 { + return Err(Error::LinkNotFound(master.to_owned())); + } + + let ifr = IfReq { + name: CString::new("sit0")?, + ifru_data: &p, }; - let _ = unsafe { CString::from_raw(tnlname) }; - let _ = unsafe { CString::from_raw(ifmaster) }; + let fd = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP); + if fd < 0 { + return Err(io::Error::last_os_error().into()); + } - if err < 0 { - Err(Error::Io(io::Error::last_os_error())) - } else { - Ok(Self { - name: name.to_owned(), - }) + if libc::ioctl(fd, SIOCADDTUNNEL, &ifr) < 0 { + return Err(io::Error::last_os_error().into()); } + + Ok(Self { + name: name.to_owned(), + }) } fn do_delete(&self) -> Result<()> { @@ -105,3 +134,46 @@ impl IpIp6 { } } } + +bitfield! { + #[derive(Default)] + struct VerIhl(u8); + impl Debug; + + version, set_version: 7, 4; + ihl, set_ihl: 3, 0; +} + +#[derive(Debug)] +#[repr(C)] +struct IpHdr { + vihl: VerIhl, + tos: u8, + tot_len: u16, + id: u16, + frag_off: u16, + ttl: u8, + protocol: u8, + check: u16, + saddr: Ipv4Addr, + daddr: Ipv4Addr, +} + +#[derive(Debug)] +#[repr(C)] +struct IpTunnelParm { + name: CString, + link: u32, + i_flags: u16, + o_flags: u16, + i_key: u32, + o_key: u32, + iph: IpHdr, +} + +#[derive(Debug)] +#[repr(C)] +struct IfReq { + name: CString, + ifru_data: *const IpTunnelParm, +} |