rwhod: implement packet sender if filtering
This commit is contained in:
@@ -36,6 +36,21 @@ in {
|
||||
description = "Path to the ignore list for users that should be hidden from rwhod.";
|
||||
};
|
||||
|
||||
interfaces = lib.mkOption {
|
||||
type = with lib.types; nullOr (list str);
|
||||
default = null;
|
||||
example = [ "eth0" "wlan0" ];
|
||||
description = ''
|
||||
List of network interfaces to broadcast rwhod packets on.
|
||||
|
||||
If set to `null`, rwhod will try to autodetect all reasonable interfaces
|
||||
to broadcast on, and use all of them.
|
||||
|
||||
If set to an empty list, rwhod will not broadcast on any interfaces,
|
||||
and will only listen for incoming packets.
|
||||
'';
|
||||
};
|
||||
|
||||
socketConfig = lib.mkOption {
|
||||
type = utils.systemdUtils.unitOptions.unitOption;
|
||||
default = { };
|
||||
|
||||
+5
-2
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
os::fd::{AsRawFd, FromRawFd, OwnedFd},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
@@ -104,6 +104,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
socket,
|
||||
whod_status_store.clone(),
|
||||
rwhod_ignore_list.clone(),
|
||||
config.rwhod.interfaces.clone(),
|
||||
));
|
||||
} else {
|
||||
tracing::debug!("RWHOD server is disabled in configuration");
|
||||
@@ -139,10 +140,12 @@ async fn rwhod_server(
|
||||
socket: UdpSocket,
|
||||
whod_status_store: RwhodStatusStore,
|
||||
ignore_list: Option<IgnoreList>,
|
||||
allowed_interfaces: Option<HashSet<String>>,
|
||||
) -> anyhow::Result<()> {
|
||||
let socket = Arc::new(socket);
|
||||
|
||||
let interfaces = roowho2_lib::server::rwhod::determine_relevant_interfaces()?;
|
||||
let interfaces =
|
||||
roowho2_lib::server::rwhod::determine_relevant_interfaces(allowed_interfaces.as_ref())?;
|
||||
let sender_task = rwhod_packet_sender_task(socket.clone(), interfaces, ignore_list);
|
||||
let receiver_task = rwhod_packet_receiver_task(socket.clone(), whod_status_store);
|
||||
|
||||
|
||||
+4
-11
@@ -1,4 +1,4 @@
|
||||
use std::{net::SocketAddrV4, path::PathBuf};
|
||||
use std::{collections::HashSet, path::PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -39,17 +39,10 @@ pub struct RwhodConfig {
|
||||
/// Path to the ignore list for users that should be hidden from rwhod.
|
||||
pub ignore_list_path: Option<PathBuf>,
|
||||
|
||||
/// Network interfaces to listen on (e.g., ["eth0", "wlan0"]).
|
||||
/// Network interfaces to send rwhod packets on (e.g., ["eth0", "wlan0"]).
|
||||
///
|
||||
/// If left as `None`, the server will automatically determine relevant interfaces.
|
||||
///
|
||||
/// Note that if `broadcast_addresses` is specified, this field is ignored.
|
||||
pub interfaces: Option<Vec<String>>,
|
||||
|
||||
/// Broadcast addresses to send rwhod packets to.
|
||||
///
|
||||
/// If left as `None`, the server will automatically determine broadcast addresses for the selected interfaces.
|
||||
pub broadcast_addresses: Option<Vec<SocketAddrV4>>,
|
||||
/// If left as `None`, the server will send on all relevant interfaces it can find.
|
||||
pub interfaces: Option<HashSet<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
||||
@@ -29,7 +29,12 @@ pub struct RwhodSendTarget {
|
||||
}
|
||||
|
||||
/// Find all networks network interfaces suitable for rwhod communication.
|
||||
pub fn determine_relevant_interfaces() -> anyhow::Result<Vec<RwhodSendTarget>> {
|
||||
///
|
||||
/// If `allowed_interfaces` is `Some`, only interfaces whose name is contained
|
||||
/// in it are considered; otherwise all suitable interfaces are returned.
|
||||
pub fn determine_relevant_interfaces(
|
||||
allowed_interfaces: Option<&HashSet<String>>,
|
||||
) -> anyhow::Result<Vec<RwhodSendTarget>> {
|
||||
getifaddrs().map_err(|e| e.into()).map(|ifaces| {
|
||||
ifaces
|
||||
// interface must be up
|
||||
@@ -40,6 +45,11 @@ pub fn determine_relevant_interfaces() -> anyhow::Result<Vec<RwhodSendTarget>> {
|
||||
.flags
|
||||
.intersects(InterfaceFlags::IFF_BROADCAST | InterfaceFlags::IFF_POINTOPOINT)
|
||||
})
|
||||
// interface must be in the configured allowlist, if any
|
||||
.filter(|iface| {
|
||||
allowed_interfaces
|
||||
.is_none_or(|allowed| allowed.contains(iface.interface_name.as_str()))
|
||||
})
|
||||
.filter_map(|iface| {
|
||||
let neighbor_addr = if iface.flags.contains(InterfaceFlags::IFF_BROADCAST) {
|
||||
iface.broadcast
|
||||
@@ -137,9 +147,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_determine_relevant_interfaces() {
|
||||
let interfaces = determine_relevant_interfaces().unwrap();
|
||||
let interfaces = determine_relevant_interfaces(None).unwrap();
|
||||
for interface in interfaces {
|
||||
println!("Interface: {} Address: {}", interface.name, interface.addr);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_determine_relevant_interfaces_with_allowlist_excludes_unlisted() {
|
||||
let allowed = HashSet::from(["definitely-not-a-real-interface".to_string()]);
|
||||
let interfaces = determine_relevant_interfaces(Some(&allowed)).unwrap();
|
||||
assert!(interfaces.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user