Coverage Report

Created: 2025-07-12 06:48

/rust/registry/src/index.crates.io-6f17d22bba15001f/cap-primitives-3.4.4/src/net/pool.rs
Line
Count
Source (jump to first uncovered line)
1
#[cfg(test)]
2
use crate::ambient_authority;
3
use crate::net::pool::net::ToSocketAddrs;
4
use crate::AmbientAuthority;
5
use ipnet::IpNet;
6
#[cfg(test)]
7
use std::str::FromStr;
8
use 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)]
14
enum AddrSet {
15
    Net(IpNet),
16
}
17
18
impl AddrSet {
19
0
    fn contains(&self, addr: net::IpAddr) -> bool {
20
0
        match self {
21
0
            Self::Net(ip_net) => ip_net.contains(&addr),
22
0
        }
23
0
    }
24
}
25
26
#[derive(Clone)]
27
struct IpGrant {
28
    set: AddrSet,
29
    ports_start: u16,
30
    ports_end: Option<u16>,
31
}
32
33
impl IpGrant {
34
0
    fn contains(&self, addr: &net::SocketAddr) -> bool {
35
0
        if !self.set.contains(addr.ip()) {
36
0
            return false;
37
0
        }
38
0
39
0
        let port = addr.port();
40
0
        if port < self.ports_start {
41
0
            return false;
42
0
        }
43
0
        if let Some(ports_end) = self.ports_end {
44
0
            if port >= ports_end {
45
0
                return false;
46
0
            }
47
0
        }
48
49
0
        true
50
0
    }
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)]
69
pub struct Pool {
70
    // TODO: when compiling for WASI, use WASI-specific handle instead
71
    grants: Vec<IpGrant>,
72
}
73
74
impl Pool {
75
    /// Construct a new empty pool.
76
0
    pub fn new() -> Self {
77
0
        Self { grants: Vec::new() }
78
0
    }
79
80
    /// Add addresses to the pool.
81
    ///
82
    /// # Ambient Authority
83
    ///
84
    /// This function allows ambient access to any IP address.
85
0
    pub fn insert<A: ToSocketAddrs>(
86
0
        &mut self,
87
0
        addrs: A,
88
0
        ambient_authority: AmbientAuthority,
89
0
    ) -> io::Result<()> {
90
0
        for addr in addrs.to_socket_addrs()? {
91
0
            self.insert_socket_addr(addr, ambient_authority);
92
0
        }
93
0
        Ok(())
94
0
    }
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
0
    pub fn insert_socket_addr(
102
0
        &mut self,
103
0
        addr: net::SocketAddr,
104
0
        ambient_authority: AmbientAuthority,
105
0
    ) {
106
0
        self.insert_ip_net(addr.ip().into(), addr.port(), ambient_authority)
107
0
    }
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
0
    pub fn insert_ip_net_port_any(
115
0
        &mut self,
116
0
        ip_net: ipnet::IpNet,
117
0
        ambient_authority: AmbientAuthority,
118
0
    ) {
119
0
        self.insert_ip_net_port_range(ip_net, 0, None, ambient_authority)
120
0
    }
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
0
    pub fn insert_ip_net_port_range(
132
0
        &mut self,
133
0
        ip_net: ipnet::IpNet,
134
0
        ports_start: u16,
135
0
        ports_end: Option<u16>,
136
0
        ambient_authority: AmbientAuthority,
137
0
    ) {
138
0
        let _ = ambient_authority;
139
0
140
0
        self.grants.push(IpGrant {
141
0
            set: AddrSet::Net(ip_net),
142
0
            ports_start,
143
0
            ports_end,
144
0
        })
145
0
    }
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
0
    pub fn insert_ip_net(
153
0
        &mut self,
154
0
        ip_net: ipnet::IpNet,
155
0
        port: u16,
156
0
        ambient_authority: AmbientAuthority,
157
0
    ) {
158
0
        self.insert_ip_net_port_range(ip_net, port, port.checked_add(1), ambient_authority)
159
0
    }
160
161
    /// Check whether the given address is within the pool.
162
0
    pub fn check_addr(&self, addr: &net::SocketAddr) -> io::Result<()> {
163
0
        if self.grants.iter().any(|grant| grant.contains(addr)) {
164
0
            Ok(())
165
        } else {
166
0
            Err(io::Error::new(
167
0
                io::ErrorKind::PermissionDenied,
168
0
                "An address was outside the pool",
169
0
            ))
170
        }
171
0
    }
172
}
173
174
/// An empty array of `SocketAddr`s.
175
pub const NO_SOCKET_ADDRS: &[net::SocketAddr] = &[];
176
177
/// Return an error for reporting that no socket addresses were available.
178
#[cold]
179
0
pub fn no_socket_addrs() -> io::Error {
180
0
    std::net::TcpListener::bind(NO_SOCKET_ADDRS).unwrap_err()
181
0
}
182
183
#[test]
184
fn 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]
200
fn 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]
220
fn 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]
242
fn 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]
263
fn 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
}