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