mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
Expose canonical for reuse in the /api/open check
This commit is contained in:
parent
32cc041e96
commit
7db1d04562
2 changed files with 19 additions and 3 deletions
|
|
@ -21,6 +21,7 @@ use crate::{
|
|||
ServerInfoResponse, SocketPacket, SocketPacketBody, SocketPacketType, SubscribeMessage,
|
||||
WriteRequest, WriteResponse, PROTOCOL_VERSION, SERVER_VERSION,
|
||||
},
|
||||
origin::canonical,
|
||||
util::{deserialize_msgpack, msgpack, msgpack_ok, serialize_msgpack},
|
||||
},
|
||||
web_api::{
|
||||
|
|
@ -369,7 +370,11 @@ impl ApiService {
|
|||
// trusted, and reachability is bounded by that hop's own authentication
|
||||
// (e.g. SSH keys or Tailscale ACLs). This gate only stops direct,
|
||||
// unauthenticated peers.
|
||||
if !self.remote_addr.ip().is_loopback() {
|
||||
//
|
||||
// An IPv4 client reaching a dual-stack (`::`) bind appears as an
|
||||
// IPv4-mapped IPv6 peer (`::ffff:127.0.0.1`), so canonicalize to the bare
|
||||
// IPv4 form before the loopback test, matching `origin`'s handling.
|
||||
if !canonical(self.remote_addr.ip()).is_loopback() {
|
||||
return msgpack(
|
||||
ErrorResponse::forbidden("/api/open is only available to local clients"),
|
||||
StatusCode::FORBIDDEN,
|
||||
|
|
|
|||
|
|
@ -139,8 +139,9 @@ pub fn allowed_hosts(bind: IpAddr, port: u16, extra: &[String]) -> Option<Allowe
|
|||
}
|
||||
|
||||
/// Collapses an IPv4-mapped IPv6 address (`::ffff:192.168.0.1`) to its IPv4 form
|
||||
/// so it classifies and compares consistently with the bare IPv4 address.
|
||||
fn canonical(ip: IpAddr) -> IpAddr {
|
||||
/// so it classifies and compares consistently with the bare IPv4 address. Shared
|
||||
/// with the `/api/open` peer check so it recognizes a mapped loopback peer too.
|
||||
pub(crate) fn canonical(ip: IpAddr) -> IpAddr {
|
||||
match ip {
|
||||
IpAddr::V6(v6) => v6.to_ipv4_mapped().map(IpAddr::V4).unwrap_or(ip),
|
||||
v4 => v4,
|
||||
|
|
@ -474,6 +475,16 @@ mod test {
|
|||
assert!(check_request_origin(&request, allowed.as_ref()).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonical_collapses_ipv4_mapped_loopback() {
|
||||
// The `/api/open` peer gate relies on this: an IPv4 loopback client
|
||||
// reaching a dual-stack (`::`) bind arrives as `::ffff:127.0.0.1`, which
|
||||
// is only recognized as loopback after canonicalization.
|
||||
let mapped: IpAddr = "::ffff:127.0.0.1".parse().unwrap();
|
||||
assert!(!mapped.is_loopback());
|
||||
assert!(canonical(mapped).is_loopback());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_host_strips_brackets_and_zone_id() {
|
||||
// Brackets and an IPv6 zone id must be removed so the result parses as an
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue