1use std::fs::{File, OpenOptions};
35use std::os::fd::AsFd;
36use std::os::unix::fs::OpenOptionsExt;
37use std::path::Path;
38
39use nix::fcntl::{open, OFlag};
40use nix::sys::stat::Mode;
41use nix::libc;
42
43use crate::ioctl::pfioc_state_kill;
44use crate::pfr_buffer::{PfrBuffer, Pfrb};
45use crate::pfr_table::pfr_table;
46use crate::common;
47use crate::{error_coded, map_error_coded, runtime_exception::*};
48
49pub enum PfCmd
61{
62 Add{ hosts: Vec<String> },
64
65 Delete{ hosts: Vec<String> },
67
68 Test{ hosts: Vec<String> },
70
71 Flush,
73}
74
75pub enum PfCmdFile<'p>
76{
77 Add{ file_path: &'p Path },
79
80 Delete{ file_path: &'p Path },
82
83 Test{ file_path: &'p Path },
85
86 Flush,
88}
89
90
91pub struct Pf
92{
93 fd: File,
94 test: bool
95}
96
97impl Pf
98{
99 const DEFAULT_PF_DEVICE: &'static str = "/dev/pf";
100
101 pub
106 fn new(pf_dev_path: Option<&str>) -> PfResult<Self>
107 {
108 let path = Path::new(pf_dev_path.unwrap_or(Self::DEFAULT_PF_DEVICE));
109
110 if path.exists() == false
111 {
112 error_coded!(PfErrCode::IOErr, "file: '{}' does not exist!", path.display());
113 }
114 else if path.is_dir() == true
115 {
116 error_coded!(PfErrCode::IOErr, "file: '{}' is directory!", path.display());
117 }
118
119 let file =
120 OpenOptions::new()
121 .custom_flags(libc::O_NONBLOCK | libc::O_RDWR)
122 .open(path)
123 .map_err(|e|
124 map_error_coded!(PfErrCode::IOErr, "open() failed path {} err: {}", Self::DEFAULT_PF_DEVICE, e)
125 )?;
126
127 return Ok(Self{ fd: file, test: false });
134 }
135
136 #[cfg(test)]
137 pub
138 fn new_test() -> PfResult<Self>
139 {
140 use std::os::fd::FromRawFd;
141
142 let file = unsafe { File::from_raw_fd(1) };
143
144 return Ok(Self{ fd: file, test: true });
145 }
146
147 pub
160 fn pfctl_kill_state<H: AsRef<str>>(&self, src: H, dest: Option<H>) -> PfResult<()>
161 {
162 return unsafe { pfioc_state_kill::new(self.fd.as_fd(), self.test, src, dest) };
163 }
164
165 pub
183 fn pfctl_table_file<'p, T: AsRef<str>>(&self, table_name: T, cmd: PfCmdFile<'p>) -> PfResult<i32>
184 {
185 let tname = table_name.as_ref();
186
187 let mut table: pfr_table = unsafe { pfr_table::new(tname)? };
188 if tname.len() >= common::PF_TABLE_NAME_SIZE
192 {
193 error_coded!(PfErrCode::Einval, "table name: '{}' is too long!", tname);
194 }
195
196 if tname.chars().all(|c| c.is_ascii()) == false
198 {
199 error_coded!(PfErrCode::Einval, "non ascii character in table_name: {}", tname);
200 }
201
202 let ret_val =
206 match cmd
207 {
208 PfCmdFile::Add{ file_path } =>
209 {
210 let mut b: PfrBuffer = PfrBuffer::new(Pfrb::PFRB_ADDRS);
211
212 unsafe
213 {
214 b.load_addr_from_file(file_path, 0)?;
215
216 table.create_table(self.fd.as_fd(), self.test)?;
217
218 table.add_addrs(self.fd.as_fd(), b, self.test)?
219 }
220 },
221 PfCmdFile::Delete{ file_path } =>
222 {
223 let mut b: PfrBuffer = PfrBuffer::new(Pfrb::PFRB_ADDRS);
224
225 unsafe
226 {
227 b.load_addr_from_file(file_path, 0)?;
228
229 table.del_addrs(self.fd.as_fd(), b)?
230 }
231 },
232 PfCmdFile::Test{ file_path } =>
233 {
234 let mut b: PfrBuffer = PfrBuffer::new(Pfrb::PFRB_ADDRS);
235
236 unsafe
237 {
238 b.load_addr_from_file(file_path, 0)?;
239
240 table.tst_addrs(self.fd.as_fd(), b)?
241 }
242 },
243 PfCmdFile::Flush =>
244 {
245 unsafe { table.fls_addrs(self.fd.as_fd())? }
246 }
247 }; return Ok(ret_val);
250 }
251
252 pub
270 fn pfctl_table<T: AsRef<str>>(&self, table_name: T, cmd: PfCmd) -> PfResult<i32>
271 {
272 let tname = table_name.as_ref();
273
274 let mut table: pfr_table = unsafe { pfr_table::new(tname)? };
275 if tname.len() >= common::PF_TABLE_NAME_SIZE
279 {
280 error_coded!(PfErrCode::Einval, "table name: '{}' is too long!", tname);
281 }
282
283 if tname.chars().all(|c| c.is_ascii()) == false
285 {
286 error_coded!(PfErrCode::Einval, "non ascii character in table_name: {}", tname);
287 }
288
289 let ret_val =
293 match cmd
294 {
295 PfCmd::Add{ hosts } =>
296 {
297 let mut b: PfrBuffer = PfrBuffer::new(Pfrb::PFRB_ADDRS);
298 for host in hosts
301 {
302 unsafe { b.load_addr_from_str(host, 0)? }; }
304
305 unsafe
306 {
307 table.create_table(self.fd.as_fd(), self.test)?;
308
309 table.add_addrs(self.fd.as_fd(), b, self.test)?
310 }
311 },
312 PfCmd::Delete{ hosts } =>
313 {
314 let mut b: PfrBuffer = PfrBuffer::new(Pfrb::PFRB_ADDRS);
315 for host in hosts
318 {
319 unsafe { b.load_addr_from_str(host, 0)? }; }
321
322 unsafe { table.del_addrs(self.fd.as_fd(), b)? }
323 },
324 PfCmd::Test{ hosts } =>
325 {
326 let mut b: PfrBuffer = PfrBuffer::new(Pfrb::PFRB_ADDRS);
327 for host in hosts
331 {
332 unsafe { b.load_addr_from_str(host, 1)? }; }
334
335 unsafe
336 {
337 table.tst_addrs(self.fd.as_fd(), b)?
338 }
339 },
340 PfCmd::Flush =>
341 {
342 unsafe { table.fls_addrs(self.fd.as_fd())? }
343 }
344 }; return Ok(ret_val);
347 }
348
349
350}
351
352#[cfg(test)]
353mod tests
354{
355 use crate::{ioctl::pfioc_table, pfr_addr::pf_addr};
356
357 use super::*;
358
359 #[test]
360 fn test_real_add()
361 {
362 let pf = Pf::new_test().unwrap();
363
364 pf.pfctl_table("test", PfCmd::Add{ hosts: vec!["192.168.2.1".to_string()] }).unwrap();
365 }
366
367 #[test]
368 fn test_real_check()
369 {
370 let pf = Pf::new_test().unwrap();
371
372 pf.pfctl_table("test", PfCmd::Test{ hosts: vec!["192.168.2.1".to_string()] }).unwrap();
373 }
374
375 #[test]
376 fn test_real_del()
377 {
378 let pf = Pf::new_test().unwrap();
379
380 pf.pfctl_table("test", PfCmd::Delete{ hosts: vec!["192.168.2.1".to_string()] }).unwrap();
381 }
382
383 #[test]
384 fn test_kill_state()
385 {
386 let pf = Pf::new_test().unwrap();
387
388 pf.pfctl_kill_state("192.168.2.104", None).unwrap();
389 }
390
391 #[test]
392 fn fake_test_real_kill_state()
393 {
394 let pf = Pf::new_test().unwrap();
395
396 pf.pfctl_kill_state("192.168.2.1", None).unwrap();
397 }
398
399 #[test]
400 fn fake_test_add()
401 {
402 let pf = Pf::new_test().unwrap();
403
404 pf.pfctl_table("test", PfCmd::Add{ hosts: vec!["192.168.2.1".to_string()] }).unwrap();
405 }
406
407 #[test]
408 fn fake_test2_add()
409 {
410 let pf = Pf::new_test().unwrap();
411
412 pf.pfctl_table("test", PfCmd::Add{ hosts: vec!["192.168.2.0/24".to_string()] }).unwrap();
413 }
414
415 #[test]
416 fn test_struct_sizes()
417 {
418 let s = std::mem::size_of::<pfioc_table>();
419 println!("sizeof(struct pfioc_table = 1104) ?= {}", s);
420 assert_eq!(1104, s);
421
422 let s = std::mem::size_of::<pfr_table>();
423 println!("sizeof(struct pfr_table = 1064) ?= {}", s);
424 assert_eq!(1064, s);
425
426 let s = std::mem::size_of::<pfioc_state_kill>();
427 println!("sizeof(struct pfioc_state_kill = 224) ?= {}", s);
428 assert_eq!(224, s);
429
430 let psk: pfioc_state_kill = unsafe {std::mem::zeroed()};
431 let s = std::mem::size_of_val(&psk.psk_af);
432 println!("sizeof(psk.psk_af) = {}", s);
433 assert_eq!(1, s);
434
435 let s = std::mem::size_of_val(&psk.psk_src);
436 println!("sizeof(psk.psk_src) = {}", s);
437 assert_eq!(56, s);
438
439 let s = std::mem::size_of_val(&psk.psk_dst);
440 println!("sizeof(psk.psk_dst) = {}", std::mem::size_of_val(&psk.psk_dst));
441 assert_eq!(56, s);
442
443 let s = std::mem::size_of_val(&psk.psk_ifname);
444 println!("sizeof(psk.psk_ifname) = {}", std::mem::size_of_val(&psk.psk_ifname));
445 assert_eq!(16, s);
446
447 let s = std::mem::size_of_val(&psk.psk_label);
448 println!("sizeof(psk.psk_label) = {}", std::mem::size_of_val(&psk.psk_label));
449 assert_eq!(64, s);
450
451 let s = std::mem::size_of_val(&psk.psk_killed);
452 println!("sizeof(psk.psk_killed) = {}", std::mem::size_of_val(&psk.psk_killed));
453 assert_eq!(4, s);
454
455 let s = std::mem::size_of_val(&psk.psk_proto);
456 println!("sizeof(psk.psk_proto) = {}", std::mem::size_of_val(&psk.psk_proto));
457 assert_eq!(4, s);
458
459 let s = std::mem::size_of_val(&psk.psk_pfcmp);
460 println!("sizeof(psk.psk_pfcmp) = {}", std::mem::size_of_val(&psk.psk_pfcmp));
461 assert_eq!(16, s);
462
463 let s = std::mem::size_of_val(&psk.psk_src.addr);
464 println!("sizeof(psk.psk_src.addr) = {}", std::mem::size_of_val(&psk.psk_src.addr));
465 assert_eq!(48, s);
466
467 let s = std::mem::size_of_val(&psk.psk_src.addr.v);
468 println!("sizeof(psk.psk_src.addr.v) = {}", std::mem::size_of_val(&psk.psk_src.addr.v));
469 assert_eq!(32, s);
470
471 let s = std::mem::size_of_val(&psk.psk_src.addr.p);
472 println!("sizeof(psk.psk_src.addr.p) = {}", std::mem::size_of_val(&psk.psk_src.addr.p));
473 assert_eq!(8, s);
474
475 let s = std::mem::size_of_val(&psk.psk_src.addr.tp);
476 println!("sizeof(psk.psk_src.addr.tp) = {}", std::mem::size_of_val(&psk.psk_src.addr.tp));
477 assert_eq!(1, s);
478
479 let s = std::mem::size_of_val(&psk.psk_src.addr.iflags);
480 println!("sizeof(psk.psk_src.addr.iflags) = {}", std::mem::size_of_val(&psk.psk_src.addr.iflags));
481 assert_eq!(1, s);
482 }
483
484 #[test]
504 fn test_unmask()
505 {
506 use std::net::Ipv4Addr;
507
508 fn create(ip: &'static str) -> libc::c_int
509 {
510 let ipv4: Ipv4Addr = ip.parse().unwrap();
511
512 let ip = pf_addr::from(ipv4.octets());
513
514 return ip.unmask(0);
515 }
516
517
518 assert_eq!(create("255.255.255.255"), 32);
519 assert_eq!(create("192.168.1.1"), 2);
520 assert_eq!(create("10.0.0.0"), 0);
521 assert_eq!(create("10.5.6.3"), 0);
522 assert_eq!(create("134.156.43.230"), 1);
523 assert_eq!(create("8.8.8.8"), 0);
524 assert_eq!(create("244.255.255.255"), 4);
525 assert_eq!(create("0.0.0.0"), 0);
526 assert_eq!(create("100.200.255.255"), 0);
527 }
528
529
530
531}