cap_primitives/net/
pool.rs

1#[cfg(test)]
2use crate::ambient_authority;
3use crate::net::pool::net::ToSocketAddrs;
4use crate::AmbientAuthority;
5use ipnet::IpNet;
6#[cfg(test)]
7use std::str::FromStr;
8use std::{io, net};
9
10// TODO: Perhaps we should have our own version of `ToSocketAddrs` which
11// returns hostnames rather than parsing them, so we can add unresolved
12// hostnames to the pool.
13#[derive(Clone)]
14enum AddrSet {
15    Net(IpNet),
16}
17
18impl AddrSet {
19    fn contains(&self, addr: net::IpAddr) -> bool {
20        match self {
21            Self::Net(ip_net) => ip_net.contains(&addr),
22        }
23    }
24}
25
26#[derive(Clone)]
27struct IpGrant {
28    set: AddrSet,
29    ports_start: u16,
30    ports_end: Option<u16>,
31}
32
33impl IpGrant {
34    fn contains(&self, addr: &net::SocketAddr) -> bool {
35        if !self.set.contains(addr.ip()) {
36            return false;
37        }
38
39        let port = addr.port();
40        if port < self.ports_start {
41            return false;
42        }
43        if let Some(ports_end) = self.ports_end {
44            if port >= ports_end {
45                return false;
46            }
47        }
48
49        true
50    }
51}
52
53/// A representation of a set of network resources that may be accessed.
54///
55/// This is presently a very simple concept, though it could grow in
56/// sophistication in the future.
57///
58/// `Pool` implements `Clone`, which creates new independent entities that
59/// carry the full authority of the originals. This means that in a borrow
60/// of a `Pool`, the scope of the authority is not necessarily limited to
61/// the scope of the borrow.
62///
63/// Similarly, the [`cap_net_ext::PoolExt`] class allows creating "binder"
64/// and "connecter" objects which represent capabilities to bind and
65/// connect to addresses.
66///
67/// [`cap_net_ext::PoolExt`]: https://docs.rs/cap-net-ext/latest/cap_net_ext/trait.PoolExt.html
68#[derive(Clone, Default)]
69pub struct Pool {
70    // TODO: when compiling for WASI, use WASI-specific handle instead
71    grants: Vec<IpGrant>,
72}
73
74impl Pool {
75    /// Construct a new empty pool.
76    pub fn new() -> Self {
77        Self { grants: Vec::new() }
78    }
79
80    /// Add addresses to the pool.
81    ///
82    /// # Ambient Authority
83    ///
84    /// This function allows ambient access to any IP address.
85    pub fn insert<A: ToSocketAddrs>(
86        &mut self,
87        addrs: A,
88        ambient_authority: AmbientAuthority,
89    ) -> io::Result<()> {
90        for addr in addrs.to_socket_addrs()? {
91            self.insert_socket_addr(addr, ambient_authority);
92        }
93        Ok(())
94    }
95
96    /// Add a specific [`net::SocketAddr`] to the pool.
97    ///
98    /// # Ambient Authority
99    ///
100    /// This function allows ambient access to any IP address.
101    pub fn insert_socket_addr(
102        &mut self,
103        addr: net::SocketAddr,
104        ambient_authority: AmbientAuthority,
105    ) {
106        self.insert_ip_net(addr.ip().into(), addr.port(), ambient_authority)
107    }
108
109    /// Add a range of network addresses, accepting any port, to the pool.
110    ///
111    /// # Ambient Authority
112    ///
113    /// This function allows ambient access to any IP address.
114    pub fn insert_ip_net_port_any(
115        &mut self,
116        ip_net: ipnet::IpNet,
117        ambient_authority: AmbientAuthority,
118    ) {
119        self.insert_ip_net_port_range(ip_net, 0, None, ambient_authority)
120    }
121
122    /// Add a range of network addresses, accepting a range of ports, to the
123    /// pool.
124    ///
125    /// This grants access to the port range starting at `ports_start` and,
126    /// if `ports_end` is provided, ending before `ports_end`.
127    ///
128    /// # Ambient Authority
129    ///
130    /// This function allows ambient access to any IP address.
131    pub fn insert_ip_net_port_range(
132        &mut self,
133        ip_net: ipnet::IpNet,
134        ports_start: u16,
135        ports_end: Option<u16>,
136        ambient_authority: AmbientAuthority,
137    ) {
138        let _ = ambient_authority;
139
140        self.grants.push(IpGrant {
141            set: AddrSet::Net(ip_net),
142            ports_start,
143            ports_end,
144        })
145    }
146
147    /// Add a range of network addresses with a specific port to the pool.
148    ///
149    /// # Ambient Authority
150    ///
151    /// This function allows ambient access to any IP address.
152    pub fn insert_ip_net(
153        &mut self,
154        ip_net: ipnet::IpNet,
155        port: u16,
156        ambient_authority: AmbientAuthority,
157    ) {
158        self.insert_ip_net_port_range(ip_net, port, port.checked_add(1), ambient_authority)
159    }
160
161    /// Check whether the given address is within the pool.
162    pub fn check_addr(&self, addr: &net::SocketAddr) -> io::Result<()> {
163        if self.grants.iter().any(|grant| grant.contains(addr)) {
164            Ok(())
165        } else {
166            Err(io::Error::new(
167                io::ErrorKind::PermissionDenied,
168                "An address was outside the pool",
169            ))
170        }
171    }
172}
173
174/// An empty array of `SocketAddr`s.
175pub const NO_SOCKET_ADDRS: &[net::SocketAddr] = &[];
176
177/// Return an error for reporting that no socket addresses were available.
178#[cold]
179pub fn no_socket_addrs() -> io::Error {
180    std::net::TcpListener::bind(NO_SOCKET_ADDRS).unwrap_err()
181}
182
183#[test]
184fn test_empty() {
185    let p = Pool::new();
186
187    p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
188        .unwrap_err();
189    p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
190        .unwrap_err();
191    p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
192        .unwrap_err();
193    p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
194        .unwrap_err();
195    p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
196        .unwrap_err();
197}
198
199#[test]
200fn test_port_any() {
201    let mut p = Pool::new();
202    p.insert_ip_net_port_any(
203        IpNet::new(net::IpAddr::V6(net::Ipv6Addr::LOCALHOST), 48).unwrap(),
204        ambient_authority(),
205    );
206
207    p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
208        .unwrap();
209    p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
210        .unwrap();
211    p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
212        .unwrap();
213    p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
214        .unwrap();
215    p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
216        .unwrap();
217}
218
219#[test]
220fn test_port_range() {
221    let mut p = Pool::new();
222    p.insert_ip_net_port_range(
223        IpNet::new(net::IpAddr::V6(net::Ipv6Addr::LOCALHOST), 48).unwrap(),
224        1024,
225        Some(9000),
226        ambient_authority(),
227    );
228
229    p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
230        .unwrap_err();
231    p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
232        .unwrap_err();
233    p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
234        .unwrap();
235    p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
236        .unwrap();
237    p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
238        .unwrap_err();
239}
240
241#[test]
242fn test_port_one() {
243    let mut p = Pool::new();
244    p.insert_ip_net(
245        IpNet::new(net::IpAddr::V6(net::Ipv6Addr::LOCALHOST), 48).unwrap(),
246        8080,
247        ambient_authority(),
248    );
249
250    p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
251        .unwrap_err();
252    p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
253        .unwrap_err();
254    p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
255        .unwrap_err();
256    p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
257        .unwrap();
258    p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
259        .unwrap_err();
260}
261
262#[test]
263fn test_addrs() {
264    let mut p = Pool::new();
265    match p.insert("example.com:80", ambient_authority()) {
266        Ok(()) => (),
267        Err(_) => return, // not all test environments have DNS
268    }
269
270    p.check_addr(&net::SocketAddr::from_str("[::1]:0").unwrap())
271        .unwrap_err();
272    p.check_addr(&net::SocketAddr::from_str("[::1]:1023").unwrap())
273        .unwrap_err();
274    p.check_addr(&net::SocketAddr::from_str("[::1]:1024").unwrap())
275        .unwrap_err();
276    p.check_addr(&net::SocketAddr::from_str("[::1]:8080").unwrap())
277        .unwrap_err();
278    p.check_addr(&net::SocketAddr::from_str("[::1]:65535").unwrap())
279        .unwrap_err();
280
281    for addr in "example.com:80".to_socket_addrs().unwrap() {
282        p.check_addr(&addr).unwrap();
283    }
284}