1use std::error::Error as StdError;
4use std::ffi::{CString, NulError};
5use std::fmt::Formatter;
6use std::net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr};
7use std::num::ParseIntError;
8
9use derive_more::{Display, From, Into};
10use ipset_derive::SetType;
11
12use crate::{binding, Session};
13
14pub struct ListMethod;
16
17pub struct BitmapMethod;
19
20pub struct HashMethod;
22
23#[derive(Copy, Clone)]
26pub enum IpDataType {
27 IPv4(libc::in_addr),
28 IPv6(libc::in6_addr),
29}
30
31impl IpDataType {
32 pub fn to_ip_addr(&self) -> IpAddr {
33 match self {
34 IpDataType::IPv4(addr) => {
35 let octets = addr.s_addr.to_ne_bytes();
36 IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]))
37 }
38 IpDataType::IPv6(addr) => {
39 let segments = [
40 u16::from_be_bytes([addr.s6_addr[0], addr.s6_addr[1]]),
41 u16::from_be_bytes([addr.s6_addr[2], addr.s6_addr[3]]),
42 u16::from_be_bytes([addr.s6_addr[4], addr.s6_addr[5]]),
43 u16::from_be_bytes([addr.s6_addr[6], addr.s6_addr[7]]),
44 u16::from_be_bytes([addr.s6_addr[8], addr.s6_addr[9]]),
45 u16::from_be_bytes([addr.s6_addr[10], addr.s6_addr[11]]),
46 u16::from_be_bytes([addr.s6_addr[12], addr.s6_addr[13]]),
47 u16::from_be_bytes([addr.s6_addr[14], addr.s6_addr[15]]),
48 ];
49 IpAddr::V6(Ipv6Addr::new(
50 segments[0],
51 segments[1],
52 segments[2],
53 segments[3],
54 segments[4],
55 segments[5],
56 segments[6],
57 segments[7],
58 ))
59 }
60 }
61 }
62}
63
64impl<T: SetType> SetData<T> for IpDataType {
65 fn set_data(&self, session: &Session<T>, from: Option<bool>) -> Result<(), Error> {
67 let (ip, family) = match self {
68 IpDataType::IPv4(ip) => (ip as *const _ as _, &binding::NFPROTO_IPV4 as *const _ as _),
69 IpDataType::IPv6(ip) => (ip as *const _ as _, &binding::NFPROTO_IPV6 as *const _ as _),
70 };
71 session.set_data(binding::ipset_opt_IPSET_OPT_FAMILY, family)?;
72 let opt = match from {
73 Some(true) => binding::ipset_opt_IPSET_OPT_IP_FROM,
74 Some(false) => binding::ipset_opt_IPSET_OPT_IP_TO,
75 None => binding::ipset_opt_IPSET_OPT_IP,
76 };
77 session.set_data(opt, ip)
78 }
79}
80
81impl Parse for IpDataType {
82 fn parse(&mut self, s: &str) -> Result<(), Error> {
83 let s = s.split(" ").next().ok_or(Error::DataParse(s.to_string()))?;
84 let ip: IpAddr = s.parse()?;
85 *self = ip.into();
86 Ok(())
87 }
88}
89
90impl Default for IpDataType {
91 fn default() -> Self {
92 IpDataType::IPv4(libc::in_addr { s_addr: 0 })
93 }
94}
95
96impl From<Ipv4Addr> for IpDataType {
97 fn from(ip: Ipv4Addr) -> Self {
98 IpDataType::IPv4(libc::in_addr {
99 s_addr: u32::from(ip).to_be(),
100 })
101 }
102}
103
104impl From<Ipv6Addr> for IpDataType {
105 fn from(ip: Ipv6Addr) -> Self {
106 IpDataType::IPv6(libc::in6_addr {
107 s6_addr: ip.octets(),
108 })
109 }
110}
111
112impl From<IpAddr> for IpDataType {
113 fn from(ip: IpAddr) -> Self {
114 match ip {
115 IpAddr::V4(v4) => v4.into(),
116 IpAddr::V6(v6) => v6.into(),
117 }
118 }
119}
120
121impl From<&IpDataType> for IpAddr {
122 fn from(value: &IpDataType) -> Self {
123 match value {
124 IpDataType::IPv4(ip) => IpAddr::from(ip.s_addr.to_ne_bytes()),
125 IpDataType::IPv6(ip) => IpAddr::from(ip.s6_addr),
126 }
127 }
128}
129
130impl Display for IpDataType {
131 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132 let ip: IpAddr = self.into();
133 write!(f, "{}", ip)
134 }
135}
136
137#[derive(Default, From, Into)]
139pub struct NetDataType {
140 ip: IpDataType,
141 cidr: u8,
142}
143
144impl NetDataType {
145 pub fn new(ip: impl Into<IpDataType>, cidr: u8) -> Self {
147 Self {
148 ip: ip.into(),
149 cidr,
150 }
151 }
152
153 pub fn ip(&self) -> IpAddr {
155 (&self.ip).into()
156 }
157
158 pub fn cidr(&self) -> u8 {
160 self.cidr
161 }
162}
163
164impl<T: SetType> SetData<T> for NetDataType {
165 fn set_data(&self, session: &Session<T>, from: Option<bool>) -> Result<(), Error> {
166 self.ip.set_data(session, from)?;
167 session.set_data(
168 binding::ipset_opt_IPSET_OPT_CIDR,
169 &self.cidr as *const _ as _,
170 )
171 }
172}
173
174impl Parse for NetDataType {
175 fn parse(&mut self, s: &str) -> Result<(), Error> {
176 let mut ss = s.split("/");
177 if let Some(ip) = ss.next() {
178 let ip: IpAddr = ip.parse()?;
179 self.ip = ip.into();
180 }
181 if let Some(cidr) = ss.next() {
182 self.cidr = cidr.parse()?;
183 } else {
184 self.cidr = 32;
185 }
186 Ok(())
187 }
188}
189
190impl Display for NetDataType {
191 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
192 write!(f, "{}/{}", self.ip, self.cidr)
193 }
194}
195
196#[derive(Default, From, Into)]
198pub struct MacDataType {
199 mac: [u8; 6],
200}
201
202impl Parse for MacDataType {
203 fn parse(&mut self, s: &str) -> Result<(), Error> {
204 let mac: Vec<u8> = s
205 .split(":")
206 .filter_map(|s| u8::from_str_radix(s, 16).ok())
207 .collect();
208 if mac.len() != 6 {
209 Err(Error::InvalidOutput(s.into()))
210 } else {
211 self.mac.copy_from_slice(mac.as_slice());
212 Ok(())
213 }
214 }
215}
216
217impl<T: SetType> SetData<T> for MacDataType {
218 fn set_data(&self, session: &Session<T>, _from: Option<bool>) -> Result<(), Error> {
219 session.set_data(binding::ipset_opt_IPSET_OPT_ETHER, self.mac.as_ptr() as _)
220 }
221}
222
223impl Display for MacDataType {
224 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
225 let data = self.mac.map(|d| format!("{:02x}", d)).join(":");
226 write!(f, "{}", data)
227 }
228}
229
230#[derive(Default, From, Into)]
232pub struct PortDataType {
233 port: u16,
234}
235
236impl<T: SetType> SetData<T> for PortDataType {
237 fn set_data(&self, session: &Session<T>, from: Option<bool>) -> Result<(), Error> {
238 let opt = match from {
239 Some(true) => binding::ipset_opt_IPSET_OPT_PORT_FROM,
240 Some(false) => binding::ipset_opt_IPSET_OPT_PORT_TO,
241 None => binding::ipset_opt_IPSET_OPT_PORT,
242 };
243 session.set_data(opt, &self.port as *const _ as _)
244 }
245}
246
247impl Parse for PortDataType {
248 fn parse(&mut self, s: &str) -> Result<(), Error> {
249 self.port = s.parse()?;
250 Ok(())
251 }
252}
253
254impl Display for PortDataType {
255 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
256 write!(f, "{}", self.port)
257 }
258}
259
260#[derive(Default)]
262pub struct IfaceDataType {
263 name: CString,
264}
265
266impl From<String> for IfaceDataType {
267 fn from(value: String) -> Self {
268 Self {
269 name: CString::new(value).unwrap(),
270 }
271 }
272}
273
274impl From<IfaceDataType> for String {
275 fn from(value: IfaceDataType) -> Self {
276 value.name.to_string_lossy().to_string()
277 }
278}
279
280impl Parse for IfaceDataType {
281 fn parse(&mut self, s: &str) -> Result<(), Error> {
282 self.name = CString::new(s)?;
283 Ok(())
284 }
285}
286
287impl<T: SetType> SetData<T> for IfaceDataType {
288 fn set_data(&self, session: &Session<T>, _from: Option<bool>) -> Result<(), Error> {
289 session.set_data(binding::ipset_opt_IPSET_OPT_IFACE, self.name.as_ptr() as _)
290 }
291}
292
293impl Display for IfaceDataType {
294 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
295 write!(f, "{}", self.name.to_string_lossy())
296 }
297}
298
299#[derive(Default, From, Into)]
301pub struct MarkDataType {
302 mark: u32,
303}
304
305impl Parse for MarkDataType {
306 fn parse(&mut self, s: &str) -> Result<(), Error> {
307 self.mark = s.parse()?;
308 Ok(())
309 }
310}
311
312impl<T: SetType> SetData<T> for MarkDataType {
313 fn set_data(&self, session: &Session<T>, _: Option<bool>) -> Result<(), Error> {
314 session.set_data(
315 binding::ipset_opt_IPSET_OPT_MARK,
316 &self.mark as *const _ as _,
317 )
318 }
319}
320
321impl Display for MarkDataType {
322 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
323 write!(f, "{}", self.mark)
324 }
325}
326
327#[derive(Default)]
329pub struct SetDataType {
330 name: CString,
331}
332
333impl From<String> for SetDataType {
334 fn from(value: String) -> Self {
335 Self {
336 name: CString::new(value).unwrap(),
337 }
338 }
339}
340
341impl From<SetDataType> for String {
342 fn from(value: SetDataType) -> Self {
343 value.name.to_string_lossy().to_string()
344 }
345}
346
347impl Parse for SetDataType {
348 fn parse(&mut self, s: &str) -> Result<(), Error> {
349 self.name = CString::new(s)?;
350 Ok(())
351 }
352}
353
354impl<T: SetType> SetData<T> for SetDataType {
355 fn set_data(&self, session: &Session<T>, _: Option<bool>) -> Result<(), Error> {
356 session.set_data(binding::ipset_opt_IPSET_OPT_NAME, self.name.as_ptr() as _)
357 }
358}
359
360impl Display for SetDataType {
361 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
362 write!(f, "{}", self.name.to_string_lossy())
363 }
364}
365
366macro_rules! impl_name {
367 ($($types:ident),+) => {
368 impl<$($types,)+> TypeName for ($($types),+)
369 where $($types:TypeName),+ {
370 fn name() -> String {
371 [$($types::name(),)+].join(",")
372 }
373 }
374 };
375
376 ($ty:ty, $name:expr) => {
377 impl TypeName for $ty {
378 fn name() -> String {
379 $name.into()
380 }
381 }
382 }
383}
384
385impl_name!(ListMethod, "list");
386impl_name!(BitmapMethod, "bitmap");
387impl_name!(HashMethod, "hash");
388impl_name!(IpDataType, "ip");
389impl_name!(NetDataType, "net");
390impl_name!(MacDataType, "mac");
391impl_name!(PortDataType, "port");
392impl_name!(IfaceDataType, "iface");
393impl_name!(MarkDataType, "mark");
394impl_name!(SetDataType, "set");
395impl_name!(A, B);
396impl_name!(A, B, C);
397
398macro_rules! impl_set_data {
399 ($($types:ident),+) => {
400 #[allow(non_snake_case)]
401 impl<T, $($types),+> SetData<T> for ($($types),+)
402 where T:SetType,
403 $($types:SetData<T>),+ {
404 fn set_data(&self, session:&Session<T>, from:Option<bool>) -> Result<(), Error> {
405 let ($($types),+) = self;
406 $($types.set_data(session, from)?;)+
407 Ok(())
408 }
409 }
410 };
411}
412
413impl_set_data!(A, B);
414impl_set_data!(A, B, C);
415
416macro_rules! impl_parse {
417 ($($types:ident),+) => {
418 #[allow(non_snake_case)]
419 impl<$($types),+> Parse for ($($types),+)
420 where $($types:Parse),+ {
421 fn parse(&mut self, s:&str) -> Result<(), Error> {
422 let ($($types),+) = self;
423 let mut ss = s.split(",");
424 $(
425 if let Some(item) = ss.next() {
426 $types.parse(item)?;
427 } else {
428 return Err(Error::InvalidOutput(s.into()));
429 };
430 )+
431 Ok(())
432 }
433 }
434 };
435}
436
437impl_parse!(A, B);
438impl_parse!(A, B, C);
439
440pub trait SetType: Sized {
445 type Method;
446 type DataType: SetData<Self> + Parse + Default;
447}
448
449pub trait TypeName {
451 fn name() -> String;
452}
453
454pub trait SetData<T: SetType> {
456 fn set_data(&self, session: &Session<T>, from: Option<bool>) -> Result<(), Error>;
457}
458
459pub trait Parse {
461 fn parse(&mut self, s: &str) -> Result<(), Error>;
462}
463
464pub trait ToCString {
466 fn to_cstring() -> CString;
467}
468
469impl<T> ToCString for T
470where
471 T: SetType,
472 T::Method: TypeName,
473 T::DataType: TypeName,
474{
475 fn to_cstring() -> CString {
476 CString::new([T::Method::name(), T::DataType::name()].join(":")).unwrap()
477 }
478}
479
480#[derive(Debug, From, Display)]
482pub enum Error {
483 #[from(ignore)]
484 #[display("DataSet:['{}', {}", _0, _1)]
485 DataSet(String, bool),
486 #[from(ignore)]
487 #[display("Cmd:['{}', {}", _0, _1)]
488 Cmd(String, bool),
489 #[from(ignore)]
490 #[display("TypeGet:['{}', {}", _0, _1)]
491 TypeGet(String, bool),
492 #[from(ignore)]
493 InvalidOutput(String),
494 #[from(ignore)]
495 SaveRestore(String),
496 AddrParse(AddrParseError),
497 ParseInt(ParseIntError),
498 Nul(NulError),
499 #[from(ignore)]
500 CAOption(String),
501 #[from(ignore)]
502 DataParse(String),
503}
504
505impl Error {
506 pub(crate) fn cmd_contains(&self, m: &str) -> bool {
507 if let Error::Cmd(message, _) = self {
508 message.contains(m)
509 } else {
510 false
511 }
512 }
513
514 pub fn is_error(&self) -> bool {
515 match self {
516 Error::DataSet(_, error) => *error,
517 Error::Cmd(_, error) => *error,
518 Error::TypeGet(_, error) => *error,
519 _ => false,
520 }
521 }
522}
523
524impl StdError for Error {}
525
526#[derive(SetType)]
529pub struct BitmapIp;
530
531#[derive(SetType)]
534pub struct BitmapIpMac;
535
536#[derive(SetType)]
538pub struct BitmapPort;
539
540#[derive(SetType)]
543pub struct HashIp;
544
545#[derive(SetType)]
548pub struct HashMac;
549
550#[derive(SetType)]
553pub struct HashIpMac;
554
555#[derive(SetType)]
558pub struct HashNet;
559
560#[derive(SetType)]
565pub struct HashNetNet;
566
567#[derive(SetType)]
570pub struct HashIpPort;
571
572#[derive(SetType)]
576pub struct HashNetPort;
577
578#[derive(SetType)]
581pub struct HashIpPortIp;
582
583#[derive(SetType)]
587pub struct HashIpPortNet;
588
589#[derive(SetType)]
591pub struct HashIpMark;
592
593#[derive(SetType)]
596pub struct HashNetPortNet;
597
598#[derive(SetType)]
600pub struct HashNetIface;
601
602#[derive(SetType)]
604pub struct ListSet;
605
606pub trait WithNetmask {}
607
608impl WithNetmask for BitmapMethod {}
609
610impl WithNetmask for HashMethod {}
611
612#[allow(unused_imports)]
613mod tests {
614 use std::net::IpAddr;
615
616 use crate::types::{
617 BitmapIp, BitmapIpMac, BitmapPort, HashIp, HashIpMac, HashIpMark, HashIpPort, HashIpPortIp,
618 HashIpPortNet, HashMac, HashNet, HashNetIface, HashNetNet, HashNetPort, HashNetPortNet,
619 ListSet,
620 };
621 use crate::types::{
622 IfaceDataType, IpDataType, MacDataType, MarkDataType, NetDataType, Parse, PortDataType,
623 SetDataType, ToCString,
624 };
625
626 #[test]
627 fn test_ip() {
628 let ip: IpAddr = "127.0.0.1".parse().unwrap();
629 let mut data: IpDataType = ip.into();
630 let ip1: IpAddr = (&data).into();
631 assert_eq!(ip, ip1);
632 assert_eq!("127.0.0.1", format!("{}", data));
633 data.parse("192.168.3.1").unwrap();
634 assert_eq!("192.168.3.1", format!("{}", data));
635 }
636
637 #[test]
638 fn test_net() {
639 let ip: IpAddr = "127.0.0.1".parse().unwrap();
640 let mut net = NetDataType::new(ip, 8);
641 assert_eq!("127.0.0.1/8", format!("{}", net));
642 net.parse("192.168.3.1/24").unwrap();
643 assert_eq!("192.168.3.1/24", format!("{}", net));
644 }
645
646 #[test]
647 fn test_mac() {
648 let mut mac: MacDataType = [124u8, 24u8, 32u8, 129u8, 84u8, 223u8].into();
649 assert_eq!("7c:18:20:81:54:df", format!("{}", mac));
650 mac.parse("00:15:5d:37:d9:2f").unwrap();
651 assert_eq!("00:15:5d:37:d9:2f", format!("{}", mac));
652 }
653
654 #[test]
655 fn test_mark() {
656 let mut mark: MarkDataType = 32u32.into();
657 assert_eq!("32", format!("{}", mark));
658 mark.parse("123").unwrap();
659 assert_eq!("123", format!("{}", 123));
660 }
661
662 #[test]
663 fn test_port() {
664 let mut port: PortDataType = 1235u16.into();
665 assert_eq!("1235", format!("{}", port));
666 port.parse("1234").unwrap();
667 assert_eq!("1234", format!("{}", port));
668 }
669
670 #[test]
671 fn test_iface() {
672 let mut iface: IfaceDataType = String::from("abc").into();
673 assert_eq!("abc", format!("{}", iface));
674 iface.parse("test").unwrap();
675 assert_eq!("test", format!("{}", iface));
676 }
677
678 #[test]
679 fn test_set() {
680 let mut set: SetDataType = String::from("abc").into();
681 assert_eq!("abc", format!("{}", set));
682 set.parse("test").unwrap();
683 assert_eq!("test", format!("{}", set));
684 }
685
686 #[test]
687 fn test_ip_port_ip() {
688 let mut data = (
689 IpDataType::default(),
690 PortDataType::default(),
691 IpDataType::default(),
692 );
693 data.parse("192.168.3.1,8080,192.168.3.2").unwrap();
694 assert_eq!("192.168.3.1", format!("{}", data.0));
695 assert_eq!("8080", format!("{}", data.1));
696 assert_eq!("192.168.3.2", format!("{}", data.2));
697 }
698
699 #[test]
700 fn test_type_name() {
701 assert_eq!(HashIp::to_cstring().to_str().unwrap(), "hash:ip");
702 assert_eq!(
703 HashNetIface::to_cstring().to_str().unwrap(),
704 "hash:net,iface"
705 );
706 assert_eq!(HashNetNet::to_cstring().to_str().unwrap(), "hash:net,net");
707 assert_eq!(HashNetPort::to_cstring().to_str().unwrap(), "hash:net,port");
708 assert_eq!(HashNet::to_cstring().to_str().unwrap(), "hash:net");
709 assert_eq!(HashIpPort::to_cstring().to_str().unwrap(), "hash:ip,port");
710 assert_eq!(HashIpMark::to_cstring().to_str().unwrap(), "hash:ip,mark");
711 assert_eq!(
712 HashIpPortNet::to_cstring().to_str().unwrap(),
713 "hash:ip,port,net"
714 );
715 assert_eq!(HashIpMac::to_cstring().to_str().unwrap(), "hash:ip,mac");
716 assert_eq!(
717 HashIpPortIp::to_cstring().to_str().unwrap(),
718 "hash:ip,port,ip"
719 );
720 assert_eq!(
721 HashNetPortNet::to_cstring().to_str().unwrap(),
722 "hash:net,port,net"
723 );
724 assert_eq!(HashMac::to_cstring().to_str().unwrap(), "hash:mac");
725 assert_eq!(ListSet::to_cstring().to_str().unwrap(), "list:set");
726 assert_eq!(BitmapPort::to_cstring().to_str().unwrap(), "bitmap:port");
727 assert_eq!(BitmapIp::to_cstring().to_str().unwrap(), "bitmap:ip");
728 assert_eq!(BitmapIpMac::to_cstring().to_str().unwrap(), "bitmap:ip,mac");
729 }
730}
731
732pub enum EnvOption {
734 Sorted,
736 Quiet,
738 Resolve,
740 Exist,
742 ListSetName,
744 ListHeader,
746}
747
748impl EnvOption {
749 pub(crate) fn to_option(self) -> binding::ipset_envopt {
751 match self {
752 EnvOption::Sorted => binding::ipset_envopt_IPSET_ENV_SORTED,
753 EnvOption::Quiet => binding::ipset_envopt_IPSET_ENV_QUIET,
754 EnvOption::Resolve => binding::ipset_envopt_IPSET_ENV_RESOLVE,
755 EnvOption::Exist => binding::ipset_envopt_IPSET_ENV_EXIST,
756 EnvOption::ListSetName => binding::ipset_envopt_IPSET_ENV_LIST_SETNAME,
757 EnvOption::ListHeader => binding::ipset_envopt_IPSET_ENV_LIST_HEADER,
758 }
759 }
760}
761
762#[derive(Debug)]
764pub enum AddOption {
765 Timeout(u32),
770 Bytes(u64),
772 Packets(u64),
774 SkbMark(u32, u32),
777 SkbPrio(u16, u16),
780 SkbQueue(u16),
782 Comment(String),
788 Nomatch,
796}
797
798pub struct NormalListResult<T: SetType> {
799 pub name: String,
800 pub typ: String,
801 pub revision: u32,
802 pub header: ListHeader,
803 pub size_in_memory: u32,
804 pub references: u32,
805 pub entry_size: u32,
806 pub items: Option<Vec<(T::DataType, Option<Vec<AddOption>>)>>,
807}
808
809impl<T: SetType> Default for NormalListResult<T> {
810 fn default() -> Self {
811 Self {
812 name: "".to_string(),
813 typ: "".to_string(),
814 revision: 0,
815 header: Default::default(),
816 size_in_memory: 0,
817 references: 0,
818 entry_size: 0,
819 items: None,
820 }
821 }
822}
823
824pub enum ListResult<T: SetType> {
825 Normal(NormalListResult<T>),
826 Terse(Vec<String>),
827}
828
829impl<T: SetType> NormalListResult<T> {
830 pub(crate) fn update_from_str(&mut self, line: &str) -> Result<(), Error> {
831 if self.items.is_none() {
832 let fields: Vec<_> = line.splitn(2, ":").collect();
833 match fields[0] {
834 "Name" => {
835 self.name = fields[1].trim().to_string();
836 }
837 "Type" => {
838 self.typ = fields[1].trim().to_string();
839 }
840 "Revision" => {
841 self.revision = fields[1].trim().parse()?;
842 }
843 "Header" => {
844 self.header = ListHeader::from_str(fields[1].trim());
845 }
846 "Size in memory" => {
847 self.size_in_memory = fields[1].trim().parse()?;
848 }
849 "References" => {
850 self.references = fields[1].trim().parse()?;
851 }
852 "Number of entries" => {
853 self.entry_size = fields[1].trim().parse()?;
854 }
855 "Members" => {
856 self.items = Some(Vec::new());
857 }
858 _ => {
859 unreachable!("unexpected {}", fields[0])
860 }
861 }
862 } else {
863 let fields: Vec<_> = line.split_ascii_whitespace().collect();
864 let mut data = T::DataType::default();
865 let mut add_options = None;
866 if fields.len() == 0 || data.parse(fields[0]).is_err() {
867 return Err(Error::InvalidOutput(String::from(line)));
868 } else if fields.len() > 1 {
869 let mut i = 1;
870 let mut options = vec![];
871 while i < fields.len() {
872 match fields[i] {
873 "timeout" => {
874 options.push(AddOption::Timeout(fields[i + 1].parse()?));
875 }
876 "packets" => {
877 options.push(AddOption::Packets(fields[i + 1].parse()?));
878 }
879 "bytes" => {
880 options.push(AddOption::Bytes(fields[i + 1].trim().replace("\0", "").parse()?));
881 }
882 "comment" => {
883 options.push(AddOption::Comment(fields[i + 1].to_string()));
884 }
885 "skbmark" => {
886 let values: Vec<_> = fields[i + 1].split('/').collect();
887 let v0 =
888 u32::from_str_radix(values[0].strip_prefix("0x").unwrap(), 16)?;
889 let v1 = if values.len() > 1 {
890 u32::from_str_radix(values[1].strip_prefix("0x").unwrap(), 16)?
891 } else {
892 u32::MAX
893 };
894 options.push(AddOption::SkbMark(v0, v1));
895 }
896 "skbprio" => {
897 let values: Vec<_> = fields[i + 1].split(':').collect();
898 let v0 = u16::from_str_radix(values[0], 16)?;
899 let v1 = u16::from_str_radix(values[1], 16)?;
900 options.push(AddOption::SkbPrio(v0, v1));
901 }
902 "skbqueue" => {
903 options.push(AddOption::SkbQueue(fields[i + 1].parse()?));
904 }
905 "nomatch" => {
906 options.push(AddOption::Nomatch);
907 i += 1;
908 continue;
909 }
910 _ => {
911 unreachable!("{} not supported", fields[i]);
912 }
913 }
914 i += 2
915 }
916 add_options = Some(options);
917 }
918 self.items.as_mut().unwrap().push((data, add_options));
919 }
920 Ok(())
921 }
922}
923
924#[derive(Default, Debug)]
925pub struct ListHeader {
926 ipv6: bool,
927 hash_size: u32,
928 bucket_size: Option<u32>,
929 max_elem: u32,
930 counters: bool,
931 comment: bool,
932 skbinfo: bool,
933 initval: Option<u32>
934}
935
936impl ListHeader {
937 pub fn from_str(s: &str) -> Self {
938 let s: Vec<_> = s.split_whitespace().collect();
939 let mut header = ListHeader::default();
940 let mut i = 0;
941 while i < s.len() {
942 match s[i] {
943 "family" => {
944 header.ipv6 = s[i + 1] == "inet6";
945 i += 2;
946 }
947 "hashsize" => {
948 header.hash_size = s[i + 1].parse().unwrap();
949 i += 2;
950 }
951 "bucketsize" => {
952 header.bucket_size = Some(s[i + 1].parse().unwrap());
953 i += 2;
954 },
955 "maxelem" => {
956 header.max_elem = s[i + 1].parse().unwrap();
957 i += 2;
958 }
959 "counters" => {
960 header.counters = true;
961 i += 1;
962 }
963 "comment" => {
964 header.comment = true;
965 i += 1;
966 }
967 "skbinfo" => {
968 header.skbinfo = true;
969 i += 1;
970 }
971 "initval" => {
972 if let Some(initval) = s[i + 1].strip_prefix("0x") {
973 header.initval = Some(u32::from_str_radix(initval, 16).unwrap());
974 }
975 i += 2;
976 }
977
978 _ => {
979 unreachable!("{} not supported", s[i]);
980 }
981 }
982 }
983 header
984 }
985}