mirror of
https://github.com/telemt/telemt.git
synced 2026-10-30 12:30:34 +03:00
WEB Carriers Safe-matrix Refactored
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
use hyper::Request;
|
||||
use hyper::header;
|
||||
use ipnetwork::IpNetwork;
|
||||
|
||||
use crate::config::WebClientIpSource;
|
||||
|
||||
/// Parses one lowercase canonical Host value restricted to the public HTTPS port.
|
||||
pub(in crate::web::http) fn canonical_request_host<B>(request: &Request<B>) -> Option<&str> {
|
||||
let values = request.headers().get_all(header::HOST);
|
||||
let mut values = values.iter();
|
||||
let value = values.next()?.to_str().ok()?;
|
||||
if values.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
let authority = value.parse::<hyper::http::uri::Authority>().ok()?;
|
||||
if authority.port_u16().is_some_and(|port| port != 443) {
|
||||
return None;
|
||||
}
|
||||
let host = value.strip_suffix(":443").unwrap_or(value);
|
||||
if authority.host() != host || host.bytes().any(|byte| byte.is_ascii_uppercase()) {
|
||||
return None;
|
||||
}
|
||||
Some(host)
|
||||
}
|
||||
|
||||
/// Accepts one forwarded client address or the direct address of a trusted peer.
|
||||
pub(in crate::web::http) fn client_ip<B>(
|
||||
request: &Request<B>,
|
||||
peer: SocketAddr,
|
||||
source: WebClientIpSource,
|
||||
trusted_proxy_cidrs: &[IpNetwork],
|
||||
) -> Option<IpAddr> {
|
||||
if !trusted_proxy_cidrs
|
||||
.iter()
|
||||
.any(|network| network.contains(peer.ip()))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let header_name = match source {
|
||||
WebClientIpSource::XForwardedFor => "x-forwarded-for",
|
||||
};
|
||||
let values = request.headers().get_all(header_name);
|
||||
let mut values = values.iter();
|
||||
let Some(value) = values.next() else {
|
||||
return Some(peer.ip());
|
||||
};
|
||||
let value = value.to_str().ok()?;
|
||||
if values.next().is_some() || value.trim() != value || value.contains(',') {
|
||||
return None;
|
||||
}
|
||||
if value.is_empty() {
|
||||
return Some(peer.ip());
|
||||
}
|
||||
value.parse::<IpAddr>().ok()
|
||||
}
|
||||
|
||||
/// Allows IP learning only for one explicit globally routable forwarded address.
|
||||
pub(in crate::web::http) fn carrier_ip_learning_eligible<B>(
|
||||
request: &Request<B>,
|
||||
effective_ip: IpAddr,
|
||||
) -> bool {
|
||||
let mut values = request.headers().get_all("x-forwarded-for").iter();
|
||||
let Some(value) = values.next().and_then(|value| value.to_str().ok()) else {
|
||||
return false;
|
||||
};
|
||||
if values.next().is_some()
|
||||
|| value.trim() != value
|
||||
|| value.contains(',')
|
||||
|| value.parse::<IpAddr>().ok() != Some(effective_ip)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
globally_routable(effective_ip)
|
||||
}
|
||||
|
||||
fn globally_routable(address: IpAddr) -> bool {
|
||||
match address {
|
||||
IpAddr::V4(address) => globally_routable_v4(address),
|
||||
IpAddr::V6(address) => {
|
||||
if let Some(address) = address.to_ipv4_mapped() {
|
||||
return globally_routable_v4(address);
|
||||
}
|
||||
let segments = address.segments();
|
||||
!address.is_unspecified()
|
||||
&& !address.is_loopback()
|
||||
&& segments[0] & 0xfe00 != 0xfc00
|
||||
&& segments[0] & 0xffc0 != 0xfe80
|
||||
&& segments[0] & 0xff00 != 0xff00
|
||||
&& !(segments[0] == 0x2001 && segments[1] == 0x0db8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn globally_routable_v4(address: std::net::Ipv4Addr) -> bool {
|
||||
let [a, b, c, _] = address.octets();
|
||||
!(a == 0
|
||||
|| a == 10
|
||||
|| a == 127
|
||||
|| (a == 100 && (64..=127).contains(&b))
|
||||
|| (a == 169 && b == 254)
|
||||
|| (a == 172 && (16..=31).contains(&b))
|
||||
|| (a == 192 && b == 0 && c == 0)
|
||||
|| (a == 192 && b == 0 && c == 2)
|
||||
|| (a == 192 && b == 168)
|
||||
|| (a == 198 && (b == 18 || b == 19))
|
||||
|| (a == 198 && b == 51 && c == 100)
|
||||
|| (a == 203 && b == 0 && c == 113)
|
||||
|| a >= 224)
|
||||
}
|
||||
Reference in New Issue
Block a user