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