@@ -3,14 +3,15 @@ use byteorder::{ByteOrder, NetworkEndian};
3
3
4
4
use Error ;
5
5
use super :: ip:: checksum;
6
+ use super :: { Ipv4Packet , Ipv4Repr } ;
6
7
7
8
enum_with_unknown ! {
8
9
/// Internet protocol control message type.
9
10
pub doc enum Message ( u8 ) {
10
11
/// Echo reply
11
12
EchoReply = 0 ,
12
13
/// Destination unreachable
13
- DstUnreachable = 1 ,
14
+ DstUnreachable = 3 ,
14
15
/// Message redirect
15
16
Redirect = 5 ,
16
17
/// Echo request
@@ -86,6 +87,47 @@ enum_with_unknown! {
86
87
}
87
88
}
88
89
90
+ impl fmt:: Display for DstUnreachable {
91
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
92
+ match self {
93
+ & DstUnreachable :: NetUnreachable =>
94
+ write ! ( f, "destination network unreachable" ) ,
95
+ & DstUnreachable :: HostUnreachable =>
96
+ write ! ( f, "destination host unreachable" ) ,
97
+ & DstUnreachable :: ProtoUnreachable =>
98
+ write ! ( f, "destination protocol unreachable" ) ,
99
+ & DstUnreachable :: PortUnreachable =>
100
+ write ! ( f, "destination port unreachable" ) ,
101
+ & DstUnreachable :: FragRequired =>
102
+ write ! ( f, "fragmentation required, and DF flag set" ) ,
103
+ & DstUnreachable :: SrcRouteFailed =>
104
+ write ! ( f, "source route failed" ) ,
105
+ & DstUnreachable :: DstNetUnknown =>
106
+ write ! ( f, "destination network unknown" ) ,
107
+ & DstUnreachable :: DstHostUnknown =>
108
+ write ! ( f, "destination host unknown" ) ,
109
+ & DstUnreachable :: SrcHostIsolated =>
110
+ write ! ( f, "source host isolated" ) ,
111
+ & DstUnreachable :: NetProhibited =>
112
+ write ! ( f, "network administratively prohibited" ) ,
113
+ & DstUnreachable :: HostProhibited =>
114
+ write ! ( f, "host administratively prohibited" ) ,
115
+ & DstUnreachable :: NetUnreachToS =>
116
+ write ! ( f, "network unreachable for ToS" ) ,
117
+ & DstUnreachable :: HostUnreachToS =>
118
+ write ! ( f, "host unreachable for ToS" ) ,
119
+ & DstUnreachable :: CommProhibited =>
120
+ write ! ( f, "communication administratively prohibited" ) ,
121
+ & DstUnreachable :: HostPrecedViol =>
122
+ write ! ( f, "host precedence violation" ) ,
123
+ & DstUnreachable :: PrecedCutoff =>
124
+ write ! ( f, "precedence cutoff in effect" ) ,
125
+ & DstUnreachable :: Unknown ( id) =>
126
+ write ! ( f, "{}" , id)
127
+ }
128
+ }
129
+ }
130
+
89
131
enum_with_unknown ! {
90
132
/// Internet protocol control message subtype for type "Redirect Message".
91
133
pub doc enum Redirect ( u8 ) {
@@ -135,6 +177,8 @@ mod field {
135
177
pub const CODE : usize = 1 ;
136
178
pub const CHECKSUM : Field = 2 ..4 ;
137
179
180
+ pub const UNUSED : Field = 4 ..8 ;
181
+
138
182
pub const ECHO_IDENT : Field = 4 ..6 ;
139
183
pub const ECHO_SEQNO : Field = 6 ..8 ;
140
184
}
@@ -206,8 +250,9 @@ impl<T: AsRef<[u8]>> Packet<T> {
206
250
/// The result depends on the value of the message type field.
207
251
pub fn header_len ( & self ) -> usize {
208
252
match self . msg_type ( ) {
209
- Message :: EchoRequest => field:: ECHO_SEQNO . end ,
210
- Message :: EchoReply => field:: ECHO_SEQNO . end ,
253
+ Message :: EchoRequest => field:: ECHO_SEQNO . end ,
254
+ Message :: EchoReply => field:: ECHO_SEQNO . end ,
255
+ Message :: DstUnreachable => field:: UNUSED . end ,
211
256
_ => field:: CHECKSUM . end // make a conservative assumption
212
257
}
213
258
}
@@ -304,6 +349,12 @@ pub enum Repr<'a> {
304
349
seq_no : u16 ,
305
350
data : & ' a [ u8 ]
306
351
} ,
352
+ DstUnreachable {
353
+ reason : DstUnreachable ,
354
+ header : Ipv4Repr ,
355
+ length : usize ,
356
+ data : [ u8 ; 8 ]
357
+ } ,
307
358
#[ doc( hidden) ]
308
359
__Nonexhaustive
309
360
}
@@ -320,13 +371,33 @@ impl<'a> Repr<'a> {
320
371
data : packet. data ( )
321
372
} )
322
373
} ,
374
+
323
375
( Message :: EchoReply , 0 ) => {
324
376
Ok ( Repr :: EchoReply {
325
377
ident : packet. echo_ident ( ) ,
326
378
seq_no : packet. echo_seq_no ( ) ,
327
379
data : packet. data ( )
328
380
} )
329
381
} ,
382
+
383
+ ( Message :: DstUnreachable , code) => {
384
+ let ip_packet = try!( Ipv4Packet :: new ( packet. data ( ) ) ) ;
385
+ let ip_repr = try!( Ipv4Repr :: parse ( & ip_packet) ) ;
386
+
387
+ let mut data = [ 0 ; 8 ] ;
388
+ let payload = & packet. data ( ) [ ip_packet. header_len ( ) as usize ..] ;
389
+ if payload. len ( ) < data. len ( ) { return Err ( Error :: Truncated ) }
390
+ data. copy_from_slice ( & payload[ 0 ..8 ] ) ;
391
+
392
+ let length = ip_packet. total_len ( ) as usize - ip_packet. header_len ( ) as usize ;
393
+
394
+ Ok ( Repr :: DstUnreachable {
395
+ reason : DstUnreachable :: from ( code) ,
396
+ header : ip_repr,
397
+ length : length,
398
+ data : data
399
+ } )
400
+ }
330
401
_ => Err ( Error :: Unrecognized )
331
402
}
332
403
}
@@ -338,6 +409,9 @@ impl<'a> Repr<'a> {
338
409
& Repr :: EchoReply { data, .. } => {
339
410
field:: ECHO_SEQNO . end + data. len ( )
340
411
} ,
412
+ & Repr :: DstUnreachable { header, data, .. } => {
413
+ field:: UNUSED . end + header. buffer_len ( ) + data. len ( )
414
+ }
341
415
& Repr :: __Nonexhaustive => unreachable ! ( )
342
416
}
343
417
}
@@ -349,18 +423,33 @@ impl<'a> Repr<'a> {
349
423
match self {
350
424
& Repr :: EchoRequest { ident, seq_no, data } => {
351
425
packet. set_msg_type ( Message :: EchoRequest ) ;
426
+ packet. set_msg_code ( 0 ) ;
352
427
packet. set_echo_ident ( ident) ;
353
428
packet. set_echo_seq_no ( seq_no) ;
354
429
let data_len = cmp:: min ( packet. data_mut ( ) . len ( ) , data. len ( ) ) ;
355
430
packet. data_mut ( ) [ ..data_len] . copy_from_slice ( & data[ ..data_len] )
356
431
} ,
432
+
357
433
& Repr :: EchoReply { ident, seq_no, data } => {
358
434
packet. set_msg_type ( Message :: EchoReply ) ;
435
+ packet. set_msg_code ( 0 ) ;
359
436
packet. set_echo_ident ( ident) ;
360
437
packet. set_echo_seq_no ( seq_no) ;
361
438
let data_len = cmp:: min ( packet. data_mut ( ) . len ( ) , data. len ( ) ) ;
362
439
packet. data_mut ( ) [ ..data_len] . copy_from_slice ( & data[ ..data_len] )
363
440
} ,
441
+
442
+ & Repr :: DstUnreachable { reason, header, length, data } => {
443
+ packet. set_msg_type ( Message :: DstUnreachable ) ;
444
+ packet. set_msg_code ( reason. into ( ) ) ;
445
+
446
+ let mut ip_packet = Ipv4Packet :: new ( packet. data_mut ( ) )
447
+ . expect ( "undersized data" ) ;
448
+ header. emit ( & mut ip_packet, length) ;
449
+ let mut payload = & mut ip_packet. into_inner ( ) [ header. buffer_len ( ) ..] ;
450
+ payload. copy_from_slice ( & data[ ..] )
451
+ }
452
+
364
453
& Repr :: __Nonexhaustive => unreachable ! ( )
365
454
}
366
455
packet. fill_checksum ( )
@@ -371,10 +460,14 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
371
460
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
372
461
match Repr :: parse ( self ) {
373
462
Ok ( repr) => write ! ( f, "{}" , repr) ,
374
- _ => {
375
- try!( write ! ( f, "ICMPv4 (unrecognized)" ) ) ;
376
- try!( write ! ( f, " type={} code={} cksum={:#04x}" ,
377
- self . msg_type( ) , self . msg_code( ) , self . checksum( ) ) ) ;
463
+ Err ( err) => {
464
+ try!( write ! ( f, "ICMPv4 ({})" , err) ) ;
465
+ try!( write ! ( f, " type={:?}" , self . msg_type( ) ) ) ;
466
+ match self . msg_type ( ) {
467
+ Message :: DstUnreachable =>
468
+ try!( write ! ( f, " code={:?}" , DstUnreachable :: from( self . msg_code( ) ) ) ) ,
469
+ _ => try!( write ! ( f, " code={}" , self . msg_code( ) ) )
470
+ }
378
471
Ok ( ( ) )
379
472
}
380
473
}
@@ -385,11 +478,14 @@ impl<'a> fmt::Display for Repr<'a> {
385
478
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
386
479
match self {
387
480
& Repr :: EchoRequest { ident, seq_no, data } =>
388
- write ! ( f, "ICMPv4 Echo Request id={} seq={} len={}" ,
481
+ write ! ( f, "ICMPv4 echo request id={} seq={} len={}" ,
389
482
ident, seq_no, data. len( ) ) ,
390
483
& Repr :: EchoReply { ident, seq_no, data } =>
391
- write ! ( f, "ICMPv4 Echo Reply id={} seq={} len={}" ,
484
+ write ! ( f, "ICMPv4 echo reply id={} seq={} len={}" ,
392
485
ident, seq_no, data. len( ) ) ,
486
+ & Repr :: DstUnreachable { reason, .. } =>
487
+ write ! ( f, "ICMPv4 destination unreachable ({})" ,
488
+ reason) ,
393
489
& Repr :: __Nonexhaustive => unreachable ! ( )
394
490
}
395
491
}
@@ -400,14 +496,21 @@ use super::pretty_print::{PrettyPrint, PrettyIndent};
400
496
impl < T : AsRef < [ u8 ] > > PrettyPrint for Packet < T > {
401
497
fn pretty_print ( buffer : & AsRef < [ u8 ] > , f : & mut fmt:: Formatter ,
402
498
indent : & mut PrettyIndent ) -> fmt:: Result {
403
- match Packet :: new ( buffer) {
404
- Err ( err) => write ! ( f, "{}({})\n " , indent, err) ,
405
- Ok ( packet) => write ! ( f, "{}{}\n " , indent, packet)
499
+ let packet = match Packet :: new ( buffer) {
500
+ Err ( err) => return write ! ( f, "{}({})\n " , indent, err) ,
501
+ Ok ( packet) => packet
502
+ } ;
503
+ try!( write ! ( f, "{}{}\n " , indent, packet) ) ;
504
+
505
+ indent. increase ( ) ;
506
+ match packet. msg_type ( ) {
507
+ Message :: DstUnreachable =>
508
+ super :: Ipv4Packet :: < & [ u8 ] > :: pretty_print ( & packet. data ( ) , f, indent) ,
509
+ _ => Ok ( ( ) )
406
510
}
407
511
}
408
512
}
409
513
410
-
411
514
#[ cfg( test) ]
412
515
mod test {
413
516
use super :: * ;
0 commit comments