aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2023-08-13 19:05:15 +0200
committerHimbeerserverDE <himbeerserverde@gmail.com>2023-08-13 19:05:15 +0200
commit72f04e3494b4f3ba810274447235e9051f5e1749 (patch)
tree81a9e909d05d85f561ec4b16b6f3c2df2a44009b
parent644023c680db2346c3144e7218d9ece7402e65b5 (diff)
add native ipv6 support0.6.0
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml6
-rw-r--r--src/error.rs4
-rw-r--r--src/main.rs82
4 files changed, 108 insertions, 6 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4d26298..774475d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index fa01d83..9876e62 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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())
+}