aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock12
-rw-r--r--Cargo.toml2
-rw-r--r--src/tunnel.rs106
3 files changed, 101 insertions, 19 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d434422..e3ef295 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -45,6 +45,12 @@ dependencies = [
]
[[package]]
+name = "bitfield"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -269,9 +275,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.147"
+version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
[[package]]
name = "log"
@@ -477,9 +483,11 @@ dependencies = [
name = "rsdsl_netlinkd"
version = "0.7.0-dev"
dependencies = [
+ "bitfield",
"futures",
"futures-util",
"ipnet",
+ "libc",
"netlink-packet-route",
"notify",
"rsdsl_ip_config",
diff --git a/Cargo.toml b/Cargo.toml
index af4256a..5760f2a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,9 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+bitfield = "0.14.0"
futures = "0.3.28"
futures-util = "0.3.27"
ipnet = "2.8.0"
+libc = "0.2.149"
netlink-packet-route = "0.17.0"
notify = "5.1.0"
rsdsl_ip_config = { git = "https://github.com/rsdsl/ip_config.git", version = "0.2.2" }
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,
+}