aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs1
-rw-r--r--src/tunnel.rs107
2 files changed, 108 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 6db46f3..f1ba963 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,3 +2,4 @@ pub mod addr;
pub mod error;
pub mod link;
pub mod route;
+pub mod tunnel;
diff --git a/src/tunnel.rs b/src/tunnel.rs
new file mode 100644
index 0000000..0de6f51
--- /dev/null
+++ b/src/tunnel.rs
@@ -0,0 +1,107 @@
+use std::ffi::CString;
+use std::io;
+use std::net::{Ipv4Addr, Ipv6Addr};
+
+use crate::{internal, Error, Result};
+
+/// A handle to a 6in4 tunnel. The interface is automatically deleted on drop.
+#[derive(Debug)]
+pub struct Sit {
+ name: String,
+}
+
+impl Drop for Sit {
+ fn drop(&mut self) {
+ let _ = self.do_delete();
+ }
+}
+
+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 err = unsafe {
+ internal::netlinkd_create_6in4(
+ tnlname,
+ ifmaster,
+ u32::from(laddr).to_be(),
+ u32::from(raddr).to_be(),
+ )
+ };
+
+ let _ = unsafe { CString::from_raw(tnlname) };
+ let _ = unsafe { CString::from_raw(ifmaster) };
+
+ if err < 0 {
+ Err(Error::Io(io::Error::last_os_error()))
+ } else {
+ Ok(Self {
+ name: name.to_owned(),
+ })
+ }
+ }
+
+ fn do_delete(&self) -> Result<()> {
+ let tnlname = CString::new(self.name.as_str())?.into_raw();
+ let err = unsafe { internal::netlinkd_delete_tunnel(tnlname) };
+ let _ = unsafe { CString::from_raw(tnlname) };
+
+ if err < 0 {
+ Err(Error::Io(io::Error::last_os_error()))
+ } else {
+ Ok(())
+ }
+ }
+}
+
+/// A handle to a 4in6 tunnel. The interface is automatically deleted on drop.
+#[derive(Debug)]
+pub struct IpIp6 {
+ name: String,
+}
+
+impl Drop for IpIp6 {
+ fn drop(&mut self) {
+ let _ = self.do_delete();
+ }
+}
+
+impl IpIp6 {
+ pub fn new(name: &str, master: &str, laddr: Ipv6Addr, raddr: Ipv6Addr) -> Result<Self> {
+ let tnlname = CString::new(name)?.into_raw();
+ let ifmaster = CString::new(master)?.into_raw();
+
+ let err = unsafe {
+ internal::netlinkd_create_4in6(
+ tnlname,
+ ifmaster,
+ &laddr.octets() as *const u8,
+ &raddr.octets() as *const u8,
+ )
+ };
+
+ let _ = unsafe { CString::from_raw(tnlname) };
+ let _ = unsafe { CString::from_raw(ifmaster) };
+
+ if err < 0 {
+ Err(Error::Io(io::Error::last_os_error()))
+ } else {
+ Ok(Self {
+ name: name.to_owned(),
+ })
+ }
+ }
+
+ fn do_delete(&self) -> Result<()> {
+ let tnlname = CString::new(self.name.as_str())?.into_raw();
+ let err = unsafe { internal::netlinkd_delete_tunnel(tnlname) };
+ let _ = unsafe { CString::from_raw(tnlname) };
+
+ if err < 0 {
+ Err(Error::Io(io::Error::last_os_error()))
+ } else {
+ Ok(())
+ }
+ }
+}