capsules_extra/net/
network_capabilities.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Capabilities for specifying capsule access to network resources
6//!
7//! A network capability specifies (1) with what IP addresses the holder of the
8//! capability may communicate, (2) from which UDP ports the holder may send,
9//! and (3) to which UDP ports the holder may send. In order to express various
10//! ranges of IP addresses, one uses the AddrRange enum. One specifies ranges of
11//! ports using the PortRange enum.
12//!
13//! Capsules must obtain static references to network capabilities from trusted
14//! code (i.e. code that must use the unsafe keyword) since the constructor of
15//! a network capability requires the NetworkCapabilityCreationCapability capability. Code that
16//! checks these capabilities must possess the appropriate visibilty privileges.
17//! UDP visibility privileges are given through the UdpVisibilityCapability capability and IP
18//! visibility privileges are given through the IpVisibilityCapability capability.
19//!
20//! An example of the visibility capabilities can be found in udp_port_table.rs.
21//! When attempting to bind to a port, we must first verify that the caller of
22//! bind has a capability to send from that port. Therefore, we check the
23//! network capability of the caller. In order to check the UDP-specific aspect
24//! of the network capability, the port table must posses a UdpVisibilityCapability reference.
25use crate::net::ipv6::ip_utils::IPAddr;
26
27const MAX_ADDR_SET_SIZE: usize = 8;
28const MAX_PORT_SET_SIZE: usize = 8;
29
30use kernel::capabilities::NetworkCapabilityCreationCapability;
31
32#[derive(Debug, Clone, Copy, PartialEq)]
33pub enum AddrRange {
34    Any, // Any address
35    NoAddrs,
36    AddrSet([IPAddr; MAX_ADDR_SET_SIZE]),
37    Addr(IPAddr),
38    Subnet(IPAddr, usize), // address, prefix length (max 128)
39}
40
41impl AddrRange {
42    pub fn is_addr_valid(&self, addr: IPAddr) -> bool {
43        match self {
44            AddrRange::Any => true,
45            AddrRange::NoAddrs => false,
46            AddrRange::AddrSet(allowed_addrs) => allowed_addrs.contains(&addr),
47            AddrRange::Addr(allowed_addr) => addr == *allowed_addr, //TODO: refs?
48            AddrRange::Subnet(allowed_addr, prefix_len) => {
49                let full_bytes: usize = prefix_len / 8;
50                let remainder_bits: usize = prefix_len % 8;
51                // initial bytes -- TODO: edge case
52                if allowed_addr.0[0..full_bytes] != addr.0[0..full_bytes] {
53                    false
54                } else if remainder_bits == 0 {
55                    true //this case is necessary bc right shifting a u8 by 8 bits is UB
56                } else {
57                    addr.0[full_bytes] >> (8 - remainder_bits)
58                        == allowed_addr.0[full_bytes] >> (8 - remainder_bits)
59                }
60            }
61        }
62    }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq)]
66pub enum PortRange {
67    Any,
68    NoPorts,
69    PortSet([u16; MAX_PORT_SET_SIZE]),
70    Range(u16, u16),
71    Port(u16),
72}
73
74impl PortRange {
75    pub fn is_port_valid(&self, port: u16) -> bool {
76        match self {
77            PortRange::Any => true,
78            PortRange::NoPorts => false,
79            PortRange::PortSet(allowed_ports) => allowed_ports.contains(&port), // TODO: check refs
80            PortRange::Range(low, high) => *low <= port && port <= *high,
81            PortRange::Port(allowed_port) => port == *allowed_port,
82        }
83    }
84}
85
86/// UDP visiblity capability.
87pub struct UdpVisibilityCapability {
88    _priv: (), // an empty private field
89}
90
91/// IP visiblity capability.
92pub struct IpVisibilityCapability {
93    _priv: (), // an empty private field
94}
95
96impl UdpVisibilityCapability {
97    pub fn new(
98        _create_net_cap: &dyn NetworkCapabilityCreationCapability,
99    ) -> UdpVisibilityCapability {
100        UdpVisibilityCapability { _priv: () }
101    }
102}
103
104impl IpVisibilityCapability {
105    pub fn new(
106        _create_net_cap: &dyn NetworkCapabilityCreationCapability,
107    ) -> IpVisibilityCapability {
108        IpVisibilityCapability { _priv: () }
109    }
110}
111
112/// Specifies access to network resourcess across the UDP and IP
113/// layers.
114///
115/// Access to layer-specific information is mediated by the
116/// UdpVsibilityCapability and the IpVisibilityCapability.
117pub struct NetworkCapability {
118    // can potentially add more
119    remote_addrs: AddrRange, // IP addresses with which the holder may communicate
120    remote_ports: PortRange, // ports to which the holder may send
121    local_ports: PortRange,  // ports from which the holder may send
122}
123
124impl NetworkCapability {
125    pub fn new(
126        remote_addrs: AddrRange,
127        remote_ports: PortRange,
128        local_ports: PortRange,
129        _create_net_cap: &dyn NetworkCapabilityCreationCapability,
130    ) -> NetworkCapability {
131        NetworkCapability {
132            remote_addrs,
133            remote_ports,
134            local_ports,
135        }
136    }
137
138    pub fn get_range(&self, _ip_cap: &'static IpVisibilityCapability) -> AddrRange {
139        self.remote_addrs
140    }
141
142    pub fn remote_addr_valid(
143        &self,
144        remote_addr: IPAddr,
145        _ip_cap: &'static IpVisibilityCapability,
146    ) -> bool {
147        self.remote_addrs.is_addr_valid(remote_addr)
148    }
149
150    pub fn get_remote_ports(&self, _udp_cap: &'static UdpVisibilityCapability) -> PortRange {
151        self.remote_ports
152    }
153
154    pub fn get_local_ports(&self, _udp_cap: &'static UdpVisibilityCapability) -> PortRange {
155        self.local_ports
156    }
157
158    pub fn remote_port_valid(
159        &self,
160        remote_port: u16,
161        _udp_cap: &'static UdpVisibilityCapability,
162    ) -> bool {
163        self.remote_ports.is_port_valid(remote_port)
164    }
165
166    pub fn local_port_valid(
167        &self,
168        local_port: u16,
169        _udp_cap: &'static UdpVisibilityCapability,
170    ) -> bool {
171        self.local_ports.is_port_valid(local_port)
172    }
173}