@push.rocks/smartnftables 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/changelog.md +37 -0
  2. package/dist_rust/smartnftables_linux_amd64_musl +0 -0
  3. package/dist_rust/smartnftables_linux_amd64_musl.tsrust-build.json +14 -0
  4. package/dist_rust/smartnftables_linux_arm64_musl +0 -0
  5. package/dist_rust/smartnftables_linux_arm64_musl.tsrust-build.json +14 -0
  6. package/dist_ts/00_commitinfo_data.js +1 -1
  7. package/dist_ts/classes.managednftables.d.ts +21 -0
  8. package/dist_ts/classes.managednftables.js +182 -0
  9. package/dist_ts/index.d.ts +2 -0
  10. package/dist_ts/index.js +2 -1
  11. package/dist_ts/managed.types.d.ts +103 -0
  12. package/dist_ts/managed.types.js +2 -0
  13. package/dist_ts/plugins.d.ts +5 -2
  14. package/dist_ts/plugins.js +6 -3
  15. package/native-notices/crates/block-buffer-0.10.4/license-apache +201 -0
  16. package/native-notices/crates/block-buffer-0.10.4/license-mit +25 -0
  17. package/native-notices/crates/cfg-if-1.0.4/license-apache +201 -0
  18. package/native-notices/crates/cfg-if-1.0.4/license-mit +25 -0
  19. package/native-notices/crates/cpufeatures-0.2.17/license-apache +201 -0
  20. package/native-notices/crates/cpufeatures-0.2.17/license-mit +25 -0
  21. package/native-notices/crates/crypto-common-0.1.7/license-apache +201 -0
  22. package/native-notices/crates/crypto-common-0.1.7/license-mit +25 -0
  23. package/native-notices/crates/digest-0.10.7/license-apache +201 -0
  24. package/native-notices/crates/digest-0.10.7/license-mit +25 -0
  25. package/native-notices/crates/generic-array-0.14.7/license +21 -0
  26. package/native-notices/crates/itoa-1.0.18/license-apache +176 -0
  27. package/native-notices/crates/itoa-1.0.18/license-mit +23 -0
  28. package/native-notices/crates/libc-0.2.189/license-apache +176 -0
  29. package/native-notices/crates/libc-0.2.189/license-mit +25 -0
  30. package/native-notices/crates/memchr-2.8.3/copying +3 -0
  31. package/native-notices/crates/memchr-2.8.3/license-mit +21 -0
  32. package/native-notices/crates/proc-macro2-1.0.107/license-apache +176 -0
  33. package/native-notices/crates/proc-macro2-1.0.107/license-mit +23 -0
  34. package/native-notices/crates/quote-1.0.47/license-apache +176 -0
  35. package/native-notices/crates/quote-1.0.47/license-mit +23 -0
  36. package/native-notices/crates/serde-1.0.229/license-apache +176 -0
  37. package/native-notices/crates/serde-1.0.229/license-mit +23 -0
  38. package/native-notices/crates/serde_core-1.0.229/license-apache +176 -0
  39. package/native-notices/crates/serde_core-1.0.229/license-mit +23 -0
  40. package/native-notices/crates/serde_derive-1.0.229/license-apache +176 -0
  41. package/native-notices/crates/serde_derive-1.0.229/license-mit +23 -0
  42. package/native-notices/crates/serde_json-1.0.151/license-apache +176 -0
  43. package/native-notices/crates/serde_json-1.0.151/license-mit +23 -0
  44. package/native-notices/crates/sha2-0.10.9/license-apache +201 -0
  45. package/native-notices/crates/sha2-0.10.9/license-mit +27 -0
  46. package/native-notices/crates/syn-3.0.5/license-apache +176 -0
  47. package/native-notices/crates/syn-3.0.5/license-mit +23 -0
  48. package/native-notices/crates/typenum-1.20.1/license +1 -0
  49. package/native-notices/crates/typenum-1.20.1/license-apache +201 -0
  50. package/native-notices/crates/typenum-1.20.1/license-mit +21 -0
  51. package/native-notices/crates/unicode-ident-1.0.24/license-apache +176 -0
  52. package/native-notices/crates/unicode-ident-1.0.24/license-mit +23 -0
  53. package/native-notices/crates/unicode-ident-1.0.24/license-unicode +39 -0
  54. package/native-notices/crates/version_check-0.9.5/license-apache +201 -0
  55. package/native-notices/crates/version_check-0.9.5/license-mit +19 -0
  56. package/native-notices/crates/zmij-1.0.23/license-mit +23 -0
  57. package/native-notices/manifest.json +520 -0
  58. package/native-notices/readme.md +36 -0
  59. package/native-notices/rust-standard-library/addr2line-0.25.1-license-apache +201 -0
  60. package/native-notices/rust-standard-library/addr2line-0.25.1-license-mit +25 -0
  61. package/native-notices/rust-standard-library/cargo.lock +522 -0
  62. package/native-notices/rust-standard-library/compiler-builtins-license.txt +275 -0
  63. package/native-notices/rust-standard-library/dependency-notices.html +9072 -0
  64. package/native-notices/rust-standard-library/license-apache +176 -0
  65. package/native-notices/rust-standard-library/license-mit +25 -0
  66. package/native-notices/rust-standard-library/llvm-libunwind-license.txt +311 -0
  67. package/native-notices/rust-standard-library/musl-1.2.5-copyright.txt +193 -0
  68. package/native-notices/rust-standard-library/unicode-license.txt +39 -0
  69. package/package.json +23 -8
  70. package/readme.md +160 -2
  71. package/rust/.cargo/config.toml +2 -0
  72. package/rust/Cargo.lock +192 -0
  73. package/rust/Cargo.toml +13 -0
  74. package/rust/src/main.rs +159 -0
  75. package/rust/src/namespace.rs +51 -0
  76. package/rust/src/owner.rs +604 -0
  77. package/rust/src/owner_namespace_tests.rs +242 -0
  78. package/rust/src/owner_tests.rs +798 -0
  79. package/rust/src/policy.rs +427 -0
  80. package/rust/src/tests.rs +97 -0
  81. package/rust/src/wire.rs +437 -0
  82. package/scripts/check-native-notices.mjs +27 -0
  83. package/ts/00_commitinfo_data.ts +1 -1
  84. package/ts/classes.managednftables.ts +153 -0
  85. package/ts/index.ts +2 -0
  86. package/ts/managed.types.ts +91 -0
  87. package/ts/plugins.ts +6 -0
  88. /package/{license → license.md} +0 -0
@@ -0,0 +1,242 @@
1
+ use super::{empty, in_namespace, ip, isolated, options};
2
+ use crate::owner::{Applied, Owner, Transition};
3
+ use serde_json::{json, Value};
4
+ use std::fs::{self, File};
5
+ use std::io::{BufRead, BufReader, Read, Write};
6
+ use std::os::fd::AsRawFd;
7
+ use std::os::unix::fs::MetadataExt;
8
+ use std::os::unix::process::CommandExt;
9
+ use std::process::{Child, Command, Stdio};
10
+ use std::sync::mpsc::{self, Receiver};
11
+ use std::thread::{self, JoinHandle};
12
+ use std::time::{Duration, Instant};
13
+
14
+ fn command(namespace: &File) -> Command {
15
+ let fd = namespace.as_raw_fd();
16
+ let mut command = Command::new("/bin/managed");
17
+ command
18
+ .args(["--management", "--network-namespace-fd", "3"])
19
+ .stdin(Stdio::piped())
20
+ .stdout(Stdio::piped())
21
+ .stderr(Stdio::inherit());
22
+ unsafe {
23
+ command.pre_exec(move || {
24
+ if libc::dup2(fd, 3) < 0 || libc::fcntl(3, libc::F_SETFD, 0) < 0 {
25
+ return Err(std::io::Error::last_os_error());
26
+ }
27
+ Ok(())
28
+ });
29
+ }
30
+ command
31
+ }
32
+
33
+ struct NativeOwner {
34
+ child: Child,
35
+ messages: Receiver<Value>,
36
+ reader: Option<JoinHandle<()>>,
37
+ }
38
+ impl NativeOwner {
39
+ fn start(namespace: &File) -> Self {
40
+ let mut child = command(namespace).spawn().unwrap();
41
+ let output = child.stdout.take().unwrap();
42
+ let (send, messages) = mpsc::channel();
43
+ let reader = thread::spawn(move || {
44
+ for line in BufReader::new(output.take(1024 * 1024)).lines() {
45
+ let Ok(line) = line else { break };
46
+ if line.len() > 262_144 {
47
+ break;
48
+ }
49
+ let Ok(value) = serde_json::from_str(&line) else {
50
+ break;
51
+ };
52
+ if send.send(value).is_err() {
53
+ break;
54
+ }
55
+ }
56
+ });
57
+ let owner = Self {
58
+ child,
59
+ messages,
60
+ reader: Some(reader),
61
+ };
62
+ assert_eq!(
63
+ owner.messages.recv_timeout(Duration::from_secs(5)).unwrap()["event"],
64
+ "ready"
65
+ );
66
+ owner
67
+ }
68
+ fn response(&mut self, method: &str, params: Value) -> Value {
69
+ writeln!(
70
+ self.child.stdin.as_mut().unwrap(),
71
+ "{}",
72
+ json!({"id":method,"method":method,"params":params})
73
+ )
74
+ .unwrap();
75
+ let response = self.messages.recv_timeout(Duration::from_secs(5)).unwrap();
76
+ assert_eq!(response["id"], method);
77
+ response
78
+ }
79
+ fn call(&mut self, method: &str, params: Value) -> Value {
80
+ let response = self.response(method, params);
81
+ assert_eq!(response["success"], true, "{response}");
82
+ response["result"].clone()
83
+ }
84
+ }
85
+ impl Drop for NativeOwner {
86
+ fn drop(&mut self) {
87
+ let _ = self.child.kill();
88
+ let _ = self.child.wait();
89
+ if let Some(reader) = self.reader.take() {
90
+ let _ = reader.join();
91
+ }
92
+ }
93
+ }
94
+
95
+ #[test]
96
+ #[ignore = "requires the explicitly isolated QEMU qualification guest"]
97
+ fn inherited_namespace_binds_policy_and_persistent_recovery() {
98
+ isolated();
99
+ ip(&["netns", "add", "fdtarget"]);
100
+ let namespace = File::open("/run/netns/fdtarget").unwrap();
101
+ let metadata = namespace.metadata().unwrap();
102
+ let initial = fs::metadata("/proc/thread-self/ns/net").unwrap();
103
+ assert_ne!(metadata.ino(), initial.ino());
104
+ let mut child = NativeOwner::start(&namespace);
105
+ let pid = child.child.id();
106
+ let status = child.call("openOwner", serde_json::to_value(options("nsfd")).unwrap());
107
+ assert_eq!(
108
+ status["identity"]["namespaceDevice"],
109
+ metadata.dev().to_string()
110
+ );
111
+ assert_eq!(
112
+ status["identity"]["namespaceInode"],
113
+ metadata.ino().to_string()
114
+ );
115
+ assert_eq!(
116
+ fs::read_dir(format!("/proc/{pid}/task")).unwrap().count(),
117
+ 1
118
+ );
119
+ let target_link = fs::read_link(format!("/proc/{pid}/ns/net")).unwrap();
120
+ for fd in fs::read_dir(format!("/proc/{pid}/fd")).unwrap() {
121
+ if let Ok(target) = fs::read_link(fd.unwrap().path()) {
122
+ assert_ne!(
123
+ target, target_link,
124
+ "child namespace descriptor must be closed"
125
+ );
126
+ }
127
+ }
128
+ let first = child.call(
129
+ "reconcilePolicy",
130
+ serde_json::to_value(Transition {
131
+ previous: None,
132
+ target: empty(1),
133
+ })
134
+ .unwrap(),
135
+ );
136
+ assert!(Owner::new(options("nsfd"))
137
+ .unwrap()
138
+ .graph()
139
+ .unwrap()
140
+ .is_none());
141
+ assert!(in_namespace("fdtarget", || Owner::new(options("nsfd"))
142
+ .unwrap()
143
+ .graph()
144
+ .unwrap()
145
+ .is_some()));
146
+ assert_eq!(
147
+ unsafe { libc::ioctl(namespace.as_raw_fd(), libc::NS_GET_NSTYPE) },
148
+ libc::CLONE_NEWNET
149
+ );
150
+ drop(child); // PERSIST must retain the target graph after native process loss.
151
+ assert!(!std::path::Path::new(&format!("/proc/{pid}")).exists());
152
+ assert!(in_namespace("fdtarget", || Owner::new(options("nsfd"))
153
+ .unwrap()
154
+ .graph()
155
+ .unwrap()
156
+ .is_some()));
157
+
158
+ let previous: Applied = serde_json::from_value(first).unwrap();
159
+ let transition = serde_json::to_value(Transition {
160
+ previous: Some(previous),
161
+ target: empty(2),
162
+ })
163
+ .unwrap();
164
+ let wrong_namespace = File::open("/proc/thread-self/ns/net").unwrap();
165
+ let mut wrong = NativeOwner::start(&wrong_namespace);
166
+ wrong.call("openOwner", serde_json::to_value(options("nsfd")).unwrap());
167
+ let denied = wrong.response("reconcilePolicy", transition.clone());
168
+ assert_eq!(denied["success"], false);
169
+ assert_eq!(denied["errorCode"], "CONFLICT");
170
+ assert!(Owner::new(options("nsfd"))
171
+ .unwrap()
172
+ .graph()
173
+ .unwrap()
174
+ .is_none());
175
+ drop(wrong);
176
+ assert!(in_namespace("fdtarget", || Owner::new(options("nsfd"))
177
+ .unwrap()
178
+ .graph()
179
+ .unwrap()
180
+ .is_some()));
181
+
182
+ let mut recovered = NativeOwner::start(&namespace);
183
+ recovered.call("openOwner", serde_json::to_value(options("nsfd")).unwrap());
184
+ drop(namespace); // The entered child keeps membership; caller capability is not consumed by it.
185
+ let applied = recovered.call("reconcilePolicy", transition);
186
+ assert_eq!(applied["receipt"]["revision"], 2);
187
+ assert_eq!(
188
+ applied["receipt"]["identity"]["namespaceInode"],
189
+ metadata.ino().to_string()
190
+ );
191
+ assert_eq!(recovered.call("inspectPolicy", json!({}))["enforced"], true);
192
+ assert_eq!(recovered.call("closeOwner", json!({}))["released"], true);
193
+ drop(recovered);
194
+ assert!(in_namespace("fdtarget", || Owner::new(options("nsfd"))
195
+ .unwrap()
196
+ .graph()
197
+ .unwrap()
198
+ .is_none()));
199
+ assert!(Owner::new(options("nsfd"))
200
+ .unwrap()
201
+ .graph()
202
+ .unwrap()
203
+ .is_none());
204
+ assert_eq!(
205
+ fs::metadata("/proc/thread-self/ns/net").unwrap().ino(),
206
+ initial.ino()
207
+ );
208
+ ip(&["netns", "delete", "fdtarget"]);
209
+ }
210
+
211
+ #[test]
212
+ #[ignore = "requires the explicitly isolated QEMU qualification guest"]
213
+ fn valid_descriptor_without_entry_permission_never_becomes_ready() {
214
+ isolated();
215
+ let namespace = File::open("/proc/thread-self/ns/net").unwrap();
216
+ let mut child = command(&namespace)
217
+ .uid(65534)
218
+ .gid(65534)
219
+ .stdin(Stdio::null())
220
+ .stderr(Stdio::piped())
221
+ .spawn()
222
+ .unwrap();
223
+ let deadline = Instant::now() + Duration::from_secs(5);
224
+ while child.try_wait().unwrap().is_none() {
225
+ if Instant::now() >= deadline {
226
+ let _ = child.kill();
227
+ let _ = child.wait();
228
+ panic!("denied namespace entry did not exit");
229
+ }
230
+ thread::sleep(Duration::from_millis(10));
231
+ }
232
+ let output = child.wait_with_output().unwrap();
233
+ assert_eq!(output.status.code(), Some(1));
234
+ assert!(output.stdout.is_empty());
235
+ assert!(String::from_utf8(output.stderr)
236
+ .unwrap()
237
+ .contains("network namespace entry failed"));
238
+ assert_eq!(
239
+ unsafe { libc::ioctl(namespace.as_raw_fd(), libc::NS_GET_NSTYPE) },
240
+ libc::CLONE_NEWNET
241
+ );
242
+ }