Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ Read the documentations of the different methods for a more details:
* [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel
* ["IEEE Standard for Local and metropolitan area networks-Media Access Control (MAC) Security," in IEEE Std 802.1AE-2018 (Revision of IEEE Std 802.1AE-2006) , vol., no., pp.1-239, 26 Dec. 2018, doi: 10.1109/IEEESTD.2018.8585421.](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8585421&isnumber=8585420)
* ["IEEE Standard for Local and metropolitan area networks--Media Access Control (MAC) Security Corrigendum 1: Tag Control Information Figure," in IEEE Std 802.1AE-2018/Cor 1-2020 (Corrigendum to IEEE Std 802.1AE-2018) , vol., no., pp.1-14, 21 July 2020, doi: 10.1109/IEEESTD.2020.9144679.](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9144679&isnumber=9144678)
* Host Extensions for IP Multicasting (IGMPv1) [RFC 1112](https://tools.ietf.org/html/rfc1112)
* Internet Group Management Protocol, Version 2 [RFC 2236](https://tools.ietf.org/html/rfc2236)
* Internet Group Management Protocol, Version 3 [RFC 9776](https://tools.ietf.org/html/rfc9776)

## License
Licensed under either of Apache License, Version 2.0 or MIT license at your option. The corresponding license texts can be found in the LICENSE-APACHE file and the LICENSE-MIT file.
Expand Down
6 changes: 6 additions & 0 deletions etherparse/src/err/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub enum Layer {
Icmpv4TimestampReply,
/// Error occurred while parsing an ICMPv6 packet.
Icmpv6,
/// Error occurred while parsing an IGMP packet.
Igmp,
/// Error occurred while parsing an Address Resolution Protocol packet.
Arp,
}
Expand Down Expand Up @@ -83,6 +85,7 @@ impl Layer {
Icmpv4Timestamp => "ICMP Timestamp Error",
Icmpv4TimestampReply => "ICMP Timestamp Reply Error",
Icmpv6 => "ICMPv6 Packet Error",
Igmp => "IGMP Packet Error",
Arp => "Address Resolution Protocol Packet Error",
}
}
Expand Down Expand Up @@ -116,6 +119,7 @@ impl core::fmt::Display for Layer {
Icmpv4Timestamp => write!(f, "ICMP timestamp message"),
Icmpv4TimestampReply => write!(f, "ICMP timestamp reply message"),
Icmpv6 => write!(f, "ICMPv6 packet"),
Igmp => write!(f, "IGMP packet"),
Arp => write!(f, "Address Resolution Protocol packet"),
}
}
Expand Down Expand Up @@ -185,6 +189,7 @@ mod test {
(Icmpv4Timestamp, "ICMP Timestamp Error"),
(Icmpv4TimestampReply, "ICMP Timestamp Reply Error"),
(Icmpv6, "ICMPv6 Packet Error"),
(Igmp, "IGMP Packet Error"),
(Arp, "Address Resolution Protocol Packet Error"),
];
for test in tests {
Expand Down Expand Up @@ -219,6 +224,7 @@ mod test {
(Icmpv4Timestamp, "ICMP timestamp message"),
(Icmpv4TimestampReply, "ICMP timestamp reply message"),
(Icmpv6, "ICMPv6 packet"),
(Igmp, "IGMP packet"),
(Arp, "Address Resolution Protocol packet"),
];
for test in tests {
Expand Down
7 changes: 7 additions & 0 deletions etherparse/src/err/value_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum ValueType {
Icmpv6PayloadLength,
/// Packet type of a Linux Cooked Capture v1 (SLL)
LinuxSllType,
/// QRV (Querier's Robustness Variable) of a IGMPv3 membership query message.
IgmpQrv,
}

impl core::fmt::Display for ValueType {
Expand All @@ -65,6 +67,7 @@ impl core::fmt::Display for ValueType {
TcpPayloadLengthIpv6 => write!(f, "TCP Payload Length (in IPv6 checksum calculation)"),
Icmpv6PayloadLength => write!(f, "ICMPv6 Payload Length"),
LinuxSllType => write!(f, "Linux Cooked Capture v1 (SLL)"),
IgmpQrv => write!(f, "IGMPv3 QRV (Querier's Robustness Variable)"),
}
}
}
Expand Down Expand Up @@ -134,5 +137,9 @@ mod test {
&format!("{}", TcpPayloadLengthIpv6)
);
assert_eq!("ICMPv6 Payload Length", &format!("{}", Icmpv6PayloadLength));
assert_eq!(
"IGMPv3 QRV (Querier's Robustness Variable)",
&format!("{}", IgmpQrv)
);
}
}
5 changes: 4 additions & 1 deletion etherparse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,10 @@
//! * [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel
//! * ["IEEE Standard for Local and metropolitan area networks-Media Access Control (MAC) Security," in IEEE Std 802.1AE-2018 (Revision of IEEE Std 802.1AE-2006) , vol., no., pp.1-239, 26 Dec. 2018, doi: 10.1109/IEEESTD.2018.8585421.](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8585421&isnumber=8585420)
//! * ["IEEE Standard for Local and metropolitan area networks--Media Access Control (MAC) Security Corrigendum 1: Tag Control Information Figure," in IEEE Std 802.1AE-2018/Cor 1-2020 (Corrigendum to IEEE Std 802.1AE-2018) , vol., no., pp.1-14, 21 July 2020, doi: 10.1109/IEEESTD.2020.9144679.](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9144679&isnumber=9144678)

//! * Host Extensions for IP Multicasting (IGMPv1) [RFC 1112](https://tools.ietf.org/html/rfc1112)
//! * Internet Group Management Protocol, Version 2 [RFC 2236](https://tools.ietf.org/html/rfc2236)
//! * Internet Group Management Protocol, Version 3 [RFC 9776](https://tools.ietf.org/html/rfc9776)
//
// # Reason for 'bool_comparison' disable:
//
// Clippy triggers triggers errors like the following if the warning stays enabled:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct RouterAdvertisementHeader {
/// "Managed address configuration" flag.
///
/// When set, it indicates that addresses are available via
/// Dynamic Host Configuration Protocol [DHCPv6].
/// Dynamic Host Configuration Protocol \[DHCPv6\].
///
/// If the M flag is set, the O flag is redundant and
/// can be ignored because DHCPv6 will return all
Expand Down
102 changes: 102 additions & 0 deletions etherparse/src/transport/igmp/group_address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/// A group address in an IGMP packet.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GroupAddress {
pub octets: [u8; 4],
}

impl GroupAddress {
pub fn new(address: [u8; 4]) -> Self {
Self { octets: address }
}

pub fn is_zero(&self) -> bool {
[0, 0, 0, 0] == self.octets
}
}

impl From<GroupAddress> for [u8; 4] {
fn from(value: GroupAddress) -> Self {
value.octets
}
}

impl From<[u8; 4]> for GroupAddress {
fn from(value: [u8; 4]) -> Self {
GroupAddress { octets: value }
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(feature = "std")]
impl From<std::net::Ipv4Addr> for GroupAddress {
fn from(value: std::net::Ipv4Addr) -> Self {
GroupAddress {
octets: value.octets(),
}
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[cfg(feature = "std")]
impl From<GroupAddress> for std::net::Ipv4Addr {
fn from(value: GroupAddress) -> Self {
std::net::Ipv4Addr::new(
value.octets[0],
value.octets[1],
value.octets[2],
value.octets[3],
)
}
}

#[cfg(test)]
mod test {
use super::*;
use alloc::format;

Check warning on line 55 in etherparse/src/transport/igmp/group_address.rs

View workflow job for this annotation

GitHub Actions / codecoverage_test

unused import: `alloc::format`
use proptest::prelude::*;

#[test]
fn test_is_zero() {
assert!(GroupAddress::new([0, 0, 0, 0]).is_zero());
assert!(!GroupAddress::new([1, 0, 0, 0]).is_zero());
assert!(!GroupAddress::new([0, 1, 0, 0]).is_zero());
assert!(!GroupAddress::new([0, 0, 1, 0]).is_zero());
assert!(!GroupAddress::new([0, 0, 0, 1]).is_zero());
}

proptest! {
#[test]
fn from_array_to_group_address_roundtrip(octets in any::<[u8;4]>()) {
let addr = GroupAddress::from(octets);
prop_assert_eq!(addr.octets, octets);

let back: [u8;4] = addr.into();
prop_assert_eq!(back, octets);
}
}

proptest! {
#[test]
fn from_group_address_to_array_roundtrip(octets in any::<[u8;4]>()) {
let addr = GroupAddress { octets };
let arr: [u8;4] = addr.into();
prop_assert_eq!(arr, octets);

let back = GroupAddress::from(arr);
prop_assert_eq!(back, addr);
}
}

#[cfg(feature = "std")]
proptest! {
#[test]
fn from_ipv4addr_to_group_address_roundtrip(octets in any::<[u8;4]>()) {
let ip = std::net::Ipv4Addr::from(octets);
let addr = GroupAddress::from(ip);
prop_assert_eq!(addr.octets, octets);

let back: std::net::Ipv4Addr = addr.into();
prop_assert_eq!(back.octets(), octets);
}
}
}
23 changes: 23 additions & 0 deletions etherparse/src/transport/igmp/leave_group_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::igmp::GroupAddress;

/// A leave group message type (introduced in IGMPv2).
///
/// ```text
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Type = 0x11 | 0 | Checksum |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Group Address |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LeaveGroupType {
/// The IP multicast group address of the group being left.
pub group_address: GroupAddress,
}

impl LeaveGroupType {
/// Number of bytes/octets an [`LeaveGroupType`] takes up in serialized form.
pub const LEN: usize = 8;
}
Comment thread
JulianSchmid marked this conversation as resolved.
60 changes: 60 additions & 0 deletions etherparse/src/transport/igmp/max_response_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/// Max response code (specifies the maximum time allowed before
/// sending a responding report in IGMPv3).
///
/// The actual time allowed, called the Max
/// Resp Time, is represented in units of 1/10 second and is derived from
/// the Max Resp Code as follows:
///
/// If Max Resp Code < 128, Max Resp Time = Max Resp Code
///
/// If Max Resp Code >= 128, Max Resp Code represents a floating-point
/// value as follows:
///
/// ```text
/// 0 1 2 3 4 5 6 7
/// +-+-+-+-+-+-+-+-+
/// |1| exp | mant |
/// +-+-+-+-+-+-+-+-+
/// ```
///
/// Max Resp Time = (mant | 0x10) << (exp + 3)
///
/// Small values of Max Resp Time allow IGMPv3 routers to tune the "leave
/// latency" (the time between the moment the last host leaves a group
/// and the moment the routing protocol is notified that there are no
/// more members). Larger values, especially in the exponential range,
/// allow tuning of the burstiness of IGMP traffic on a network.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MaxResponseCode(pub u8);

impl MaxResponseCode {
/// Returns the max response time in 10th seconds (converts raw value).
pub fn as_10th_secs(&self) -> u16 {
if 0 != self.0 & 0b1000_0000 {
u16::from((self.0 & 0b0000_1111) | 0x10) << u16::from(((self.0 & 0b0111_0000) >> 4) + 3)
} else {
u16::from(self.0)
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
use std::format;

Check warning on line 45 in etherparse/src/transport/igmp/max_response_code.rs

View workflow job for this annotation

GitHub Actions / codecoverage_test

unused import: `std::format`

proptest! {
#[test]
fn as_10th_secs_linear_range(raw in 0u8..=0b0111_1111u8) {
prop_assert_eq!(MaxResponseCode(raw).as_10th_secs(), u16::from(raw));
}

#[test]
fn as_10th_secs_exponential_range(mant in 0u8..=0b1111, exp in 0u8..=0b111u8) {
let raw = 0b1000_0000 | (exp << 4) | mant;
let expected = u16::from(mant | 0x10) << u16::from(exp + 3);
prop_assert_eq!(MaxResponseCode(raw).as_10th_secs(), expected);
}
}
}
44 changes: 44 additions & 0 deletions etherparse/src/transport/igmp/membership_query_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::igmp::GroupAddress;

/// IGMPv1/IGMPv2 Membership Query message type.
///
/// IGMPv1 & IGMPv2 can be distinguished via the `max_response_time` field:
///
/// * For IGMPv1 the `max_response_time` field is set to zero
/// * For IGMPv2 the `max_response_time` field is set to NOT zero
///
/// ```text
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Type = 0x11 | Max Resp Time | Checksum |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Group Address |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MembershipQueryType {
/// The maximum response time for the membership report
/// (only for IGMPv2, set to 0 for IGMPv1).
///
/// Specifies the maximum allowed time before sending a
/// responding report in units of 1/10 second.
///
/// For IGMPv1, this field is always set to zero.
pub max_response_time: u8,

/// The group address being queried.
///
/// Set to zero for general queries, to learn which groups
/// have members on an attached network. Filled for group-specific
/// queries to learn if a particular group has members on an
/// attached network.
///
/// For IGMPv1, this field is always set to zero.
pub group_address: GroupAddress,
}

impl MembershipQueryType {
/// Number of bytes/octets an [`MembershipQueryType`] takes up in serialized form.
pub const LEN: usize = 8;
}
Loading
Loading