5959
6060#![ deny( rust_2018_idioms) ]
6161
62- #[ macro_use]
63- pub extern crate error_chain;
64-
6562use std:: {
6663 ffi:: CStr ,
64+ fmt:: Display ,
6765 fs:: File ,
6866 mem,
6967 os:: unix:: io:: { AsRawFd , RawFd } ,
7068} ;
69+ use thiserror:: Error ;
7170
7271pub use ipnetwork;
7372
@@ -92,40 +91,89 @@ pub use crate::ruleset::*;
9291mod transaction;
9392pub use crate :: transaction:: * ;
9493
95- mod errors {
96- error_chain ! {
97- errors {
98- DeviceOpenError ( s: & ' static str ) {
99- description( "Unable to open PF device file" )
100- display( "Unable to open PF device file at '{}'" , s)
101- }
102- InvalidArgument ( s: & ' static str ) {
103- display( "Invalid argument: {}" , s)
104- }
105- StateAlreadyActive {
106- description( "Target state is already active" )
107- }
108- InvalidRuleCombination ( s: String ) {
109- description( "Rule contains incompatible values" )
110- display( "Incompatible values in rule: {}" , s)
111- }
112- AnchorDoesNotExist {
113- display( "Anchor does not exist" )
114- }
94+ #[ derive( Error , Debug ) ]
95+ #[ non_exhaustive]
96+ pub enum ErrorSource {
97+ #[ error( "Unable to open PF device file at {}" , _0) ]
98+ DeviceOpen ( & ' static str , #[ source] :: std:: io:: Error ) ,
99+
100+ #[ error( "Lower port is greater than upper port." ) ]
101+ LowerIsGreaterPort ,
102+
103+ #[ error( "String does not fit destination" ) ]
104+ StrCopyNotFits ,
105+
106+ #[ error( "String has null byte" ) ]
107+ StrCopyNullByte ,
108+
109+ #[ error( "Target state is already active" ) ]
110+ StateAlreadyActive ( #[ source] :: std:: io:: Error ) ,
111+
112+ #[ error( "Incompatible values in rule: {}" , _0) ]
113+ InvalidRuleCombination ( String ) ,
114+
115+ #[ error( "Anchor does not exist" ) ]
116+ AnchorDoesNotExist ,
117+
118+ #[ error( "Cstr not null terminated" ) ]
119+ CstrNotTerminated ,
120+
121+ #[ error( "Ioctl Error" ) ]
122+ Ioctl ( #[ from] :: std:: io:: Error ) ,
123+ }
124+
125+ #[ derive( Error , Debug ) ]
126+ pub struct Error {
127+ pub info : Option < ErrorInfo > ,
128+ #[ source]
129+ pub source : ErrorSource ,
130+ }
131+
132+ impl Error {
133+ fn new ( info : ErrorInfo , err : Error ) -> Self {
134+ Self {
135+ info : Some ( info) ,
136+ source : err. source ,
115137 }
116- foreign_links {
117- IoctlError ( :: std:: io:: Error ) ;
138+ }
139+ }
140+
141+ impl Display for Error {
142+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
143+ if let Some ( info) = self . info . as_ref ( ) {
144+ info. fmt ( f) ?;
118145 }
146+ Ok ( ( ) )
119147 }
120148}
121- pub use crate :: errors:: * ;
122149
123- /// Returns the given input result, except if it is an `Err` matching the given `ErrorKind`,
150+ impl From < ErrorSource > for Error {
151+ fn from ( source : ErrorSource ) -> Self {
152+ Self { info : None , source }
153+ }
154+ }
155+
156+ #[ derive( Error , Debug ) ]
157+ #[ non_exhaustive]
158+ pub enum ErrorInfo {
159+ #[ error( "Invalid anchor name" ) ]
160+ InvalidAnchorName ,
161+
162+ #[ error( "Incompatible interface name" ) ]
163+ IncompatibleInterfaceName ,
164+
165+ #[ error( "Invalid route target" ) ]
166+ InvalidRouteTarget ,
167+ }
168+
169+ pub type Result < T > = :: std:: result:: Result < T , Error > ;
170+
171+ /// Returns the given input result, except if it is an `Err` matching the given `Error`,
124172/// then it returns `Ok(())` instead, so the error is ignored.
125173macro_rules! ignore_error_kind {
126174 ( $result: expr, $kind: pat) => {
127175 match $result {
128- Err ( $crate:: Error ( $kind, _ ) ) => Ok ( ( ) ) ,
176+ Err ( $crate:: Error { source : $kind, .. } ) => Ok ( ( ) ) ,
129177 result => result,
130178 }
131179 } ;
@@ -148,7 +196,9 @@ use crate::conversion::*;
148196
149197/// Internal function to safely compare Rust string with raw C string slice
150198fn compare_cstr_safe ( s : & str , cchars : & [ std:: os:: raw:: c_char ] ) -> Result < bool > {
151- ensure ! ( cchars. iter( ) . any( |& c| c == 0 ) , "Not null terminated" ) ;
199+ if !( cchars. iter ( ) . any ( |& c| c == 0 ) ) {
200+ return Err ( ErrorSource :: CstrNotTerminated . into ( ) ) ;
201+ }
152202 let cs = unsafe { CStr :: from_ptr ( cchars. as_ptr ( ) ) } ;
153203 Ok ( s. as_bytes ( ) == cs. to_bytes ( ) )
154204}
@@ -174,7 +224,7 @@ impl PfCtl {
174224 /// Same as `enable`, but `StateAlreadyActive` errors are supressed and exchanged for
175225 /// `Ok(())`.
176226 pub fn try_enable ( & mut self ) -> Result < ( ) > {
177- ignore_error_kind ! ( self . enable( ) , ErrorKind :: StateAlreadyActive )
227+ ignore_error_kind ! ( self . enable( ) , crate :: ErrorSource :: StateAlreadyActive ( _ ) )
178228 }
179229
180230 /// Tries to disable PF. If the firewall is already disabled it will return an
@@ -186,7 +236,7 @@ impl PfCtl {
186236 /// Same as `disable`, but `StateAlreadyActive` errors are supressed and exchanged for
187237 /// `Ok(())`.
188238 pub fn try_disable ( & mut self ) -> Result < ( ) > {
189- ignore_error_kind ! ( self . disable( ) , ErrorKind :: StateAlreadyActive )
239+ ignore_error_kind ! ( self . disable( ) , crate :: ErrorSource :: StateAlreadyActive ( _ ) )
190240 }
191241
192242 /// Tries to determine if PF is enabled or not.
@@ -201,7 +251,7 @@ impl PfCtl {
201251
202252 pfioc_rule. rule . action = kind. into ( ) ;
203253 name. try_copy_to ( & mut pfioc_rule. anchor_call [ ..] )
204- . chain_err ( || ErrorKind :: InvalidArgument ( "Invalid anchor name" ) ) ?;
254+ . map_err ( |e| Error :: new ( ErrorInfo :: InvalidAnchorName , e ) ) ?;
205255
206256 ioctl_guard ! ( ffi:: pf_insert_rule( self . fd( ) , & mut pfioc_rule) ) ?;
207257 Ok ( ( ) )
@@ -210,7 +260,10 @@ impl PfCtl {
210260 /// Same as `add_anchor`, but `StateAlreadyActive` errors are supressed and exchanged for
211261 /// `Ok(())`.
212262 pub fn try_add_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
213- ignore_error_kind ! ( self . add_anchor( name, kind) , ErrorKind :: StateAlreadyActive )
263+ ignore_error_kind ! (
264+ self . add_anchor( name, kind) ,
265+ crate :: ErrorSource :: StateAlreadyActive ( _)
266+ )
214267 }
215268
216269 pub fn remove_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
@@ -224,7 +277,7 @@ impl PfCtl {
224277 pub fn try_remove_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
225278 ignore_error_kind ! (
226279 self . remove_anchor( name, kind) ,
227- ErrorKind :: AnchorDoesNotExist
280+ crate :: ErrorSource :: AnchorDoesNotExist
228281 )
229282 }
230283
@@ -236,7 +289,7 @@ impl PfCtl {
236289 pfioc_rule. ticket = utils:: get_ticket ( self . fd ( ) , & anchor, AnchorKind :: Filter ) ?;
237290 anchor
238291 . try_copy_to ( & mut pfioc_rule. anchor [ ..] )
239- . chain_err ( || ErrorKind :: InvalidArgument ( "Invalid anchor name" ) ) ?;
292+ . map_err ( |e| Error :: new ( ErrorInfo :: InvalidAnchorName , e ) ) ?;
240293 rule. try_copy_to ( & mut pfioc_rule. rule ) ?;
241294
242295 pfioc_rule. action = ffi:: pfvar:: PF_CHANGE_ADD_TAIL as u32 ;
@@ -287,7 +340,7 @@ impl PfCtl {
287340
288341 /// Clear states created by rules in anchor.
289342 /// Returns total number of removed states upon success, otherwise
290- /// ErrorKind ::AnchorDoesNotExist if anchor does not exist.
343+ /// Error ::AnchorDoesNotExist if anchor does not exist.
291344 pub fn clear_states ( & mut self , anchor_name : & str , kind : AnchorKind ) -> Result < u32 > {
292345 let pfsync_states = self . get_states ( ) ?;
293346 if !pfsync_states. is_empty ( ) {
@@ -317,7 +370,7 @@ impl PfCtl {
317370 let mut pfioc_state_kill = unsafe { mem:: zeroed :: < ffi:: pfvar:: pfioc_state_kill > ( ) } ;
318371 interface
319372 . try_copy_to ( & mut pfioc_state_kill. psk_ifname )
320- . chain_err ( || ErrorKind :: InvalidArgument ( "Incompatible interface name" ) ) ?;
373+ . map_err ( |e| Error :: new ( ErrorInfo :: IncompatibleInterfaceName , e ) ) ?;
321374 ioctl_guard ! ( ffi:: pf_clear_states( self . fd( ) , & mut pfioc_state_kill) ) ?;
322375 // psk_af holds the number of killed states
323376 Ok ( pfioc_state_kill. psk_af as u32 )
@@ -342,7 +395,7 @@ impl PfCtl {
342395 /// The return value from closure is transparently passed to the caller.
343396 ///
344397 /// - Returns Result<R> from call to closure on match.
345- /// - Returns `ErrorKind ::AnchorDoesNotExist` on mismatch, the closure is not called in that
398+ /// - Returns `Error ::AnchorDoesNotExist` on mismatch, the closure is not called in that
346399 /// case.
347400 fn with_anchor_rule < F , R > ( & self , name : & str , kind : AnchorKind , f : F ) -> Result < R >
348401 where
@@ -359,7 +412,7 @@ impl PfCtl {
359412 return f ( pfioc_rule) ;
360413 }
361414 }
362- bail ! ( ErrorKind :: AnchorDoesNotExist ) ;
415+ Err ( ErrorSource :: AnchorDoesNotExist . into ( ) )
363416 }
364417
365418 /// Returns global number of states created by all stateful rules (see keep_state)
@@ -419,7 +472,10 @@ mod tests {
419472 let cchars: & [ i8 ] = unsafe { mem:: transmute ( cstr. as_bytes ( ) ) } ;
420473 assert_matches ! (
421474 compare_cstr_safe( "Hello" , cchars) ,
422- Err ( ref e) if e. description( ) == "Not null terminated"
475+ Err ( Error {
476+ source: ErrorSource :: CstrNotTerminated ,
477+ ..
478+ } )
423479 ) ;
424480 }
425481
0 commit comments