Skip to content

Commit

Permalink
Add a Pool::insert_ip_net_any_port function. (#299)
Browse files Browse the repository at this point in the history
* Add a `Pool::insert_ip_net_any_port` function.

Add a function to `Pool` to allow inserting a network that can accept
any port.

* Add support for port ranges, and add some unit tests.
  • Loading branch information
sunfishcode authored Mar 16, 2023
1 parent 58dd07c commit c7b2e50
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 13 deletions.
30 changes: 30 additions & 0 deletions cap-async-std/src/net/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,36 @@ impl Pool {
}
}

/// Add a range of network addresses, accepting any port, to the pool.
///
/// Unlike `insert_ip_net`, this function grants access to any requested
/// port.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net_port_any(&mut self, ip_net: ipnet::IpNet, ambient_authority: AmbientAuthority) {
self.cap.insert_ip_net_port_any(ip_net, ambient_authority)
}

/// Add a range of network addresses, accepting a range of ports, to the pool.
///
/// This grants access to the port range starting at `ports_start` and,
/// if `ports_end` is provided, ending before `ports_end`.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net_port_range(
&mut self,
ip_net: ipnet::IpNet,
ports_start: u16,
ports_end: Option<u16>,
ambient_authority: AmbientAuthority,
) {
self.cap.insert_ip_net_port_range(ip_net, ports_start, ports_end, ambient_authority)
}

/// Add a range of network addresses with a specific port to the pool.
///
/// # Ambient Authority
Expand Down
151 changes: 138 additions & 13 deletions cap-primitives/src/net/pool.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use ambient_authority::AmbientAuthority;
#[cfg(test)]
use crate::ambient_authority;
use crate::AmbientAuthority;
use ipnet::IpNet;
#[cfg(test)]
use std::str::FromStr;
use std::{io, net};

// TODO: Perhaps we should have our own version of `ToSocketAddrs` which
Expand All @@ -21,12 +25,27 @@ impl AddrSet {
#[derive(Clone)]
struct IpGrant {
set: AddrSet,
port: u16, // TODO: IANA port names, TODO: range
ports_start: u16,
ports_end: Option<u16>,
}

impl IpGrant {
fn contains(&self, addr: &net::SocketAddr) -> bool {
self.set.contains(addr.ip()) && addr.port() == self.port
if !self.set.contains(addr.ip()) {
return false;
}

let port = addr.port();
if port < self.ports_start {
return false;
}
if let Some(ports_end) = self.ports_end {
if port >= ports_end {
return false;
}
}

true
}
}

Expand All @@ -46,25 +65,57 @@ impl Pool {
Self { grants: Vec::new() }
}

/// Add a range of network addresses with a specific port to the pool.
/// Add a range of network addresses, accepting any port, to the pool.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net(
pub fn insert_ip_net_port_any(
&mut self,
ip_net: ipnet::IpNet,
port: u16,
ambient_authority: AmbientAuthority,
) {
self.insert_ip_net_port_range(ip_net, 0, None, ambient_authority)
}

/// Add a range of network addresses, accepting a range of ports, to the pool.
///
/// This grants access to the port range starting at `ports_start` and,
/// if `ports_end` is provided, ending before `ports_end`.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net_port_range(
&mut self,
ip_net: ipnet::IpNet,
ports_start: u16,
ports_end: Option<u16>,
ambient_authority: AmbientAuthority,
) {
let _ = ambient_authority;

self.grants.push(IpGrant {
set: AddrSet::Net(ip_net),
port,
ports_start,
ports_end,
})
}

/// Add a range of network addresses with a specific port to the pool.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net(
&mut self,
ip_net: ipnet::IpNet,
port: u16,
ambient_authority: AmbientAuthority,
) {
self.insert_ip_net_port_range(ip_net, port, port.checked_add(1), ambient_authority)
}

/// Add a specific [`net::SocketAddr`] to the pool.
///
/// # Ambient Authority
Expand All @@ -75,12 +126,7 @@ impl Pool {
addr: net::SocketAddr,
ambient_authority: AmbientAuthority,
) {
let _ = ambient_authority;

self.grants.push(IpGrant {
set: AddrSet::Net(addr.ip().into()),
port: addr.port(),
})
self.insert_ip_net(addr.ip().into(), addr.port(), ambient_authority)
}

/// Check whether the given address is within the pool.
Expand All @@ -98,3 +144,82 @@ impl Pool {

/// An empty array of `SocketAddr`s.
pub const NO_SOCKET_ADDRS: &[net::SocketAddr] = &[];

#[test]
fn test_empty() {
let p = Pool::new();

p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
.unwrap_err();
}

#[test]
fn test_port_any() {
let mut p = Pool::new();
p.insert_ip_net_port_any(
IpNet::new(net::IpAddr::V6(net::Ipv6Addr::LOCALHOST), 48).unwrap(),
ambient_authority(),
);

p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
.unwrap();
}

#[test]
fn test_port_range() {
let mut p = Pool::new();
p.insert_ip_net_port_range(
IpNet::new(net::IpAddr::V6(net::Ipv6Addr::LOCALHOST), 48).unwrap(),
1024,
Some(9000),
ambient_authority(),
);

p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
.unwrap_err();
}

#[test]
fn test_port_one() {
let mut p = Pool::new();
p.insert_ip_net(
IpNet::new(net::IpAddr::V6(net::Ipv6Addr::LOCALHOST), 48).unwrap(),
8080,
ambient_authority(),
);

p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
.unwrap_err();
p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
.unwrap();
p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
.unwrap_err();
}
35 changes: 35 additions & 0 deletions cap-std/src/net/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,41 @@ impl Pool {
}
}

/// Add a range of network addresses, accepting any port, to the pool.
///
/// Unlike `insert_ip_net`, this function grants access to any requested
/// port.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net_port_any(
&mut self,
ip_net: ipnet::IpNet,
ambient_authority: AmbientAuthority,
) {
self.cap.insert_ip_net_port_any(ip_net, ambient_authority)
}

/// Add a range of network addresses, accepting a range of ports, to the pool.
///
/// This grants access to the port range starting at `ports_start` and,
/// if `ports_end` is provided, ending before `ports_end`.
///
/// # Ambient Authority
///
/// This function allows ambient access to any IP address.
pub fn insert_ip_net_port_range(
&mut self,
ip_net: ipnet::IpNet,
ports_start: u16,
ports_end: Option<u16>,
ambient_authority: AmbientAuthority,
) {
self.cap
.insert_ip_net_port_range(ip_net, ports_start, ports_end, ambient_authority)
}

/// Add a range of network addresses with a specific port to the pool.
///
/// # AmbientAuthority
Expand Down

0 comments on commit c7b2e50

Please sign in to comment.