"global" ACLs config option, block room directory requests to forbidden servers

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-04-15 22:02:08 -04:00 committed by June
parent 47c43769d7
commit 97c63604fd
6 changed files with 284 additions and 2 deletions

View file

@ -214,6 +214,15 @@ registration_token = "change this token for something specific to your server"
# No default. # No default.
# forbidden_alias_names = [] # forbidden_alias_names = []
# List of forbidden server names that we will block all client room joins, incoming federated room directory requests, incoming federated invites for, and incoming federated joins. This check is applied on the room ID, room alias, sender server name, and sender user's server name.
# Basically "global" ACLs. For our user (client) checks, admin users are allowed.
# No default.
# forbidden_remote_server_names = []
# List of forbidden server names that we will block all outgoing federated room directory requests for. Useful for preventing our users from wandering into bad servers or spaces.
# No default.
# forbidden_remote_room_directory_server_names = []
# Set this to true to allow your server's public room directory to be federated. # Set this to true to allow your server's public room directory to be federated.
# Set this to false to protect against /publicRooms spiders, but will forbid external users # Set this to false to protect against /publicRooms spiders, but will forbid external users
# from viewing your server's public room directory. If federation is disabled entirely # from viewing your server's public room directory. If federation is disabled entirely

View file

@ -34,6 +34,19 @@ use crate::{services, Error, Result, Ruma};
pub async fn get_public_rooms_filtered_route( pub async fn get_public_rooms_filtered_route(
body: Ruma<get_public_rooms_filtered::v3::Request>, body: Ruma<get_public_rooms_filtered::v3::Request>,
) -> Result<get_public_rooms_filtered::v3::Response> { ) -> Result<get_public_rooms_filtered::v3::Response> {
if let Some(server) = &body.server {
if services()
.globals
.forbidden_remote_room_directory_server_names()
.contains(server)
{
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
let response = get_public_rooms_filtered_helper( let response = get_public_rooms_filtered_helper(
body.server.as_deref(), body.server.as_deref(),
body.limit, body.limit,
@ -58,6 +71,19 @@ pub async fn get_public_rooms_filtered_route(
pub async fn get_public_rooms_route( pub async fn get_public_rooms_route(
body: Ruma<get_public_rooms::v3::Request>, body: Ruma<get_public_rooms::v3::Request>,
) -> Result<get_public_rooms::v3::Response> { ) -> Result<get_public_rooms::v3::Response> {
if let Some(server) = &body.server {
if services()
.globals
.forbidden_remote_room_directory_server_names()
.contains(server)
{
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
let response = get_public_rooms_filtered_helper( let response = get_public_rooms_filtered_helper(
body.server.as_deref(), body.server.as_deref(),
body.limit, body.limit,

View file

@ -55,6 +55,26 @@ pub async fn join_room_by_id_route(body: Ruma<join_room_by_id::v3::Request>) ->
)); ));
} }
if let Some(server) = body.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
&& !services().users.is_admin(sender_user)?
{
warn!(
"User {sender_user} tried joining room ID {} which has a server name that is globally forbidden. \
Rejecting.",
body.room_id
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"This remote server is banned on this homeserver.",
));
}
}
// There is no body.server_name for /roomId/join // There is no body.server_name for /roomId/join
let mut servers = services() let mut servers = services()
.rooms .rooms
@ -112,6 +132,25 @@ pub async fn join_room_by_id_or_alias_route(
)); ));
} }
if let Some(server) = room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
&& !services().users.is_admin(sender_user)?
{
warn!(
"User {sender_user} tried joining room ID {room_id} which has a server name that is globally \
forbidden. Rejecting.",
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"This remote server is banned on this homeserver.",
));
}
}
let mut servers = body.server_name.clone(); let mut servers = body.server_name.clone();
servers.extend( servers.extend(
@ -136,13 +175,13 @@ pub async fn join_room_by_id_or_alias_route(
); );
if let Some(server) = room_id.server_name() { if let Some(server) = room_id.server_name() {
servers.push(server.into()); servers.push(server.to_owned());
} }
(servers, room_id) (servers, room_id)
}, },
Err(room_alias) => { Err(room_alias) => {
let response = get_alias_helper(room_alias).await?; let response = get_alias_helper(room_alias.clone()).await?;
if services().rooms.metadata.is_banned(&response.room_id)? && !services().users.is_admin(sender_user)? { if services().rooms.metadata.is_banned(&response.room_id)? && !services().users.is_admin(sender_user)? {
return Err(Error::BadRequest( return Err(Error::BadRequest(
@ -151,6 +190,44 @@ pub async fn join_room_by_id_or_alias_route(
)); ));
} }
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&room_alias.server_name().to_owned())
&& !services().users.is_admin(sender_user)?
{
warn!(
"User {sender_user} tried joining room alias {} with room ID {} which has a server name that is \
globally forbidden. Rejecting.",
&room_alias, &response.room_id
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"This remote server is banned on this homeserver.",
));
}
if let Some(server) = response.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
&& !services().users.is_admin(sender_user)?
{
warn!(
"User {sender_user} tried joining room alias {} with room ID {} which has a server name that \
is globally forbidden. Rejecting.",
&room_alias, &response.room_id
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"This remote server is banned on this homeserver.",
));
}
}
(response.servers, response.room_id) (response.servers, response.room_id)
}, },
}; };
@ -210,6 +287,20 @@ pub async fn invite_user_route(body: Ruma<invite_user::v3::Request>) -> Result<i
)); ));
} }
if let Some(server) = body.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
{
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
if let invite_user::v3::InvitationRecipient::UserId { if let invite_user::v3::InvitationRecipient::UserId {
user_id, user_id,
} = &body.recipient } = &body.recipient

View file

@ -908,6 +908,37 @@ pub async fn create_join_event_template_route(
.event_handler .event_handler
.acl_check(sender_servername, &body.room_id)?; .acl_check(sender_servername, &body.room_id)?;
if services()
.globals
.config
.forbidden_remote_server_names
.contains(sender_servername)
{
warn!(
"Server {sender_servername} for remote user {} tried joining room ID {} which has a server name that is \
globally forbidden. Rejecting.",
&body.user_id, &body.room_id,
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
if let Some(server) = body.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
{
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
let mutex_state = Arc::clone( let mutex_state = Arc::clone(
services() services()
.globals .globals
@ -1201,6 +1232,42 @@ pub async fn create_join_event_v1_route(
.as_ref() .as_ref()
.expect("server is authenticated"); .expect("server is authenticated");
if services()
.globals
.config
.forbidden_remote_server_names
.contains(sender_servername)
{
warn!(
"Server {sender_servername} tried joining room ID {} who has a server name that is globally forbidden. \
Rejecting.",
&body.room_id,
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
if let Some(server) = body.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
{
warn!(
"Server {sender_servername} tried joining room ID {} which has a server name that is globally \
forbidden. Rejecting.",
&body.room_id,
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
let room_state = create_join_event(sender_servername, &body.room_id, &body.pdu).await?; let room_state = create_join_event(sender_servername, &body.room_id, &body.pdu).await?;
Ok(create_join_event::v1::Response { Ok(create_join_event::v1::Response {
@ -1219,6 +1286,37 @@ pub async fn create_join_event_v2_route(
.as_ref() .as_ref()
.expect("server is authenticated"); .expect("server is authenticated");
if services()
.globals
.config
.forbidden_remote_server_names
.contains(sender_servername)
{
warn!(
"Server {sender_servername} tried joining room ID {} who has a server name that is globally forbidden. \
Rejecting.",
&body.room_id,
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
if let Some(server) = body.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
{
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
let create_join_event::v1::RoomState { let create_join_event::v1::RoomState {
auth_chain, auth_chain,
state, state,
@ -1448,6 +1546,40 @@ pub async fn create_invite_route(body: Ruma<create_invite::v2::Request>) -> Resu
)); ));
} }
if let Some(server) = body.room_id.server_name() {
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&server.to_owned())
{
warn!(
"Received federated/remote invite from banned server {sender_servername} for room ID {}. Rejecting.",
body.room_id
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
}
if services()
.globals
.config
.forbidden_remote_server_names
.contains(&sender_servername.to_owned())
{
warn!(
"Received federated/remote invite from banned server {sender_servername} for room ID {}. Rejecting.",
body.room_id
);
return Err(Error::BadRequest(
ErrorKind::forbidden(),
"Server is banned on this homeserver.",
));
}
if let Some(via) = &body.via { if let Some(via) = &body.via {
if via.is_empty() { if via.is_empty() {
return Err(Error::BadRequest(ErrorKind::InvalidParam, "via field must not be empty.")); return Err(Error::BadRequest(ErrorKind::InvalidParam, "via field must not be empty."));

View file

@ -269,6 +269,10 @@ pub struct Config {
#[serde(default = "Vec::new")] #[serde(default = "Vec::new")]
pub prevent_media_downloads_from: Vec<OwnedServerName>, pub prevent_media_downloads_from: Vec<OwnedServerName>,
#[serde(default = "Vec::new")]
pub forbidden_remote_server_names: Vec<OwnedServerName>,
#[serde(default = "Vec::new")]
pub forbidden_remote_room_directory_server_names: Vec<OwnedServerName>,
#[serde(default = "default_ip_range_denylist")] #[serde(default = "default_ip_range_denylist")]
pub ip_range_denylist: Vec<String>, pub ip_range_denylist: Vec<String>,
@ -689,6 +693,20 @@ impl fmt::Display for Config {
} }
&lst.join(", ") &lst.join(", ")
}), }),
("Forbidden Remote Server Names (\"Global\" ACLs)", {
let mut lst = vec![];
for domain in &self.forbidden_remote_server_names {
lst.push(domain.host());
}
&lst.join(", ")
}),
("Forbidden Remote Room Directory Server Names", {
let mut lst = vec![];
for domain in &self.forbidden_remote_room_directory_server_names {
lst.push(domain.host());
}
&lst.join(", ")
}),
("Outbound Request IP Range Denylist", { ("Outbound Request IP Range Denylist", {
let mut lst = vec![]; let mut lst = vec![];
for item in self.ip_range_denylist.iter().cloned().enumerate() { for item in self.ip_range_denylist.iter().cloned().enumerate() {

View file

@ -323,6 +323,12 @@ impl Service<'_> {
pub fn prevent_media_downloads_from(&self) -> &[OwnedServerName] { &self.config.prevent_media_downloads_from } pub fn prevent_media_downloads_from(&self) -> &[OwnedServerName] { &self.config.prevent_media_downloads_from }
pub fn forbidden_remote_server_names(&self) -> &[OwnedServerName] { &self.config.forbidden_remote_server_names }
pub fn forbidden_remote_room_directory_server_names(&self) -> &[OwnedServerName] {
&self.config.forbidden_remote_room_directory_server_names
}
pub fn ip_range_denylist(&self) -> &[String] { &self.config.ip_range_denylist } pub fn ip_range_denylist(&self) -> &[String] { &self.config.ip_range_denylist }
pub fn well_known_support_page(&self) -> &Option<Url> { &self.config.well_known.support_page } pub fn well_known_support_page(&self) -> &Option<Url> { &self.config.well_known.support_page }