v0.18.0 MACsec Support & ECN+DSCP Support for IPv6
What are the major changes?
- Support for MACsec (IEEE 802.1AE)
- The
vlanfield inSlicedPacket,LaxSlicedPacket,PacketHeaders,LaxPacketHeadershas been replaced withlink_exts. Ipv4Ecn&Ipv4Dscphave been replaced byIpEcn&IpDscp.Ipv6Header&Ipv6HeaderSlicenow supports the reading & setting ofIpEcn&IpDscp(thanks to @baxterjo)LaxEtherPayloadSlicehas been introduced &len_sourceadded toEtherPayloadSlice.source_addr()&destination_addr()methods ofIpSlice,Ipv4HeaderSlice,Ipv6Header,Ipv6HeaderSlice,LaxIpSliceare now available in non-std mode (thanks to @Dominaezzz)- Minimum supported Rust version as been configured to 1.83.0 (thanks to @baxterjo)
What is MACsec (IEEE 802.1AE)?
MACsec is a protocol that allows the signing and/or encryption of packet contents from the link layer downwards. The main difference between MACsec and IPSec is that IPSec is located after the IP header while MACsec is located above the IP header and can also encrypt the contents of the IP header itself while IPSSec does not encrypt the IP header. As such MACsec is usually used to secure local networks, while IPSec is more commonly used for VPNs and alike that leave the local network.
Changes needed for MACsec Support
Adding MACsec support required some breaking changes, specifically on how VLAN headers are handled. The MACsec SECTAG is a header that can be present in the same locations as "VLAN" headers. It has no fixed position and can be located before or after VLAN headers or after the Ethernet 2 header without a VLAN header being present at all. This invalidates the assumption etherparse had in previous versions that VLAN headers are always directly located after the Ethernet2 header and that if there are multiple VLAN headers that they are directly located after each other. Now there could be a MACsec header present in between VLAN headers.
To support the different combinations of MACSec & VLAN headers the vlan field in SlicedPacket, PacketHeaders, LaxSlicedPacket & LaxPacketHeaders has been replaced with a link_exts field that can contain up to three "link extensions":
pub struct SlicedPacket<'a> {
/// Ethernet II header if present.
pub link: Option<LinkSlice<'a>>,
- /// Single or double vlan headers if present.
- pub vlan: Option<VlanSlice<'a>>,
+ /// Link extensions (VLAN & MAC Sec headers).
+ pub link_exts: ArrayVec<LinkExtSlice<'a>, { SlicedPacket::LINK_EXTS_CAP }>,
/// IPv4 or IPv6 header, IP extension headers & payload if present.
pub net: Option<NetSlice<'a>>,
/// TCP or UDP header & payload if present.
pub transport: Option<TransportSlice<'a>>,
}
impl<'a> SlicedPacket<'a> {
+ /// Maximum supported number of link extensions.
+ pub const LINK_EXTS_CAP: usize = 3;LinkExtSlice, LinkExtHeader & LaxLinkExtSlice are enums that can either contain a MACsec or VLAN header:
/// A slice containing the link layer extension header (currently only Ethernet II and
/// SLL are supported).
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LinkExtSlice<'a> {
/// Slice containing a VLAN header & payload.
Vlan(SingleVlanSlice<'a>),
/// Slice containing MACsec header & payload.
Macsec(MacsecSlice<'a>),
}LINK_EXTS_CAP is currently set to 3. This means that up to three MACsec & VLAN headers can be parsed by etherparse.
New Methods to access VLAN related data:
In case you don't care about MACsec and only care about VLAN a new vlan() method has been added to SlicedPacket, PacketHeaders, LaxSlicedPacket & LaxPacketHeaders that behave the same as the old vlan field:
/// Returns the first two VLAN headers.
pub fn vlan(&self) -> Option<VlanHeader> {If you only care about the VLAN ids you can also use the new vlan_ids() method in SlicedPacket, PacketHeaders, LaxSlicedPacket & LaxPacketHeaders:
/// Returns the VLAN ids present in this packet.
pub fn vlan_ids(&self) -> ArrayVec<VlanId, { SlicedPacket::LINK_EXTS_CAP }> {New LaxEtherPayloadSlice & EtherPayloadSlice
As MACsec has an optional length field new LaxEtherPayloadSlice & EtherPayloadSlice structs have been introduced that can be used to keep track where the original length of the payload came from.
MacsecPayloadSlice
As MACsec can be "encrypted", "unencrypted without payload modification" and "unencrypted with payload modifications" a new payload enum has been introduced:
pub enum MacsecPayloadSlice<'a> {
/// Unencrypted unmodified ether payload.
Unmodified(EtherPayloadSlice<'a>),
/// Modified payload (either by encryption or other algorithm).
Modified(&'a [u8]),
}In the unmodified case the next ether_type value can be read from the EtherPayloadSlice. In the encrypted or modified case this is not possible as there are no informations available on how to decrypt the packet or how the payload was modified.
What does the MACSec implementation not support?
Currently the ICV present at the end of an MACsec packet is not separated. The current implementation relies on the length fields of the lower layers (IP header, UDP or other transport length fields) to make sure it is not interpreted as data from a lower layer. The implementation is also missing any support for encrypting/decrypting payload data or verifying signatures. It is purely a "parse the parsable header fields" implementation.
Pull Requests
- Minor spelling error TRHEE -> THREE by @hawkinsw in #115
- Add MSRV and CI Check for MSRV by @baxterjo in #117
- Use
core::netoverstd::netby @Dominaezzz in #120 - Add IEEE 802.1AE (also known as MACsec) support by @JulianSchmid in #121
- Add Traffic class support for IPv6 by @baxterjo in #118
- Update version to 0.18.0 by @JulianSchmid in #123
- Add ECN & DSCP methods to Ipv6HeaderSlice by @JulianSchmid in #124
New Contributors
- @hawkinsw made their first contribution in #115
- @baxterjo made their first contribution in #117
- @Dominaezzz made their first contribution in #120
Thanks for your contributions.
Full Changelog: v0.17.0...v0.18.0