5959
6060#![ deny( rust_2018_idioms) ]
6161
62- #[ macro_use]
63- pub extern crate error_chain;
64-
6562use std:: {
6663 ffi:: CStr ,
64+ fmt:: { Debug , 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,117 @@ 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" )
94+ #[ derive( Error , Debug ) ]
95+ #[ non_exhaustive]
96+ pub enum Error {
97+ #[ error( "Unable to open PF device file at {}" , _0) ]
98+ DeviceOpen ( & ' static str , #[ source] :: std:: io:: Error ) ,
99+
100+ #[ error( "Target state is already active" ) ]
101+ StateAlreadyActive ( #[ source] :: std:: io:: Error ) ,
102+
103+ #[ error( "Incompatible values in rule: {}" , _0) ]
104+ InvalidRuleCombination ( String ) ,
105+
106+ #[ error( "Anchor does not exist" ) ]
107+ AnchorDoesNotExist ,
108+
109+ #[ error( "Cstr not null terminated" ) ]
110+ CstrNotTerminated ,
111+
112+ #[ error( "TryCopyTo conversion failed" ) ]
113+ Conversion ( #[ from] TryCopyToErrorWithKind ) ,
114+
115+ #[ error( "Ioctl Error" ) ]
116+ Ioctl ( #[ from] :: std:: io:: Error ) ,
117+ }
118+
119+ #[ derive( Error , Debug ) ]
120+ #[ non_exhaustive]
121+ pub enum TryCopyToError {
122+ #[ error( "Lower port is greater than upper port." ) ]
123+ InvalidPortRange ,
124+
125+ #[ error( "Insufficient string buffer length" ) ]
126+ InsufficientStringBufferLength ,
127+
128+ #[ error( "String should not contain null byte" ) ]
129+ StringContainsNullByte ,
130+ }
131+
132+ #[ derive( Debug ) ]
133+ #[ non_exhaustive]
134+ pub enum TryCopyToErrorKind {
135+ InvalidAnchorName ,
136+ IncompatibleInterfaceName ,
137+ InvalidRouteTarget ,
138+ }
139+
140+ impl Display for TryCopyToErrorKind {
141+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
142+ match self {
143+ TryCopyToErrorKind :: InvalidAnchorName => write ! ( f, "Invalid anchor name" ) ,
144+ TryCopyToErrorKind :: IncompatibleInterfaceName => {
145+ write ! ( f, "Incompatible interface name" )
114146 }
147+ TryCopyToErrorKind :: InvalidRouteTarget => write ! ( f, "Invalid route target" ) ,
148+ }
149+ }
150+ }
151+
152+ #[ derive( Debug ) ]
153+ pub struct TryCopyToErrorWithKind {
154+ pub kind : Option < TryCopyToErrorKind > ,
155+ pub source : TryCopyToError ,
156+ }
157+
158+ impl Display for TryCopyToErrorWithKind {
159+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
160+ if let Some ( kind) = self . kind . as_ref ( ) {
161+ Display :: fmt ( kind, f)
162+ } else {
163+ Display :: fmt ( & self . source , f)
115164 }
116- foreign_links {
117- IoctlError ( :: std:: io:: Error ) ;
165+ }
166+ }
167+
168+ impl std:: error:: Error for TryCopyToErrorWithKind {
169+ fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
170+ self . kind . as_ref ( ) ?;
171+ Some ( & self . source )
172+ }
173+ }
174+
175+ impl TryCopyToErrorWithKind {
176+ fn new ( kind : TryCopyToErrorKind , err : TryCopyToError ) -> Self {
177+ Self {
178+ kind : Some ( kind) ,
179+ source : err,
118180 }
119181 }
120182}
121- pub use crate :: errors:: * ;
122183
123- /// Returns the given input result, except if it is an `Err` matching the given `ErrorKind`,
184+ impl From < TryCopyToError > for TryCopyToErrorWithKind {
185+ fn from ( source : TryCopyToError ) -> Self {
186+ Self { kind : None , source }
187+ }
188+ }
189+
190+ impl From < TryCopyToError > for Error {
191+ fn from ( source : TryCopyToError ) -> Self {
192+ Self :: Conversion ( TryCopyToErrorWithKind { kind : None , source } )
193+ }
194+ }
195+
196+ pub type Result < T > = :: std:: result:: Result < T , Error > ;
197+ pub type TryCopyToResult < T > = :: std:: result:: Result < T , TryCopyToError > ;
198+
199+ /// Returns the given input result, except if it is an `Err` matching the given `Error`,
124200/// then it returns `Ok(())` instead, so the error is ignored.
125201macro_rules! ignore_error_kind {
126202 ( $result: expr, $kind: pat) => {
127203 match $result {
128- Err ( $crate :: Error ( $ kind, _ ) ) => Ok ( ( ) ) ,
204+ Err ( $kind) => Ok ( ( ) ) ,
129205 result => result,
130206 }
131207 } ;
@@ -141,14 +217,18 @@ mod conversion {
141217
142218 /// Internal trait for all types that can try to write their value into another type.
143219 pub trait TryCopyTo < T : ?Sized > {
144- fn try_copy_to ( & self , dst : & mut T ) -> crate :: Result < ( ) > ;
220+ type Result ;
221+
222+ fn try_copy_to ( & self , dst : & mut T ) -> Self :: Result ;
145223 }
146224}
147225use crate :: conversion:: * ;
148226
149227/// Internal function to safely compare Rust string with raw C string slice
150228fn compare_cstr_safe ( s : & str , cchars : & [ std:: os:: raw:: c_char ] ) -> Result < bool > {
151- ensure ! ( cchars. iter( ) . any( |& c| c == 0 ) , "Not null terminated" ) ;
229+ if !( cchars. iter ( ) . any ( |& c| c == 0 ) ) {
230+ return Err ( Error :: CstrNotTerminated ) ;
231+ }
152232 let cs = unsafe { CStr :: from_ptr ( cchars. as_ptr ( ) ) } ;
153233 Ok ( s. as_bytes ( ) == cs. to_bytes ( ) )
154234}
@@ -174,7 +254,7 @@ impl PfCtl {
174254 /// Same as `enable`, but `StateAlreadyActive` errors are supressed and exchanged for
175255 /// `Ok(())`.
176256 pub fn try_enable ( & mut self ) -> Result < ( ) > {
177- ignore_error_kind ! ( self . enable( ) , ErrorKind :: StateAlreadyActive )
257+ ignore_error_kind ! ( self . enable( ) , Error :: StateAlreadyActive ( _ ) )
178258 }
179259
180260 /// Tries to disable PF. If the firewall is already disabled it will return an
@@ -186,7 +266,7 @@ impl PfCtl {
186266 /// Same as `disable`, but `StateAlreadyActive` errors are supressed and exchanged for
187267 /// `Ok(())`.
188268 pub fn try_disable ( & mut self ) -> Result < ( ) > {
189- ignore_error_kind ! ( self . disable( ) , ErrorKind :: StateAlreadyActive )
269+ ignore_error_kind ! ( self . disable( ) , Error :: StateAlreadyActive ( _ ) )
190270 }
191271
192272 /// Tries to determine if PF is enabled or not.
@@ -201,7 +281,7 @@ impl PfCtl {
201281
202282 pfioc_rule. rule . action = kind. into ( ) ;
203283 name. try_copy_to ( & mut pfioc_rule. anchor_call [ ..] )
204- . chain_err ( || ErrorKind :: InvalidArgument ( "Invalid anchor name" ) ) ?;
284+ . map_err ( |e| TryCopyToErrorWithKind :: new ( TryCopyToErrorKind :: InvalidAnchorName , e ) ) ?;
205285
206286 ioctl_guard ! ( ffi:: pf_insert_rule( self . fd( ) , & mut pfioc_rule) ) ?;
207287 Ok ( ( ) )
@@ -210,7 +290,7 @@ impl PfCtl {
210290 /// Same as `add_anchor`, but `StateAlreadyActive` errors are supressed and exchanged for
211291 /// `Ok(())`.
212292 pub fn try_add_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
213- ignore_error_kind ! ( self . add_anchor( name, kind) , ErrorKind :: StateAlreadyActive )
293+ ignore_error_kind ! ( self . add_anchor( name, kind) , Error :: StateAlreadyActive ( _ ) )
214294 }
215295
216296 pub fn remove_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
@@ -222,10 +302,7 @@ impl PfCtl {
222302 /// Same as `remove_anchor`, but `AnchorDoesNotExist` errors are supressed and exchanged for
223303 /// `Ok(())`.
224304 pub fn try_remove_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
225- ignore_error_kind ! (
226- self . remove_anchor( name, kind) ,
227- ErrorKind :: AnchorDoesNotExist
228- )
305+ ignore_error_kind ! ( self . remove_anchor( name, kind) , Error :: AnchorDoesNotExist )
229306 }
230307
231308 // TODO(linus): Make more generic. No hardcoded ADD_TAIL etc.
@@ -236,7 +313,7 @@ impl PfCtl {
236313 pfioc_rule. ticket = utils:: get_ticket ( self . fd ( ) , & anchor, AnchorKind :: Filter ) ?;
237314 anchor
238315 . try_copy_to ( & mut pfioc_rule. anchor [ ..] )
239- . chain_err ( || ErrorKind :: InvalidArgument ( "Invalid anchor name" ) ) ?;
316+ . map_err ( |e| TryCopyToErrorWithKind :: new ( TryCopyToErrorKind :: InvalidAnchorName , e ) ) ?;
240317 rule. try_copy_to ( & mut pfioc_rule. rule ) ?;
241318
242319 pfioc_rule. action = ffi:: pfvar:: PF_CHANGE_ADD_TAIL as u32 ;
@@ -287,7 +364,7 @@ impl PfCtl {
287364
288365 /// Clear states created by rules in anchor.
289366 /// Returns total number of removed states upon success, otherwise
290- /// ErrorKind ::AnchorDoesNotExist if anchor does not exist.
367+ /// Error ::AnchorDoesNotExist if anchor does not exist.
291368 pub fn clear_states ( & mut self , anchor_name : & str , kind : AnchorKind ) -> Result < u32 > {
292369 let pfsync_states = self . get_states ( ) ?;
293370 if !pfsync_states. is_empty ( ) {
@@ -317,7 +394,9 @@ impl PfCtl {
317394 let mut pfioc_state_kill = unsafe { mem:: zeroed :: < ffi:: pfvar:: pfioc_state_kill > ( ) } ;
318395 interface
319396 . try_copy_to ( & mut pfioc_state_kill. psk_ifname )
320- . chain_err ( || ErrorKind :: InvalidArgument ( "Incompatible interface name" ) ) ?;
397+ . map_err ( |e| {
398+ TryCopyToErrorWithKind :: new ( TryCopyToErrorKind :: IncompatibleInterfaceName , e)
399+ } ) ?;
321400 ioctl_guard ! ( ffi:: pf_clear_states( self . fd( ) , & mut pfioc_state_kill) ) ?;
322401 // psk_af holds the number of killed states
323402 Ok ( pfioc_state_kill. psk_af as u32 )
@@ -342,7 +421,7 @@ impl PfCtl {
342421 /// The return value from closure is transparently passed to the caller.
343422 ///
344423 /// - Returns Result<R> from call to closure on match.
345- /// - Returns `ErrorKind ::AnchorDoesNotExist` on mismatch, the closure is not called in that
424+ /// - Returns `Error ::AnchorDoesNotExist` on mismatch, the closure is not called in that
346425 /// case.
347426 fn with_anchor_rule < F , R > ( & self , name : & str , kind : AnchorKind , f : F ) -> Result < R >
348427 where
@@ -359,7 +438,7 @@ impl PfCtl {
359438 return f ( pfioc_rule) ;
360439 }
361440 }
362- bail ! ( ErrorKind :: AnchorDoesNotExist ) ;
441+ Err ( Error :: AnchorDoesNotExist )
363442 }
364443
365444 /// Returns global number of states created by all stateful rules (see keep_state)
@@ -419,7 +498,7 @@ mod tests {
419498 let cchars: & [ i8 ] = unsafe { mem:: transmute ( cstr. as_bytes ( ) ) } ;
420499 assert_matches ! (
421500 compare_cstr_safe( "Hello" , cchars) ,
422- Err ( ref e ) if e . description ( ) == "Not null terminated"
501+ Err ( Error :: CstrNotTerminated )
423502 ) ;
424503 }
425504
0 commit comments