Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions crates/sandlock-core/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ fn parse_port_from_sockaddr(bytes: &[u8]) -> Option<u16> {
}
}

fn set_port_in_sockaddr(bytes: &mut [u8], port: u16) {
if bytes.len() >= 4 {
let port_bytes = port.to_be_bytes();
bytes[2] = port_bytes[0];
bytes[3] = port_bytes[1];
}
}

// ============================================================
// query_socket_protocol — derive the rule Protocol from a fd via getsockopt
// ============================================================
Expand Down Expand Up @@ -144,7 +152,7 @@ async fn connect_on_behalf(
let dest_port = parse_port_from_sockaddr(&addr_bytes);
let dup_fd = match crate::seccomp::notif::dup_fd_from_pid(notif.pid, sockfd) {
Ok(fd) => fd,
Err(_) => return NotifAction::Errno(libc::ENOSYS),
Err(e) => return NotifAction::Errno(e.raw_os_error().unwrap_or(libc::EBADF)),
};
let protocol = match query_socket_protocol(dup_fd.as_raw_fd()) {
Some(p) => p,
Expand Down Expand Up @@ -179,14 +187,19 @@ async fn connect_on_behalf(
let http_acl_addr = ns.http_acl_addr;
let http_acl_intercept = dest_port.map_or(false, |p| ns.http_acl_ports.contains(&p));
let http_acl_orig_dest = ns.http_acl_orig_dest.clone();
let remapped_loopback_port = if ctx.policy.port_remap && ip.is_loopback() {
dest_port.and_then(|p| ns.port_map.get_real(p))
} else {
None
};

drop(ns);

// Determine the actual connect target (redirect HTTP/HTTPS to proxy)
let mut redirected = false;
let is_ipv6 = parse_ip_from_sockaddr(&addr_bytes)
.map_or(false, |ip| ip.is_ipv6());
let (connect_addr, connect_len) = if let Some(proxy_addr) = http_acl_addr {
let (mut connect_addr, connect_len) = if let Some(proxy_addr) = http_acl_addr {
if http_acl_intercept {
redirected = true;
if is_ipv6 {
Expand Down Expand Up @@ -240,6 +253,13 @@ async fn connect_on_behalf(
} else {
(addr_bytes.clone(), addr_len)
};
if !redirected {
if let Some(real_port) = remapped_loopback_port {
// The child sees virtual ports via getsockname(); connect
// still has to target the real bound loopback port.
set_port_in_sockaddr(&mut connect_addr, real_port);
}
}

// (The supervisor-side dup is the same fd we already created
// for the SO_PROTOCOL probe above — reuse it rather than
Expand Down Expand Up @@ -396,7 +416,7 @@ async fn sendto_on_behalf(
let dest_port = parse_port_from_sockaddr(&addr_bytes);
let dup_fd = match crate::seccomp::notif::dup_fd_from_pid(notif.pid, sockfd) {
Ok(fd) => fd,
Err(_) => return NotifAction::Errno(libc::ENOSYS),
Err(e) => return NotifAction::Errno(e.raw_os_error().unwrap_or(libc::EBADF)),
};
let protocol = match query_socket_protocol(dup_fd.as_raw_fd()) {
Some(p) => p,
Expand Down Expand Up @@ -484,7 +504,7 @@ async fn sendmsg_on_behalf(

let dup_fd = match crate::seccomp::notif::dup_fd_from_pid(notif.pid, sockfd) {
Ok(fd) => fd,
Err(_) => return NotifAction::Errno(libc::ENOSYS),
Err(e) => return NotifAction::Errno(e.raw_os_error().unwrap_or(libc::EBADF)),
};
let protocol = match query_socket_protocol(dup_fd.as_raw_fd()) {
Some(p) => p,
Expand Down Expand Up @@ -721,7 +741,7 @@ async fn sendmmsg_on_behalf(

let dup_fd = match crate::seccomp::notif::dup_fd_from_pid(notif.pid, sockfd) {
Ok(fd) => fd,
Err(_) => return NotifAction::Errno(libc::ENOSYS),
Err(e) => return NotifAction::Errno(e.raw_os_error().unwrap_or(libc::EBADF)),
};
let protocol = match query_socket_protocol(dup_fd.as_raw_fd()) {
Some(p) => p,
Expand Down
Loading
Loading