aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2023-08-13 23:08:23 +0200
committerHimbeerserverDE <himbeerserverde@gmail.com>2023-08-13 23:08:23 +0200
commit2f4f15a8f7501021af74bcf97e73350502cba4fd (patch)
treed672dafad9568ad71b1ae3e4d477134c32cb36d6 /src
parentce1cb086b68f9259ccb882201f6d82ee9b047002 (diff)
initial b4 impl
Diffstat (limited to 'src')
-rw-r--r--src/error.rs27
-rw-r--r--src/lib.rs2
-rw-r--r--src/main.rs102
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)
}