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