mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 04:01:58 +00:00
fix: treat all private IPs as private traffic, not just same-subnet
Previously, traffic was only classified as private if the source IP was in a known interface subnet. This prevented private access from VPNs on different VLANs. Now all RFC 1918 IPv4 and ULA/link-local IPv6 addresses are treated as private, and DNS resolution for private domains works for these sources by returning IPs from all interfaces.
This commit is contained in:
@@ -32,6 +32,7 @@ use crate::context::{CliContext, RpcContext};
|
|||||||
use crate::db::model::Database;
|
use crate::db::model::Database;
|
||||||
use crate::db::model::public::NetworkInterfaceInfo;
|
use crate::db::model::public::NetworkInterfaceInfo;
|
||||||
use crate::net::gateway::NetworkInterfaceWatcher;
|
use crate::net::gateway::NetworkInterfaceWatcher;
|
||||||
|
use crate::net::utils::is_private_ip;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::util::future::NonDetachingJoinHandle;
|
use crate::util::future::NonDetachingJoinHandle;
|
||||||
use crate::util::io::file_string_stream;
|
use crate::util::io::file_string_stream;
|
||||||
@@ -400,6 +401,18 @@ impl Resolver {
|
|||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
return Some(res);
|
return Some(res);
|
||||||
|
} else if is_private_ip(src) {
|
||||||
|
// Source is a private IP not in any known subnet (e.g. VPN on a different VLAN).
|
||||||
|
// Return all private IPs from all interfaces.
|
||||||
|
let res: Vec<IpAddr> = self.net_iface.peek(|i| {
|
||||||
|
i.values()
|
||||||
|
.filter_map(|i| i.ip_info.as_ref())
|
||||||
|
.flat_map(|ip_info| ip_info.subnets.iter().map(|s| s.addr()))
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
if !res.is_empty() {
|
||||||
|
return Some(res);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"{}",
|
"{}",
|
||||||
|
|||||||
@@ -66,6 +66,13 @@ pub fn ipv6_is_local(addr: Ipv6Addr) -> bool {
|
|||||||
addr.is_loopback() || (addr.segments()[0] & 0xfe00) == 0xfc00 || ipv6_is_link_local(addr)
|
addr.is_loopback() || (addr.segments()[0] & 0xfe00) == 0xfc00 || ipv6_is_link_local(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_private_ip(addr: IpAddr) -> bool {
|
||||||
|
match addr {
|
||||||
|
IpAddr::V4(v4) => v4.is_private() || v4.is_loopback() || v4.is_link_local(),
|
||||||
|
IpAddr::V6(v6) => ipv6_is_local(v6),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_iface_ip(output: &str) -> Result<Vec<&str>, Error> {
|
fn parse_iface_ip(output: &str) -> Result<Vec<&str>, Error> {
|
||||||
let output = output.trim();
|
let output = output.trim();
|
||||||
if output.is_empty() {
|
if output.is_empty() {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ use crate::net::ssl::{CertStore, RootCaTlsHandler};
|
|||||||
use crate::net::tls::{
|
use crate::net::tls::{
|
||||||
ChainedHandler, TlsHandlerAction, TlsHandlerWrapper, TlsListener, TlsMetadata, WrapTlsHandler,
|
ChainedHandler, TlsHandlerAction, TlsHandlerWrapper, TlsListener, TlsMetadata, WrapTlsHandler,
|
||||||
};
|
};
|
||||||
use crate::net::utils::ipv6_is_link_local;
|
use crate::net::utils::{ipv6_is_link_local, is_private_ip};
|
||||||
use crate::net::web_server::{Accept, AcceptStream, ExtractVisitor, TcpMetadata, extract};
|
use crate::net::web_server::{Accept, AcceptStream, ExtractVisitor, TcpMetadata, extract};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::util::collections::EqSet;
|
use crate::util::collections::EqSet;
|
||||||
@@ -732,8 +732,9 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let src = tcp.peer_addr.ip();
|
let src = tcp.peer_addr.ip();
|
||||||
// Public: source is outside all known subnets (direct internet)
|
// Private: source is in a known subnet or is a private IP (e.g. VPN on a different VLAN)
|
||||||
let is_public = !ip_info.subnets.iter().any(|s| s.contains(&src));
|
let is_public =
|
||||||
|
!ip_info.subnets.iter().any(|s| s.contains(&src)) && !is_private_ip(src);
|
||||||
|
|
||||||
if is_public {
|
if is_public {
|
||||||
self.public.contains(&gw.id)
|
self.public.contains(&gw.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user