diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-10-14 12:59:34 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2023-10-14 12:59:34 +0200 |
commit | 581daea52fac3a88883cb3b18801600920db90e5 (patch) | |
tree | 3b9838e6572861f4079fc0962e3c5604d7f8ceef | |
parent | 3ce62ec3ac9cfc88fc7ad85f495b2026619c1ff5 (diff) |
send unicast replies to router solicitations
-rw-r--r-- | src/main.rs | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/src/main.rs b/src/main.rs index 593a199..f5188c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -use std::io::{self, Read}; +use std::io; +use std::mem::MaybeUninit; use std::net::{Ipv6Addr, SocketAddrV6}; use std::thread; use std::time::Duration; @@ -7,11 +8,14 @@ use ipnet::Ipv6Net; use pnet_packet::icmpv6::ndp::{MutableRouterAdvertPacket, NdpOption, NdpOptionType, RouterAdvert}; use pnet_packet::icmpv6::{Icmpv6Code, Icmpv6Type}; use rsdsl_netlinkd::link; -use socket2::{Domain, Protocol, Socket, Type}; +use socket2::{Domain, Protocol, SockAddr, Socket, Type}; use thiserror::Error; #[derive(Debug, Error)] enum Error { + #[error("sockaddr is not an ipv6 address")] + SockAddrNotIpv6, + #[error("io: {0}")] Io(#[from] io::Error), @@ -54,7 +58,7 @@ fn run(link: String) -> Result<()> { let ifi = link::index(link.clone())?; - let mut sock = Socket::new(Domain::IPV6, Type::RAW, Some(Protocol::ICMPV6))?; + let sock = Socket::new(Domain::IPV6, Type::RAW, Some(Protocol::ICMPV6))?; sock.join_multicast_v6(&Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 2), ifi)?; sock.set_multicast_hops_v6(255)?; @@ -64,7 +68,7 @@ fn run(link: String) -> Result<()> { let sock2 = sock.try_clone()?; let link2 = link.clone(); thread::spawn(move || loop { - match send_ra_multicast(&sock2, &link2, ifi) { + match send_ra_multicast(&sock2, link2.clone(), ifi) { Ok(_) => {} Err(e) => println!("[warn] multicast ra {}: {}", link2, e), } @@ -72,25 +76,33 @@ fn run(link: String) -> Result<()> { thread::sleep(Duration::from_secs(1200)); }); - let mut buf = [0; 1500]; loop { - let n = sock.read(&mut buf)?; + let mut buf = [MaybeUninit::new(0); 1500]; + let (n, raddr) = sock.recv_from(&mut buf)?; + + // See unstable `MaybeUninit::slice_assume_init_ref`. + let buf = unsafe { &*(&buf as *const [MaybeUninit<u8>] as *const [u8]) }; + let buf = &buf[..n]; // Router Solicitation if buf[0] == 133 { println!("[info] recv rs {}", link); - match send_ra_multicast(&sock, &link, ifi) { + match send_ra_unicast(&sock, link.clone(), &raddr) { Ok(_) => {} - Err(e) => println!("[warn] multicast ra {}: {}", link, e), + Err(e) => println!( + "[warn] unicast ra {} to {}: {}", + link, + raddr.as_socket_ipv6().ok_or(Error::SockAddrNotIpv6)?.ip(), + e + ), } } } } -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(); +fn create_ra_pkt(link: String) -> Result<(Vec<u8>, Vec<Ipv6Net>)> { let global = Ipv6Net::new(Ipv6Addr::new(0x2000, 0, 0, 0, 0, 0, 0, 0), 3).unwrap(); let mut rdnss_data = [ @@ -105,9 +117,9 @@ fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> Result<()> { length: 3, data: rdnss_data.to_vec(), }]; - let mut prefs = Vec::new(); + let mut prefixes = Vec::new(); - for prefix in linkaddrs::ipv6_addresses(link.to_owned())? + for prefix in linkaddrs::ipv6_addresses(link)? .into_iter() .filter(|addr| global.contains(addr)) { @@ -121,7 +133,7 @@ fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> Result<()> { ]; prefix_data[14..].copy_from_slice(&prefix.trunc().addr().octets()); - prefs.push(prefix); + prefixes.push(prefix); ndp_opts.push(NdpOption { option_type: NdpOptionType::new(3), @@ -149,9 +161,16 @@ fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> Result<()> { let mut pkt = MutableRouterAdvertPacket::new(&mut buf).unwrap(); pkt.populate(&adv); - sock.send_to(&buf, &all_nodes)?; + Ok((buf, prefixes)) +} - let prefixes = prefs +fn send_ra_multicast(sock: &Socket, link: String, ifi: u32) -> Result<()> { + let all_nodes = SocketAddrV6::new(Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 1), 0, 0, ifi).into(); + + let (pkt, pkt_prefixes) = create_ra_pkt(link.clone())?; + sock.send_to(&pkt, &all_nodes)?; + + let prefixes = pkt_prefixes .into_iter() .map(|prefix| format!("{}", prefix)) .reduce(|acc, prefix| acc + ", " + &prefix) @@ -160,3 +179,22 @@ fn send_ra_multicast(sock: &Socket, link: &str, ifi: u32) -> Result<()> { println!("[info] multicast ra {} net {}", link, prefixes); Ok(()) } + +fn send_ra_unicast(sock: &Socket, link: String, raddr: &SockAddr) -> Result<()> { + let (pkt, pkt_prefixes) = create_ra_pkt(link.clone())?; + sock.send_to(&pkt, raddr)?; + + let prefixes = pkt_prefixes + .into_iter() + .map(|prefix| format!("{}", prefix)) + .reduce(|acc, prefix| acc + ", " + &prefix) + .unwrap_or(String::from("::/64")); + + println!( + "[info] unicast ra {} to {} net {}", + link, + raddr.as_socket_ipv6().ok_or(Error::SockAddrNotIpv6)?.ip(), + prefixes + ); + Ok(()) +} |