diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-08-13 23:08:23 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-08-13 23:08:23 +0200 |
commit | 2f4f15a8f7501021af74bcf97e73350502cba4fd (patch) | |
tree | d672dafad9568ad71b1ae3e4d477134c32cb36d6 /src | |
parent | ce1cb086b68f9259ccb882201f6d82ee9b047002 (diff) |
initial b4 impl
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 27 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 102 |
3 files changed, 129 insertions, 2 deletions
diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..5264e41 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,27 @@ +use std::io; + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("not enough ipv6 subnets")] + NotEnoughIpv6Subnets, + #[error("no address associated with aftr name")] + NoDnsRecord, + + #[error("io: {0}")] + Io(#[from] io::Error), + + #[error("ipnet prefix len: {0}")] + IpnetPrefixLen(#[from] ipnet::PrefixLenError), + #[error("rsdsl_netlinkd: {0}")] + RsdslNetlinkd(#[from] rsdsl_netlinkd::error::Error), + #[error("rsdsl_netlinkd_sys: {0}")] + RsdslNetlinkdSys(#[from] rsdsl_netlinkd_sys::Error), + #[error("serde_json: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("trust_dns_resolver resolve: {0}")] + TrustDnsResolverResolve(#[from] trust_dns_resolver::error::ResolveError), +} + +pub type Result<T> = std::result::Result<T, Error>; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7edf3bf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +mod error; +pub use error::*; diff --git a/src/main.rs b/src/main.rs index e7a11a9..f597b04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,101 @@ -fn main() { - println!("Hello, world!"); +use std::fs::File; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::path::Path; +use std::thread; +use std::time::Duration; + +use ipnet::Ipv6Net; +use rsdsl_dslite::{Error, Result}; +use rsdsl_ip_config::DsConfig; +use rsdsl_netlinkd::{addr, link, route}; +use rsdsl_netlinkd_sys::IpIp6; +use rsdsl_pd_config::PdConfig; +use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}; +use trust_dns_resolver::Resolver; + +const ADDR4_AFTR: Ipv4Addr = Ipv4Addr::new(192, 0, 0, 1); +const ADDR4_B4: Ipv4Addr = Ipv4Addr::new(192, 0, 0, 2); + +fn main() -> Result<()> { + println!("wait for up ppp0"); + link::wait_up("ppp0".into())?; + + let pd_config = Path::new(rsdsl_pd_config::LOCATION); + + println!("wait for dhcp6"); + while !pd_config.exists() { + thread::sleep(Duration::from_secs(8)); + } + + let mut file = File::open(rsdsl_pd_config::LOCATION)?; + let pdconfig: PdConfig = serde_json::from_reader(&mut file)?; + + if let Some(ref aftr) = pdconfig.aftr { + let local = local_address(&pdconfig)?; + let remote = resolve6(&pdconfig, aftr)?; + let _tnl = IpIp6::new("dslite0", "ppp0", local, remote)?; + + configure_dslite(); + } else { + println!("no aftr"); + } + + loop { + thread::sleep(Duration::MAX); + } +} + +fn configure_dslite() { + match configure_dslite0() { + Ok(_) => println!("configure dslite0"), + Err(e) => println!("can't configure dslite0: {}", e), + } +} + +fn configure_dslite0() -> Result<()> { + link::up("dslite0".into())?; + + addr::flush("dslite0".into())?; + addr::add("dslite0".into(), ADDR4_B4.into(), 29)?; + + let mut file = File::open(rsdsl_ip_config::LOCATION)?; + let dsconfig: DsConfig = serde_json::from_reader(&mut file)?; + + // Check for native connectivity to avoid breaking netlinkd. + if dsconfig.v4.is_none() { + route::add4(Ipv4Addr::UNSPECIFIED, 0, Some(ADDR4_AFTR), "dslite0".into())?; + } + + Ok(()) +} + +fn local_address(pdconfig: &PdConfig) -> Result<Ipv6Addr> { + let prefix = Ipv6Net::new(pdconfig.prefix, pdconfig.len)?.trunc(); + let mut subnets = prefix.subnets(64)?; + + let addr = next_ifid1(&mut subnets)?; + Ok(addr) +} + +fn next_ifid1<T: Iterator<Item = Ipv6Net>>(subnets: &mut T) -> Result<Ipv6Addr> { + Ok((u128::from(subnets.next().ok_or(Error::NotEnoughIpv6Subnets)?.addr()) + 1).into()) +} + +fn resolve6(pdconfig: &PdConfig, fqdn: &str) -> Result<Ipv6Addr> { + let mut cfg = ResolverConfig::new(); + + cfg.add_name_server(NameServerConfig::new( + SocketAddr::new(pdconfig.dns1.into(), 53), + Protocol::Udp, + )); + cfg.add_name_server(NameServerConfig::new( + SocketAddr::new(pdconfig.dns2.into(), 53), + Protocol::Udp, + )); + + let resolver = Resolver::new(cfg, ResolverOpts::default())?; + let response = resolver.ipv6_lookup(fqdn)?; + + let addr = response.iter().next().ok_or(Error::NoDnsRecord)?; + Ok(*addr) } |