diff --git a/CHANGELOG.md b/CHANGELOG.md index 988dcab..11a5ee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 for instance when using `traceroute`. - Check the local seqno request cache before sending a seqno request to a peer, to avoid spamming in certain occasions. +- Don't accept packet for a destination if we only have fallback routes for said + destination. ## [0.6.0] - 2025-04-25 diff --git a/mycelium/src/data.rs b/mycelium/src/data.rs index 015e974..21ec08e 100644 --- a/mycelium/src/data.rs +++ b/mycelium/src/data.rs @@ -274,7 +274,7 @@ where } // Get shared secret from node and dest address - let shared_secret = match self.router.get_shared_secret_from_dest(dst_ip.into()) { + let shared_secret = match self.router.get_shared_secret_if_selected(dst_ip.into()) { Some(ss) => ss, // If we don't have a route to the destination subnet, reply with ICMP no route to // host. Do this here as well to avoid encrypting the ICMP to ourselves. diff --git a/mycelium/src/router.rs b/mycelium/src/router.rs index a2e839c..06f3001 100644 --- a/mycelium/src/router.rs +++ b/mycelium/src/router.rs @@ -260,6 +260,52 @@ where } } + /// Get a [`SharedSecret`] for a remote, if a selected route exists to the remote. + // TODO: Naming + pub fn get_shared_secret_if_selected(&self, dest: IpAddr) -> Option { + // TODO: proper fix + match self.routing_table.best_routes(dest) { + Routes::Exist(routes) => { + if routes.selected().is_some() { + Some(routes.shared_secret().clone()) + } else { + // Optimistically try to fetch a new route for the subnet for next time. + // TODO: this can likely be handled better, but that relies on continuously + // quering routes in use, and handling unfeasible routes + if let Some(route_entry) = routes.iter().next() { + // We have a fallback route, use the source key from that to do a seqno + // request. Since the next hop might be dead, just do a broadcast. This + // might be blocked by the seqno request cache. + self.send_seqno_request(route_entry.source(), None, None); + } else { + // We don't have any routes, so send a route request. this might fail due + // to the source table. + self.send_route_request( + Subnet::new(dest, 64) + .expect("64 is a valid subnet size for an IPv6 address; qed"), + ); + } + + None + } + } + Routes::Queried => { + tokio::task::block_in_place(|| std::thread::sleep(QUERY_CHECK_DURATION)); + self.get_shared_secret_if_selected(dest) + } + Routes::NoRoute => None, + Routes::None => { + // NOTE: we request the full /64 subnet + self.send_route_request( + Subnet::new(dest, 64) + .expect("64 is a valid subnet size for an IPv6 address; qed"), + ); + tokio::task::block_in_place(|| std::thread::sleep(QUERY_CHECK_DURATION)); + self.get_shared_secret_if_selected(dest) + } + } + } + /// Gets the cached [`SharedSecret`] based on the associated [`PublicKey`] of the remote. #[inline] pub fn get_shared_secret_by_pubkey(&self, dest: &PublicKey) -> Option {