1use crate::compat::private::OptionCompatLevelMut;
2use crate::{
3 uapi, Access, AddRuleError, AddRulesError, CompatError, CompatLevel, CompatResult, CompatState,
4 Compatible, HandleAccessError, HandleAccessesError, PrivateAccess, PrivateRule, Rule, Ruleset,
5 RulesetCreated, TailoredCompatLevel, TryCompat, ABI,
6};
7use enumflags2::{bitflags, BitFlags};
8use std::mem::zeroed;
9
10#[bitflags]
40#[repr(u64)]
41#[derive(Copy, Clone, Debug, PartialEq, Eq)]
42#[non_exhaustive]
43pub enum AccessNet {
44 BindTcp = uapi::LANDLOCK_ACCESS_NET_BIND_TCP as u64,
46 ConnectTcp = uapi::LANDLOCK_ACCESS_NET_CONNECT_TCP as u64,
48}
49
50impl Access for AccessNet {
55 fn from_all(abi: ABI) -> BitFlags<Self> {
56 match abi {
57 ABI::Unsupported | ABI::V1 | ABI::V2 | ABI::V3 => BitFlags::EMPTY,
58 ABI::V4 | ABI::V5 => AccessNet::BindTcp | AccessNet::ConnectTcp,
59 }
60 }
61}
62
63impl PrivateAccess for AccessNet {
64 fn ruleset_handle_access(
65 ruleset: &mut Ruleset,
66 access: BitFlags<Self>,
67 ) -> Result<(), HandleAccessesError> {
68 ruleset.requested_handled_net |= access;
70 ruleset.actual_handled_net |= match access
71 .try_compat(
72 ruleset.compat.abi(),
73 ruleset.compat.level,
74 &mut ruleset.compat.state,
75 )
76 .map_err(HandleAccessError::Compat)?
77 {
78 Some(a) => a,
79 None => return Ok(()),
80 };
81 Ok(())
82 }
83
84 fn into_add_rules_error(error: AddRuleError<Self>) -> AddRulesError {
85 AddRulesError::Net(error)
86 }
87
88 fn into_handle_accesses_error(error: HandleAccessError<Self>) -> HandleAccessesError {
89 HandleAccessesError::Net(error)
90 }
91}
92
93#[cfg_attr(test, derive(Debug))]
105pub struct NetPort {
106 attr: uapi::landlock_net_port_attr,
107 port: u16,
109 allowed_access: BitFlags<AccessNet>,
110 compat_level: Option<CompatLevel>,
111}
112
113impl NetPort {
116 pub fn new<A>(port: u16, access: A) -> Self
121 where
122 A: Into<BitFlags<AccessNet>>,
123 {
124 NetPort {
125 attr: unsafe { zeroed() },
127 port,
128 allowed_access: access.into(),
129 compat_level: None,
130 }
131 }
132}
133
134impl Rule<AccessNet> for NetPort {}
135
136impl PrivateRule<AccessNet> for NetPort {
137 const TYPE_ID: uapi::landlock_rule_type = uapi::landlock_rule_type_LANDLOCK_RULE_NET_PORT;
138
139 fn as_ptr(&mut self) -> *const libc::c_void {
140 self.attr.port = self.port as u64;
141 self.attr.allowed_access = self.allowed_access.bits();
142 &self.attr as *const _ as _
143 }
144
145 fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError> {
146 if ruleset.requested_handled_net.contains(self.allowed_access) {
151 Ok(())
152 } else {
153 Err(AddRuleError::UnhandledAccess {
154 access: self.allowed_access,
155 incompatible: self.allowed_access & !ruleset.requested_handled_net,
156 }
157 .into())
158 }
159 }
160}
161
162#[test]
163fn net_port_check_consistency() {
164 use crate::*;
165
166 let bind = AccessNet::BindTcp;
167 let bind_connect = bind | AccessNet::ConnectTcp;
168
169 assert!(matches!(
170 Ruleset::from(ABI::Unsupported)
171 .handle_access(bind)
172 .unwrap()
173 .create()
174 .unwrap()
175 .add_rule(NetPort::new(1, bind_connect))
176 .unwrap_err(),
177 RulesetError::AddRules(AddRulesError::Net(AddRuleError::UnhandledAccess { access, incompatible }))
178 if access == bind_connect && incompatible == AccessNet::ConnectTcp
179 ));
180}
181
182impl TryCompat<AccessNet> for NetPort {
183 fn try_compat_children<L>(
184 mut self,
185 abi: ABI,
186 parent_level: L,
187 compat_state: &mut CompatState,
188 ) -> Result<Option<Self>, CompatError<AccessNet>>
189 where
190 L: Into<CompatLevel>,
191 {
192 self.allowed_access = match self.allowed_access.try_compat(
194 abi,
195 self.tailored_compat_level(parent_level),
196 compat_state,
197 )? {
198 Some(a) => a,
199 None => return Ok(None),
200 };
201 Ok(Some(self))
202 }
203
204 fn try_compat_inner(
205 &mut self,
206 _abi: ABI,
207 ) -> Result<CompatResult<AccessNet>, CompatError<AccessNet>> {
208 Ok(CompatResult::Full)
209 }
210}
211
212impl OptionCompatLevelMut for NetPort {
213 fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
214 &mut self.compat_level
215 }
216}
217
218impl OptionCompatLevelMut for &mut NetPort {
219 fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
220 &mut self.compat_level
221 }
222}
223
224impl Compatible for NetPort {}
225
226impl Compatible for &mut NetPort {}