From 423fc6dad02b7e2be61582f246dc2276ad53def0 Mon Sep 17 00:00:00 2001
From: Jason Volk <jason@zemos.net>
Date: Sun, 21 Apr 2024 22:32:45 -0700
Subject: [PATCH] precompute cidr range denylist; move validator.

Signed-off-by: Jason Volk <jason@zemos.net>
---
 src/service/globals/mod.rs  | 22 +++++++++++++++++++++-
 src/service/sending/send.rs | 13 ++-----------
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs
index 874ba22ed..1aea4e32b 100644
--- a/src/service/globals/mod.rs
+++ b/src/service/globals/mod.rs
@@ -14,6 +14,7 @@
 use base64::{engine::general_purpose, Engine as _};
 pub use data::Data;
 use hickory_resolver::TokioAsyncResolver;
+use ipaddress::IPAddress;
 use regex::RegexSet;
 use ruma::{
 	api::{
@@ -25,7 +26,7 @@
 	RoomVersionId, ServerName, UserId,
 };
 use tokio::sync::{broadcast, watch::Receiver, Mutex, RwLock, Semaphore};
-use tracing::{error, info};
+use tracing::{error, info, trace};
 use tracing_subscriber::{EnvFilter, Registry};
 use url::Url;
 
@@ -46,6 +47,7 @@ pub struct Service<'a> {
 
 	pub tracing_reload_handle: tracing_subscriber::reload::Handle<EnvFilter, Registry>,
 	pub config: Config,
+	pub cidr_range_denylist: Vec<IPAddress>,
 	keypair: Arc<ruma::signatures::Ed25519KeyPair>,
 	jwt_decoding_key: Option<jsonwebtoken::DecodingKey>,
 	pub resolver: Arc<resolver::Resolver>,
@@ -138,10 +140,18 @@ pub fn load(
 			argon2::Params::new(19456, 2, 1, None).expect("valid parameters"),
 		);
 
+		let mut cidr_range_denylist = Vec::new();
+		for cidr in config.ip_range_denylist.clone() {
+			let cidr = IPAddress::parse(cidr).expect("valid cidr range");
+			trace!("Denied CIDR range: {:?}", cidr);
+			cidr_range_denylist.push(cidr);
+		}
+
 		let mut s = Self {
 			tracing_reload_handle,
 			db,
 			config: config.clone(),
+			cidr_range_denylist,
 			keypair: Arc::new(keypair),
 			resolver: resolver.clone(),
 			client: client::Client::new(config, &resolver),
@@ -424,6 +434,16 @@ pub fn well_known_server(&self) -> &Option<OwnedServerName> { &self.config.well_
 
 	pub fn unix_socket_path(&self) -> &Option<PathBuf> { &self.config.unix_socket_path }
 
+	pub fn valid_cidr_range(&self, ip: &IPAddress) -> bool {
+		for cidr in &self.cidr_range_denylist {
+			if cidr.includes(ip) {
+				return false;
+			}
+		}
+
+		true
+	}
+
 	pub fn shutdown(&self) {
 		self.shutdown.store(true, atomic::Ordering::Relaxed);
 		// On shutdown
diff --git a/src/service/sending/send.rs b/src/service/sending/send.rs
index 726ceffe3..d6bd36d2e 100644
--- a/src/service/sending/send.rs
+++ b/src/service/sending/send.rs
@@ -536,17 +536,8 @@ fn validate_destination_ip_literal(destination: &ServerName) -> Result<()> {
 }
 
 fn validate_ip(ip: &IPAddress) -> Result<()> {
-	let cidr_ranges_s = services().globals.ip_range_denylist().to_vec();
-	let mut cidr_ranges: Vec<IPAddress> = Vec::new();
-	for cidr in cidr_ranges_s {
-		cidr_ranges.push(IPAddress::parse(cidr).expect("we checked this at startup"));
-	}
-
-	trace!("List of pushed CIDR ranges: {:?}", cidr_ranges);
-	for cidr in cidr_ranges {
-		if cidr.includes(ip) {
-			return Err(Error::BadServerResponse("Not allowed to send requests to this IP"));
-		}
+	if !services().globals.valid_cidr_range(ip) {
+		return Err(Error::BadServerResponse("Not allowed to send requests to this IP"));
 	}
 
 	Ok(())
-- 
GitLab