diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-08-13 19:05:15 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-08-13 19:05:15 +0200 |
commit | 72f04e3494b4f3ba810274447235e9051f5e1749 (patch) | |
tree | 81a9e909d05d85f561ec4b16b6f3c2df2a44009b | |
parent | 644023c680db2346c3144e7218d9ece7402e65b5 (diff) |
add native ipv6 support0.6.0
-rw-r--r-- | Cargo.lock | 22 | ||||
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | src/error.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 82 |
4 files changed, 108 insertions, 6 deletions
@@ -236,6 +236,12 @@ dependencies = [ ] [[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -461,20 +467,22 @@ dependencies = [ [[package]] name = "rsdsl_ip_config" -version = "0.2.1" -source = "git+https://github.com/rsdsl/ip_config.git#26c15096a1f4b69c6c06b5373b507c9dbbfc54c5" +version = "0.2.2" +source = "git+https://github.com/rsdsl/ip_config.git#3239a5eeef22de4c50d4d00a9f51bebb5207633c" dependencies = [ "serde", ] [[package]] name = "rsdsl_netlinkd" -version = "0.5.0" +version = "0.6.0" dependencies = [ "futures-util", + "ipnet", "netlink-packet-route", "notify", "rsdsl_ip_config", + "rsdsl_pd_config", "rtnetlink", "serde_json", "thiserror", @@ -482,6 +490,14 @@ dependencies = [ ] [[package]] +name = "rsdsl_pd_config" +version = "0.1.0" +source = "git+https://github.com/rsdsl/pd_config.git#98ee1876a08a1c3844d0b439a8ba52e5b3423810" +dependencies = [ + "serde", +] + +[[package]] name = "rtnetlink" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1,15 +1,17 @@ [package] name = "rsdsl_netlinkd" -version = "0.5.0" +version = "0.6.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] futures-util = "0.3.27" +ipnet = "2.8.0" netlink-packet-route = "0.17.0" notify = "5.1.0" -rsdsl_ip_config = { git = "https://github.com/rsdsl/ip_config.git", version = "0.2.1" } +rsdsl_ip_config = { git = "https://github.com/rsdsl/ip_config.git", version = "0.2.2" } +rsdsl_pd_config = { git = "https://github.com/rsdsl/pd_config.git", version = "0.1.0" } rtnetlink = "0.13.1" serde_json = "1.0" thiserror = "1.0" diff --git a/src/error.rs b/src/error.rs index 78bd0ba..6458cc1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,8 +7,12 @@ use thiserror::Error; pub enum Error { #[error("link {0} not found")] LinkNotFound(String), + #[error("not enough ipv6 subnets")] + NotEnoughIpv6Subnets, #[error("io: {0}")] Io(#[from] io::Error), + #[error("ipnet prefix len: {0}")] + IpnetPrefixLen(#[from] ipnet::PrefixLenError), #[error("net: parse ip address: {0}")] NetAddrParseError(#[from] net::AddrParseError), #[error("notify: {0}")] diff --git a/src/main.rs b/src/main.rs index 3afefcb..8ea3f89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use rsdsl_netlinkd::error::Result; +use rsdsl_netlinkd::error::{Error, Result}; use rsdsl_netlinkd::{addr, link, route}; use std::fs::{self, File}; @@ -7,9 +7,13 @@ use std::path::Path; use std::thread; use std::time::Duration; +use ipnet::Ipv6Net; use notify::event::{CreateKind, ModifyKind}; use notify::{Event, EventKind, RecursiveMode, Watcher}; use rsdsl_ip_config::DsConfig; +use rsdsl_pd_config::PdConfig; + +const LINK_LOCAL: Ipv6Addr = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 1); fn main() -> Result<()> { println!("wait for eth0"); @@ -37,6 +41,9 @@ fn main() -> Result<()> { fs::write("/proc/sys/net/ipv4/ip_forward", "1")?; println!("enable ipv4 routing"); + fs::write("/proc/sys/net/ipv6/conf/all/forwarding", "1")?; + println!("enable ipv6 routing"); + println!("wait for eth1"); link::wait_exists("eth1".into())?; println!("detect eth1"); @@ -74,6 +81,30 @@ fn main() -> Result<()> { watcher.watch(ip_config, RecursiveMode::NonRecursive)?; + let pd_config = Path::new(rsdsl_pd_config::LOCATION); + + println!("wait for dhcp6"); + while !pd_config.exists() { + thread::sleep(Duration::from_secs(8)); + } + + configure_ipv6(); + + let mut watcher = notify::recommended_watcher(|res: notify::Result<Event>| match res { + Ok(event) => match event.kind { + EventKind::Create(kind) if kind == CreateKind::File => { + configure_ipv6(); + } + EventKind::Modify(kind) if matches!(kind, ModifyKind::Data(_)) => { + configure_ipv6(); + } + _ => {} + }, + Err(e) => println!("watch error: {:?}", e), + })?; + + watcher.watch(pd_config, RecursiveMode::NonRecursive)?; + loop { thread::sleep(Duration::MAX) } @@ -139,3 +170,52 @@ fn configure_ppp0() -> Result<()> { Ok(()) } + +fn configure_ipv6() { + match configure_all_v6() { + Ok(_) => println!("configure ipv6"), + Err(e) => println!("can't configure ipv6: {:?}", e), + } +} + +fn configure_all_v6() -> Result<()> { + let mut file = File::open(rsdsl_pd_config::LOCATION)?; + let pd_config: PdConfig = serde_json::from_reader(&mut file)?; + + let prefix = Ipv6Net::new(pd_config.prefix, pd_config.len)?.trunc(); + let mut subnets = prefix.subnets(64)?; + + addr::add("ppp0".into(), IpAddr::V6(next_ifid1(&mut subnets)?), 64)?; + + let addr = next_ifid1(&mut subnets)?; + + fs::write("/proc/sys/net/ipv6/conf/eth0/accept_ra", "0")?; + + addr::add_link_local("eth0".into(), LINK_LOCAL.into(), 64)?; + addr::add("eth0".into(), addr.into(), 64)?; + + println!("configure eth0 ({}/64)", addr); + + let zones = ["trusted", "untrusted", "isolated", "exposed"]; + for (i, zone) in zones.iter().enumerate() { + let vlan_id = 10 * (i + 1); + let vlan_name = format!("eth0.{}", vlan_id); + let vlan_addr = next_ifid1(&mut subnets)?; + + fs::write( + format!("/proc/sys/net/ipv6/conf/{}/accept_ra", vlan_name), + "0", + )?; + + addr::add_link_local(vlan_name.clone(), LINK_LOCAL.into(), 64)?; + addr::add(vlan_name.clone(), vlan_addr.into(), 64)?; + + println!("configure {} ({}/64) zone {}", vlan_name, vlan_addr, zone); + } + + Ok(()) +} + +fn next_ifid1<T: Iterator<Item = Ipv6Net>>(subnets: &mut T) -> Result<Ipv6Addr> { + Ok((u128::from(subnets.next().ok_or(Error::NotEnoughIpv6Subnets)?.addr()) + 1).into()) +} |