59
59
60
60
#![ deny( rust_2018_idioms) ]
61
61
62
- #[ macro_use]
63
- pub extern crate error_chain;
64
-
65
62
use std:: {
66
63
ffi:: CStr ,
64
+ fmt:: { Debug , Display } ,
67
65
fs:: File ,
68
66
mem,
69
67
os:: unix:: io:: { AsRawFd , RawFd } ,
70
68
} ;
69
+ use thiserror:: Error ;
71
70
72
71
pub use ipnetwork;
73
72
@@ -92,40 +91,117 @@ pub use crate::ruleset::*;
92
91
mod transaction;
93
92
pub use crate :: transaction:: * ;
94
93
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 error" ) ]
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" )
114
146
}
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)
115
164
}
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,
118
180
}
119
181
}
120
182
}
121
- pub use crate :: errors:: * ;
122
183
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`,
124
200
/// then it returns `Ok(())` instead, so the error is ignored.
125
201
macro_rules! ignore_error_kind {
126
202
( $result: expr, $kind: pat) => {
127
203
match $result {
128
- Err ( $crate :: Error ( $ kind, _ ) ) => Ok ( ( ) ) ,
204
+ Err ( $kind) => Ok ( ( ) ) ,
129
205
result => result,
130
206
}
131
207
} ;
@@ -141,14 +217,18 @@ mod conversion {
141
217
142
218
/// Internal trait for all types that can try to write their value into another type.
143
219
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 ;
145
223
}
146
224
}
147
225
use crate :: conversion:: * ;
148
226
149
227
/// Internal function to safely compare Rust string with raw C string slice
150
228
fn 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
+ }
152
232
let cs = unsafe { CStr :: from_ptr ( cchars. as_ptr ( ) ) } ;
153
233
Ok ( s. as_bytes ( ) == cs. to_bytes ( ) )
154
234
}
@@ -174,7 +254,7 @@ impl PfCtl {
174
254
/// Same as `enable`, but `StateAlreadyActive` errors are supressed and exchanged for
175
255
/// `Ok(())`.
176
256
pub fn try_enable ( & mut self ) -> Result < ( ) > {
177
- ignore_error_kind ! ( self . enable( ) , ErrorKind :: StateAlreadyActive )
257
+ ignore_error_kind ! ( self . enable( ) , Error :: StateAlreadyActive ( _ ) )
178
258
}
179
259
180
260
/// Tries to disable PF. If the firewall is already disabled it will return an
@@ -186,7 +266,7 @@ impl PfCtl {
186
266
/// Same as `disable`, but `StateAlreadyActive` errors are supressed and exchanged for
187
267
/// `Ok(())`.
188
268
pub fn try_disable ( & mut self ) -> Result < ( ) > {
189
- ignore_error_kind ! ( self . disable( ) , ErrorKind :: StateAlreadyActive )
269
+ ignore_error_kind ! ( self . disable( ) , Error :: StateAlreadyActive ( _ ) )
190
270
}
191
271
192
272
/// Tries to determine if PF is enabled or not.
@@ -201,7 +281,7 @@ impl PfCtl {
201
281
202
282
pfioc_rule. rule . action = kind. into ( ) ;
203
283
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 ) ) ?;
205
285
206
286
ioctl_guard ! ( ffi:: pf_insert_rule( self . fd( ) , & mut pfioc_rule) ) ?;
207
287
Ok ( ( ) )
@@ -210,7 +290,7 @@ impl PfCtl {
210
290
/// Same as `add_anchor`, but `StateAlreadyActive` errors are supressed and exchanged for
211
291
/// `Ok(())`.
212
292
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 ( _ ) )
214
294
}
215
295
216
296
pub fn remove_anchor ( & mut self , name : & str , kind : AnchorKind ) -> Result < ( ) > {
@@ -222,10 +302,7 @@ impl PfCtl {
222
302
/// Same as `remove_anchor`, but `AnchorDoesNotExist` errors are supressed and exchanged for
223
303
/// `Ok(())`.
224
304
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 )
229
306
}
230
307
231
308
// TODO(linus): Make more generic. No hardcoded ADD_TAIL etc.
@@ -236,7 +313,7 @@ impl PfCtl {
236
313
pfioc_rule. ticket = utils:: get_ticket ( self . fd ( ) , & anchor, AnchorKind :: Filter ) ?;
237
314
anchor
238
315
. try_copy_to ( & mut pfioc_rule. anchor [ ..] )
239
- . chain_err ( || ErrorKind :: InvalidArgument ( "Invalid anchor name" ) ) ?;
316
+ . map_err ( |e| TryCopyToErrorWithKind :: new ( TryCopyToErrorKind :: InvalidAnchorName , e ) ) ?;
240
317
rule. try_copy_to ( & mut pfioc_rule. rule ) ?;
241
318
242
319
pfioc_rule. action = ffi:: pfvar:: PF_CHANGE_ADD_TAIL as u32 ;
@@ -287,7 +364,7 @@ impl PfCtl {
287
364
288
365
/// Clear states created by rules in anchor.
289
366
/// 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.
291
368
pub fn clear_states ( & mut self , anchor_name : & str , kind : AnchorKind ) -> Result < u32 > {
292
369
let pfsync_states = self . get_states ( ) ?;
293
370
if !pfsync_states. is_empty ( ) {
@@ -317,7 +394,9 @@ impl PfCtl {
317
394
let mut pfioc_state_kill = unsafe { mem:: zeroed :: < ffi:: pfvar:: pfioc_state_kill > ( ) } ;
318
395
interface
319
396
. 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
+ } ) ?;
321
400
ioctl_guard ! ( ffi:: pf_clear_states( self . fd( ) , & mut pfioc_state_kill) ) ?;
322
401
// psk_af holds the number of killed states
323
402
Ok ( pfioc_state_kill. psk_af as u32 )
@@ -342,7 +421,7 @@ impl PfCtl {
342
421
/// The return value from closure is transparently passed to the caller.
343
422
///
344
423
/// - 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
346
425
/// case.
347
426
fn with_anchor_rule < F , R > ( & self , name : & str , kind : AnchorKind , f : F ) -> Result < R >
348
427
where
@@ -359,7 +438,7 @@ impl PfCtl {
359
438
return f ( pfioc_rule) ;
360
439
}
361
440
}
362
- bail ! ( ErrorKind :: AnchorDoesNotExist ) ;
441
+ Err ( Error :: AnchorDoesNotExist )
363
442
}
364
443
365
444
/// Returns global number of states created by all stateful rules (see keep_state)
@@ -419,7 +498,7 @@ mod tests {
419
498
let cchars: & [ i8 ] = unsafe { mem:: transmute ( cstr. as_bytes ( ) ) } ;
420
499
assert_matches ! (
421
500
compare_cstr_safe( "Hello" , cchars) ,
422
- Err ( ref e ) if e . description ( ) == "Not null terminated"
501
+ Err ( Error :: CstrNotTerminated )
423
502
) ;
424
503
}
425
504
0 commit comments