summaryrefslogtreecommitdiff
path: root/src/protocol
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2023-09-12 14:34:56 +0800
committerluwenpeng <[email protected]>2023-09-12 14:39:33 +0800
commit8755e95f068da56c099e9c51dc4a89b55960e48d (patch)
tree3db6cea2db66eb55d64a67dc214af5ed4fd18157 /src/protocol
parent88172ebc1d79a7b289b125418ddc50f20421d944 (diff)
[feature] Support IPv6 Extensions Decode
Diffstat (limited to 'src/protocol')
-rw-r--r--src/protocol/ethernet.rs2
-rw-r--r--src/protocol/ip.rs29
-rw-r--r--src/protocol/ipv4.rs2
-rw-r--r--src/protocol/ipv6.rs342
-rw-r--r--src/protocol/mpls.rs4
-rw-r--r--src/protocol/tcp.rs2
-rw-r--r--src/protocol/udp.rs2
-rw-r--r--src/protocol/vlan.rs2
8 files changed, 373 insertions, 12 deletions
diff --git a/src/protocol/ethernet.rs b/src/protocol/ethernet.rs
index 6e25696..a588c0d 100644
--- a/src/protocol/ethernet.rs
+++ b/src/protocol/ethernet.rs
@@ -60,7 +60,7 @@ pub enum EtherType {
Other(u16),
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EthernetFrame {
pub source_mac: MacAddress,
pub dest_mac: MacAddress,
diff --git a/src/protocol/ip.rs b/src/protocol/ip.rs
index d7a1fe9..8d22e15 100644
--- a/src/protocol/ip.rs
+++ b/src/protocol/ip.rs
@@ -6,9 +6,10 @@ use nom::IResult;
* Struct
******************************************************************************/
+#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IPProtocol {
- HOPOPT,
+ IPV6_HOP_HDR,
ICMP,
IGMP,
GGP,
@@ -27,7 +28,12 @@ pub enum IPProtocol {
CHAOS,
UDP,
IPV6,
+ IPV6_ROUTING_HDR,
+ IPV6_FRAGMENT_HDR,
+ ESP,
+ AUTH,
ICMP6,
+ IPV6_DEST_HDR,
Other(u8),
}
@@ -38,7 +44,7 @@ pub enum IPProtocol {
impl From<u8> for IPProtocol {
fn from(raw: u8) -> Self {
match raw {
- 0 => IPProtocol::HOPOPT,
+ 0 => IPProtocol::IPV6_HOP_HDR, // IPv6 Hop-by-Hop Options
1 => IPProtocol::ICMP,
2 => IPProtocol::IGMP,
3 => IPProtocol::GGP,
@@ -57,12 +63,31 @@ impl From<u8> for IPProtocol {
16 => IPProtocol::CHAOS,
17 => IPProtocol::UDP,
41 => IPProtocol::IPV6,
+ 43 => IPProtocol::IPV6_ROUTING_HDR, // IPv6 Routing Header
+ 44 => IPProtocol::IPV6_FRAGMENT_HDR, // IPv6 Fragment Header
+ 50 => IPProtocol::ESP, // Encap Security Payload [RFC4303]
+ 51 => IPProtocol::AUTH, // Authentication Header [RFC4302]
58 => IPProtocol::ICMP6,
+ 60 => IPProtocol::IPV6_DEST_HDR, // IPv6 Destination Options
other => IPProtocol::Other(other),
}
}
}
+impl IPProtocol {
+ pub fn is_ipv6_ext_header(next_header: IPProtocol) -> bool {
+ match next_header {
+ IPProtocol::IPV6_HOP_HDR => true,
+ IPProtocol::IPV6_ROUTING_HDR => true,
+ IPProtocol::IPV6_FRAGMENT_HDR => true,
+ // IPProtocol::ESP => true,
+ IPProtocol::AUTH => true,
+ IPProtocol::IPV6_DEST_HDR => true,
+ _ => false,
+ }
+ }
+}
+
impl Decode for IPProtocol {
type Iterm = IPProtocol;
fn decode(input: &[u8]) -> IResult<&[u8], IPProtocol> {
diff --git a/src/protocol/ipv4.rs b/src/protocol/ipv4.rs
index f0ee008..61dce29 100644
--- a/src/protocol/ipv4.rs
+++ b/src/protocol/ipv4.rs
@@ -31,7 +31,7 @@ use std::net::Ipv4Addr;
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IPv4Header {
pub version: u8, // 4 bit
pub ihl: u8, // 4 bit
diff --git a/src/protocol/ipv6.rs b/src/protocol/ipv6.rs
index f8bafdd..5a30847 100644
--- a/src/protocol/ipv6.rs
+++ b/src/protocol/ipv6.rs
@@ -41,7 +41,32 @@ use std::net::Ipv6Addr;
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+/*
+ * IPv6 AH Format
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Next Header | Payload Len | RESERVED |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Security Parameters Index (SPI) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Sequence Number Field |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + Integrity Check Value-ICV (variable) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct IPv6Extension {
+ pub next_header: IPProtocol,
+ pub ext_length: u8, // Extension total Length
+ pub data: Vec<u8>, // Extension data length (ext_length - 2)
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IPv6Header {
pub version: u8, // 4 bit
pub dsc: u8, // Differentiated Services Codepoint: 6 bit
@@ -52,6 +77,7 @@ pub struct IPv6Header {
pub hop_limit: u8,
pub source_address: Ipv6Addr,
pub dest_address: Ipv6Addr,
+ pub extensions: Vec<IPv6Extension>,
}
/******************************************************************************
@@ -71,6 +97,34 @@ fn address_v6_decode(input: &[u8]) -> IResult<&[u8], Ipv6Addr> {
Ok((input, Ipv6Addr::from(<[u8; 16]>::try_from(ipv6).unwrap())))
}
+fn extension_decode(input: &[u8], curr_proto: IPProtocol) -> IResult<&[u8], IPv6Extension> {
+ let (input, next_header) = IPProtocol::decode(input)?;
+ let (input, mut ext_length) = number::streaming::be_u8(input)?;
+
+ /*
+ * https://datatracker.ietf.org/doc/html/rfc4302#page-4
+ *
+ * (Note that although IPv6 [DH98] characterizes AH as
+ * an extension header, its length is measured in 32-bit words, not the
+ * 64-bit words used by other IPv6 extension headers.)
+ */
+ if curr_proto == IPProtocol::AUTH {
+ ext_length = ext_length * 4 + 8 // update Authentication Header length
+ } else {
+ ext_length = ext_length * 8 + 8; // update other extension header length
+ }
+ let (input, data) = bytes::streaming::take(ext_length - 2)(input)?;
+
+ Ok((
+ input,
+ IPv6Extension {
+ next_header,
+ ext_length,
+ data: data.to_vec(),
+ },
+ ))
+}
+
impl Decode for IPv6Header {
type Iterm = IPv6Header;
fn decode(input: &[u8]) -> IResult<&[u8], IPv6Header> {
@@ -84,10 +138,18 @@ impl Decode for IPv6Header {
let (input, source_address) = address_v6_decode(input)?;
let (input, dest_address) = address_v6_decode(input)?;
- // TODO IPv6 Ext Header Decode
+ let mut remain = input;
+ let mut next_proto = next_header;
+ let mut extensions = Vec::new();
+ while IPProtocol::is_ipv6_ext_header(next_proto) {
+ let (left, extension) = extension_decode(remain, next_proto)?;
+ remain = left;
+ next_proto = extension.next_header;
+ extensions.push(extension);
+ }
Ok((
- input,
+ remain,
IPv6Header {
version: ver_tc.0,
dsc: (ver_tc.1 << 2) + ((tc_fl.0 & 0b1100) >> 2),
@@ -98,6 +160,7 @@ impl Decode for IPv6Header {
hop_limit,
source_address,
dest_address,
+ extensions,
},
))
}
@@ -109,6 +172,7 @@ impl Decode for IPv6Header {
#[cfg(test)]
mod tests {
+ use super::IPv6Extension;
use super::IPv6Header;
use crate::protocol::codec::Decode;
use crate::protocol::ip::IPProtocol;
@@ -160,6 +224,81 @@ mod tests {
dest_address: Ipv6Addr::new(
0x2409, 0x8034, 0x4040, 0x5301, 0x0000, 0x0000, 0x0000, 0x0204,
),
+ extensions: Vec::new(),
+ };
+
+ assert_eq!(IPv6Header::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = IPv6Header::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+ }
+
+ #[test]
+ fn ipv6_hop_extension_decode() {
+ /*
+ * Internet Protocol Version 6, Src: ::, Dst: ff02::16
+ * 0110 .... = Version: 6
+ * .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
+ * .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
+ * .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
+ * .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
+ * Payload Length: 36
+ * Next Header: IPv6 Hop-by-Hop Option (0)
+ * Hop Limit: 1
+ * Source Address: ::
+ * Destination Address: ff02::16
+ * IPv6 Hop-by-Hop Option
+ * Next Header: ICMPv6 (58)
+ * Length: 0
+ * [Length: 8 bytes]
+ * Router Alert
+ * Type: Router Alert (0x05)
+ * 00.. .... = Action: Skip and continue (0)
+ * ..0. .... = May Change: No
+ * ...0 0101 = Low-Order Bits: 0x05
+ * Length: 2
+ * Router Alert: MLD (0)
+ * PadN
+ * Type: PadN (0x01)
+ * 00.. .... = Action: Skip and continue (0)
+ * ..0. .... = May Change: No
+ * ...0 0001 = Low-Order Bits: 0x01
+ * Length: 0
+ * PadN: <none>
+ */
+
+ let bytes = [
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x3a, 0x00,
+ 0x05, 0x02, 0x00, 0x00, 0x01, 0x00, /* Extensions Data */
+ 0xff, /* Payload */
+ ];
+
+ let expectation = IPv6Header {
+ version: 6,
+ dsc: 0,
+ ecn: 0,
+ flow_label: 0,
+ length: 36,
+ next_header: IPProtocol::IPV6_HOP_HDR,
+ hop_limit: 1,
+ source_address: Ipv6Addr::new(
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ ),
+ dest_address: Ipv6Addr::new(
+ 0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0016,
+ ),
+ extensions: vec![IPv6Extension {
+ next_header: IPProtocol::ICMP6,
+ ext_length: 8,
+ data: vec![0x05, 0x02, 0x00, 0x00, 0x01, 0x00],
+ }],
};
assert_eq!(IPv6Header::decode(&bytes), Ok((LAST_SLICE, expectation)));
@@ -171,5 +310,202 @@ mod tests {
} else {
println!("return: Incomplete data");
}
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ fn ipv6_routing_extension_decode() {
+ /*
+ * Internet Protocol Version 6, Src: 2200::244:212:3fff:feae:22f7, Dst: 2200::240:2:0:0:4
+ * 0110 .... = Version: 6
+ * .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
+ * .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
+ * .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
+ * .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
+ * Payload Length: 32
+ * Next Header: Routing Header for IPv6 (43)
+ * Hop Limit: 4
+ * Source Address: 2200::244:212:3fff:feae:22f7
+ * Destination Address: 2200::240:2:0:0:4
+ * [Source SLAAC MAC: Dell_ae:22:f7 (00:12:3f:ae:22:f7)]
+ * Routing Header for IPv6 (Segment Routing)
+ * Next Header: ICMPv6 (58)
+ * Length: 2
+ * [Length: 24 bytes]
+ * Type: Segment Routing (4)
+ * Segments Left: 1
+ * Last Entry: 0
+ * Flags: 0x00
+ * Tag: 0000
+ * Address[0]: 2200::210:2:0:0:4
+ */
+
+ let bytes = [
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2b, 0x04, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x44, 0x02, 0x12, 0x3f, 0xff, 0xfe, 0xae, 0x22, 0xf7, 0x22, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3a, 0x02,
+ 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* Extensions Data */
+ 0xff, /* Payload */
+ ];
+
+ let expectation = IPv6Header {
+ version: 6,
+ dsc: 0,
+ ecn: 0,
+ flow_label: 0,
+ length: 32,
+ next_header: IPProtocol::IPV6_ROUTING_HDR,
+ hop_limit: 4,
+ source_address: Ipv6Addr::new(
+ 0x2200, 0x0000, 0x0000, 0x0244, 0x0212, 0x3fff, 0xfeae, 0x22f7,
+ ),
+ dest_address: Ipv6Addr::new(
+ 0x2200, 0x0000, 0x0000, 0x0240, 0x0002, 0x0000, 0x0000, 0x0004,
+ ),
+ extensions: vec![IPv6Extension {
+ next_header: IPProtocol::ICMP6,
+ ext_length: 24,
+ data: vec![
+ 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ ],
+ }],
+ };
+
+ assert_eq!(IPv6Header::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = IPv6Header::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ fn ipv6_auth_extension_decode() {
+ // TODO need test
+ }
+
+ #[test]
+ fn ipv6_mutil_extension_decode() {
+ /*
+ * Internet Protocol Version 6, Src: ::1, Dst: ::3
+ * 0110 .... = Version: 6
+ * .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
+ * .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
+ * .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
+ * .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
+ * Payload Length: 32
+ * Next Header: IPv6 Hop-by-Hop Option (0)
+ * Hop Limit: 64
+ * Source Address: ::1
+ * Destination Address: ::3
+ * IPv6 Hop-by-Hop Option
+ * Next Header: Destination Options for IPv6 (60)
+ * Length: 0
+ * [Length: 8 bytes]
+ * PadN
+ * Type: PadN (0x01)
+ * 00.. .... = Action: Skip and continue (0)
+ * ..0. .... = May Change: No
+ * ...0 0001 = Low-Order Bits: 0x01
+ * Length: 4
+ * PadN: 00000000
+ * Destination Options for IPv6
+ * Next Header: Routing Header for IPv6 (43)
+ * Length: 0
+ * [Length: 8 bytes]
+ * PadN
+ * Type: PadN (0x01)
+ * 00.. .... = Action: Skip and continue (0)
+ * ..0. .... = May Change: No
+ * ...0 0001 = Low-Order Bits: 0x01
+ * Length: 4
+ * PadN: 00000000
+ * Routing Header for IPv6 (Source Route)
+ * Next Header: Fragment Header for IPv6 (44)
+ * Length: 0
+ * [Length: 8 bytes]
+ * Type: Source Route (0)
+ * [Expert Info (Note/Deprecated): Routing header type is deprecated]
+ * [Routing header type is deprecated]
+ * [Severity level: Note]
+ * [Group: Deprecated]
+ * Segments Left: 0
+ * Reserved: 00000000
+ * Fragment Header for IPv6
+ * Next header: No Next Header for IPv6 (59)
+ * Reserved octet: 0x00
+ * 0000 0000 0000 0... = Offset: 0 (0 bytes)
+ * .... .... .... .00. = Reserved bits: 0
+ * .... .... .... ...0 = More Fragments: No
+ * Identification: 0x00000000
+ */
+
+ let bytes = [
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x00,
+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, /* Extensions Data */
+ 0xff, /* Payload */
+ ];
+
+ let expectation = IPv6Header {
+ version: 6,
+ dsc: 0,
+ ecn: 0,
+ flow_label: 0,
+ length: 32,
+ next_header: IPProtocol::IPV6_HOP_HDR,
+ hop_limit: 64,
+ source_address: Ipv6Addr::new(
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
+ ),
+ dest_address: Ipv6Addr::new(
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003,
+ ),
+ extensions: vec![
+ IPv6Extension {
+ next_header: IPProtocol::IPV6_DEST_HDR,
+ ext_length: 8,
+ data: vec![0x01, 0x04, 0x00, 0x00, 0x00, 0x00],
+ },
+ IPv6Extension {
+ next_header: IPProtocol::IPV6_ROUTING_HDR,
+ ext_length: 8,
+ data: vec![0x01, 0x04, 0x00, 0x00, 0x00, 0x00],
+ },
+ IPv6Extension {
+ next_header: IPProtocol::IPV6_FRAGMENT_HDR,
+ ext_length: 8,
+ data: vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+ },
+ IPv6Extension {
+ next_header: IPProtocol::Other(59),
+ ext_length: 8,
+ data: vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
+ },
+ ],
+ };
+
+ assert_eq!(IPv6Header::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = IPv6Header::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
}
}
diff --git a/src/protocol/mpls.rs b/src/protocol/mpls.rs
index 2c4c443..e6a7a37 100644
--- a/src/protocol/mpls.rs
+++ b/src/protocol/mpls.rs
@@ -9,7 +9,7 @@ use nom::IResult;
* Struct
******************************************************************************/
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MplsHeader {
pub label: u32,
pub experimental: u8,
@@ -17,7 +17,7 @@ pub struct MplsHeader {
pub ttl: u8,
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
// Ethernet pseudowire (PW) https://tools.ietf.org/html/rfc4448#section-3.1
pub struct PwEthHeader {
pub control_word: u32,
diff --git a/src/protocol/tcp.rs b/src/protocol/tcp.rs
index a34fc37..5a88b25 100644
--- a/src/protocol/tcp.rs
+++ b/src/protocol/tcp.rs
@@ -69,7 +69,7 @@ pub enum TcpOption {
},
}
-#[derive(Clone, Debug, PartialEq, Eq, Default)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TcpHeader {
pub source_port: u16,
pub dest_port: u16,
diff --git a/src/protocol/udp.rs b/src/protocol/udp.rs
index 0eba88f..43cf75c 100644
--- a/src/protocol/udp.rs
+++ b/src/protocol/udp.rs
@@ -20,7 +20,7 @@ use nom::IResult;
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UdpHeader {
pub source_port: u16,
pub dest_port: u16,
diff --git a/src/protocol/vlan.rs b/src/protocol/vlan.rs
index 7f64780..7533e41 100644
--- a/src/protocol/vlan.rs
+++ b/src/protocol/vlan.rs
@@ -9,7 +9,7 @@ use nom::IResult;
* Struct
******************************************************************************/
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VlanHeader {
// A 3 bit number which refers to the IEEE 802.1p class of service and maps to the frame priority level.
pub priority_code_point: u8,