diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-05-07 20:01:34 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-05-07 20:01:34 +0200 |
commit | 1c39727c4ac81120828afafe28b750f32b981bf8 (patch) | |
tree | ec3f5ee61c22314180bb5259e30d5361d6f4687d | |
parent | 5c69c25fca3ef40bafea6840ab7c2cb554894ee2 (diff) |
hand out addresses from the prefixes assigned to the corresponding interface
-rw-r--r-- | Cargo.lock | 21 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/main.rs | 124 |
3 files changed, 124 insertions, 24 deletions
@@ -212,6 +212,12 @@ dependencies = [ ] [[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + +[[package]] name = "itoa" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -244,6 +250,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024" [[package]] +name = "linkaddrs" +version = "0.1.0" +source = "git+https://github.com/HimbeerserverDE/linkaddrs.git#412f8341bc1631acdae5ded45e53a23d93477e63" +dependencies = [ + "futures", + "ipnet", + "netlink-packet-route", + "rtnetlink", + "tokio", +] + +[[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -513,9 +531,12 @@ dependencies = [ name = "rsdsl_radvd" version = "0.1.0" dependencies = [ + "ipnet", + "linkaddrs", "pnet_packet", "rsdsl_netlinkd", "socket2 0.5.2", + "thiserror", ] [[package]] @@ -4,6 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] +ipnet = "2.7.1" +linkaddrs = { git = "https://github.com/HimbeerserverDE/linkaddrs.git", version = "0.1.0" } pnet_packet = "0.33.0" rsdsl_netlinkd = { git = "https://github.com/rsdsl/netlinkd.git", version = "0.3.0" } socket2 = { version = "0.5.2", features = ["all"] } +thiserror = "1.0" diff --git a/src/main.rs b/src/main.rs index c199dce..29a7199 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,47 @@ use std::io::{self, Read}; use std::net::{Ipv6Addr, SocketAddrV6}; +use std::thread; +use std::time::Duration; +use ipnet::Ipv6Net; use pnet_packet::icmpv6::ndp::{MutableRouterAdvertPacket, NdpOption, NdpOptionType, RouterAdvert}; use pnet_packet::icmpv6::{Icmpv6Code, Icmpv6Type}; -use rsdsl_netlinkd::error::Result; use rsdsl_netlinkd::link; use socket2::{Domain, Protocol, Socket, Type}; +use thiserror::Error; + +#[derive(Debug, Error)] +enum Error { + #[error("io: {0}")] + Io(#[from] io::Error), + #[error("linkaddrs: {0}")] + LinkAddrs(#[from] linkaddrs::Error), + #[error("rsdsl_netlinkd: {0}")] + RsdslNetlinkd(#[from] rsdsl_netlinkd::error::Error), +} + +type Result<T> = std::result::Result<T, Error>; fn main() -> Result<()> { + for i in 1..=4 { + let vlan_id = i * 10; + let vlan_name = format!("eth0.{}", vlan_id); + + thread::spawn(move || match run(vlan_name.clone()) { + Ok(_) => {} + Err(e) => println!("[radvd] can't init {}: {}", vlan_name, e), + }); + } + run("eth0".into())?; Ok(()) } fn run(link: String) -> Result<()> { + println!("[radvd] wait for {}", link); + link::wait_up(link.clone())?; + thread::sleep(Duration::from_secs(1)); + println!("[radvd] init {}", link); let ifi = link::index(link.clone())?; @@ -22,7 +51,21 @@ fn run(link: String) -> Result<()> { sock.join_multicast_v6(&Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 2), ifi)?; sock.set_multicast_hops_v6(255)?; - send_ra_multicast(&sock, &link, ifi)?; + // Periodically send NDP RAs so SLAAC addresses don't expire. + // The interval is five minutes shorter than the preferred lifetime. + let sock2 = sock.try_clone()?; + let link2 = link.clone(); + thread::spawn(move || loop { + match send_ra_multicast(&sock2, &link2, ifi) { + Ok(_) => {} + Err(e) => println!( + "[radvd] warning: can't send ra multicast on {}: {}", + link2, e + ), + } + + thread::sleep(Duration::from_secs(1200)); + }); let mut buf = [0; 1500]; loop { @@ -32,13 +75,47 @@ fn run(link: String) -> Result<()> { // Router Solicitation if buf[0] == 133 { println!("[radvd] recv nd-rs on {}", link); - send_ra_multicast(&sock, &link, ifi)?; + + match send_ra_multicast(&sock, &link, ifi) { + Ok(_) => {} + Err(e) => println!( + "[radvd] warning: can't send ra multicast on {}: {}", + link, e + ), + } } } } -fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> io::Result<()> { +fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> Result<()> { let all_nodes = SocketAddrV6::new(Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 1), 0, 0, ifi).into(); + let global = Ipv6Net::new(Ipv6Addr::new(0x2000, 0, 0, 0, 0, 0, 0, 0), 3).unwrap(); + + let mut ndp_opts = Vec::new(); + let mut prefs = Vec::new(); + + for prefix in linkaddrs::ipv6_addresses(link.to_owned())? + .into_iter() + .filter(|addr| global.contains(addr)) + { + let mut prefix_data = [ + 64, // Prefix Length, always /64 + 0xc0, // Flags: On-Link + SLAAC + 0, 0, 0x07, 0x08, // Valid Lifetime: 1800s + 0, 0, 0x05, 0xdc, // Preferred Lifetime: 1500s + 0, 0, 0, 0, // Reserved + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Prefix (inserted later) + ]; + prefix_data[14..].copy_from_slice(&prefix.trunc().addr().octets()); + + prefs.push(prefix); + + ndp_opts.push(NdpOption { + option_type: NdpOptionType::new(3), + length: 4, + data: prefix_data.to_vec(), + }); + } let adv = RouterAdvert { icmpv6_type: Icmpv6Type::new(134), @@ -49,33 +126,32 @@ fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> io::Result<()> { lifetime: 1800, reachable_time: 0, retrans_time: 0, - options: vec![ - NdpOption { - option_type: NdpOptionType::new(3), - length: 4, - data: vec![ - 64, 0b11000000, 0, 0, 0, 30, 0, 0, 0, 20, 0, 0, 0, 0, 0x20, 0x01, 0xab, 0xab, - 0xab, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - }, - /*NdpOption { - option_type: NdpOptionType::new(25), - length: 3, - data: vec![ - 0, 0, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, - ], - },*/ - ], + options: ndp_opts.clone(), + /*NdpOption { + option_type: NdpOptionType::new(25), + length: 3, + data: vec![ + 0, 0, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, + ], + },*/ payload: vec![], }; - let mut buf = [0; 16 + 32]; + let mut buf = Vec::new(); + buf.resize(16 + (32 * ndp_opts.len()), 0); + let mut pkt = MutableRouterAdvertPacket::new(&mut buf).unwrap(); pkt.populate(&adv); sock.send_to(&buf, &all_nodes)?; - println!("[radvd] send multicast nd-ra ::/64 on {}", link); + let prefixes = prefs + .into_iter() + .map(|prefix| format!("{}", prefix)) + .reduce(|acc, prefix| acc + &prefix) + .unwrap_or(String::from("::/64")); + + println!("[radvd] send multicast nd-ra {} on {}", prefixes, link); Ok(()) } |