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 => AccessNet::BindTcp | AccessNet::ConnectTcp,
61 }
62 }
63}
64
65impl HandledAccess for AccessNet {}
66
67impl PrivateHandledAccess for AccessNet {
68 fn ruleset_handle_access(
69 ruleset: &mut Ruleset,
70 access: BitFlags<Self>,
71 ) -> Result<(), HandleAccessesError> {
72 ruleset.requested_handled_net |= access;
74 ruleset.actual_handled_net |= match access
75 .try_compat(
76 ruleset.compat.abi(),
77 ruleset.compat.level,
78 &mut ruleset.compat.state,
79 )
80 .map_err(HandleAccessError::Compat)?
81 {
82 Some(a) => a,
83 None => return Ok(()),
84 };
85 Ok(())
86 }
87
88 fn into_add_rules_error(error: AddRuleError<Self>) -> AddRulesError {
89 AddRulesError::Net(error)
90 }
91
92 fn into_handle_accesses_error(error: HandleAccessError<Self>) -> HandleAccessesError {
93 HandleAccessesError::Net(error)
94 }
95}
96
97#[cfg_attr(test, derive(Debug))]
109pub struct NetPort {
110 attr: uapi::landlock_net_port_attr,
111 port: u16,
113 allowed_access: BitFlags<AccessNet>,
114 compat_level: Option<CompatLevel>,
115}
116
117impl NetPort {
120 pub fn new<A>(port: u16, access: A) -> Self
125 where
126 A: Into<BitFlags<AccessNet>>,
127 {
128 NetPort {
129 attr: unsafe { zeroed() },
131 port,
132 allowed_access: access.into(),
133 compat_level: None,
134 }
135 }
136}
137
138impl Rule<AccessNet> for NetPort {}
139
140impl PrivateRule<AccessNet> for NetPort {
141 const TYPE_ID: uapi::landlock_rule_type = uapi::landlock_rule_type_LANDLOCK_RULE_NET_PORT;
142
143 fn as_ptr(&mut self) -> *const libc::c_void {
144 self.attr.port = self.port as u64;
145 self.attr.allowed_access = self.allowed_access.bits();
146 &self.attr as *const _ as _
147 }
148
149 fn check_consistency(&self, ruleset: &RulesetCreated) -> Result<(), AddRulesError> {
150 if ruleset.requested_handled_net.contains(self.allowed_access) {
155 Ok(())
156 } else {
157 Err(AddRuleError::UnhandledAccess {
158 access: self.allowed_access,
159 incompatible: self.allowed_access & !ruleset.requested_handled_net,
160 }
161 .into())
162 }
163 }
164}
165
166#[test]
167fn net_port_check_consistency() {
168 use crate::*;
169
170 let bind = AccessNet::BindTcp;
171 let bind_connect = bind | AccessNet::ConnectTcp;
172
173 assert!(matches!(
174 Ruleset::from(ABI::Unsupported)
175 .handle_access(bind)
176 .unwrap()
177 .create()
178 .unwrap()
179 .add_rule(NetPort::new(1, bind_connect))
180 .unwrap_err(),
181 RulesetError::AddRules(AddRulesError::Net(AddRuleError::UnhandledAccess { access, incompatible }))
182 if access == bind_connect && incompatible == AccessNet::ConnectTcp
183 ));
184}
185
186impl TryCompat<AccessNet> for NetPort {
187 fn try_compat_children<L>(
188 mut self,
189 abi: ABI,
190 parent_level: L,
191 compat_state: &mut CompatState,
192 ) -> Result<Option<Self>, CompatError<AccessNet>>
193 where
194 L: Into<CompatLevel>,
195 {
196 self.allowed_access = match self.allowed_access.try_compat(
198 abi,
199 self.tailored_compat_level(parent_level),
200 compat_state,
201 )? {
202 Some(a) => a,
203 None => return Ok(None),
204 };
205 Ok(Some(self))
206 }
207
208 fn try_compat_inner(
209 &mut self,
210 _abi: ABI,
211 ) -> Result<CompatResult<AccessNet>, CompatError<AccessNet>> {
212 Ok(CompatResult::Full)
213 }
214}
215
216impl OptionCompatLevelMut for NetPort {
217 fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
218 &mut self.compat_level
219 }
220}
221
222impl OptionCompatLevelMut for &mut NetPort {
223 fn as_option_compat_level_mut(&mut self) -> &mut Option<CompatLevel> {
224 &mut self.compat_level
225 }
226}
227
228impl Compatible for NetPort {}
229
230impl Compatible for &mut NetPort {}