From c856ab990011d3c6efe1b0551a1d8859045e547b Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Wed, 29 Jan 2025 22:13:14 +0100 Subject: [PATCH] Redo safety checks for instance_info Using the `ip` feature, and some clever use of `Url::set_host` and `Url::host_str` --- src/api/instance_info.rs | 28 +++++++++++++++++++++------- src/main.rs | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/api/instance_info.rs b/src/api/instance_info.rs index a670d0a..276e947 100644 --- a/src/api/instance_info.rs +++ b/src/api/instance_info.rs @@ -1,3 +1,5 @@ +use std::net::ToSocketAddrs; + use rocket::serde::json::Json; use serde::{Deserialize, Serialize}; use url::Url; @@ -79,16 +81,28 @@ async fn get_info_from_manifest(url: Url) -> Option<[Option; 3]> { #[get("/instance_info//")] pub async fn instance_info(secure: bool, host: &str) -> Option> { - let mut url = Url::parse(&format!( - "http{}://{host}/manifest.json", - if secure { "s" } else { "" } - )) + let mut url = Url::parse(if secure { + "https://temp.host/manifest.json" + } else { + "http://temp.host/manifest.json" + }) .ok()?; - // I'm not sure if you can sneak in a path, but better safe than sorry - // I don't really care about username/password/port, those are fine - if url.path() != "/manifest.json" { + url.set_host(Some(host)).ok()?; // Using this to catch malformed hosts + let host = url.host_str()?; // Shadow the original host in case things were filtered out + + // Check if the host is globally routable. + // This should help filter out a bunch of invalid or potentially malicious requests + let host_with_port = format!("{host}:{}", url.port_or_known_default()?); + if !host_with_port + .to_socket_addrs() + .ok()? + .next()? + .ip() + .is_global() + { return None; } + let [name, short_name, icon_url] = get_info_from_manifest(url.clone()) .await .unwrap_or_default(); diff --git a/src/main.rs b/src/main.rs index 3ef9570..c12ec48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![feature(ip)] #[macro_use] extern crate rocket;