Skip to content

Commit 9fd5758

Browse files
authored
Merge pull request #130 from JulianSchmid/coverage-fixups
Minor fixups for ICMPv6 NeighborSolicitation & NeighborAdvertisement
2 parents 9e967ba + cd9266d commit 9fd5758

14 files changed

+577
-191
lines changed

README.md

Lines changed: 74 additions & 74 deletions
Large diffs are not rendered by default.

etherparse/src/transport/icmp_echo_header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
/// node SHOULD also implement an application-layer interface for
88
/// originating Echo Requests and receiving Echo Replies, for diagnostic
99
/// purposes.
10-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
1111
pub struct IcmpEchoHeader {
1212
/// An identifier to aid in matching Echo Replies to Echo Requests. May be zero.
1313
pub id: u16,

etherparse/src/transport/icmpv6/dest_unreachable_code.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use super::*;
1010
/// that cannot be delivered to its destination address for reasons other
1111
/// than congestion. (An ICMPv6 message MUST NOT be generated if a
1212
/// packet is dropped due to congestion.)
13-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
1414
pub enum DestUnreachableCode {
1515
/// No route to destination
1616
NoRoute = 0,

etherparse/src/transport/icmpv6/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ pub use parameter_problem_header::*;
1010
mod time_exceeded_code;
1111
pub use time_exceeded_code::*;
1212

13-
mod neighbour_discovery;
14-
pub use neighbour_discovery::*;
13+
mod neighbor_advertisement_header;
14+
pub use neighbor_advertisement_header::*;
15+
16+
mod router_advertisement_header;
17+
pub use router_advertisement_header::*;
1518

1619
/// The maximum number of bytes/octets the ICMPv6 part of a packet can contain.
1720
///
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/// ICMPv6 neighbor advertisement header (part of "Neighbor Discovery Protocol"
2+
/// [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861)).
3+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
4+
pub struct NeighborAdvertisementHeader {
5+
pub router: bool,
6+
pub solicited: bool,
7+
pub r#override: bool,
8+
}
9+
10+
impl NeighborAdvertisementHeader {
11+
/// Mask to read out the "router" flag out of the 5th byte of the ICMPv6 header.
12+
pub const ROUTER_MASK: u8 = 0b10000000;
13+
14+
/// Mask to read out the "solicited" flag out of the 5th byte of the ICMPv6 header.
15+
pub const SOLICITED_MASK: u8 = 0b01000000;
16+
17+
/// Mask to read out the "override" flag out of the 5th byte of the ICMPv6 header.
18+
pub const OVERRIDE_MASK: u8 = 0b00100000;
19+
20+
/// Decodes the header from the on the wire bytes.
21+
pub fn from_bytes(bytes: [u8; 4]) -> Self {
22+
let first_byte = bytes[0];
23+
24+
Self {
25+
router: (first_byte & Self::ROUTER_MASK) == Self::ROUTER_MASK,
26+
solicited: (first_byte & Self::SOLICITED_MASK) == Self::SOLICITED_MASK,
27+
r#override: (first_byte & Self::OVERRIDE_MASK) == Self::OVERRIDE_MASK,
28+
}
29+
}
30+
31+
/// Converts the header to the on the wire bytes.
32+
pub fn to_bytes(&self) -> [u8; 4] {
33+
let mut first_byte = 0u8;
34+
35+
if self.router {
36+
first_byte |= Self::ROUTER_MASK;
37+
}
38+
if self.solicited {
39+
first_byte |= Self::SOLICITED_MASK;
40+
}
41+
if self.r#override {
42+
first_byte |= Self::OVERRIDE_MASK;
43+
}
44+
45+
[first_byte, 0, 0, 0]
46+
}
47+
}
48+
49+
#[cfg(test)]
50+
mod tests {
51+
use super::*;
52+
use proptest::prelude::*;
53+
54+
proptest! {
55+
#[test]
56+
fn to_and_from_bytes(
57+
router in any::<bool>(),
58+
solicited in any::<bool>(),
59+
r#override in any::<bool>()
60+
) {
61+
let bytes = NeighborAdvertisementHeader{
62+
router,
63+
solicited,
64+
r#override
65+
}.to_bytes();
66+
assert_eq!(
67+
NeighborAdvertisementHeader::from_bytes(bytes),
68+
NeighborAdvertisementHeader {
69+
router,
70+
solicited,
71+
r#override,
72+
}
73+
);
74+
}
75+
}
76+
77+
#[test]
78+
fn reads_router_bit_correctly() {
79+
assert!(NeighborAdvertisementHeader::from_bytes([0b10000000, 0, 0, 0]).router);
80+
assert!(!NeighborAdvertisementHeader::from_bytes([0, 0, 0, 0]).router);
81+
}
82+
83+
#[test]
84+
fn reads_solicited_bit_correctly() {
85+
assert!(NeighborAdvertisementHeader::from_bytes([0b01000000, 0, 0, 0]).solicited);
86+
assert!(!NeighborAdvertisementHeader::from_bytes([0, 0, 0, 0]).solicited);
87+
}
88+
89+
#[test]
90+
fn reads_override_bit_correctly() {
91+
assert!(NeighborAdvertisementHeader::from_bytes([0b00100000, 0, 0, 0]).r#override);
92+
assert!(!NeighborAdvertisementHeader::from_bytes([0, 0, 0, 0]).r#override);
93+
}
94+
95+
#[test]
96+
fn reads_combined_bit_correctly() {
97+
let header = NeighborAdvertisementHeader::from_bytes([0b11100000, 0, 0, 0]);
98+
99+
assert!(header.router);
100+
assert!(header.solicited);
101+
assert!(header.r#override);
102+
}
103+
}

etherparse/src/transport/icmpv6/neighbour_discovery.rs

Lines changed: 0 additions & 70 deletions
This file was deleted.

etherparse/src/transport/icmpv6/parameter_problem_code.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::*;
33
/// Code values for ICMPv6 parameter problem messages.
44
///
55
/// Source: <https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-codes-5>
6-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
77
pub enum ParameterProblemCode {
88
/// Erroneous header field encountered (from [RFC 4443](https://tools.ietf.org/html/rfc4443))
99
ErroneousHeaderField = 0,

etherparse/src/transport/icmpv6/parameter_problem_header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22

33
/// ICMPv6 parameter problem header.
4-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
55
pub struct ParameterProblemHeader {
66
/// The code can offer additional informations about what kind of parameter
77
/// problem caused the error.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/// ICMPv6 router advertisement header (part of "Neighbor Discovery Protocol"
2+
/// [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861)).
3+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
4+
pub struct RouterAdvertisementHeader {
5+
/// The default value that should be placed in the Hop Count
6+
/// field of the IP header for outgoing IP packets.
7+
///
8+
/// A value of zero means unspecified (by this router).
9+
pub cur_hop_limit: u8,
10+
11+
/// "Managed address configuration" flag.
12+
///
13+
/// When set, it indicates that addresses are available via
14+
/// Dynamic Host Configuration Protocol [DHCPv6].
15+
///
16+
/// If the M flag is set, the O flag is redundant and
17+
/// can be ignored because DHCPv6 will return all
18+
/// available configuration information.
19+
pub managed_address_config: bool,
20+
21+
/// "Other configuration" flag.
22+
///
23+
/// When set, it indicates that other configuration information
24+
/// is available via DHCPv6. Examples of such information are
25+
/// DNS-related information or information on other servers
26+
/// within the network.
27+
pub other_config: bool,
28+
29+
/// The lifetime associated with the default router in units of
30+
/// seconds.
31+
///
32+
/// The field can contain values up to 65535 and receivers should
33+
/// handle any value, while the sending rules in Section 6 of
34+
/// [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861) limit
35+
/// the lifetime to 9000 seconds. A Lifetime of 0 indicates that
36+
/// the router is not a default router and SHOULD NOT appear on
37+
/// the default router list. The Router Lifetime applies only to
38+
/// the router's usefulness as a default router; it does not apply
39+
/// to information contained in other message fields or options.
40+
/// Options that need time limits for their information include
41+
/// their own lifetime fields.
42+
pub router_lifetime: u16,
43+
}
44+
45+
impl RouterAdvertisementHeader {
46+
/// Mask to read out the "Managed Address Configuration" flag out of
47+
/// the 5th byte of the ICMPv6 header.
48+
pub const MANAGED_ADDRESS_CONFIG_MASK: u8 = 0b1000_0000;
49+
50+
/// Mask to read out the "Other Configuration" flag out of the 5th
51+
/// byte of the ICMPv6 header.
52+
pub const OTHER_CONFIG_MASK: u8 = 0b0100_0000;
53+
54+
/// Decodes the header from the on the wire bytes.
55+
pub fn from_bytes(bytes: [u8; 4]) -> Self {
56+
RouterAdvertisementHeader {
57+
cur_hop_limit: bytes[0],
58+
managed_address_config: 0 != bytes[1] & Self::MANAGED_ADDRESS_CONFIG_MASK,
59+
other_config: 0 != bytes[1] & Self::OTHER_CONFIG_MASK,
60+
router_lifetime: u16::from_be_bytes([bytes[2], bytes[3]]),
61+
}
62+
}
63+
64+
/// Converts the header to the on the wire bytes.
65+
pub fn to_bytes(&self) -> [u8; 4] {
66+
let rl_be = self.router_lifetime.to_be_bytes();
67+
[
68+
self.cur_hop_limit,
69+
(if self.managed_address_config {
70+
Self::MANAGED_ADDRESS_CONFIG_MASK
71+
} else {
72+
0
73+
} | if self.other_config {
74+
Self::OTHER_CONFIG_MASK
75+
} else {
76+
0
77+
}),
78+
rl_be[0],
79+
rl_be[1],
80+
]
81+
}
82+
}
83+
84+
#[cfg(test)]
85+
mod test {
86+
use super::*;
87+
use proptest::prelude::*;
88+
89+
proptest! {
90+
#[test]
91+
fn to_and_from_bytes(
92+
cur_hop_limit in any::<u8>(),
93+
managed_address_config in any::<bool>(),
94+
other_config in any::<bool>(),
95+
router_lifetime in any::<u16>()
96+
) {
97+
let expected = RouterAdvertisementHeader{
98+
cur_hop_limit,
99+
managed_address_config,
100+
other_config,
101+
router_lifetime
102+
};
103+
let actual = RouterAdvertisementHeader::from_bytes(
104+
expected.to_bytes()
105+
);
106+
assert_eq!(actual, expected);
107+
}
108+
}
109+
}

etherparse/src/transport/icmpv6/time_exceeded_code.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22

33
/// Code values for ICMPv6 time exceeded message.
4-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
55
pub enum TimeExceededCode {
66
/// "hop limit exceeded in transit"
77
HopLimitExceeded = 0,

0 commit comments

Comments
 (0)