diff --git a/README.md b/README.md index 19a2505e..2ca803c7 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ A zero allocation supporting library for parsing & writing a bunch of packet bas Currently supported are: * Ethernet II * IEEE 802.1Q VLAN Tagging Header +* ARP * IPv4 * IPv6 (supporting the most common extension headers, but not all) * UDP @@ -49,7 +50,7 @@ match SlicedPacket::from_ethernet(&packet) { Ok(value) => { println!("link: {:?}", value.link); println!("vlan: {:?}", value.vlan); - println!("net: {:?}", value.net); // contains ip + println!("net: {:?}", value.net); // contains ip & arp println!("transport: {:?}", value.transport); } } @@ -77,7 +78,7 @@ match PacketHeaders::from_ethernet_slice(&packet) { Ok(value) => { println!("link: {:?}", value.link); println!("vlan: {:?}", value.vlan); - println!("net: {:?}", value.net); // contains ip + println!("net: {:?}", value.net); // contains ip & arp println!("transport: {:?}", value.transport); } } @@ -103,6 +104,7 @@ It is also possible to only slice one packet layer: * [`Ethernet2Slice::from_slice_without_fcs`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Slice.html#method.from_slice_without_fcs) & [`Ethernet2Slice::from_slice_with_crc32_fcs`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Slice.html#method.from_slice_with_crc32_fcs) * [`LinuxSllSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllSlice.html#method.from_slice) * [`SingleVlanSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanSlice.html#method.from_slice) & [`DoubleVlanSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanSlice.html#method.from_slice) +* [`ArpPacketSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.ArpPacketSlice.html#method.from_slice) * [`IpSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/enum.IpSlice.html#method.from_slice) & [`LaxIpSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/enum.LaxIpSlice.html#method.from_slice) * [`Ipv4Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Slice.html#method.from_slice) & [`LaxIpv4Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LaxIpv4Slice.html#method.from_slice) * [`Ipv6Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv6Slice.html#method.from_slice) & [`LaxIpv6Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LaxIpv6Slice.html#method.from_slice) @@ -141,6 +143,7 @@ And for deserialization into the corresponding header structs have a look at: * [`LinuxSllHeader::read`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.read) & [`LinuxSllHeader::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.from_slice) * [`SingleVlanHeader::read`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.read) & [`SingleVlanHeader::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.from_slice) * [`DoubleVlanHeader::read`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.read) & [`DoubleVlanHeader::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.from_slice) +* [`ArpPacket::read`](https://docs.rs/etherparse/~0/etherparse/struct.ArpPacket.html#method.read) & [`ArpPacket::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.ArpPacket.html#method.from_slice) * [`IpHeaders::read`](https://docs.rs/etherparse/~0/etherparse/enum.IpHeaders.html#method.read) & [`IpHeaders::from_slice`](https://docs.rs/etherparse/~0/etherparse/enum.IpHeaders.html#method.from_slice) * [`Ipv4Header::read`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.read) & [`Ipv4Header::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.from_slice) * [`Ipv4Extensions::read`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Extensions.html#method.read) & [`Ipv4Extensions::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Extensions.html#method.from_slice) @@ -198,6 +201,8 @@ Read the documentations of the different methods for a more details: * [`LinuxSllHeader::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.to_bytes) & [`LinuxSllHeader::write`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.write) * [`SingleVlanHeader::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.to_bytes) & [`SingleVlanHeader::write`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.write) * [`DoubleVlanHeader::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.to_bytes) & [`DoubleVlanHeader::write`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.write) +* [`ArpPacket::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.ArpPacket.html#method.to_bytes) & [`ArpPacket::write`](https://docs.rs/etherparse/~0/etherparse/struct.ArpPacket.html#method.write) +* [`ArpEthIpv4Packet::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.ArpEthIpv4Packet.html#method.to_bytes) * [`Ipv4Header::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.to_bytes) & [`Ipv4Header::write`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.write) & [`Ipv4Header::write_raw`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.write_raw) * [`Ipv4Extensions::write`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Extensions.html#method.write) * [`Ipv6Header::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv6Header.html#method.to_bytes) & [`Ipv6Header::write`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv6Header.html#method.write) diff --git a/etherparse/examples/read_by_slicing.rs b/etherparse/examples/read_by_slicing.rs index f9299daa..2186f945 100644 --- a/etherparse/examples/read_by_slicing.rs +++ b/etherparse/examples/read_by_slicing.rs @@ -92,6 +92,7 @@ fn main() { println!(" {:?}", ipv6.extensions()); } } + Some(Arp(value)) => println!(" Arp {:?}", value), None => {} } diff --git a/etherparse/proptest-regressions/compositions_tests.txt b/etherparse/proptest-regressions/compositions_tests.txt index 6bd98dbf..edd40dac 100644 --- a/etherparse/proptest-regressions/compositions_tests.txt +++ b/etherparse/proptest-regressions/compositions_tests.txt @@ -6,3 +6,4 @@ # everyone who runs the test benefits from these saved cases. cc 93464c2fb682bf96a32f9800d3932df8611a278bf6c993dc3ad6301d17795715 # shrinks to ref eth = Ethernet2Header { source: [0, 0, 0, 0, 0, 0], destination: [0, 0, 0, 0, 0, 0], ether_type: 0 }, ref vlan_outer = SingleVlanHeader { priority_code_point: 0, drop_eligible_indicator: false, vlan_identifier: 0, ether_type: 0 }, ref vlan_inner = SingleVlanHeader { priority_code_point: 0, drop_eligible_indicator: false, vlan_identifier: 0, ether_type: 0 }, ref ipv4 = Ipv4Header { ihl: 7, differentiated_services_code_point: 0, explicit_congestion_notification: 0, payload_len: 0, identification: 0, dont_fragment: false, more_fragments: false, fragments_offset: 0, time_to_live: 0, protocol: 4, header_checksum: 0, source: [0, 0, 0, 0], destination: [0, 0, 0, 0], options: [0, 0, 0, 0, 0, 0, 0, 0] }, ref ipv4_exts = Ipv4Extensions { auth: None }, ref ipv6 = Ipv6Header { traffic_class: 213, flow_label: 798389, payload_length: 24896, next_header: 187, hop_limit: 229, source: [14, 32, 160, 168, 37, 154, 115, 40, 38, 87, 212, 112, 188, 142, 254, 197], destination: [6, 159, 253, 179, 126, 197, 144, 208, 190, 191, 89, 166, 208, 140, 54, 50] }, ref ipv6_exts = Ipv6Extensions { hop_by_hop_options: None, destination_options: None, routing: None, fragment: Some(Ipv6FragmentHeader { next_header: 156, fragment_offset: 2564, more_fragments: false, identification: 3123850911 }), auth: None }, ref udp = UdpHeader { source_port: 45157, destination_port: 34201, length: 57104, checksum: 21037 }, ref tcp = TcpHeader { source_port: 51159, destination_port: 19610, sequence_number: 3703908533, acknowledgment_number: 8047906, data_offset: 13, ns: true, fin: false, syn: false, rst: false, psh: false, ack: false, urg: true, ece: false, cwr: true, window_size: 3326, checksum: 50866, urgent_pointer: 1068, options: [Err(UnknownId(34))] }, ref icmpv4 = Icmpv4Header { icmp_type: TimestampReply(TimestampMessage { id: 54195, seq: 33654, originate_timestamp: 2593543617, receive_timestamp: 534962444, transmit_timestamp: 141913819 }), checksum: 50019 }, ref icmpv6 = Icmpv6Header { icmp_type: Unknown { type_u8: 228, code_u8: 213, bytes5to8: [17, 44, 158, 162] }, checksum: 51305 }, ref payload = [176, 206, 197, 85, 12, 15, 112, 1, 92, 102, 232, 123, 66, 67, 0, 129, 111, 164, 134, 24, 82, 206, 103, 137, 239, 130, 78, 149, 131, 220, 160, 114, 222, 169, 165, 141, 202, 80, 8, 234, 94, 151, 21, 242, 120, 93, 230, 85, 162, 209, 105, 154, 72, 203, 198, 235, 64, 239, 33, 102, 54, 45, 201, 245, 26, 192, 182, 10, 232, 131, 82, 9, 32, 183, 65, 225, 132, 208, 61, 251, 109, 66, 234, 46, 65, 240, 148, 46, 146, 56, 17, 205, 103, 253, 158, 32, 21, 148, 243, 191, 23, 135, 145, 188, 136, 139, 125, 99, 144, 34, 142, 229, 128, 46, 226, 88, 205, 126, 2, 39, 87, 16, 74, 20, 184, 165, 75, 34, 0, 206, 61, 220, 196, 39, 190, 113, 217, 4, 238, 26, 232, 52, 18, 123, 48, 196, 238, 75, 120, 241, 41, 229, 114, 161, 65, 143, 237, 251, 87, 156, 155, 210, 178, 43, 166, 184, 11, 9, 250, 221, 22, 72, 65, 160, 116, 60, 242, 239, 97, 249, 39, 207, 214, 47, 6, 120, 51, 165, 69, 122, 156, 142, 159, 27, 224, 171, 233, 105, 79, 49, 32, 118, 141, 227, 174, 207, 109, 135, 5, 13, 248, 235, 33, 113, 233, 53, 131, 52, 188, 52, 203, 12, 88, 54, 84, 21, 132, 41, 211, 30, 215, 46, 108, 126, 141, 13, 113, 21, 233, 111, 115, 109, 107, 246, 214, 65, 211, 186, 60, 224, 211, 214, 191, 65, 62, 169, 122, 246, 237, 107, 183, 160, 179, 144, 106, 63, 10, 0, 87, 75, 175, 228, 178, 219, 35, 227, 161, 214, 134, 106, 156, 244, 126, 186, 201, 199, 202, 30, 220, 163, 146, 208, 192, 179, 241, 219, 6, 43, 39, 21, 231, 16, 213, 192, 194, 82, 33, 121, 188, 56, 108, 79, 219, 183, 20, 18, 192, 42, 7, 109, 217, 25, 42, 170, 154, 206, 35, 131, 193, 187, 217, 185, 178, 196, 130, 25, 85, 228, 103, 112, 163, 53, 154, 65, 68, 219, 219, 163, 208, 44, 33, 90, 118, 133, 114, 43, 242, 58, 196, 246, 55, 223, 181, 14, 249, 35, 73, 179, 242, 211, 188, 156, 4, 213, 54, 205, 50, 83, 116, 13, 128, 133, 239, 122, 106, 98, 140, 171, 202, 8, 11, 51, 219, 68, 19, 114, 8, 229, 177, 199, 9, 228, 130, 194, 211, 59, 16, 145, 23, 163, 228, 186, 187, 24, 194, 93, 75, 44, 23, 192, 96, 226, 164, 242, 75, 135, 48, 118, 108, 49, 62, 63, 228, 71, 153, 134, 15, 192, 249, 103, 44, 211] cc 19938c0e61de8fbe9f8df17d1325091a1825e2b209a4adb8b21dcd28a0e0f558 # shrinks to ref eth = Ethernet2Header { source: [0, 0, 0, 0, 0, 0], destination: [0, 0, 0, 0, 0, 0], ether_type: 0 }, ref vlan_outer = SingleVlanHeader { priority_code_point: 0, drop_eligible_indicator: false, vlan_identifier: 0, ether_type: 0 }, ref vlan_inner = SingleVlanHeader { priority_code_point: 0, drop_eligible_indicator: false, vlan_identifier: 0, ether_type: 0 }, ref ipv4 = Ipv4Header { ihl: 8, differentiated_services_code_point: 0, explicit_congestion_notification: 0, payload_len: 34240, identification: 0, dont_fragment: false, more_fragments: false, fragments_offset: 0, time_to_live: 0, protocol: 95, header_checksum: 2458, source: [0, 0, 0, 0], destination: [0, 0, 0, 0], options: [80, 229, 92, 224, 82, 126, 48, 60, 105, 201, 96, 77] }, ref ipv4_exts = Ipv4Extensions { auth: None }, ref ipv6 = Ipv6Header { traffic_class: 129, flow_label: 787898, payload_length: 54827, next_header: 33, hop_limit: 254, source: [109, 7, 4, 79, 149, 61, 253, 73, 214, 117, 64, 10, 168, 230, 137, 73], destination: [44, 199, 106, 47, 71, 14, 18, 94, 107, 95, 41, 238, 83, 187, 218, 132] }, ref ipv6_exts = Ipv6Extensions { hop_by_hop_options: Some(Ipv6RawExtensionHeader { next_header: 60, payload: [112, 231, 1, 88, 255, 168, 119, 95, 144, 149, 61, 29, 235, 11, 182, 192, 83, 15, 201, 180, 189, 232, 85, 231, 220, 116, 192, 132, 43, 162, 23, 161, 129, 246, 28, 236, 164, 174, 67, 235, 121, 212, 9, 73, 30, 98, 190, 173, 122, 133, 58, 154, 142, 6, 24, 203, 3, 230, 232, 50, 77, 203, 83, 151, 3, 157, 193, 242, 25, 246, 224, 4, 178, 173, 156, 5, 210, 3, 97, 27, 171, 152, 187, 16, 98, 73, 57, 176, 35, 25, 246, 71, 154, 32, 132, 227, 164, 29, 92, 159, 74, 247, 144, 68, 39, 254, 227, 156, 63, 140, 246, 246, 199, 111, 101, 173, 179, 116, 79, 114, 249, 162, 71, 113, 121, 224, 229, 237, 67, 3, 4, 162, 152, 120, 58, 132, 244, 196, 136, 196, 206, 160, 45, 83, 167, 218, 32, 206, 52, 246, 144, 220, 133, 150, 36, 91, 193, 118, 28, 33, 236, 64, 255, 72, 190, 70, 160, 38, 139, 134, 80, 153, 236, 93, 198, 211, 21, 19, 251, 131, 119, 219, 161, 19, 144, 96, 6, 188, 115, 43, 91, 216, 5, 135, 101, 166, 99, 11, 174, 169, 255, 248, 101, 23, 62, 55, 169, 40, 6, 186, 195, 235, 76, 41] }), destination_options: Some(Ipv6RawExtensionHeader { next_header: 43, payload: [238, 203, 236, 202, 32, 25, 193, 164, 167, 189, 30, 208, 207, 108, 114, 10, 12, 226, 180, 59, 207, 44, 143, 244, 221, 200, 232, 154, 140, 180, 167, 70, 197, 72, 31, 249, 141, 75, 7, 255, 201, 53, 76, 234, 201, 187, 214, 141, 249, 216, 232, 12, 45, 196, 208, 110, 78, 14, 60, 251, 17, 239, 13, 141, 216, 29, 230, 120, 102, 88, 104, 237, 17, 252, 108, 126, 203, 75] }), routing: Some(Ipv6RoutingExtensions { routing: Ipv6RawExtensionHeader { next_header: 44, payload: [254, 77, 166, 70, 182, 207, 149, 153, 212, 40, 122, 249, 15, 84, 41, 126, 254, 103, 2, 162, 52, 216, 226, 175, 148, 253, 5, 153, 50, 16, 32, 44, 139, 24, 73, 245, 17, 9, 50, 18, 176, 70, 177, 29, 220, 255, 253, 255, 94, 39, 69, 225, 93, 176, 139, 48, 98, 210, 151, 80, 3, 105, 114, 59, 232, 171, 163, 235, 40, 56, 9, 85, 180, 225, 71, 230, 216, 128, 194, 109, 150, 198, 175, 68, 186, 112, 223, 48, 61, 245, 191, 34, 3, 207, 250, 27, 110, 21, 229, 221, 166, 76, 220, 214, 215, 104, 137, 46, 134, 94, 106, 89, 129, 218, 113, 234, 119, 79, 84, 147, 98, 202, 148, 239, 67, 99, 223, 222, 139, 13, 237, 170, 164, 89, 15, 185, 202, 252, 2, 156, 33, 28, 194, 52, 180, 232, 239, 202, 23, 123, 215, 81, 236, 65, 80, 192, 136, 184, 237, 135, 205, 183, 104, 66, 253, 128, 176, 245, 213, 65, 120, 202, 15, 130, 202, 55, 28, 94, 189, 8, 11, 59, 112, 96, 196, 186, 15, 96, 32, 60, 193, 8, 95, 44, 110, 224, 32, 71, 96, 140, 69, 124, 69, 241, 153, 87, 65, 15, 171, 113, 248, 239, 156, 78, 174, 47, 99, 190, 159, 163, 29, 197, 75, 161, 4, 209, 213, 236, 86, 120, 74, 15, 147, 85, 135, 147, 242, 220, 144, 55, 202, 170, 71, 90, 107, 103, 170, 8, 231, 169, 231, 170, 153, 184, 158, 99, 127, 228, 243, 191, 139, 69, 75, 133, 185, 212, 104, 214, 233, 171, 0, 135, 73, 14, 31, 2, 90, 187, 82, 205, 161, 69, 251, 143, 243, 15, 56, 250, 98, 175, 82, 196, 216, 95, 249, 127, 84, 181, 211, 50, 81, 36, 26, 247, 224, 3, 92, 61, 120, 67, 163, 170, 185, 61, 254, 91, 248, 20, 150, 19, 49, 71, 52, 102, 152, 209, 105, 219, 65, 151, 19, 101, 102, 133, 216, 94, 237, 221, 232, 168, 51, 28, 214, 231, 179, 180, 235, 17, 36, 19, 33, 54, 232, 131, 150, 95, 96, 84, 13, 6, 20, 28, 160, 92, 193, 206, 231, 10, 238, 240, 6, 77, 44, 78, 6, 253, 142, 54, 72, 135, 39, 144, 95, 132, 194, 5, 25, 225, 46, 143, 153, 93, 213, 32, 114, 214, 230, 61, 21, 189, 86, 34, 12, 85, 75, 242, 112, 3, 251, 4, 129, 141, 153, 47, 228, 157, 65, 13, 82, 38, 80, 34, 7, 52, 172, 210, 141, 83, 27, 39, 100, 16, 0, 216, 114, 134, 195, 220, 156, 79, 174, 220, 88, 252, 193, 210, 93, 190, 229, 6, 16, 63, 190, 46, 5, 126, 28, 10, 51, 102, 19, 8, 153, 157, 142, 125, 6, 40, 100, 68, 139, 231, 69, 159, 46, 98, 36, 25, 200, 140, 107, 101, 15, 70, 25, 89, 211, 3, 17, 253, 9, 50, 39, 60, 47, 185, 135, 17, 218, 116, 65, 107, 110, 122, 227, 202, 155, 71, 164, 119, 189, 84, 128, 8, 180, 93, 177, 45, 15, 198, 16, 79, 179, 46, 103, 85, 91, 229, 254, 12, 152, 129, 160, 104, 16, 217, 157, 157, 61, 137, 189, 194, 132, 234, 243, 123, 91, 70, 132, 5, 222, 200, 134, 26, 129, 182, 254, 254, 151, 165, 184, 13, 85, 106, 44, 20, 79, 183, 130, 223, 209, 88, 35, 174, 160, 91, 199, 118, 168, 40, 189, 181, 59, 38, 74, 43, 24, 80, 25, 224, 73, 119, 241, 101, 41, 109, 115, 24, 35, 204, 181, 100, 33, 78, 109, 253, 192, 21, 137, 4, 203, 143, 243, 152, 96, 237, 209, 26, 217, 68, 239, 59, 1, 200, 219, 177, 22, 196, 180, 1, 102, 202, 126, 216, 32, 221, 143, 99, 223, 7, 129, 183, 252, 35, 59, 15, 204, 56, 18, 118, 229, 215, 81, 147, 172, 69, 116, 46, 51, 169, 157, 22, 69, 178, 97, 224, 190, 198, 11, 216, 188, 108, 161, 120, 196, 181, 172, 21, 41, 124, 197, 106, 58, 193, 102, 16, 67, 127, 109, 45, 135, 60, 110, 30, 155, 88, 173, 34, 14, 78, 117, 93, 158, 51, 117, 168, 226, 43, 44, 173, 185, 20, 111, 151, 32, 95, 226, 103, 101, 76, 229, 117, 14, 56, 187, 185, 131, 185, 50, 68, 20, 173, 69, 94, 131, 252, 114, 133, 98, 55, 143, 45, 12, 25, 226, 189, 170, 73, 70, 163, 98, 27, 195, 211, 38, 108, 243, 46, 5, 140, 56, 85, 136, 98, 154, 22, 112, 91, 192, 81, 51, 252, 190, 222, 16, 151, 178, 51, 209, 208, 15, 72, 17, 127, 219, 117, 10, 93, 193, 133, 55, 125, 98, 95, 35, 63, 115, 88, 44, 80, 120, 10, 224, 207, 98, 243, 227, 236, 149, 9, 163, 166, 250, 134, 32, 144, 182, 144, 212, 237, 231, 157, 18, 39, 46, 116, 226, 106, 195, 193, 129, 171, 121, 5, 135, 72, 160, 170, 139, 83, 138, 70, 124, 115, 12, 219, 197, 250, 209, 205, 250, 55, 107, 37, 26, 107, 141, 164, 107, 93, 45, 26, 7, 240, 168, 25, 169, 241, 21, 22, 142, 216, 164, 17, 50, 214, 204, 32, 31, 184, 179, 11, 134, 255, 229, 160, 130, 167, 149, 190, 141, 191, 64, 247, 35, 182, 183, 9, 119, 116, 199, 43, 91, 48, 101, 117, 52, 145, 248, 62, 25, 82, 129, 253, 53, 206, 51, 195, 80, 45, 83, 239, 194, 4, 108, 177, 156, 196, 42, 215, 45, 2, 2, 251, 9, 122, 230, 239, 39, 83, 129, 88, 192, 181, 57, 235, 22, 25, 122, 54, 9, 242, 32, 96, 178, 29, 2, 9, 212, 157, 250, 227, 114, 138, 238, 202, 121, 90, 101, 42, 137, 159, 27, 112, 225, 206, 201, 104, 201, 177, 177, 26, 103, 227, 100, 190, 231, 117, 136, 230, 180, 121, 54, 60, 113, 26, 49, 140, 66, 76, 150, 183, 116, 193, 170, 130, 166, 214, 204, 212, 125, 75, 19, 17, 79, 245, 198, 176, 15, 17, 43, 92, 169, 227, 25, 11, 194, 245, 93, 126, 247, 254, 74, 148, 187, 231, 153, 196, 193, 177, 125, 67, 183, 79, 219, 77, 89, 233, 42, 45, 38, 232, 164, 146, 228, 179, 204, 107, 191, 254, 232, 61, 172, 148, 144, 56, 60, 178, 90, 211, 72, 255, 93, 3, 25, 220, 180, 82, 70, 85, 209, 97, 92, 7, 232, 204, 201, 202, 235, 31, 75, 60, 157, 149, 147, 168, 175, 138, 116, 118, 127, 123, 98, 115, 205, 37, 81, 74, 136, 150, 89, 83, 204, 201, 105, 154, 27, 1, 104, 193, 102, 17, 247, 204, 236, 134, 110, 165, 141, 123, 21, 229, 56, 215, 184, 3, 251, 7, 181, 246, 50, 133, 74, 50, 36, 224, 12, 171, 200, 245, 193, 110, 42, 93, 115, 215, 182, 128, 107, 175, 64, 170, 131, 206, 74, 124, 194, 150, 191, 102, 85, 139, 127, 117, 35, 239, 137, 225, 68, 108, 118, 250, 127, 250, 128, 167, 149, 240, 21, 238, 117, 98, 181, 186, 162, 83, 152, 255, 80, 111, 235, 55, 133, 209, 43, 118, 151, 148, 140, 253, 249, 178, 148, 174, 254, 236, 250, 172, 27, 220, 189, 20, 26, 201, 253, 187, 109, 55, 51, 26, 243, 44, 65, 59, 131, 116, 15, 52, 222, 174, 63, 49, 150, 113, 71, 98, 228, 48, 27, 236, 183, 240, 184, 87, 21, 146, 248, 224, 54, 46, 81, 109, 129, 243, 104, 48, 239, 36, 8, 232, 9, 229, 82, 164, 3, 186, 86, 202, 128, 224, 218, 19, 161, 92, 187, 55, 41, 203, 143, 139, 54, 50, 120, 253, 62, 26, 232, 113, 97, 136, 6, 53, 89, 90, 200, 202, 246, 102, 193, 14, 244, 179, 226, 253, 205, 189, 236, 98, 51, 154, 217, 83, 254, 238, 229, 32, 197, 124, 71, 165, 235, 224, 67, 190, 207, 23, 232, 240, 34, 203, 137, 64, 93, 65, 240, 205, 71, 61, 36, 104, 99, 125, 94, 9, 255, 131, 204, 210, 17, 210, 205, 112, 188, 146, 246, 237, 76, 128, 24, 198, 43, 184, 72, 22, 77, 196, 8, 77, 138, 105, 155, 165, 215, 253, 162, 248, 172, 95, 79, 102, 199, 90, 251, 122, 74, 24, 69, 65, 112, 172, 227, 140, 202, 104, 235, 119, 220, 80, 78, 234, 21, 129, 138, 250, 188, 87, 131, 20, 185, 76, 24, 103, 231, 145, 48, 207, 167, 230, 18, 30, 80, 190, 139, 36, 22, 165, 21, 176, 240, 227, 82, 246, 112, 184, 21, 226, 116, 175, 147, 250, 109, 236, 83, 52, 112, 156, 180, 111, 220, 43, 77, 112, 98, 193, 125, 145, 31, 38, 115, 213, 67, 95, 62, 81, 208, 123, 8, 158, 157, 171, 133, 246, 210, 56, 169, 221, 27, 153, 121, 210, 134, 24, 202, 90, 183, 78, 229, 99, 153, 245, 135, 122, 55, 158, 129, 216, 147, 80, 150, 203, 182, 220, 9, 95, 65, 222, 120, 144, 133, 148, 45, 134, 7, 113, 74, 219, 238, 229, 1, 112, 173, 189, 232, 176, 219, 14, 143, 14, 134, 108, 209, 218, 59, 252, 192, 185, 255, 142, 96, 87, 1, 77, 243, 219, 46, 78, 253, 128, 249, 182, 149, 144, 174, 176, 198, 64, 3, 200, 129, 217, 102, 131, 119, 102, 74, 10, 212, 86, 143, 165, 108, 235, 36, 100, 18, 3, 241, 8, 113, 92, 201, 114, 216, 97, 120, 199, 196, 172, 29, 179, 205, 252, 163, 199, 187, 139, 42, 103, 99, 51, 51, 8, 205, 180, 149, 177, 245, 77, 111, 26, 246, 112, 174, 236, 221, 168, 72, 137, 38, 59, 10, 89, 6, 68, 66, 158, 17, 246, 149, 239, 165, 221, 28, 144, 252, 247, 102, 194, 215, 90, 15, 206, 93, 133, 197, 15, 81, 155, 143, 200, 201, 112, 105, 60, 84, 52, 179, 179, 18, 67, 178, 126, 113, 15, 45, 26, 159, 223, 161, 249, 141, 31, 179, 43, 94, 8, 125, 194, 219, 26, 65, 57, 166, 236, 185, 24, 63, 206, 215, 22, 85, 117, 41, 197, 182, 147, 46, 202, 167, 206, 154, 89, 200, 95, 238, 93, 125, 4, 101, 195, 253, 179, 29, 13, 234, 225, 171, 72, 82, 224, 60, 191, 74, 113, 217, 161, 10, 13, 202, 196, 144, 104, 46, 71, 49, 212, 22, 181, 250, 28, 27, 95, 151, 158, 25, 84, 226, 200] }, final_destination_options: None }), fragment: Some(Ipv6FragmentHeader { next_header: 109, fragment_offset: 2113, more_fragments: true, identification: 5944605 }), auth: None }, ref udp = UdpHeader { source_port: 27523, destination_port: 52161, length: 45869, checksum: 14910 }, ref tcp = TcpHeader { source_port: 17245, destination_port: 46697, sequence_number: 160328470, acknowledgment_number: 2631620014, data_offset: 10, ns: false, fin: false, syn: false, rst: true, psh: false, ack: true, urg: false, ece: true, cwr: false, window_size: 24158, checksum: 53442, urgent_pointer: 8968, options: [Err(UnknownId(173))] }, ref icmpv4 = Icmpv4Header { icmp_type: Unknown { type_u8: 234, code_u8: 221, bytes5to8: [200, 89, 56, 131] }, checksum: 16430 }, ref icmpv6 = Icmpv6Header { icmp_type: Unknown { type_u8: 30, code_u8: 106, bytes5to8: [52, 110, 228, 155] }, checksum: 38251 }, ref payload = [111, 188, 151, 183, 149, 185, 18, 245, 219, 34, 101, 100, 224, 105, 138, 24, 34, 92, 6, 75, 219, 201, 60, 187, 214, 136, 150, 248, 6, 50, 64, 136, 89, 13, 42, 46, 93, 80, 5, 22, 114, 77, 34, 58, 115, 121, 159, 158, 151, 132, 171, 188, 57, 49, 52, 166, 160, 191, 60, 116, 6, 117, 215, 53, 99, 85, 33, 16, 109, 90, 48, 192, 31, 77, 71, 43, 229, 66, 22, 199, 176, 216, 156, 180, 197, 105, 72, 60, 198, 61, 119, 201, 118, 240, 131, 5, 102, 75, 200, 84, 254, 216, 228, 209, 150, 251, 234, 232, 20, 243, 127, 121, 97, 68, 16, 43, 140, 15, 235, 75, 178, 41, 209, 114, 244, 16, 163, 224, 223, 132, 128, 56, 142, 160, 184, 140, 89, 35, 167, 84, 217, 209, 200, 3, 120, 124, 220, 113, 169, 39, 64, 82, 255, 81, 239, 172, 199, 48, 179, 102, 109, 53, 167, 253, 203, 114, 225, 103, 233, 1, 72, 29, 178, 90, 44, 246, 248, 43, 137, 46, 5, 250, 25, 94, 155, 183, 46, 229, 121, 120, 16, 105, 40, 15, 168, 29, 93, 71, 42, 36, 179, 253, 67, 132, 81, 196, 190, 165, 130, 54, 57, 212, 240, 76, 252, 175, 147, 200, 18, 179, 196, 82, 9, 135, 197, 217, 12, 60, 130, 144, 129, 206, 133, 122, 183, 87, 194, 149, 79, 206, 67, 178, 51, 38, 60, 143, 132, 9, 221, 193, 27, 31, 145, 245, 137, 134, 248, 231, 68, 211, 125, 22, 234, 78, 231, 119, 27, 241, 143, 43, 173, 231, 117, 180, 255, 230, 138, 68, 233, 225, 184, 16, 132, 168, 65, 84, 177, 210, 183, 55, 188, 216, 82, 7, 137, 1, 81, 69, 14, 104, 82, 239, 73, 218, 70, 196, 163, 59, 183, 151, 95, 197, 81, 49, 97, 162, 96, 9, 95, 254, 137, 252, 100, 190, 218, 124, 130, 82, 32, 154, 253, 44, 253, 58, 149, 116, 45, 82, 104, 103, 119, 42, 175, 208, 203, 25, 65, 154, 218, 222, 22, 148, 94, 5, 226, 217, 158, 148, 30, 84, 36, 142, 214, 166, 176, 62, 198, 178, 94, 205, 220, 155, 5, 86, 48, 167, 114, 108, 210, 127, 105, 247, 106, 30, 77, 100, 149, 109, 139, 60, 174, 121, 24, 203, 35, 163, 15, 212, 151, 206, 94, 134, 28, 253, 192, 66, 12, 167, 45, 146, 101] +cc 8a9b0a970a9a2fe38d925b7ce0f4ff73ba262d7258e2d20e1ff7c9251885a396 # shrinks to ref eth = Ethernet2Header { source: [0, 0, 0, 0, 0, 0], destination: [0, 0, 0, 0, 0, 0], ether_type: 0x0000 }, ref vlan_outer = SingleVlanHeader { pcp: VlanPcp(0), drop_eligible_indicator: false, vlan_id: VlanId(0), ether_type: 0x0000 }, ref vlan_inner = SingleVlanHeader { pcp: VlanPcp(0), drop_eligible_indicator: false, vlan_id: VlanId(0), ether_type: 0x0806 (Address Resolution Protocol (ARP)) }, ref ipv4 = Ipv4Header { dscp: Ipv4Dscp(0), ecn: Ipv4Ecn(0), total_len: 20, identification: 0, dont_fragment: false, more_fragments: false, fragment_offset: IpFragOffset(0), time_to_live: 0, protocol: 29 (ISO-TP4 - ISO Transport Protocol Class 4), header_checksum: 0, source: [0, 0, 0, 0], destination: [0, 0, 0, 0], options: [] }, ref ipv4_exts = Ipv4Extensions { auth: Some(IpAuthHeader { next_header: 24 (TRUNK-2 - Trunk-2), spi: 2509063036, sequence_number: 3755394165, raw_icv: [92, 181, 195, 73, 130, 142, 140, 140, 223, 45, 197, 36, 9, 69, 55, 43, 149, 231, 9, 4, 120, 102, 160, 165, 107, 87, 64, 204, 231, 179, 197, 165, 115, 145, 144, 125, 94, 30, 168, 176, 19, 63, 236, 79, 115, 199, 15, 92, 162, 106, 139, 90, 248, 240, 127, 37, 144, 179, 147, 224, 57, 41, 152, 198, 117, 161, 199, 197, 98, 23, 220, 31, 79, 25, 99, 100, 171, 127, 4, 248, 29, 2, 189, 178, 206, 124, 247, 24, 51, 75, 240, 246, 123, 220, 42, 147, 91, 187, 218, 92, 90, 171, 47, 1, 54, 19, 58, 73, 82, 207, 143, 83, 100, 150, 44, 228, 214, 246, 111, 239, 107, 35, 187, 109, 244, 118, 33, 58, 192, 37, 195, 191, 74, 82, 149, 2, 25, 245, 127, 172, 34, 72, 200, 6, 37, 121, 147, 136, 76, 40, 209, 25, 202, 208, 118, 230, 122, 151, 38, 140, 238, 68, 101, 149, 46, 233, 83, 180, 105, 169, 213, 123, 189, 109, 9, 214, 192, 238, 95, 177, 223, 71, 103, 7, 243, 54, 156, 100, 138, 195, 151, 91, 193, 151, 177, 82, 165, 16, 106, 253, 90, 76, 0, 204, 20, 190, 229, 54, 147, 227, 190, 57, 233, 143, 98, 114, 82, 106, 157, 134, 187, 18, 66, 21, 220, 135, 175, 76, 33, 91, 242, 181, 47, 74, 206, 252, 84, 28, 248, 36, 94, 8, 124, 219, 150, 145, 213, 192, 233, 11, 56, 72, 201, 140, 48, 93, 198, 77, 26, 31, 208, 179, 191, 185, 195, 83, 39, 3, 110, 92, 146, 229, 222, 36, 53, 176, 178, 49, 44, 110, 75, 8, 104, 135, 52, 26, 50, 4, 183, 70, 84, 67, 8, 76, 25, 45, 106, 225, 33, 107, 142, 35, 90, 100, 141, 25, 202, 82, 41, 43, 49, 103, 33, 202, 244, 125, 123, 69, 118, 118, 118, 72, 244, 53, 71, 161, 133, 88, 131, 144, 109, 3, 60, 40, 166, 109, 206, 115, 18, 97, 172, 157, 50, 144, 179, 3, 7, 154, 121, 56, 138, 174, 242, 151, 95, 245, 204, 195, 241, 62, 200, 106, 28, 205, 27, 201, 190, 66, 12, 127, 70, 30, 227, 173, 225, 6, 142, 228, 215, 244, 138, 130, 171, 59, 180, 180, 127, 145, 1, 228, 40, 222, 36, 43, 141, 74, 226, 229, 46, 9, 101, 229, 99, 111, 102, 188, 153, 86, 118, 111, 1, 235, 176, 218, 83, 130, 14, 60, 142, 42, 26, 99, 245, 73, 213, 247, 185, 176, 118, 29, 139, 236, 218, 167, 13, 129, 124, 105, 194, 63, 95, 95, 197, 97, 65, 41, 221, 32, 122, 48, 218, 198, 95, 95, 124, 6, 2, 84, 160, 96, 128, 125, 172, 240, 53, 131, 49, 10, 254, 166, 16, 127, 66, 232, 206, 172, 31, 24, 115, 213, 172, 29, 96, 116, 88, 163, 135, 121, 233, 223, 63, 65, 45, 18, 119, 145, 192, 246, 94, 235, 25, 83, 174, 244, 215, 135, 229, 230, 216, 101, 146, 157, 118, 91, 43, 16, 196, 2, 167, 72, 139, 20, 105, 112, 167, 191, 83, 233, 43, 43, 254, 199, 49, 68, 69, 91, 192, 153, 244, 15, 59, 119, 80, 51, 129, 220, 154, 172, 193, 147, 59, 241, 215, 70, 224, 110, 21, 33, 34, 216, 177, 174, 227, 84, 38, 181, 249, 95, 87, 152, 165, 132, 95, 134, 37, 228] }) }, ref ipv6 = Ipv6Header { traffic_class: 15, flow_label: Ipv6FlowLabel(377208), payload_length: 39375, next_header: 11 (NVP-II - Network Voice Protocol), hop_limit: 164, source: [130, 247, 84, 229, 201, 228, 210, 155, 39, 71, 113, 56, 54, 232, 243, 221], destination: [42, 1, 131, 202, 153, 22, 76, 246, 14, 164, 20, 54, 68, 234, 189, 145] }, ref ipv6_exts = Ipv6Extensions { hop_by_hop_options: Some(Ipv6RawExtHeader { next_header: 60 (IPv6-Opts - Destination Options for IPv6), payload: [62, 47, 61, 126, 20, 254, 36, 110, 35, 19, 117, 163, 115, 86, 52, 46, 27, 154, 128, 33, 173, 71, 49, 222, 253, 62, 14, 57, 125, 78, 228, 70, 248, 103, 253, 195, 35, 6, 89, 220, 194, 161, 100, 221, 94, 202, 232, 176, 37, 104, 84, 204, 136, 200, 112, 93, 234, 1, 245, 194, 81, 94, 114, 17, 71, 224, 146, 87, 167, 234, 170, 48, 69, 136, 130, 154, 143, 122, 81, 104, 95, 50, 213, 82, 77, 182, 60, 31, 192, 201, 244, 231, 252, 125, 130, 59, 128, 141, 185, 41, 125, 190, 138, 143, 72, 81, 15, 3, 56, 216, 52, 209, 87, 197, 249, 92, 165, 226, 237, 205, 210, 3, 182, 13, 89, 244, 39, 149, 201, 75, 104, 25, 209, 124, 87, 125, 44, 51, 84, 70, 144, 225, 60, 8, 220, 2, 47, 131, 62, 183, 243, 165, 43, 20, 222, 245, 223, 171, 74, 184, 83, 63, 66, 200, 185, 58, 27, 172, 193, 98, 113, 56, 199, 151, 136, 20, 241, 232, 212, 165, 82, 187, 209, 172, 128, 153, 175, 140, 151, 178, 207, 210, 232, 57, 124, 187, 90, 140, 2, 203, 59, 81, 175, 81, 242, 125, 217, 19, 67, 109, 148, 37, 253, 127, 22, 118, 105, 86, 190, 137, 172, 53, 96, 87, 166, 105, 151, 59, 192, 91, 76, 58, 186, 14, 61, 133, 213, 36, 178, 48, 71, 226, 35, 225, 153, 252, 43, 154, 118, 6, 58, 243, 47, 180, 225, 73, 137, 234, 81, 56, 91, 175, 90, 151, 177, 210, 6, 73, 250, 9, 158, 217, 181, 141, 37, 184, 233, 148, 143, 13, 110, 161, 112, 191, 234, 14, 69, 54, 88, 227, 6, 43, 248, 36, 191, 157, 200, 209, 170, 189, 46, 203, 128, 37, 247, 62, 31, 116, 145, 11, 91, 150, 186, 252, 188, 28, 195, 202, 242, 240, 5, 204, 27, 102, 36, 94, 55, 244, 238, 9, 199, 126, 145, 192, 77, 88, 154, 197, 74, 186, 94, 81, 172, 19, 213, 130, 78, 98, 160, 53, 199, 70, 150, 17, 167, 36, 138, 239, 164, 89, 252, 210, 188, 230, 252, 180, 138, 105, 82, 71, 221, 160, 48, 40, 54, 168, 39, 153, 124, 210, 125, 202, 57, 145, 202, 186, 49, 218, 153, 18, 230, 234, 222, 250, 125, 160, 11, 228, 185, 111, 15, 183, 24, 54, 112, 220, 188, 185, 132, 199, 20, 9, 81, 53, 195, 100, 208, 40, 167, 241, 8, 215, 70, 112, 245, 242, 210, 225, 54, 113, 80, 45, 123, 44, 8, 54, 64, 21, 176, 55, 26, 47, 197, 145, 107, 144, 28, 110, 182, 27, 0, 1, 47, 166, 244, 61, 0, 10, 116, 36, 106, 85, 214, 49, 37, 215, 25, 113, 22, 34, 49, 194, 206, 54, 75, 250, 86, 72, 15, 180, 147, 202, 211, 42, 192, 83, 95, 133, 78, 13, 26, 51, 176, 183, 149, 132, 51, 13, 173, 190, 205, 236, 235, 28, 244, 110, 185, 136, 10, 52, 244, 24, 23, 202, 51, 101, 139, 150, 79, 118, 138, 55, 60, 90, 146, 20, 136, 15, 253, 103, 24, 159, 155, 229, 119, 121, 21, 60, 168, 62, 95, 95, 46, 230, 165, 224, 255, 68, 80, 233, 89, 185, 215, 238, 33, 186, 174, 233, 170, 65, 205, 66, 127, 30, 85, 119, 248, 136, 163, 213, 15, 159, 132, 160, 58, 4, 155, 47, 52, 166, 16, 195, 116, 156, 167, 25, 125, 160, 101, 29, 96, 11, 191, 192, 20, 96, 166, 203, 40, 233, 187, 197, 199, 27, 21, 152, 63, 26, 61, 148, 11, 101, 175, 137, 233, 155, 41, 178, 106, 177, 178, 138, 80, 93, 114, 47, 24, 166, 30, 109, 48, 54, 243, 44, 214, 250, 146, 62, 145, 212, 244, 227, 10, 68, 35, 137, 172, 242, 219, 175, 173, 66, 92, 87, 110, 244, 41, 10, 67, 161, 217, 164, 140, 199, 197, 195, 20, 165, 89, 133, 9, 128, 171, 67, 127, 142, 207, 60, 0, 69, 127, 52, 26, 222, 36, 254, 236, 223, 172, 209, 155, 199, 13, 241, 158, 249, 196, 185, 173, 37, 195, 94, 15, 183, 129, 51, 81, 28, 244, 179, 196, 200, 248, 33, 72, 202, 238, 176, 25, 197, 83, 42, 224, 214, 41, 11, 187, 211, 100, 57, 245, 80, 135, 213, 174, 58, 16, 1, 98, 13, 162, 178, 13, 61, 55, 165, 150, 209, 62, 115, 88, 178, 168, 2, 245, 21, 231, 221, 84, 131, 243, 0, 99, 193, 157, 227, 244, 41, 47, 127, 151, 23, 30, 83, 189, 104, 239, 97, 111, 79, 213, 165, 19, 75, 237, 148, 161, 132, 81, 29, 197, 193, 199, 119, 189, 102, 227, 122, 38, 110, 186, 178, 234, 41, 116, 127, 123, 65, 110, 128, 171, 65, 10, 156, 131, 186, 49, 112, 22, 189, 222, 27, 95, 65, 233, 51, 151, 52, 43, 185, 171, 194, 108, 200, 196, 8, 77, 238, 81, 37, 195, 19, 220, 248, 177, 227, 141, 76, 1, 150, 158, 187, 133, 49, 147, 64, 151, 48, 212, 97, 241, 153, 118, 8, 253, 119, 125, 8, 136, 228, 54, 174, 147, 63, 68, 219, 79, 5, 56, 43, 16, 144, 47, 79, 171, 180, 66, 142, 186, 132, 44, 50, 172, 44, 118, 96, 150, 161, 174, 218, 68, 217, 94, 113, 33, 49, 116, 13, 161, 46, 48, 206, 28, 53, 200, 208, 243, 104, 97, 204, 186, 126, 153, 70, 141, 149, 28, 189, 206, 100, 101, 179, 183, 106, 15, 243, 49, 90, 119, 183, 222, 49, 244, 50, 218, 16, 186, 19, 153, 141, 2, 210, 227, 45, 191, 60, 50, 226, 254, 160, 109, 3, 24, 189, 138, 220, 230, 73, 51, 61, 238, 228, 242, 183, 71, 166, 59, 183, 32, 223, 40, 233, 218, 48, 2, 215, 103, 222, 229, 8, 134, 145, 136, 143, 66, 139, 95, 212, 59, 173, 225, 105, 138, 189, 234, 113, 174, 7, 232, 207, 226, 74, 50, 247, 212, 76, 237, 177, 103, 145, 92, 3, 41, 13, 139, 149, 187, 128, 43, 202, 130, 94, 25, 82, 250, 220, 192, 164, 148, 221, 98, 94, 105, 178, 60, 20, 142, 231, 23, 76, 136, 12, 85, 180, 85, 75, 134, 195, 147, 194, 211, 59, 183, 85, 127, 123, 195, 153, 201, 197, 37, 212, 160, 39, 68, 229, 244, 71, 79, 248, 77, 84, 130, 71, 155, 4, 141, 158, 211, 173, 62, 87, 146, 15, 3, 122, 154, 175, 34, 158, 255, 137, 84, 218, 30, 59, 182, 59, 193, 92, 13, 174, 243, 178, 227, 194, 228, 41, 12, 121, 71, 170, 15, 201, 10, 155, 108, 48, 122, 69, 246, 158, 192, 155, 67, 100, 254, 16, 151, 85, 69, 24, 6, 254, 13, 94, 134, 144, 16, 5, 112, 80, 235, 159, 73, 15, 87, 114, 216, 36, 8, 168, 11, 215, 188, 210, 243, 85, 78, 96, 27, 242, 83, 32, 207, 27, 191, 176, 75, 76, 50, 200, 104, 154, 228, 203, 31, 232, 105, 79, 78, 89, 63, 146, 52, 108, 114, 8, 186, 201, 229, 162, 179, 214, 46, 177, 173, 146, 84, 73, 21, 79, 22, 137, 187, 240, 72, 47, 88, 165, 195, 244, 133, 27, 252, 218, 149, 50, 231, 92, 253, 198, 255, 51, 214, 53, 147, 189, 100, 71, 174, 39, 17, 247, 177, 185, 8, 181, 160, 139, 211, 223, 172, 33, 73, 116, 108, 182, 248, 82, 39, 215, 136, 26, 141, 159, 226, 129, 99, 232, 155, 174, 28, 115, 117, 119, 231, 30, 173, 235, 156, 13, 161, 1, 52, 174] }), destination_options: Some(Ipv6RawExtHeader { next_header: 44 (IPv6-Frag - Fragment Header for IPv6), payload: [32, 35, 195, 46, 88, 189, 22, 199, 230, 162, 123, 89, 66, 218, 24, 103, 194, 32, 107, 137, 196, 98, 188, 82, 148, 190, 188, 13, 7, 214, 106, 129, 158, 134, 232, 135, 109, 7, 40, 241, 74, 227, 139, 81, 143, 182, 224, 235, 137, 14, 81, 157, 200, 186, 195, 164, 166, 184, 143, 252, 54, 118, 10, 11, 253, 83, 239, 71, 139, 127, 25, 28, 91, 186, 238, 170, 141, 38, 47, 164, 229, 109, 243, 71, 182, 25, 136, 223, 183, 40, 91, 105, 9, 169, 64, 149, 69, 103, 60, 81, 192, 20, 161, 114, 111, 222, 211, 64, 255, 79, 20, 28, 205, 59, 6, 58, 243, 42, 228, 120, 180, 47, 106, 177, 89, 25, 53, 159, 172, 159, 96, 119, 139, 68, 27, 234, 249, 37, 174, 0, 78, 138, 48, 181, 7, 58, 62, 134, 209, 152, 63, 7, 167, 33, 48, 0, 204, 240, 31, 135, 59, 245, 179, 144, 36, 71, 18, 25, 132, 86, 133, 135, 186, 30, 198, 189, 95, 143, 189, 141, 108, 134, 202, 110, 171, 178, 92, 230, 238, 255, 155, 7, 233, 217, 134, 190, 33, 127, 176, 90, 11, 146, 61, 11, 79, 196, 173, 41, 88, 125, 15, 124, 8, 68, 88, 145, 171, 125, 177, 115, 162, 157, 127, 171, 41, 209, 86, 179, 79, 69, 28, 197, 177, 11, 211, 170, 162, 45, 123, 46, 59, 112, 11, 132, 84, 167, 203, 152, 42, 204, 198, 204, 248, 88, 61, 195, 248, 241, 145, 19, 231, 207, 226, 95, 130, 216, 147, 124, 19, 2, 55, 69, 223, 30, 178, 166, 99, 76, 122, 6, 136, 36, 19, 123, 147, 144, 105, 205, 243, 85, 216, 117, 77, 151, 122, 1, 161, 20, 133, 47, 0, 23, 127, 205, 49, 146, 136, 12, 98, 52, 141, 4, 237, 120, 230, 103, 248, 181, 37, 105, 127, 1, 174, 183, 137, 187, 134, 119, 102, 124, 195, 229, 3, 111, 49, 203, 33, 22, 18, 110, 11, 163, 202, 92, 158, 15, 187, 172, 222, 135, 79, 72, 178, 135, 131, 248, 213, 21, 243, 106, 98, 144, 114, 194, 103, 175, 69, 182, 57, 15, 93, 146, 221, 86, 173, 19, 112, 155, 52, 74, 82, 104, 174, 125, 47, 203, 64, 77, 230, 90, 110, 37, 36, 254, 210, 96, 29, 161, 124, 195, 83, 164, 43, 200, 101, 65] }), routing: None, fragment: Some(Ipv6FragmentHeader { next_header: 51 (AH - Authentication Header), fragment_offset: IpFragOffset(40), more_fragments: false, identification: 936320599 }), auth: Some(IpAuthHeader { next_header: 50 (ESP - Encap Security Payload), spi: 1791434917, sequence_number: 265966117, raw_icv: [226, 4, 122, 88, 130, 221, 201, 80, 210, 94, 96, 230, 244, 224, 150, 80, 90, 103, 75, 80, 142, 100, 22, 49, 19, 18, 103, 246, 4, 136, 202, 81, 234, 216, 135, 16, 59, 70, 188, 72, 16, 69, 103, 133, 58, 104, 118, 132, 203, 4, 197, 196, 209, 61, 43, 216, 193, 158, 252, 235, 62, 176, 46, 22, 85, 121, 196, 55, 203, 99, 107, 202, 139, 163, 4, 43, 215, 57, 61, 135, 76, 79, 100, 179, 207, 129, 248, 136, 109, 67, 122, 133, 83, 221, 197, 195, 207, 30, 196, 26, 122, 186, 45, 90, 27, 145, 130, 62, 159, 10, 18, 250, 179, 135, 90, 159, 56, 160, 141, 78, 234, 181, 54, 177, 30, 122, 102, 236, 57, 143, 72, 148, 169, 129, 165, 114, 216, 73, 88, 62, 207, 82, 87, 241, 130, 203, 224, 142, 244, 149, 108, 61, 147, 60, 45, 129, 140, 184, 248, 87, 128, 163, 202, 235, 5, 215, 128, 67, 251, 220, 80, 196, 27, 25, 114, 119, 216, 197, 29, 212, 42, 18, 143, 89, 7, 247, 195, 83, 206, 210, 81, 214, 42, 59, 42, 130, 98, 192, 168, 195, 208, 68, 155, 172, 68, 69, 214, 85, 223, 245, 217, 63, 159, 119, 114, 250, 162, 118, 227, 52, 135, 81, 254, 127, 79, 91, 236, 233, 41, 194, 143, 216, 26, 116, 33, 163, 141, 4, 218, 81, 169, 168, 223, 212, 84, 75, 241, 47, 148, 84, 170, 192, 125, 251, 4, 131, 113, 185, 170, 168, 243, 250, 238, 179, 55, 77, 112, 231, 69, 109, 232, 134, 1, 33, 46, 205, 222, 34, 75, 161, 47, 132, 19, 253, 16, 76, 213, 108, 218, 211, 25, 136, 167, 246, 153, 246, 40, 30, 238, 57, 153, 123, 156, 86, 131, 132, 40, 220, 143, 242, 217, 198, 197, 236, 155, 15, 142, 157, 24, 204, 2, 222, 185, 172, 224, 226, 91, 159, 15, 16, 197, 136, 229, 78, 78, 198, 54, 7, 255, 197, 179, 160, 176, 177, 50, 55, 28, 32, 203, 232, 251, 177, 129, 92, 29, 185, 90, 69, 125, 146, 205, 109, 51, 35, 75, 233, 189, 10, 133, 177, 73, 14, 65, 151, 56, 152, 214, 74, 139, 135, 139, 17, 108, 66, 201, 87, 117, 52, 37, 76, 247, 158, 129, 84, 28, 248, 46, 32, 115, 4, 94, 0, 244, 14, 245, 68, 38, 142, 6, 47, 6, 224, 158, 18, 95, 142, 250, 64, 229, 178, 176, 251, 50, 182, 245, 206, 90, 184, 111, 198, 240, 81, 177, 44, 78, 169, 175, 170, 135, 207, 192, 171, 199, 228, 164, 111, 18, 53, 253, 123, 38, 44, 175, 190, 78, 113, 65, 146, 97, 180, 141, 90, 160, 227, 222, 46, 156, 64, 42, 104, 216, 208, 114, 2, 181, 123, 194, 176, 188, 122, 235, 223, 224, 74, 157, 182, 84, 172, 150, 234, 99, 166, 39, 103, 242, 247, 219, 75, 223, 92, 154, 54, 80, 238, 226, 18, 17, 81, 108, 162, 87, 51, 128, 239, 96, 174, 56, 51, 122, 130, 143, 178, 140, 188, 153, 141, 120, 4, 183, 54, 42, 87, 158, 20, 182, 136, 248, 40, 154, 108, 116, 143, 167, 140, 77, 136, 212, 23, 29, 218, 246, 248, 129, 103, 33, 99, 195, 33, 13, 56, 64, 230, 120, 141, 99, 102, 102, 37, 236, 166, 214, 165, 235, 52, 104, 22, 229, 182, 167, 107, 251, 158, 192, 184, 7, 13, 245, 144, 39, 201, 228, 99, 92, 49, 182, 183, 195, 101, 35, 221, 59, 253, 174, 138, 130, 87, 167, 231, 233, 117, 244, 39, 187, 98, 254, 13, 210, 71, 236, 231, 166, 108, 172, 157, 216, 176, 180, 210, 181, 195, 86, 135, 86, 73, 56, 249, 192, 135, 242, 237, 216, 74, 173, 153, 12, 204, 187, 143, 83, 118, 243, 110, 115, 190, 151, 193, 229, 2, 88, 190, 87, 81, 35, 14, 161, 112, 126, 69, 134, 55, 18, 201, 217, 9, 189, 223, 205, 149, 231, 44, 132, 24, 78, 1, 191, 34, 43, 122, 200, 83, 124, 98, 99, 21, 118, 217, 215, 181, 129, 38, 177, 231, 251, 206, 149, 119, 177, 246, 198, 95, 50, 131, 253, 147, 97, 75, 132, 96, 64, 88, 182, 56, 193, 142, 147, 198, 62, 190, 157, 230, 229, 35, 193, 150, 46, 88, 250, 176, 190, 152, 239, 129, 162, 208, 38, 204, 42, 11, 118, 69, 82, 159, 60, 192, 82, 69, 57, 81, 45, 63, 106, 129, 200, 70, 234, 232, 252, 230, 87, 122, 17, 83, 147, 7, 255, 195, 30, 22, 246, 238, 139, 155, 59, 219, 75, 176, 174, 135, 176, 86, 12, 6, 161, 96, 112, 119, 226, 90, 144, 38, 248, 39, 170, 9, 183, 76, 227, 22, 162, 241, 140, 31, 62, 134, 157, 28, 72, 154, 128, 47, 30, 93, 184, 234, 163, 117, 10, 47, 30, 174, 53, 247, 20, 142, 66, 87, 22, 152, 208, 79, 240, 92, 45, 156, 43, 175, 81, 122, 48, 155, 190, 155, 25, 188, 231, 135, 192, 234, 227, 237, 240, 41, 125, 28, 209, 125, 74, 76, 241, 81, 212, 255, 255, 20, 68, 137, 24, 100, 128, 25, 50, 180, 168, 154, 114, 205, 45, 3, 174, 21, 4, 220, 135, 233, 62, 215, 141, 123, 223, 19, 125, 9, 143, 19, 60, 98, 183, 219, 95, 45, 234, 188, 253, 112, 172, 187, 240, 193, 124, 201, 174, 21, 55, 220, 35, 113, 245, 76, 160, 174, 56, 255, 2, 242, 69, 206, 165, 79, 245, 98, 66, 100, 92, 20, 140, 133, 37, 152, 221, 124, 43, 242, 116, 153, 82, 21, 120, 145, 106, 218, 47, 131, 244, 98, 18, 177, 186, 102, 221, 164, 13, 220, 210, 251, 199, 183, 204, 93, 203, 122] }) }, ref udp = UdpHeader { source_port: 37417, destination_port: 9108, length: 55031, checksum: 30539 }, ref tcp = TcpHeader { source_port: 890, destination_port: 63900, sequence_number: 1007304455, acknowledgment_number: 4179598739, ns: false, fin: false, syn: false, rst: true, psh: true, ack: true, urg: true, ece: false, cwr: false, window_size: 26948, checksum: 44775, urgent_pointer: 49253, options: [Err(UnknownId(91))] }, ref icmpv4 = Icmpv4Header { icmp_type: Unknown { type_u8: 115, code_u8: 63, bytes5to8: [197, 108, 248, 120] }, checksum: 2225 }, ref icmpv6 = Icmpv6Header { icmp_type: Unknown { type_u8: 78, code_u8: 128, bytes5to8: [71, 156, 20, 196] }, checksum: 11773 }, ref payload = [167, 22, 235, 99, 149, 6, 145, 225, 240, 172, 90, 57, 224, 202, 18, 160, 59, 126, 6, 142, 246, 221, 178, 142, 119, 149, 118, 24, 85, 202, 49, 206, 46, 138, 89, 120, 205, 44, 146, 68, 109, 183, 62, 194, 214, 224, 242, 51, 244, 121, 41, 30, 100, 88, 113, 252, 247, 30, 5, 51, 65, 174, 180, 40, 186, 204, 107, 12, 94, 171, 77, 238, 219, 1, 48, 192, 233, 160, 118, 122, 231, 175, 205, 222, 71, 3, 152, 89, 179, 124, 235, 147, 214, 240, 151, 170, 249, 41, 219, 41, 174, 39, 72, 81, 93, 33, 92, 38, 81, 230, 203, 184, 62, 40, 164, 56, 17, 246, 208, 119, 53, 119, 56, 57, 208, 123, 242, 126, 113, 173, 155, 254, 34, 97, 224, 150, 30, 183, 26, 88, 233, 142, 107, 189, 73, 181, 188, 88, 191, 151, 196, 115, 94, 128, 216, 121, 206, 65, 184, 150, 7, 85, 157, 169, 48, 0, 91, 59, 140, 20, 61, 231, 19, 43, 25, 8, 45, 153, 139, 171, 203, 72, 129, 96, 125, 200, 107, 24, 66, 116, 196, 166, 70, 84, 100, 252, 148, 198, 140, 190, 179, 227, 171, 217, 73, 201, 196, 252, 103, 198, 139, 22, 44, 141, 44, 49, 115, 210, 114, 152, 85, 78, 192, 14, 153, 14, 216, 154, 194, 198, 148, 217, 216, 28, 163, 245, 132, 125, 198, 159, 156, 92, 241, 20, 198, 42, 79, 230, 130, 38, 126, 161, 11, 92, 79, 203, 0, 104, 164, 106, 146, 111, 205, 110, 59, 18, 211, 10, 1, 215, 152, 28, 161, 31, 213, 126, 52, 199, 37, 225, 26, 181, 172, 222, 157, 154, 89, 215, 89, 91, 22, 86, 209, 30, 49, 149, 245, 117, 42, 128, 12, 38, 228, 11, 123, 4, 20, 233, 167, 243, 162, 158, 85, 20, 26, 13, 56, 54, 140, 115, 124, 233, 205, 48, 216, 209, 24, 245, 201, 81, 124, 205, 226, 125, 168, 248, 160, 149, 105, 214, 105, 200, 88, 229, 231, 148, 61, 84, 108, 111, 227, 248, 41, 155, 141, 56, 50, 10, 62, 239, 227, 153, 54, 253, 167, 244, 2, 96, 251, 214, 151, 51, 26, 240, 151, 251, 49, 68, 199, 115, 158, 72, 220, 201, 221, 238, 235, 163, 62, 221, 143, 228, 206, 176, 232, 134, 88, 55, 239, 9, 16, 20, 170, 132, 185, 192, 183, 227, 25, 192, 190, 109, 197, 130, 244, 221, 246, 129, 185, 45, 83, 250, 230, 19, 17, 167, 53, 2, 58, 206, 250, 223, 172, 35, 161, 236, 241, 62, 48, 120, 252, 211, 64, 57, 197, 163, 207, 224, 97, 67, 98, 225, 232, 193, 3, 173, 63, 83, 208, 180, 85, 133, 217, 177, 127, 4, 83, 113, 190, 79, 44, 36, 135, 204, 213, 181, 92, 154, 81, 8, 96, 191, 91, 5, 156, 218, 86, 145, 145, 223, 3, 111, 113, 118, 201, 40, 188, 31, 173, 75, 75, 239, 52, 253, 125, 88, 33, 169, 110, 187, 46, 103, 172, 70, 65, 160, 214, 149, 119, 36, 247, 215, 247, 91, 174, 111, 33, 180, 116, 196, 18, 142, 170, 40, 254, 155, 252, 96, 233, 59, 227, 218, 60, 219, 50, 183, 191, 19, 217, 175, 91, 226, 201, 246, 119, 151, 30, 179, 161, 243, 140, 221, 241, 144, 7, 80, 218, 64, 130, 44, 149, 253, 30, 64, 102, 58, 7, 184, 195, 16, 22, 127, 220, 129, 169, 45, 227, 162, 222, 144, 129, 10, 214, 191, 198, 12, 226, 227, 96, 96, 206, 101, 42, 110, 187, 140, 235, 160, 180, 201, 233, 146, 73, 67, 88, 81, 159, 116, 121, 73, 152, 161, 155, 241, 104, 71, 192, 252, 199, 162, 135, 203, 243, 38, 156, 198, 220, 13, 77, 57, 78, 40, 30, 127, 227, 104, 95, 81, 58, 156, 141, 193, 142, 36, 243, 57, 42, 43, 255, 72, 3, 101, 2, 124, 126, 77, 225, 190, 211, 134, 82, 180, 50, 0, 160, 155, 232, 219, 242, 36, 57, 46, 165, 60, 68, 123, 196, 144, 153, 209, 191, 62, 224, 188, 250, 211, 179, 157, 71, 164, 218, 132, 202, 63, 21, 83, 68, 132, 213, 204, 189, 169, 126, 242, 176, 93, 211, 209, 164, 134, 153, 161, 22, 134, 197, 184, 105, 191, 186, 152, 145, 133, 119, 183, 65, 55, 248, 204, 31, 28, 172, 85, 228, 86, 235, 47, 63, 235, 254, 93, 132, 86, 70, 233, 216, 2, 63, 26, 82, 45, 10, 182, 171, 13, 142, 142, 154, 50, 15, 133, 65, 137, 197, 3, 209, 20, 126, 93, 195, 249, 135, 44, 114, 55, 115, 33, 231, 195, 252, 42, 143, 181, 34, 52, 2, 183, 132, 124, 255, 83, 13, 19, 99, 236, 138, 64, 54, 176, 106, 29, 46, 222, 141, 142, 26, 167, 207, 104, 82, 178, 150, 26, 2, 59, 105, 37, 10, 229, 93, 30, 46, 204, 55, 56, 4, 29, 8, 212, 178, 77, 221, 53, 222, 191, 172, 85, 127, 159, 44, 73, 37, 251, 153, 173, 134, 13, 224, 164, 23, 35, 153, 190, 22, 22, 52, 28, 6, 28, 112, 117, 123, 216, 141, 98, 47, 140, 113, 1, 84, 236, 144, 94, 7, 71, 16, 196, 144, 96, 129, 29, 209, 66, 237, 67, 224, 10, 16, 160, 244, 217, 145, 241, 58, 83, 30, 77, 179, 140, 124, 243, 97, 121, 10, 54, 1, 30, 11, 116, 127, 188, 15, 122, 29, 133, 100, 178, 110, 201, 188, 63, 216, 168, 30, 6, 55, 127, 57, 255, 158, 222, 190, 110, 23, 36, 64, 230, 20, 155, 114, 16, 4, 60, 7, 71, 18, 44, 110, 66, 47, 217, 153, 202, 72, 66, 158, 204, 97, 44, 107, 172] diff --git a/etherparse/proptest-regressions/net/arp_eth_ipv4_packet.txt b/etherparse/proptest-regressions/net/arp_eth_ipv4_packet.txt new file mode 100644 index 00000000..3642797e --- /dev/null +++ b/etherparse/proptest-regressions/net/arp_eth_ipv4_packet.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 586bfcca48a89809a557b83c703e64b33458a7b99e492937dc9d27cd15f12884 # shrinks to arp = ArpEthIpv4Packet { operation: ArpOperation(0), sender_mac: [0, 0, 0, 0, 0, 0], sender_ipv4: [0, 0, 0, 0], target_mac: [0, 0, 0, 0, 0, 0], target_ipv4: [0, 0, 0, 0] } diff --git a/etherparse/proptest-regressions/net/arp_packet.txt b/etherparse/proptest-regressions/net/arp_packet.txt new file mode 100644 index 00000000..e7850cf3 --- /dev/null +++ b/etherparse/proptest-regressions/net/arp_packet.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 851d44d91acc679380cc543da5c9c124ada08859a988834338417d6e186c45bc # shrinks to arp_eth_ipv4 = ArpEthIpv4Packet { operation: ArpOperation(0), sender_mac: [0, 0, 0, 0, 0, 0], sender_ipv4: [0, 0, 0, 0], target_mac: [0, 0, 0, 0, 0, 0], target_ipv4: [0, 0, 0, 0] } diff --git a/etherparse/proptest-regressions/net/arp_packet_slice.txt b/etherparse/proptest-regressions/net/arp_packet_slice.txt new file mode 100644 index 00000000..b74c5a8e --- /dev/null +++ b/etherparse/proptest-regressions/net/arp_packet_slice.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 1a4c5722fbe8b2c58d2ebb4f140cb4655407ddbc5972f4b14f50f743ef72a03b # shrinks to packet = ArpPacket { hw_addr_type: 0 (from KA9Q: NET/ROM pseudo), proto_addr_type: 0x0000, hw_addr_size: 211, proto_addr_size: 74, operation: ArpOperation(0), sender_hw_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 202, 150, 216, 12, 76, 238, 98, 229, 121, 39, 172, 59, 94, 140, 211, 148, 188, 50, 18, 80, 41, 153, 167, 119, 35, 140, 120, 152, 201, 226, 208, 223, 192, 247, 79, 30, 145, 16, 135, 44, 22, 146, 117, 102, 57, 159, 179, 81, 83, 74, 49, 97, 20, 237, 86, 202, 21, 122, 12, 146, 146, 252, 253, 218, 153, 94, 71, 147, 137, 188, 54], sender_protocol_addr: [237, 238, 108, 127, 141, 251, 105, 6, 10, 128, 214, 186, 26, 165, 196, 137, 202, 142, 53, 175, 48, 169, 149, 76, 22, 140, 61, 223, 245, 75, 180, 131, 219, 57, 64, 35, 165, 205, 38, 212, 168, 70, 247, 208, 172, 207, 47, 145, 65, 19, 165, 171, 7, 197, 135, 227, 209, 37, 29, 37, 67, 8, 93, 201, 250, 131, 20, 22, 157, 238, 56, 156, 86, 115], target_hw_addr: [29, 254, 122, 18, 135, 228, 147, 190, 154, 52, 156, 255, 94, 78, 80, 14, 239, 11, 128, 100, 202, 250, 166, 103, 210, 14, 9, 195, 75, 199, 69, 33, 198, 87, 125, 118, 21, 151, 253, 121, 246, 50, 3, 196, 25, 38, 210, 101, 25, 232, 171, 65, 110, 233, 57, 62, 53, 8, 13, 125, 248, 185, 13, 237, 152, 249, 246, 236, 147, 230, 143, 82, 0, 220, 177, 106, 162, 237, 217, 30, 58, 31, 39, 244, 191, 33, 248, 201, 46, 153, 38, 20, 120, 124, 215, 93, 65, 91, 242, 45, 184, 248, 243, 64, 93, 158, 214, 244, 77, 247, 76, 85, 3, 146, 203, 79, 111, 82, 87, 72, 118, 100, 215, 186, 155, 139, 241, 162, 13, 55, 24, 114, 238, 27, 180, 101, 35, 50, 161, 46, 242, 17, 29, 20, 38, 66, 252, 226, 110, 92, 99, 177, 207, 108, 188, 169, 193, 51, 42, 107, 157, 73, 217, 229, 141, 89, 215, 149, 139, 196, 30, 24, 242, 220, 164, 5, 86, 191, 128, 177, 177, 99, 37, 198, 20, 102, 185, 163, 245, 25, 178, 210, 196, 156, 240, 65, 218, 127, 254, 20, 240, 41, 137, 29, 241, 160, 198, 218, 50, 61, 131], target_protocol_addr: [66, 87, 247, 183, 139, 227, 187, 185, 147, 188, 228, 171, 89, 50, 198, 181, 249, 92, 139, 114, 49, 17, 111, 191, 145, 5, 84, 204, 190, 174, 36, 0, 224, 9, 76, 117, 226, 198, 32, 247, 238, 245, 182, 73, 7, 239, 26, 25, 14, 62, 110, 34, 88, 156, 78, 118, 223, 127, 36, 229, 50, 96, 248, 145, 41, 80, 135, 169, 195, 101, 215, 24, 8, 24] } diff --git a/etherparse/src/compositions_tests.rs b/etherparse/src/compositions_tests.rs index fd04b690..ba3dd8e9 100644 --- a/etherparse/src/compositions_tests.rs +++ b/etherparse/src/compositions_tests.rs @@ -8,7 +8,7 @@ use proptest::prelude::*; struct ComponentTest { link: Option, vlan: Option, - ip: Option, + net: Option, transport: Option, payload: Vec, } @@ -28,7 +28,7 @@ impl ComponentTest { } + match &self.vlan { Some(header) => header.header_len(), None => 0, - } + match &self.ip { + } + match &self.net { Some(headers) => headers.header_len(), None => 0, } + match &self.transport { @@ -48,15 +48,18 @@ impl ComponentTest { Some(Double(header)) => header.write(&mut buffer).unwrap(), None => {} } - match &self.ip { - Some(IpHeaders::Ipv4(header, exts)) => { + match &self.net { + Some(NetHeaders::Ipv4(header, exts)) => { header.write_raw(&mut buffer).unwrap(); exts.write(&mut buffer, header.protocol).unwrap(); } - Some(IpHeaders::Ipv6(header, exts)) => { + Some(NetHeaders::Ipv6(header, exts)) => { header.write(&mut buffer).unwrap(); exts.write(&mut buffer, header.next_header).unwrap(); } + Some(NetHeaders::Arp(arp)) => { + arp.write(&mut buffer).unwrap(); + } None => {} } match &self.transport { @@ -84,9 +87,9 @@ impl ComponentTest { let mut test = self.clone(); // set the payload length - if let Some(ip) = test.ip.as_mut() { - match ip { - IpHeaders::Ipv4(ipv4, exts) => { + if let Some(net) = test.net.as_mut() { + match net { + NetHeaders::Ipv4(ipv4, exts) => { ipv4.set_payload_len( exts.header_len() + self.transport.as_ref().map_or(0, |t| t.header_len()) @@ -94,7 +97,7 @@ impl ComponentTest { ) .unwrap(); } - IpHeaders::Ipv6(ipv6, exts) => { + NetHeaders::Ipv6(ipv6, exts) => { ipv6.set_payload_length( exts.header_len() + self.transport.as_ref().map_or(0, |t| t.header_len()) @@ -102,6 +105,7 @@ impl ComponentTest { ) .unwrap(); } + NetHeaders::Arp(_) => {} } } if let Some(TransportHeader::Udp(udp)) = test.transport.as_mut() { @@ -176,7 +180,7 @@ impl ComponentTest { } // packet from the internet layer down (without ethernet2 & vlan headers) - if test.ip.is_some() { + if test.net.as_ref().map(|v| v.is_ip()).unwrap_or(false) { // serialize from the ip layer downwards let ip_down = { let mut ip_down = test.clone(); @@ -240,9 +244,9 @@ impl ComponentTest { } } } - if let Some(ip) = self.ip.as_ref() { - use IpHeaders::*; - match ip { + if let Some(net) = self.net.as_ref() { + use NetHeaders::*; + match net { Ipv4(header, exts) => { builder.add(header.header_len()); if let Some(auth) = exts.auth.as_ref() { @@ -270,6 +274,9 @@ impl ComponentTest { builder.add(e.header_len()); } } + Arp(arp) => { + builder.add(arp.packet_len()); + } } } if let Some(transport) = self.transport.as_ref() { @@ -282,7 +289,7 @@ impl ComponentTest { fn assert_headers(&self, actual: PacketHeaders) { assert_eq!(self.link, actual.link); assert_eq!(self.vlan, actual.vlan); - assert_eq!(self.ip, self.ip); + assert_eq!(self.net, self.net); assert_eq!(self.transport, actual.transport); assert_eq!(self.payload[..], actual.payload.slice()[..]); } @@ -307,16 +314,16 @@ impl ComponentTest { assert_eq!(self.vlan, result.vlan.as_ref().map(|ref x| x.to_header())); //ip - assert_eq!(self.ip, { + assert_eq!(self.net, { use crate::NetSlice::*; match result.net.as_ref() { - Some(Ipv4(actual)) => Some(IpHeaders::Ipv4( + Some(Ipv4(actual)) => Some(NetHeaders::Ipv4( actual.header().to_header(), Ipv4Extensions { auth: actual.extensions().auth.map(|ref x| x.to_header()), }, )), - Some(Ipv6(actual)) => Some(IpHeaders::Ipv6( + Some(Ipv6(actual)) => Some(NetHeaders::Ipv6( actual.header().to_header(), Ipv6Extensions::from_slice( actual.header().next_header(), @@ -325,6 +332,7 @@ impl ComponentTest { .unwrap() .0, )), + Some(Arp(arp)) => Some(NetHeaders::Arp(arp.to_packet())), None => None, } }); @@ -372,6 +380,7 @@ impl ComponentTest { match ip { NetSlice::Ipv4(s) => s.payload.payload, NetSlice::Ipv6(s) => s.payload.payload, + NetSlice::Arp(_) => &[], } ); } else { @@ -391,6 +400,7 @@ impl ComponentTest { &self, outer_vlan: &SingleVlanHeader, inner_vlan: &SingleVlanHeader, + arp: &ArpPacket, ipv4: &Ipv4Header, ipv4_ext: &Ipv4Extensions, ipv6: &Ipv6Header, @@ -429,12 +439,14 @@ impl ComponentTest { //single setup_single(inner_vlan.ether_type).run(); + setup_single(ether_type::ARP).run_arp(arp); setup_single(ether_type::IPV4).run_ipv4(ipv4, ipv4_ext, udp, tcp, icmpv4, icmpv6); setup_single(ether_type::IPV6).run_ipv6(ipv6, ipv6_ext, udp, tcp, icmpv4, icmpv6); //double for ether_type in VLAN_ETHER_TYPES { setup_double(*ether_type, inner_vlan.ether_type).run(); + setup_double(*ether_type, ether_type::ARP).run_arp(arp); setup_double(*ether_type, ether_type::IPV4) .run_ipv4(ipv4, ipv4_ext, udp, tcp, icmpv4, icmpv6); setup_double(*ether_type, ether_type::IPV6) @@ -442,6 +454,13 @@ impl ComponentTest { } } + fn run_arp(&self, arp: &ArpPacket) { + let mut test = self.clone(); + test.net = Some(NetHeaders::Arp(arp.clone())); + test.payload.clear(); + test.run(); + } + fn run_ipv4( &self, ip: &Ipv4Header, @@ -454,14 +473,14 @@ impl ComponentTest { // fragmenting { let mut test = self.clone(); - test.ip = Some({ + test.net = Some({ let mut frag = ip.clone(); if false == frag.is_fragmenting_payload() { frag.more_fragments = true; } - let mut header = IpHeaders::Ipv4(frag, ip_exts.clone()); - header.set_next_headers(ip.protocol); - header + let mut ip_exts = ip_exts.clone(); + frag.protocol = ip_exts.set_next_headers(ip.protocol); + NetHeaders::Ipv4(frag, ip_exts.clone()) }); // run without transport header @@ -471,13 +490,13 @@ impl ComponentTest { // non fragmenting { let mut test = self.clone(); - test.ip = Some({ + test.net = Some({ let mut non_frag = ip.clone(); non_frag.more_fragments = false; non_frag.fragment_offset = 0.try_into().unwrap(); - let mut header = IpHeaders::Ipv4(non_frag, ip_exts.clone()); - header.set_next_headers(ip.protocol); - header + let mut ip_exts = ip_exts.clone(); + non_frag.protocol = ip_exts.set_next_headers(ip.protocol); + NetHeaders::Ipv4(non_frag, ip_exts) }); test.run_transport(udp, tcp, icmpv4, icmpv6); } @@ -495,7 +514,7 @@ impl ComponentTest { // fragmenting { let mut test = self.clone(); - test.ip = Some({ + test.net = Some({ let mut frag = ip_exts.clone(); if let Some(frag) = frag.fragment.as_mut() { if false == frag.is_fragmenting_payload() { @@ -509,9 +528,9 @@ impl ComponentTest { 0, )); } - let mut header = IpHeaders::Ipv6(ip.clone(), frag); - header.set_next_headers(ip.next_header); - header + let mut ip = ip.clone(); + ip.next_header = frag.set_next_headers(ip.next_header); + NetHeaders::Ipv6(ip, frag) }); test.run(); } @@ -519,12 +538,12 @@ impl ComponentTest { // non fragmenting { let mut test = self.clone(); - test.ip = Some({ + test.net = Some({ let mut non_frag = ip_exts.clone(); non_frag.fragment = None; - let mut header = IpHeaders::Ipv6(ip.clone(), non_frag); - header.set_next_headers(ip.next_header); - header + let mut ip = ip.clone(); + ip.next_header = non_frag.set_next_headers(ip.next_header); + NetHeaders::Ipv6(ip, non_frag) }); test.run_transport(udp, tcp, icmpv4, icmpv6); } @@ -543,7 +562,11 @@ impl ComponentTest { // udp { let mut test = self.clone(); - test.ip.as_mut().unwrap().set_next_headers(ip_number::UDP); + test.net + .as_mut() + .unwrap() + .try_set_next_headers(ip_number::UDP) + .unwrap(); test.transport = Some(TransportHeader::Udp(udp.clone())); test.run() } @@ -551,7 +574,11 @@ impl ComponentTest { // tcp { let mut test = self.clone(); - test.ip.as_mut().unwrap().set_next_headers(ip_number::TCP); + test.net + .as_mut() + .unwrap() + .try_set_next_headers(ip_number::TCP) + .unwrap(); test.transport = Some(TransportHeader::Tcp(tcp.clone())); test.run() } @@ -559,14 +586,22 @@ impl ComponentTest { // icmpv4 if let Some(payload_size) = icmpv4.fixed_payload_size() { let mut test = self.clone(); - test.ip.as_mut().unwrap().set_next_headers(ip_number::ICMP); + test.net + .as_mut() + .unwrap() + .try_set_next_headers(ip_number::ICMP) + .unwrap(); test.transport = Some(TransportHeader::Icmpv4(icmpv4.clone())); // resize the payload in case it does not have to be as big test.payload.resize(payload_size, 0); test.run() } else { let mut test = self.clone(); - test.ip.as_mut().unwrap().set_next_headers(ip_number::ICMP); + test.net + .as_mut() + .unwrap() + .try_set_next_headers(ip_number::ICMP) + .unwrap(); test.transport = Some(TransportHeader::Icmpv4(icmpv4.clone())); test.run() } @@ -574,20 +609,22 @@ impl ComponentTest { // icmpv6 if let Some(payload_size) = icmpv6.fixed_payload_size() { let mut test = self.clone(); - test.ip + test.net .as_mut() .unwrap() - .set_next_headers(ip_number::IPV6_ICMP); + .try_set_next_headers(ip_number::IPV6_ICMP) + .unwrap(); test.transport = Some(TransportHeader::Icmpv6(icmpv6.clone())); // resize the payload in case it does not have to be as big test.payload.resize(payload_size, 0); test.run() } else { let mut test = self.clone(); - test.ip + test.net .as_mut() .unwrap() - .set_next_headers(ip_number::IPV6_ICMP); + .try_set_next_headers(ip_number::IPV6_ICMP) + .unwrap(); test.transport = Some(TransportHeader::Icmpv6(icmpv6.clone())); test.run() } @@ -605,6 +642,7 @@ proptest! { ref ipv4_exts in ipv4_extensions_unknown(), ref ipv6 in ipv6_unknown(), ref ipv6_exts in ipv6_extensions_unknown(), + ref arp in arp_packet_any(), ref udp in udp_any(), ref tcp in tcp_any(), ref icmpv4 in icmpv4_header_any(), @@ -620,19 +658,20 @@ proptest! { LinkHeader::Ethernet2(result) }), vlan: None, - ip: None, + net: None, transport: None } }; //ethernet 2: standalone, ipv4, ipv6 setup_eth(eth.ether_type).run(); + setup_eth(ether_type::ARP).run_arp(arp); setup_eth(ether_type::IPV4).run_ipv4(ipv4, ipv4_exts, udp, tcp, icmpv4, icmpv6); setup_eth(ether_type::IPV6).run_ipv6(ipv6, ipv6_exts, udp, tcp, icmpv4, icmpv6); //vlans for ether_type in VLAN_ETHER_TYPES { - setup_eth(*ether_type).run_vlan(vlan_outer, vlan_inner, ipv4, ipv4_exts, ipv6, ipv6_exts, udp, tcp, icmpv4, icmpv6); + setup_eth(*ether_type).run_vlan(vlan_outer, vlan_inner, arp, ipv4, ipv4_exts, ipv6, ipv6_exts, udp, tcp, icmpv4, icmpv6); } } } @@ -654,7 +693,7 @@ fn test_packet_slicing_panics() { ether_type: 0.into(), })), vlan: None, - ip: None, + net: None, transport: None, payload: vec![], } diff --git a/etherparse/src/defrag/ip_defrag_pool.rs b/etherparse/src/defrag/ip_defrag_pool.rs index d7c2f192..b3234139 100644 --- a/etherparse/src/defrag/ip_defrag_pool.rs +++ b/etherparse/src/defrag/ip_defrag_pool.rs @@ -12,7 +12,7 @@ use std::vec::Vec; /// /// # This implementation is NOT safe against "Out of Memory" attacks /// -/// If you use the [`DefragPool`] in an untrusted environment an attacker could +/// If you use the [`IpDefragPool`] in an untrusted environment an attacker could /// cause an "out of memory error" by opening up multiple parallel TP streams, /// never ending them and filling them up with as much data as possible. /// @@ -143,7 +143,7 @@ where false, ) } - None => { + Some(NetSlice::Arp(_)) | None => { // nothing to defragment here, skip packet return Ok(None); } diff --git a/etherparse/src/err/arp/arp_eth_ipv4_from_error.rs b/etherparse/src/err/arp/arp_eth_ipv4_from_error.rs new file mode 100644 index 00000000..b27fb21f --- /dev/null +++ b/etherparse/src/err/arp/arp_eth_ipv4_from_error.rs @@ -0,0 +1,95 @@ +use crate::*; + +/// Error while converting an [`crate::ArpPacket`] to an [`crate::ArpEthIpv4Packet`]. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum ArpEthIpv4FromError { + /// Error if `hw_addr_type` is not [`crate::ArpHardwareId::ETHERNET`]. + NonMatchingHwType(ArpHardwareId), + + /// Error if `proto_addr_type` is not [`crate::EtherType::IPV4`]. + NonMatchingProtocolType(EtherType), + + /// Error if `hw_addr_size` is not `6` + NonMatchingHwAddrSize(u8), + + /// Error if `hw_addr_size` is not `6` + NonMatchingProtoAddrSize(u8), +} + +impl core::fmt::Display for ArpEthIpv4FromError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ArpEthIpv4FromError::NonMatchingHwType(t) => + write!(f, "Hardware address type is expected to have the type '1 (Ethernet)' but is '{t:?}'"), + ArpEthIpv4FromError::NonMatchingProtocolType(t) => + write!(f, "Protocol address type is expected to have the type '0x0800 (Internet Protocol version 4 (IPv4))' but is '{t:?}'"), + ArpEthIpv4FromError::NonMatchingHwAddrSize(len) => + write!(f, "Hardware address size is expected to be 6 but is {len}"), + ArpEthIpv4FromError::NonMatchingProtoAddrSize(len) => + write!(f, "Protocol address size is expected to be 4 but is {len}"), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for ArpEthIpv4FromError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +#[cfg(test)] +mod tests { + use super::{ArpEthIpv4FromError::*, ArpHardwareId, EtherType}; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn debug() { + assert_eq!( + "NonMatchingProtoAddrSize(3)", + format!("{:?}", NonMatchingProtoAddrSize(3)) + ); + } + + #[test] + fn clone_eq_hash() { + let err = NonMatchingProtoAddrSize(3); + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + let tests = [ + (NonMatchingHwType(ArpHardwareId::CHAOS), "Hardware address type is expected to have the type '1 (Ethernet)' but is '5 (Chaosnet)'"), + (NonMatchingProtocolType(EtherType::IPV6), "Protocol address type is expected to have the type '0x0800 (Internet Protocol version 4 (IPv4))' but is '0x86DD (Internet Protocol Version 6 (IPV6))'"), + (NonMatchingHwAddrSize(21), "Hardware address size is expected to be 6 but is 21"), + (NonMatchingProtoAddrSize(22), "Protocol address size is expected to be 4 but is 22") + ]; + for test in tests { + assert_eq!(format!("{}", test.0), test.1); + } + } + + #[cfg(feature = "std")] + #[test] + fn source() { + assert!(NonMatchingProtoAddrSize(3).source().is_none()); + } +} diff --git a/etherparse/src/err/arp/arp_hw_addr_error.rs b/etherparse/src/err/arp/arp_hw_addr_error.rs new file mode 100644 index 00000000..47135be9 --- /dev/null +++ b/etherparse/src/err/arp/arp_hw_addr_error.rs @@ -0,0 +1,80 @@ +/// Error in the hardware addresses when creating an [`crate::ArpPacket`] or +/// changing the hardware addresses in an [`crate::ArpPacket`]. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum ArpHwAddrError { + /// Error if the given hardware address is longer than + /// the maximum of 255 bytes/octets. + LenTooBig(usize), + + /// Hardware address lengths of sender and target differ. + LenNonMatching(usize, usize), +} + +impl core::fmt::Display for ArpHwAddrError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ArpHwAddrError::LenTooBig(len) => + write!(f, "ARP Hardware Address Error: Given hardware address has a length of {len} which is greater then the maximum of 255."), + ArpHwAddrError::LenNonMatching(len_sender, len_target) => + write!(f, "ARP Hardware Address Error: Given sender & target hardware addresses have differing lengths of {len_sender} & {len_target} (must be matching)."), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for ArpHwAddrError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +#[cfg(test)] +mod tests { + use super::ArpHwAddrError::*; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn debug() { + assert_eq!("LenTooBig(300)", format!("{:?}", LenTooBig(300))); + } + + #[test] + fn clone_eq_hash() { + let err = LenTooBig(300); + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + let tests = [ + (LenTooBig(300), "ARP Hardware Address Error: Given hardware address has a length of 300 which is greater then the maximum of 255."), + (LenNonMatching(21, 22), "ARP Hardware Address Error: Given sender & target hardware addresses have differing lengths of 21 & 22 (must be matching)."), + ]; + for test in tests { + assert_eq!(format!("{}", test.0), test.1); + } + } + + #[cfg(feature = "std")] + #[test] + fn source() { + assert!(LenTooBig(300).source().is_none()); + } +} diff --git a/etherparse/src/err/arp/arp_new_error.rs b/etherparse/src/err/arp/arp_new_error.rs new file mode 100644 index 00000000..11e26752 --- /dev/null +++ b/etherparse/src/err/arp/arp_new_error.rs @@ -0,0 +1,85 @@ +use super::{ArpHwAddrError, ArpProtoAddrError}; + +/// Error while creating a new [`crate::ArpPacket`]. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum ArpNewError { + /// Error in the given hardware addresses. + HwAddr(ArpHwAddrError), + + /// Error in the given protocol addresses. + ProtoAddr(ArpProtoAddrError), +} + +impl core::fmt::Display for ArpNewError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ArpNewError::HwAddr(err) => err.fmt(f), + ArpNewError::ProtoAddr(err) => err.fmt(f), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for ArpNewError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +#[cfg(test)] +mod tests { + use crate::err::arp::{ArpHwAddrError, ArpProtoAddrError}; + + use super::ArpNewError::*; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn debug() { + assert_eq!( + "HwAddr(LenTooBig(300))", + format!("{:?}", HwAddr(ArpHwAddrError::LenTooBig(300))) + ); + } + + #[test] + fn clone_eq_hash() { + let err = HwAddr(ArpHwAddrError::LenTooBig(300)); + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + let tests = [ + (HwAddr(ArpHwAddrError::LenTooBig(300)), "ARP Hardware Address Error: Given hardware address has a length of 300 which is greater then the maximum of 255."), + (ProtoAddr(ArpProtoAddrError::LenTooBig(301)), "ARP Protocol Address Error: Given protocol address has a length of 301 which is greater then the maximum of 255."), + (HwAddr(ArpHwAddrError::LenNonMatching(21, 22)), "ARP Hardware Address Error: Given sender & target hardware addresses have differing lengths of 21 & 22 (must be matching)."), + (ProtoAddr(ArpProtoAddrError::LenNonMatching(23, 24)), "ARP Protocol Address Error: Given sender & target protocol addresses have differing lengths of 23 & 24 (must be matching).") + ]; + for test in tests { + assert_eq!(format!("{}", test.0), test.1); + } + } + + #[cfg(feature = "std")] + #[test] + fn source() { + assert!(HwAddr(ArpHwAddrError::LenTooBig(300)).source().is_none()); + } +} diff --git a/etherparse/src/err/arp/arp_proto_addr_error.rs b/etherparse/src/err/arp/arp_proto_addr_error.rs new file mode 100644 index 00000000..5203d37b --- /dev/null +++ b/etherparse/src/err/arp/arp_proto_addr_error.rs @@ -0,0 +1,80 @@ +/// Error in the protocol addresses when creating an [`crate::ArpPacket`] or +/// changing the protocol addresses in an [`crate::ArpPacket`]. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum ArpProtoAddrError { + /// Error if the given protocol address is longer than + /// the maximum of 255 bytes/octets. + LenTooBig(usize), + + /// Protocol address lengths of sender and target differ. + LenNonMatching(usize, usize), +} + +impl core::fmt::Display for ArpProtoAddrError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ArpProtoAddrError::LenTooBig(len) => + write!(f, "ARP Protocol Address Error: Given protocol address has a length of {len} which is greater then the maximum of 255."), + ArpProtoAddrError::LenNonMatching(len_sender, len_target) => + write!(f, "ARP Protocol Address Error: Given sender & target protocol addresses have differing lengths of {len_sender} & {len_target} (must be matching)."), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for ArpProtoAddrError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +#[cfg(test)] +mod tests { + use super::ArpProtoAddrError::*; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn debug() { + assert_eq!("LenTooBig(300)", format!("{:?}", LenTooBig(300))); + } + + #[test] + fn clone_eq_hash() { + let err = LenTooBig(300); + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + let tests = [ + (LenTooBig(301), "ARP Protocol Address Error: Given protocol address has a length of 301 which is greater then the maximum of 255."), + (LenNonMatching(23, 24), "ARP Protocol Address Error: Given sender & target protocol addresses have differing lengths of 23 & 24 (must be matching).") + ]; + for test in tests { + assert_eq!(format!("{}", test.0), test.1); + } + } + + #[cfg(feature = "std")] + #[test] + fn source() { + assert!(LenTooBig(300).source().is_none()); + } +} diff --git a/etherparse/src/err/arp/mod.rs b/etherparse/src/err/arp/mod.rs new file mode 100644 index 00000000..fca131be --- /dev/null +++ b/etherparse/src/err/arp/mod.rs @@ -0,0 +1,11 @@ +mod arp_eth_ipv4_from_error; +pub use arp_eth_ipv4_from_error::*; + +mod arp_hw_addr_error; +pub use arp_hw_addr_error::*; + +mod arp_new_error; +pub use arp_new_error::*; + +mod arp_proto_addr_error; +pub use arp_proto_addr_error::*; diff --git a/etherparse/src/err/from_slice_error.rs b/etherparse/src/err/from_slice_error.rs index e879edf9..fae13831 100644 --- a/etherparse/src/err/from_slice_error.rs +++ b/etherparse/src/err/from_slice_error.rs @@ -438,7 +438,7 @@ mod tests { layer_start_offset: 0, }), LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }), DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(123), @@ -469,7 +469,7 @@ mod tests { layer_start_offset: 0, }; let linux_sll_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }; let double_vlan_error = || double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(1), @@ -548,7 +548,7 @@ mod tests { // linux sll { let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }; assert_eq!( &header_error(), diff --git a/etherparse/src/err/layer.rs b/etherparse/src/err/layer.rs index 16e2ce2c..a8647e32 100644 --- a/etherparse/src/err/layer.rs +++ b/etherparse/src/err/layer.rs @@ -45,6 +45,8 @@ pub enum Layer { Icmpv4TimestampReply, /// Error occurred while parsing an ICMPv6 packet. Icmpv6, + /// Error occurred while parsing an Address Resolution Protocol packet. + Arp, } impl Layer { @@ -74,6 +76,7 @@ impl Layer { Icmpv4Timestamp => "ICMP Timestamp Error", Icmpv4TimestampReply => "ICMP Timestamp Reply Error", Icmpv6 => "ICMPv6 Packet Error", + Arp => "Address Resolution Protocol Packet Error", } } } @@ -104,6 +107,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"), + Arp => write!(f, "Address Resolution Protocol packet"), } } } diff --git a/etherparse/src/err/len_error.rs b/etherparse/src/err/len_error.rs index bf60e152..0ff1ff8e 100644 --- a/etherparse/src/err/len_error.rs +++ b/etherparse/src/err/len_error.rs @@ -84,6 +84,9 @@ impl core::fmt::Display for LenError { } UdpHeaderLen => "length calculated from the UDP header 'length' field", TcpHeaderLen => "length calculated from the TCP header 'length' field", + ArpAddrLengths => { + "length calculated from the ARP 'hw_addr_size' & 'proto_addr_size' fields" + } } }; diff --git a/etherparse/src/err/linux_sll/header_error.rs b/etherparse/src/err/linux_sll/header_error.rs index 2fb504df..e745566f 100644 --- a/etherparse/src/err/linux_sll/header_error.rs +++ b/etherparse/src/err/linux_sll/header_error.rs @@ -17,7 +17,7 @@ impl core::fmt::Display for HeaderError { use HeaderError::*; match self { UnsupportedPacketTypeField { packet_type } => write!(f, "Linux cooked capture v1 (SLL) Header Error: Encountered '{}' as the packet type, but its not supported.", packet_type), - UnsupportedArpHardwareId { arp_hardware_type } => write!(f, "Linux cooked capture v1 (SLL) Header Error: Encountered '{}' as the ARP harware type, but its not supported.", arp_hardware_type), + UnsupportedArpHardwareId { arp_hardware_type } => write!(f, "Linux cooked capture v1 (SLL) Header Error: Encountered '{:?}' as the ARP harware type, but its not supported.", arp_hardware_type), } } } @@ -78,8 +78,8 @@ mod tests { format!("{}", UnsupportedPacketTypeField{ packet_type: 6 }) ); assert_eq!( - "Linux cooked capture v1 (SLL) Header Error: Encountered '1 (Ethernet 10Mbps)' as the ARP harware type, but its not supported.", - format!("{}", UnsupportedArpHardwareId{ arp_hardware_type: ArpHardwareId::ETHER }) + "Linux cooked capture v1 (SLL) Header Error: Encountered '1 (Ethernet)' as the ARP harware type, but its not supported.", + format!("{}", UnsupportedArpHardwareId{ arp_hardware_type: ArpHardwareId::ETHERNET }) ); } @@ -89,7 +89,7 @@ mod tests { let values = [ UnsupportedPacketTypeField { packet_type: 6 }, UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }, ]; for v in values { diff --git a/etherparse/src/err/mod.rs b/etherparse/src/err/mod.rs index 27d97d18..4d0b1d10 100644 --- a/etherparse/src/err/mod.rs +++ b/etherparse/src/err/mod.rs @@ -1,3 +1,4 @@ +pub mod arp; pub mod double_vlan; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] @@ -10,6 +11,7 @@ pub mod ipv4_exts; pub mod ipv6; pub mod ipv6_exts; pub mod linux_sll; +pub mod net; pub mod packet; pub mod tcp; diff --git a/etherparse/src/err/net/mod.rs b/etherparse/src/err/net/mod.rs new file mode 100644 index 00000000..8a53c5dc --- /dev/null +++ b/etherparse/src/err/net/mod.rs @@ -0,0 +1,2 @@ +mod net_set_next_header_error; +pub use net_set_next_header_error::*; diff --git a/etherparse/src/err/net/net_set_next_header_error.rs b/etherparse/src/err/net/net_set_next_header_error.rs new file mode 100644 index 00000000..fc2c95aa --- /dev/null +++ b/etherparse/src/err/net/net_set_next_header_error.rs @@ -0,0 +1,79 @@ +/// Errors when setting the next header IP number. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum NetSetNextHeaderError { + /// It is possible to set the ip_number in an ARP header. + ArpHeader, +} + +impl core::fmt::Display for NetSetNextHeaderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use NetSetNextHeaderError::*; + match self { + ArpHeader => write!( + f, + "It is not possible to set the payload 'IP number' for an ARP header." + ), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for NetSetNextHeaderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn debug() { + assert_eq!( + "ArpHeader", + format!("{:?}", NetSetNextHeaderError::ArpHeader) + ); + } + + #[test] + fn clone_eq_hash() { + let err = NetSetNextHeaderError::ArpHeader; + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + assert_eq!( + "It is not possible to set the payload 'IP number' for an ARP header.", + format!("{}", NetSetNextHeaderError::ArpHeader) + ); + } + + #[cfg(feature = "std")] + #[test] + fn source() { + let values = [NetSetNextHeaderError::ArpHeader]; + for v in values { + assert!(v.source().is_none()); + } + } +} diff --git a/etherparse/src/err/packet/build_write_error.rs b/etherparse/src/err/packet/build_write_error.rs index 67251c5a..e81a052b 100644 --- a/etherparse/src/err/packet/build_write_error.rs +++ b/etherparse/src/err/packet/build_write_error.rs @@ -25,6 +25,9 @@ pub enum BuildWriteError { /// Error if ICMPv6 is packaged in an IPv4 packet (it is undefined /// how to calculate the checksum). Icmpv6InIpv4, + + /// address size defined in the ARP header does not match the actual size + ArpHeaderNotMatch, } #[cfg(feature = "std")] @@ -82,6 +85,7 @@ impl core::fmt::Display for BuildWriteError { PayloadLen(err) => err.fmt(f), Ipv4Exts(err) => err.fmt(f), Ipv6Exts(err) => err.fmt(f), + ArpHeaderNotMatch => write!(f, "address size defined in the ARP header does not match the actual size"), Icmpv6InIpv4 => write!(f, "Error: ICMPv6 can not be combined with an IPv4 headers (checksum can not be calculated)."), } } @@ -98,6 +102,7 @@ impl std::error::Error for BuildWriteError { Ipv4Exts(err) => Some(err), Ipv6Exts(err) => Some(err), Icmpv6InIpv4 => None, + ArpHeaderNotMatch => None, } } } diff --git a/etherparse/src/err/packet/slice_error.rs b/etherparse/src/err/packet/slice_error.rs index 13261566..5123c038 100644 --- a/etherparse/src/err/packet/slice_error.rs +++ b/etherparse/src/err/packet/slice_error.rs @@ -177,7 +177,7 @@ mod tests { // IpHeaders { let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }; assert!(LinuxSll(err).source().is_some()); } diff --git a/etherparse/src/err/read_error.rs b/etherparse/src/err/read_error.rs index 8fab928b..f0fb68aa 100644 --- a/etherparse/src/err/read_error.rs +++ b/etherparse/src/err/read_error.rs @@ -490,7 +490,7 @@ mod tests { ( "LinuxSll", LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }), ), ( @@ -555,7 +555,7 @@ mod tests { layer_start_offset: 0, }), LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }), DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(123), @@ -683,7 +683,7 @@ mod tests { // linux sll { let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER, + arp_hardware_type: ArpHardwareId::ETHERNET, }; assert_eq!( &header_error(), diff --git a/etherparse/src/lax_packet_headers.rs b/etherparse/src/lax_packet_headers.rs index 42f4df61..b8a255f1 100644 --- a/etherparse/src/lax_packet_headers.rs +++ b/etherparse/src/lax_packet_headers.rs @@ -83,6 +83,9 @@ impl<'a> LaxPacketHeaders<'a> { /// // net (ip) & transport (udp or tcp) /// println!("net: {:?}", value.net); /// match value.payload { + /// LaxPayloadSlice::Empty => { + /// // in case of ARP packet the payload is empty + /// } /// LaxPayloadSlice::Ether(e) => { /// println!("ether payload (ether type {:?}): {:?}", e.ether_type, e.payload); /// } @@ -194,6 +197,9 @@ impl<'a> LaxPacketHeaders<'a> { /// // net (ip) & transport (udp or tcp) /// println!("net: {:?}", value.net); /// match value.payload { + /// LaxPayloadSlice::Empty => { + /// // Some packets don't have seperate payloads. For example ARP packets. + /// } /// LaxPayloadSlice::Ether(e) => { /// println!("ether payload (ether type {:?}): {:?}", e.ether_type, e.payload); /// } @@ -305,7 +311,7 @@ impl<'a> LaxPacketHeaders<'a> { _ => None, }; - // parse ip + // parse ip or arp match ether_type { IPV4 | IPV6 => match result.add_ip(offset, rest) { Ok(_) => {} @@ -321,6 +327,18 @@ impl<'a> LaxPacketHeaders<'a> { return result; } }, + ARP => { + let arp = match ArpPacket::from_slice(rest) { + Ok(value) => value, + Err(mut err) => { + err.layer_start_offset += offset; + result.stop_err = Some((Len(err), Layer::Arp)); + return result; + } + }; + result.net = Some(NetHeaders::Arp(arp)); + return result; + } _ => {} }; @@ -392,8 +410,9 @@ impl<'a> LaxPacketHeaders<'a> { /// // net (ip) & transport (udp or tcp) /// println!("net: {:?}", value.net); /// match value.payload { - /// // if you parse from IP down there will be no ether payload - /// LaxPayloadSlice::Ether(e) => unreachable!(), + /// // if you parse from IP down there will be no ether payload and the + /// // empty payload does not appear (only present in ARP packets). + /// LaxPayloadSlice::Ether(_) | LaxPayloadSlice::Empty => unreachable!(), /// LaxPayloadSlice::Ip(ip) => { /// println!("IP payload (IP number {:?}): {:?}", ip.ip_number, ip.payload); /// if ip.incomplete { @@ -674,7 +693,7 @@ mod test { fn from_x_slice_vlan_variants(base: &TestPacket) { // none - from_x_slice_ip_variants(base); + from_x_slice_net_variants(base); // single vlan header { @@ -691,7 +710,7 @@ mod test { test.vlan = Some(VlanHeader::Single(single.clone())); // ok vlan header - from_x_slice_ip_variants(&test); + from_x_slice_net_variants(&test); // len error { @@ -740,7 +759,7 @@ mod test { test.vlan = Some(VlanHeader::Double(double.clone())); // ok double vlan header - from_x_slice_ip_variants(&test); + from_x_slice_net_variants(&test); // len error { @@ -768,10 +787,57 @@ mod test { } } - fn from_x_slice_ip_variants(base: &TestPacket) { + fn from_x_slice_net_variants(base: &TestPacket) { // none from_x_slice_transport_variants(base); + // arp + { + let arp = ArpPacket::new( + ArpHardwareId::ETHERNET, + EtherType::IPV4, + ArpOperation::REQUEST, + &[1, 2, 3, 4, 5, 6], + &[7, 8, 9, 10], + &[11, 12, 13, 14, 15, 16], + &[17, 18, 19, 20], + ) + .unwrap(); + + let mut test = base.clone(); + test.set_ether_type(ether_type::ARP); + test.net = Some(NetHeaders::Arp(arp.clone())); + from_x_slice_assert_ok(&test); + + // arp len error + { + let data = test.to_vec(&[]); + for len in 0..arp.packet_len() { + let base_len = test.len(&[]) - arp.packet_len(); + + let err = LenError { + required_len: if len < 8 { 8 } else { arp.packet_len() }, + len, + len_source: if len < 8 { + LenSource::Slice + } else { + LenSource::ArpAddrLengths + }, + layer: Layer::Arp, + layer_start_offset: base_len, + }; + + assert_test_result( + &test, + &[], + &data[..base_len + len], + Some(err::ip::LaxHeaderSliceError::Len(err.clone())), + Some((SliceError::Len(err.clone()), Layer::Arp)), + ); + } + } + } + // ipv4 for fragmented in [false, true] { let ipv4 = { @@ -1140,6 +1206,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::UDP); ip.into() @@ -1169,6 +1236,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::UdpHeader, layer_start_offset: base_len, @@ -1192,6 +1260,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::TCP); ip.into() @@ -1220,6 +1289,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::TcpHeader, layer_start_offset: base_len, @@ -1263,6 +1333,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::ICMP); ip.into() @@ -1289,6 +1360,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::Icmpv4, layer_start_offset: base_len, @@ -1313,6 +1385,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::IPV6_ICMP); ip.into() @@ -1339,6 +1412,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::Icmpv6, layer_start_offset: base_len, @@ -1410,18 +1484,20 @@ mod test { } } - fn compare_ip_header_only(test: &TestPacket, actual: &LaxPacketHeaders) { + fn compare_net_only(test: &TestPacket, actual: &LaxPacketHeaders) { assert_eq!( test.net.as_ref().map(|s| -> NetHeaders { match s { NetHeaders::Ipv4(h, _) => NetHeaders::Ipv4(h.clone(), Default::default()), NetHeaders::Ipv6(h, _) => NetHeaders::Ipv6(h.clone(), Default::default()), + NetHeaders::Arp(h) => NetHeaders::Arp(h.clone()), } }), actual.net.as_ref().map(|s| -> NetHeaders { match s { NetHeaders::Ipv4(h, _) => NetHeaders::Ipv4(h.clone(), Default::default()), NetHeaders::Ipv6(h, _) => NetHeaders::Ipv6(h.clone(), Default::default()), + NetHeaders::Arp(h) => NetHeaders::Arp(h.clone()), } }) ); @@ -1520,7 +1596,10 @@ mod test { assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ether(_))); } - Some(Layer::Ipv6Header) | Some(Layer::Ipv4Header) | Some(Layer::IpHeader) => { + Some(Layer::Ipv6Header) + | Some(Layer::Ipv4Header) + | Some(Layer::IpHeader) + | Some(Layer::Arp) => { assert_eq!(test.link, actual.link); compare_vlan(test, data, &actual); assert_eq!(None, actual.net); @@ -1535,7 +1614,7 @@ mod test { | Some(Layer::Ipv6FragHeader) => { assert_eq!(test.link, actual.link); compare_vlan(test, data, &actual); - compare_ip_header_only(test, &actual); + compare_net_only(test, &actual); assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ip(_))); } @@ -1549,7 +1628,7 @@ mod test { assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ip(_))); } - _ => unreachable!("error in an unexpected layer"), + layer => unreachable!("error in an unexpected layer {layer:?}"), } } } @@ -1574,7 +1653,10 @@ mod test { assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ether(_))); } - Some(Layer::Ipv6Header) | Some(Layer::Ipv4Header) | Some(Layer::IpHeader) => { + Some(Layer::Ipv6Header) + | Some(Layer::Ipv4Header) + | Some(Layer::IpHeader) + | Some(Layer::Arp) => { assert_eq!(None, actual.net); assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ether(_))); @@ -1585,7 +1667,7 @@ mod test { | Some(Layer::Ipv6DestOptionsHeader) | Some(Layer::Ipv6RouteHeader) | Some(Layer::Ipv6FragHeader) => { - compare_ip_header_only(test, &actual); + compare_net_only(test, &actual); assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ip(_))); } @@ -1601,17 +1683,18 @@ mod test { } } } - // from_ether_type (ip at start) + // from_ether_type (ip or arp at start) if test.link.is_none() && test.vlan.is_none() { - if let Some(ip) = &test.net { - let ether_type = match ip { + if let Some(net) = &test.net { + let ether_type = match net { NetHeaders::Ipv4(_, _) => ether_type::IPV4, NetHeaders::Ipv6(_, _) => ether_type::IPV6, + NetHeaders::Arp(_) => ether_type::ARP, }; let actual = LaxPacketHeaders::from_ether_type(ether_type, &data); assert_eq!(actual.stop_err, expected_stop_err); assert_eq!(None, actual.link); - assert_eq!(test.vlan, None); + assert_eq!(None, test.vlan); match expected_stop_err.as_ref().map(|v| v.1) { None => { assert_eq!(test.net, actual.net); @@ -1622,7 +1705,10 @@ mod test { &actual, ); } - Some(Layer::Ipv6Header) | Some(Layer::Ipv4Header) | Some(Layer::IpHeader) => { + Some(Layer::Ipv6Header) + | Some(Layer::Ipv4Header) + | Some(Layer::IpHeader) + | Some(Layer::Arp) => { assert_eq!(None, actual.net); assert_eq!(None, actual.transport); assert_eq!( @@ -1639,7 +1725,7 @@ mod test { | Some(Layer::Ipv6DestOptionsHeader) | Some(Layer::Ipv6RouteHeader) | Some(Layer::Ipv6FragHeader) => { - compare_ip_header_only(test, &actual); + compare_net_only(test, &actual); assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ip(_))); } @@ -1656,7 +1742,11 @@ mod test { } } // from_ip_slice - if test.link.is_none() && test.vlan.is_none() && test.net.is_some() { + if test.link.is_none() + && test.vlan.is_none() + && test.net.is_some() + && !matches!(test.net, Some(NetHeaders::Arp(_))) + { if let Some(err) = expected_ip_err { assert_eq!(err, LaxPacketHeaders::from_ip(&data).unwrap_err()); } else { @@ -1680,7 +1770,7 @@ mod test { | Some(Layer::Ipv6DestOptionsHeader) | Some(Layer::Ipv6RouteHeader) | Some(Layer::Ipv6FragHeader) => { - compare_ip_header_only(test, &actual); + compare_net_only(test, &actual); assert_eq!(None, actual.transport); assert!(matches!(actual.payload, LaxPayloadSlice::Ip(_))); } diff --git a/etherparse/src/lax_payload_slice.rs b/etherparse/src/lax_payload_slice.rs index 704531b9..e1934bd0 100644 --- a/etherparse/src/lax_payload_slice.rs +++ b/etherparse/src/lax_payload_slice.rs @@ -4,6 +4,8 @@ use crate::*; /// information if the payload is incomplete. #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum LaxPayloadSlice<'a> { + /// No specific payload (e.g. ARP packet). + Empty, /// Payload with it's type identified by an ether type number /// (e.g. after an ethernet II or vlan header). Ether(EtherPayloadSlice<'a>), @@ -37,6 +39,7 @@ pub enum LaxPayloadSlice<'a> { impl<'a> LaxPayloadSlice<'a> { pub fn slice(&self) -> &'a [u8] { match self { + LaxPayloadSlice::Empty => &[], LaxPayloadSlice::Ether(e) => e.payload, LaxPayloadSlice::Ip(i) => i.payload, LaxPayloadSlice::Udp { diff --git a/etherparse/src/lax_sliced_packet.rs b/etherparse/src/lax_sliced_packet.rs index 3c6364ca..d790529c 100644 --- a/etherparse/src/lax_sliced_packet.rs +++ b/etherparse/src/lax_sliced_packet.rs @@ -264,6 +264,7 @@ impl<'a> LaxSlicedPacket<'a> { match net { Ipv4(v) => Some(v.payload()), Ipv6(v) => Some(v.payload()), + Arp(_) => None, } } else { None @@ -1034,6 +1035,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::UDP); ip.into() @@ -1063,6 +1065,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::UdpHeader, layer_start_offset: base_len, @@ -1086,6 +1089,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::TCP); ip.into() @@ -1114,6 +1118,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::TcpHeader, layer_start_offset: base_len, @@ -1157,6 +1162,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::ICMP); ip.into() @@ -1183,6 +1189,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::Icmpv4, layer_start_offset: base_len, @@ -1207,6 +1214,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::IPV6_ICMP); ip.into() @@ -1233,6 +1241,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::Icmpv6, layer_start_offset: base_len, @@ -1328,6 +1337,7 @@ mod test { .unwrap() .0, ), + LaxNetSlice::Arp(arp) => NetHeaders::Arp(arp.to_packet()), } }) ); @@ -1339,6 +1349,7 @@ mod test { match s { NetHeaders::Ipv4(h, _) => NetHeaders::Ipv4(h.clone(), Default::default()), NetHeaders::Ipv6(h, _) => NetHeaders::Ipv6(h.clone(), Default::default()), + NetHeaders::Arp(_) => unreachable!(), } }), actual.net.as_ref().map(|s| -> NetHeaders { @@ -1349,6 +1360,7 @@ mod test { LaxNetSlice::Ipv6(ipv6) => { NetHeaders::Ipv6(ipv6.header().to_header(), Default::default()) } + LaxNetSlice::Arp(arp) => NetHeaders::Arp(arp.to_packet()), } }) ); @@ -1523,6 +1535,7 @@ mod test { let ether_type = match ip { NetHeaders::Ipv4(_, _) => ether_type::IPV4, NetHeaders::Ipv6(_, _) => ether_type::IPV6, + NetHeaders::Arp(_) => unreachable!(), }; let actual = LaxSlicedPacket::from_ether_type(ether_type, &data); assert_eq!(actual.stop_err, expected_stop_err); diff --git a/etherparse/src/lax_sliced_packet_cursor.rs b/etherparse/src/lax_sliced_packet_cursor.rs index 5464c162..9aff1ebd 100644 --- a/etherparse/src/lax_sliced_packet_cursor.rs +++ b/etherparse/src/lax_sliced_packet_cursor.rs @@ -61,11 +61,11 @@ impl<'a> LaxSlicedPacketCursor<'a> { }; use ether_type::*; match ether_type { - IPV4 => cursor.slice_ip(slice), - IPV6 => cursor.slice_ip(slice), + IPV4 | IPV6 => cursor.slice_ip(slice), VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => { cursor.slice_vlan(slice) } + ARP => cursor.slice_arp(slice), _ => cursor.result, } } @@ -168,6 +168,19 @@ impl<'a> LaxSlicedPacketCursor<'a> { } } + pub fn slice_arp(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a> { + let arp = match ArpPacketSlice::from_slice(slice) { + Ok(arp) => arp, + Err(mut e) => { + e.layer_start_offset += self.offset; + self.result.stop_err = Some((err::packet::SliceError::Len(e), Layer::Arp)); + return self.result; + } + }; + self.result.net = Some(LaxNetSlice::Arp(arp)); + self.result + } + pub fn slice_ip(mut self, slice: &'a [u8]) -> LaxSlicedPacket<'a> { // ip slice let ip = match LaxIpSlice::from_slice(slice) { diff --git a/etherparse/src/len_source.rs b/etherparse/src/len_source.rs index 45d00393..16ff5c7d 100644 --- a/etherparse/src/len_source.rs +++ b/etherparse/src/len_source.rs @@ -12,6 +12,8 @@ pub enum LenSource { UdpHeaderLen, /// Error occurred while decoding a TCP header. TcpHeaderLen, + /// Error occurred while decoding a ARP packet. + ArpAddrLengths, } #[cfg(test)] diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 2da16e7e..676edb55 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -3,6 +3,7 @@ //! Currently supported are: //! * Ethernet II //! * IEEE 802.1Q VLAN Tagging Header +//! * ARP //! * IPv4 //! * IPv6 (supporting the most common extension headers, but not all) //! * UDP @@ -57,7 +58,7 @@ //! Ok(value) => { //! println!("link: {:?}", value.link); //! println!("vlan: {:?}", value.vlan); -//! println!("net: {:?}", value.net); // contains ip +//! println!("net: {:?}", value.net); // contains ip & arp //! println!("transport: {:?}", value.transport); //! } //! } @@ -101,7 +102,7 @@ //! Ok(value) => { //! println!("link: {:?}", value.link); //! println!("vlan: {:?}", value.vlan); -//! println!("net: {:?}", value.net); // contains ip +//! println!("net: {:?}", value.net); // contains ip & arp //! println!("transport: {:?}", value.transport); //! } //! } @@ -149,6 +150,7 @@ //! * [`LinuxSllHeaderSlice::from_slice`] //! * [`SingleVlanHeaderSlice::from_slice`] //! * [`DoubleVlanHeaderSlice::from_slice`] +//! * [`ArpPacketSlice::from_slice`] //! * [`Ipv4HeaderSlice::from_slice`] //! * [`Ipv4ExtensionsSlice::from_slice`] //! * [`Ipv6HeaderSlice::from_slice`] @@ -165,6 +167,7 @@ //! * [`LinuxSllHeader::read`] & [`LinuxSllHeader::from_slice`] //! * [`SingleVlanHeader::read`] & [`SingleVlanHeader::from_slice`] //! * [`DoubleVlanHeader::read`] & [`DoubleVlanHeader::from_slice`] +//! * [`ArpPacket::read`] & [`ArpPacket::from_slice`] //! * [`IpHeaders::read`] & [`IpHeaders::from_slice`] //! * [`Ipv4Header::read`] & [`Ipv4Header::from_slice`] //! * [`Ipv4Extensions::read`] & [`Ipv4Extensions::from_slice`] @@ -229,6 +232,8 @@ //! * [`LinuxSllHeader::to_bytes`] & [`LinuxSllHeader::write`] //! * [`SingleVlanHeader::to_bytes`] & [`SingleVlanHeader::write`] //! * [`DoubleVlanHeader::to_bytes`] & [`DoubleVlanHeader::write`] +//! * [`ArpPacket::to_bytes`] & [`ArpPacket::write`] +//! * [`ArpEthIpv4Packet::to_bytes`] //! * [`Ipv4Header::to_bytes`] & [`Ipv4Header::write`] & [`Ipv4Header::write_raw`] //! * [`Ipv4Extensions::write`] //! * [`Ipv6Header::to_bytes`] & [`Ipv6Header::write`] @@ -310,31 +315,7 @@ pub mod err; pub mod defrag; mod link; -pub use crate::link::arp_hardware_id::*; -pub use crate::link::double_vlan_header::*; -pub use crate::link::double_vlan_header_slice::*; -pub use crate::link::double_vlan_slice::*; -pub use crate::link::ether_payload_slice::*; -pub use crate::link::ether_type_impl::*; -pub use crate::link::ethernet2_header::*; -pub use crate::link::ethernet2_header_slice::*; -pub use crate::link::ethernet2_slice::*; -pub use crate::link::link_header::*; -pub use crate::link::link_slice::*; -pub use crate::link::linux_nonstandard_ether_type::*; -pub use crate::link::linux_sll_header::*; -pub use crate::link::linux_sll_header_slice::*; -pub use crate::link::linux_sll_packet_type::*; -pub use crate::link::linux_sll_payload_slice::*; -pub use crate::link::linux_sll_protocol_type::*; -pub use crate::link::linux_sll_slice::*; -pub use crate::link::single_vlan_header::*; -pub use crate::link::single_vlan_header_slice::*; -pub use crate::link::single_vlan_slice::*; -pub use crate::link::vlan_header::*; -pub use crate::link::vlan_id::*; -pub use crate::link::vlan_pcp::*; -pub use crate::link::vlan_slice::*; +pub use link::*; #[cfg(test)] pub(crate) mod test_gens; @@ -347,29 +328,7 @@ pub use net::*; pub mod io; mod transport; -pub use crate::transport::icmp_echo_header::*; -pub use crate::transport::icmpv4; -pub use crate::transport::icmpv4_header::*; -pub use crate::transport::icmpv4_slice::*; -pub use crate::transport::icmpv4_type::*; -pub use crate::transport::icmpv6; -pub use crate::transport::icmpv6_header::*; -pub use crate::transport::icmpv6_slice::*; -pub use crate::transport::icmpv6_type::*; -pub use crate::transport::tcp_header::*; -pub use crate::transport::tcp_header_slice::*; -pub use crate::transport::tcp_option_element::*; -pub use crate::transport::tcp_option_impl::*; -pub use crate::transport::tcp_option_read_error::*; -pub use crate::transport::tcp_option_write_error::*; -pub use crate::transport::tcp_options::*; -pub use crate::transport::tcp_options_iterator::*; -pub use crate::transport::tcp_slice::*; -pub use crate::transport::transport_header::*; -pub use crate::transport::transport_slice::*; -pub use crate::transport::udp_header::*; -pub use crate::transport::udp_header_slice::*; -pub use crate::transport::udp_slice::*; +pub use transport::*; /// Helpers for calculating checksums. pub mod checksum; diff --git a/etherparse/src/link/double_vlan_slice.rs b/etherparse/src/link/double_vlan_slice.rs index ead1c36e..7b2de5f9 100644 --- a/etherparse/src/link/double_vlan_slice.rs +++ b/etherparse/src/link/double_vlan_slice.rs @@ -106,7 +106,7 @@ impl<'a> DoubleVlanSlice<'a> { } } -impl<'a> core::fmt::Debug for DoubleVlanSlice<'a> { +impl core::fmt::Debug for DoubleVlanSlice<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("DoubleVlanSlice") .field("outer", &self.outer().to_header()) diff --git a/etherparse/src/link/ethernet2_slice.rs b/etherparse/src/link/ethernet2_slice.rs index 5460632b..b3097079 100644 --- a/etherparse/src/link/ethernet2_slice.rs +++ b/etherparse/src/link/ethernet2_slice.rs @@ -155,7 +155,7 @@ impl<'a> Ethernet2Slice<'a> { } } -impl<'a> core::fmt::Debug for Ethernet2Slice<'a> { +impl core::fmt::Debug for Ethernet2Slice<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Ethernet2Slice") .field("header", &self.to_header()) diff --git a/etherparse/src/link/link_slice.rs b/etherparse/src/link/link_slice.rs index 3257e6c4..fb1bd031 100644 --- a/etherparse/src/link/link_slice.rs +++ b/etherparse/src/link/link_slice.rs @@ -187,4 +187,70 @@ mod test { } } } + + proptest! { + #[test] + fn sll_payload( + ref eth in ethernet_2_unknown(), + ref linux_sll in linux_sll_any() + ) { + let p = [1,2,3,4]; + { + let mut bytes = Vec::with_capacity(Ethernet2Header::LEN + p.len()); + bytes.extend_from_slice(ð.to_bytes()); + bytes.extend_from_slice(&p); + let slice = LinkSlice::Ethernet2( + Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap() + ); + assert_eq!( + slice.sll_payload(), + LinuxSllPayloadSlice{ + protocol_type: LinuxSllProtocolType::EtherType(eth.ether_type), + payload: &p + } + ); + } + { + let slice = LinkSlice::EtherPayload(EtherPayloadSlice { + ether_type: eth.ether_type, + payload: &p + }); + assert_eq!( + slice.sll_payload(), + LinuxSllPayloadSlice{ + protocol_type: LinuxSllProtocolType::EtherType(eth.ether_type), + payload: &p + } + ); + } + { + let mut bytes = Vec::with_capacity(LinuxSllHeader::LEN + p.len()); + bytes.extend_from_slice(&linux_sll.to_bytes()); + bytes.extend_from_slice(&p); + let slice = LinkSlice::LinuxSll( + LinuxSllSlice::from_slice(&bytes).unwrap() + ); + assert_eq!( + slice.sll_payload(), + LinuxSllPayloadSlice{ + protocol_type: linux_sll.protocol_type, + payload: &p + } + ); + } + { + let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice { + protocol_type: linux_sll.protocol_type, + payload: &p + }); + assert_eq!( + slice.sll_payload(), + LinuxSllPayloadSlice{ + protocol_type: linux_sll.protocol_type, + payload: &p + } + ); + } + } + } } diff --git a/etherparse/src/link/linux_sll_protocol_type.rs b/etherparse/src/link/linux_sll_protocol_type.rs index da259b6e..7ee53c29 100644 --- a/etherparse/src/link/linux_sll_protocol_type.rs +++ b/etherparse/src/link/linux_sll_protocol_type.rs @@ -39,7 +39,7 @@ impl LinuxSllProtocolType { ArpHardwareId::IPGRE, ArpHardwareId::IEEE80211_RADIOTAP, ArpHardwareId::FRAD, - ArpHardwareId::ETHER, + ArpHardwareId::ETHERNET, ]; pub fn change_value(&mut self, value: u16) { @@ -75,7 +75,7 @@ impl TryFrom<(ArpHardwareId, u16)> for LinuxSllProtocolType { } ArpHardwareId::IEEE80211_RADIOTAP => Ok(LinuxSllProtocolType::Ignored(protocol_type)), ArpHardwareId::FRAD => Ok(LinuxSllProtocolType::Ignored(protocol_type)), - ArpHardwareId::ETHER => match LinuxNonstandardEtherType::try_from(protocol_type) { + ArpHardwareId::ETHERNET => match LinuxNonstandardEtherType::try_from(protocol_type) { Ok(v) => Ok(LinuxSllProtocolType::LinuxNonstandardEtherType(v)), Err(_) => Ok(LinuxSllProtocolType::EtherType(EtherType(protocol_type))), }, @@ -122,7 +122,7 @@ mod test { ); assert_eq!( LinuxSllProtocolType::try_from(( - ArpHardwareId::ETHER, + ArpHardwareId::ETHERNET, u16::from(LinuxNonstandardEtherType::N802_3) )), Ok(LinuxSllProtocolType::LinuxNonstandardEtherType( @@ -130,7 +130,7 @@ mod test { )) ); assert_eq!( - LinuxSllProtocolType::try_from((ArpHardwareId::ETHER, u16::from(EtherType::IPV4))), + LinuxSllProtocolType::try_from((ArpHardwareId::ETHERNET, u16::from(EtherType::IPV4))), Ok(LinuxSllProtocolType::EtherType(EtherType::IPV4)) ); } diff --git a/etherparse/src/link/linux_sll_slice.rs b/etherparse/src/link/linux_sll_slice.rs index 9c2f2191..3adb34ea 100644 --- a/etherparse/src/link/linux_sll_slice.rs +++ b/etherparse/src/link/linux_sll_slice.rs @@ -132,7 +132,7 @@ impl<'a> LinuxSllSlice<'a> { } } -impl<'a> core::fmt::Debug for LinuxSllSlice<'a> { +impl core::fmt::Debug for LinuxSllSlice<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("LinuxSllSlice") .field("header", &self.to_header()) diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index fab5b803..5f94511e 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -1,25 +1,71 @@ -pub mod arp_hardware_id; -pub mod double_vlan_header; -pub mod double_vlan_header_slice; -pub mod double_vlan_slice; -pub mod ether_payload_slice; -pub mod ether_type_impl; -pub mod ethernet2_header; -pub mod ethernet2_header_slice; -pub mod ethernet2_slice; -pub mod link_header; -pub mod link_slice; -pub mod linux_nonstandard_ether_type; -pub mod linux_sll_header; -pub mod linux_sll_header_slice; -pub mod linux_sll_packet_type; -pub mod linux_sll_payload_slice; -pub mod linux_sll_protocol_type; -pub mod linux_sll_slice; -pub mod single_vlan_header; -pub mod single_vlan_header_slice; -pub mod single_vlan_slice; -pub mod vlan_header; -pub mod vlan_id; -pub mod vlan_pcp; -pub mod vlan_slice; +mod double_vlan_header; +pub use double_vlan_header::*; + +mod double_vlan_header_slice; +pub use double_vlan_header_slice::*; + +mod double_vlan_slice; +pub use double_vlan_slice::*; + +mod ether_payload_slice; +pub use ether_payload_slice::*; + +mod ether_type_impl; +pub use ether_type_impl::*; + +mod ethernet2_header; +pub use ethernet2_header::*; + +mod ethernet2_header_slice; +pub use ethernet2_header_slice::*; + +mod ethernet2_slice; +pub use ethernet2_slice::*; + +mod link_header; +pub use link_header::*; + +mod link_slice; +pub use link_slice::*; + +mod linux_nonstandard_ether_type; +pub use linux_nonstandard_ether_type::*; + +mod linux_sll_header; +pub use linux_sll_header::*; + +mod linux_sll_header_slice; +pub use linux_sll_header_slice::*; + +mod linux_sll_packet_type; +pub use linux_sll_packet_type::*; + +mod linux_sll_payload_slice; +pub use linux_sll_payload_slice::*; + +mod linux_sll_protocol_type; +pub use linux_sll_protocol_type::*; + +mod linux_sll_slice; +pub use linux_sll_slice::*; + +mod single_vlan_header; +pub use single_vlan_header::*; + +mod single_vlan_header_slice; +pub use single_vlan_header_slice::*; + +mod single_vlan_slice; +pub use single_vlan_slice::*; + +mod vlan_header; +pub use vlan_header::*; + +mod vlan_id; +pub use vlan_id::*; + +mod vlan_pcp; +pub use vlan_pcp::*; + +mod vlan_slice; +pub use vlan_slice::*; diff --git a/etherparse/src/link/single_vlan_slice.rs b/etherparse/src/link/single_vlan_slice.rs index ca3ce29d..77a060ea 100644 --- a/etherparse/src/link/single_vlan_slice.rs +++ b/etherparse/src/link/single_vlan_slice.rs @@ -133,7 +133,7 @@ impl<'a> SingleVlanSlice<'a> { } } -impl<'a> core::fmt::Debug for SingleVlanSlice<'a> { +impl core::fmt::Debug for SingleVlanSlice<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("SingleVlanSlice") .field("header", &self.to_header()) diff --git a/etherparse/src/net/arp_eth_ipv4_packet.rs b/etherparse/src/net/arp_eth_ipv4_packet.rs new file mode 100644 index 00000000..0bf55468 --- /dev/null +++ b/etherparse/src/net/arp_eth_ipv4_packet.rs @@ -0,0 +1,212 @@ +use core::net::Ipv4Addr; + +use crate::{ArpHardwareId, EtherType}; + +use super::{ArpOperation, ArpPacket}; + +/// An ethernet & IPv4 "Address Resolution Protocol" Packet (a specific +/// version of [`crate::ArpPacket`]). +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ArpEthIpv4Packet { + /// Specifies the operation that the sender is performing. + pub operation: ArpOperation, + + /// Sender MAC address. + pub sender_mac: [u8; 6], + + /// Sender IPv4 address. + pub sender_ipv4: [u8; 4], + + /// Sender MAC address. + pub target_mac: [u8; 6], + + /// Target IPv4 address. + pub target_ipv4: [u8; 4], +} + +impl ArpEthIpv4Packet { + /// Number of octets/bytes of the serialized packet. + pub const LEN: usize = 8 + 6 * 2 + 4 * 2; + + /// Sender IPv4 address as [`core::net::Ipv4Addr`]. + #[inline] + pub const fn sender_ipv4_addr(&self) -> Ipv4Addr { + Ipv4Addr::new( + self.sender_ipv4[0], + self.sender_ipv4[1], + self.sender_ipv4[2], + self.sender_ipv4[3], + ) + } + + /// Target IPv4 address as [`core::net::Ipv4Addr`]. + #[inline] + pub const fn target_ipv4_addr(&self) -> Ipv4Addr { + Ipv4Addr::new( + self.target_ipv4[0], + self.target_ipv4[1], + self.target_ipv4[2], + self.target_ipv4[3], + ) + } + + /// Returns the serialized header. + pub const fn to_bytes(&self) -> [u8; Self::LEN] { + const ETH_HW_TYPE: [u8; 2] = ArpHardwareId::ETHERNET.0.to_be_bytes(); + const IPV4_ETH_TYPE: [u8; 2] = EtherType::IPV4.0.to_be_bytes(); + let op = self.operation.0.to_be_bytes(); + [ + ETH_HW_TYPE[0], + ETH_HW_TYPE[1], + IPV4_ETH_TYPE[0], + IPV4_ETH_TYPE[1], + 6, + 4, + op[0], + op[1], + self.sender_mac[0], + self.sender_mac[1], + self.sender_mac[2], + self.sender_mac[3], + self.sender_mac[4], + self.sender_mac[5], + self.sender_ipv4[0], + self.sender_ipv4[1], + self.sender_ipv4[2], + self.sender_ipv4[3], + self.target_mac[0], + self.target_mac[1], + self.target_mac[2], + self.target_mac[3], + self.target_mac[4], + self.target_mac[5], + self.target_ipv4[0], + self.target_ipv4[1], + self.target_ipv4[2], + self.target_ipv4[3], + ] + } + + /// Converts the packet to generic arp packet. + #[inline] + pub const fn to_arp_packet(&self) -> ArpPacket { + // SAFETY: This is safe as + // * Both the hardware addresses have matching length 6 which is bellow the max of 255. + // * Both the protocol addresses have matching length 6 which is bellow the max of 255. + unsafe { + ArpPacket::new_unchecked( + ArpHardwareId::ETHERNET, + EtherType::IPV4, + self.operation, + &self.sender_mac, + &self.sender_ipv4, + &self.target_mac, + &self.target_ipv4, + ) + } + } +} + +impl From for ArpPacket { + fn from(value: ArpEthIpv4Packet) -> Self { + value.to_arp_packet() + } +} + +impl TryFrom for ArpEthIpv4Packet { + type Error = crate::err::arp::ArpEthIpv4FromError; + + fn try_from(value: ArpPacket) -> Result { + value.try_eth_ipv4() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_gens::*; + use proptest::prelude::*; + + proptest! { + #[test] + fn sender_ipv4_addr( + arp in arp_eth_ipv4_packet_any() + ) { + assert_eq!( + arp.sender_ipv4_addr(), + Ipv4Addr::new( + arp.sender_ipv4[0], + arp.sender_ipv4[1], + arp.sender_ipv4[2], + arp.sender_ipv4[3] + ) + ) + } + } + + proptest! { + #[test] + fn target_ipv4_addr( + arp in arp_eth_ipv4_packet_any() + ) { + assert_eq!( + arp.target_ipv4_addr(), + Ipv4Addr::new( + arp.target_ipv4[0], + arp.target_ipv4[1], + arp.target_ipv4[2], + arp.target_ipv4[3] + ) + ) + } + } + + proptest! { + #[test] + fn to_bytes( + arp in arp_eth_ipv4_packet_any() + ) { + assert_eq!( + &arp.to_bytes()[..], + &arp.to_arp_packet().to_bytes()[..] + ); + } + } + + proptest! { + #[test] + fn to_arp_packet( + arp in arp_eth_ipv4_packet_any() + ) { + let actual = arp.to_arp_packet(); + assert_eq!(ArpHardwareId::ETHERNET, actual.hw_addr_type); + assert_eq!(EtherType::IPV4, actual.proto_addr_type); + assert_eq!(6, actual.hw_addr_size()); + assert_eq!(4, actual.protocol_addr_size()); + assert_eq!(&arp.target_mac[..], actual.target_hw_addr()); + assert_eq!(&arp.target_ipv4[..], actual.target_protocol_addr()); + assert_eq!(&arp.sender_mac[..], actual.sender_hw_addr()); + assert_eq!(&arp.sender_ipv4[..], actual.sender_protocol_addr()); + } + } + + proptest! { + #[test] + fn into_arp_packet( + arp in arp_eth_ipv4_packet_any() + ) { + let actual = ArpPacket::from(arp.clone()); + assert_eq!(actual, arp.to_arp_packet()); + } + } + + proptest! { + #[test] + fn try_from_arp_packet( + arp in arp_packet_any() + ) { + let actual = ArpEthIpv4Packet::try_from(arp.clone()); + assert_eq!(actual, arp.clone().try_eth_ipv4()); + } + } +} diff --git a/etherparse/src/link/arp_hardware_id.rs b/etherparse/src/net/arp_hardware_id.rs similarity index 76% rename from etherparse/src/link/arp_hardware_id.rs rename to etherparse/src/net/arp_hardware_id.rs index 2f89ce48..351a8434 100644 --- a/etherparse/src/link/arp_hardware_id.rs +++ b/etherparse/src/net/arp_hardware_id.rs @@ -6,40 +6,153 @@ /// ``` /// use etherparse::ArpHardwareId; /// -/// assert_eq!(ArpHardwareId::ETHER.0, 0x0001); -/// assert_eq!(ArpHardwareId::ETHER, ArpHardwareId(0x0001)); +/// assert_eq!(ArpHardwareId::ETHERNET.0, 0x0001); +/// assert_eq!(ArpHardwareId::ETHERNET, ArpHardwareId(0x0001)); /// /// // convert to ArpHardwareId using the from & into trait /// let arp_hrd_id: ArpHardwareId = 0x0001.into(); -/// assert_eq!(ArpHardwareId::ETHER, arp_hrd_id); +/// assert_eq!(ArpHardwareId::ETHERNET, arp_hrd_id); /// /// // convert to u16 using the from & into trait -/// let num: u16 = ArpHardwareId::ETHER.into(); +/// let num: u16 = ArpHardwareId::ETHERNET.into(); /// assert_eq!(0x0001, num); /// ``` /// - -#[derive(Clone, Copy, Eq, PartialEq, Default, Hash)] +#[derive(Clone, Copy, Eq, PartialEq, Default, Ord, PartialOrd, Hash)] pub struct ArpHardwareId(pub u16); impl ArpHardwareId { - // Numbers sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + // Numbers sourced from + // * https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml + // * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + /// Reserved pub const NETROM: ArpHardwareId = Self(0); + + /// Ethernet (10Mb) + pub const ETHERNET: ArpHardwareId = Self(1); + + /// Deprecated use [`ArpHardwareId::ETHERNET`] instead + #[deprecated(since = "0.17.0", note = "Use `ArpHardwareId::ETHERNET` instead")] pub const ETHER: ArpHardwareId = Self(1); + + /// Experimental Ethernet (3Mb) pub const EETHER: ArpHardwareId = Self(2); + + /// Amateur Radio AX.25 pub const AX25: ArpHardwareId = Self(3); + + /// Proteon ProNET Token Ring pub const PRONET: ArpHardwareId = Self(4); + + /// Chaos pub const CHAOS: ArpHardwareId = Self(5); + + /// IEEE 802 Networks pub const IEEE802: ArpHardwareId = Self(6); + + /// ARCNET pub const ARCNET: ArpHardwareId = Self(7); + + /// Hyperchannel + pub const HYPERCHANNEL: ArpHardwareId = Self(8); + + /// APPLEtalk pub const APPLETLK: ArpHardwareId = Self(8); + + /// Lanstar + pub const LANSTAR: ArpHardwareId = Self(9); + + /// Autonet Short Address + pub const AUTONET_SHORT_ADDRESS: ArpHardwareId = Self(10); + + /// LocalTalk + pub const LOCAL_TALK: ArpHardwareId = Self(11); + + /// LocalNet (IBM PCNet or SYTEK LocalNET) + pub const LOCAL_NET: ArpHardwareId = Self(12); + + /// Ultra link + pub const ULTRA_LINK: ArpHardwareId = Self(13); + + /// SMDS + pub const SMDS: ArpHardwareId = Self(14); + + /// DLCI (alias for [`ArpHardwareId::FRAME_RELAY`]) pub const DLCI: ArpHardwareId = Self(15); + + /// Frame Relay (alias for [`ArpHardwareId::DLCI`]) + pub const FRAME_RELAY: ArpHardwareId = Self(15); + + /// Asynchronous Transmission Mode (ATM) \[JXB2\] + pub const ATM_JXB2: ArpHardwareId = Self(16); + + /// HDLC + pub const HDLC: ArpHardwareId = Self(17); + + /// Fibre Channel + pub const FIBRE_CHANNEL: ArpHardwareId = Self(18); + + /// Asynchronous Transmission Mode (ATM) \[RFC2225\] pub const ATM: ArpHardwareId = Self(19); + + /// Serial Line + pub const SERIAL_LINE: ArpHardwareId = Self(20); + + /// Asynchronous Transmission Mode (ATM) \[Mike_Burrows\] + pub const ATM_21: ArpHardwareId = Self(21); + + /// MIL-STD-188-220 + pub const MIL_STD_188_220: ArpHardwareId = Self(22); + + /// Metricom pub const METRICOM: ArpHardwareId = Self(23); + + /// IEEE 1394.1995 pub const IEEE1394: ArpHardwareId = Self(24); + + /// MAPOS + pub const MAPOS: ArpHardwareId = Self(25); + + /// Twinaxial + pub const TWINAXIAL: ArpHardwareId = Self(26); + + /// EUI-64 pub const EUI64: ArpHardwareId = Self(27); + + /// HIPARP + pub const HIPARP: ArpHardwareId = Self(28); + + /// IP and ARP over ISO 7816-3 + pub const IP_AND_ARP_OVER_ISO_7816_3: ArpHardwareId = Self(29); + + /// ARPSec + pub const ARPSEC: ArpHardwareId = Self(30); + + /// IPsec tunnel + pub const IPSEC_TUNNEL: ArpHardwareId = Self(31); + + /// InfiniBand pub const INFINIBAND: ArpHardwareId = Self(32); + + /// TIA-102 Project 25 Common Air Interface (CAI) + pub const CAI: ArpHardwareId = Self(33); + + /// Wiegand Interface + pub const WIEGAND_INTERFACE: ArpHardwareId = Self(34); + + /// Pure IP + pub const PURE_IP: ArpHardwareId = Self(35); + + /// HW_EXP1 + pub const HW_EXP1: ArpHardwareId = Self(36); + + /// HFI + pub const HFI: ArpHardwareId = Self(37); + + /// Unified Bus (UB) + pub const UNIFIED_BUS: ArpHardwareId = Self(38); + pub const SLIP: ArpHardwareId = Self(256); pub const CSLIP: ArpHardwareId = Self(257); pub const SLIP6: ArpHardwareId = Self(258); @@ -107,26 +220,54 @@ impl From for u16 { } } -impl core::fmt::Display for ArpHardwareId { - // Names sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21 - +impl core::fmt::Debug for ArpHardwareId { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { Self::NETROM => write!(f, "{} (from KA9Q: NET/ROM pseudo)", self.0), - Self::ETHER => write!(f, "{} (Ethernet 10Mbps)", self.0), + Self::ETHERNET => write!(f, "{} (Ethernet)", self.0), Self::EETHER => write!(f, "{} (Experimental Ethernet)", self.0), Self::AX25 => write!(f, "{} (AX.25 Level 2)", self.0), Self::PRONET => write!(f, "{} (PROnet token ring)", self.0), Self::CHAOS => write!(f, "{} (Chaosnet)", self.0), Self::IEEE802 => write!(f, "{} (IEEE 802.2 Ethernet/TR/TB)", self.0), Self::ARCNET => write!(f, "{} (ARCnet)", self.0), - Self::APPLETLK => write!(f, "{} (APPLEtalk)", self.0), + Self::APPLETLK => write!(f, "{} (APPLEtalk or Hyperchannel)", self.0), + Self::LANSTAR => write!(f, "{} (Lanstar)", self.0), + Self::AUTONET_SHORT_ADDRESS => write!(f, "{} (Autonet Short Address)", self.0), + Self::LOCAL_TALK => write!(f, "{} (LocalTalk)", self.0), + Self::LOCAL_NET => write!(f, "{} (LocalNet)", self.0), + Self::ULTRA_LINK => write!(f, "{} (Ultra link)", self.0), + Self::SMDS => write!(f, "{} (SMDS)", self.0), Self::DLCI => write!(f, "{} (Frame Relay DLCI)", self.0), + Self::ATM_JXB2 => write!(f, "{} (Asynchronous Transmission Mode (ATM) JXB2)", self.0), + Self::HDLC => write!(f, "{} (HDLC)", self.0), + Self::FIBRE_CHANNEL => write!(f, "{} (Fibre Channel)", self.0), Self::ATM => write!(f, "{} (ATM)", self.0), + Self::SERIAL_LINE => write!(f, "{} (Serial Line)", self.0), + Self::ATM_21 => write!(f, "{} (Asynchronous Transmission Mode (ATM))", self.0), + Self::MIL_STD_188_220 => write!(f, "{} (MIL-STD-188-220)", self.0), Self::METRICOM => write!(f, "{} (Metricom STRIP (new IANA id))", self.0), Self::IEEE1394 => write!(f, "{} (IEEE 1394 IPv4 - RFC 2734)", self.0), + Self::MAPOS => write!(f, "{} (MAPOS)", self.0), + Self::TWINAXIAL => write!(f, "{} (Twinaxial)", self.0), Self::EUI64 => write!(f, "{} (EUI-64)", self.0), + Self::HIPARP => write!(f, "{} (HIPARP)", self.0), + Self::IP_AND_ARP_OVER_ISO_7816_3 => { + write!(f, "{} (IP and ARP over ISO 7816-3)", self.0) + } + Self::ARPSEC => write!(f, "{} (ARPSec)", self.0), + Self::IPSEC_TUNNEL => write!(f, "{} (IPsec tunnel)", self.0), Self::INFINIBAND => write!(f, "{} (InfiniBand)", self.0), + Self::CAI => write!( + f, + "{} (TIA-102 Project 25 Common Air Interface (CAI))", + self.0 + ), + Self::WIEGAND_INTERFACE => write!(f, "{} (Wiegand Interface)", self.0), + Self::PURE_IP => write!(f, "{} (Pure IP)", self.0), + Self::HW_EXP1 => write!(f, "{} (HW_EXP1)", self.0), + Self::HFI => write!(f, "{} (HFI)", self.0), + Self::UNIFIED_BUS => write!(f, "{} (Unified Bus (UB))", self.0), Self::SLIP => write!(f, "{} (SLIP)", self.0), Self::CSLIP => write!(f, "{} (CSLIP)", self.0), Self::SLIP6 => write!(f, "{} (SLIP6)", self.0), @@ -183,12 +324,6 @@ impl core::fmt::Display for ArpHardwareId { } } -impl core::fmt::Debug for ArpHardwareId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Display::fmt(&self, f) - } -} - #[cfg(test)] mod test { use super::*; @@ -197,7 +332,7 @@ mod test { #[test] fn to_u16() { assert_eq!(0, u16::from(ArpHardwareId::NETROM)); - assert_eq!(1, u16::from(ArpHardwareId::ETHER)); + assert_eq!(1, u16::from(ArpHardwareId::ETHERNET)); assert_eq!(2, u16::from(ArpHardwareId::EETHER)); assert_eq!(3, u16::from(ArpHardwareId::AX25)); assert_eq!(4, u16::from(ArpHardwareId::PRONET)); @@ -273,7 +408,7 @@ mod test { #[test] fn from_u16() { assert_eq!(ArpHardwareId::from(0), ArpHardwareId::NETROM); - assert_eq!(ArpHardwareId::from(1), ArpHardwareId::ETHER); + assert_eq!(ArpHardwareId::from(1), ArpHardwareId::ETHERNET); assert_eq!(ArpHardwareId::from(2), ArpHardwareId::EETHER); assert_eq!(ArpHardwareId::from(3), ArpHardwareId::AX25); assert_eq!(ArpHardwareId::from(4), ArpHardwareId::PRONET); @@ -350,20 +485,59 @@ mod test { fn display_dbg() { let pairs = &[ (ArpHardwareId::NETROM, "0 (from KA9Q: NET/ROM pseudo)"), - (ArpHardwareId::ETHER, "1 (Ethernet 10Mbps)"), + (ArpHardwareId::ETHERNET, "1 (Ethernet)"), (ArpHardwareId::EETHER, "2 (Experimental Ethernet)"), (ArpHardwareId::AX25, "3 (AX.25 Level 2)"), (ArpHardwareId::PRONET, "4 (PROnet token ring)"), (ArpHardwareId::CHAOS, "5 (Chaosnet)"), (ArpHardwareId::IEEE802, "6 (IEEE 802.2 Ethernet/TR/TB)"), (ArpHardwareId::ARCNET, "7 (ARCnet)"), - (ArpHardwareId::APPLETLK, "8 (APPLEtalk)"), + (ArpHardwareId::APPLETLK, "8 (APPLEtalk or Hyperchannel)"), + (ArpHardwareId::LANSTAR, "9 (Lanstar)"), + ( + ArpHardwareId::AUTONET_SHORT_ADDRESS, + "10 (Autonet Short Address)", + ), + (ArpHardwareId::LOCAL_TALK, "11 (LocalTalk)"), + (ArpHardwareId::LOCAL_NET, "12 (LocalNet)"), + (ArpHardwareId::ULTRA_LINK, "13 (Ultra link)"), + (ArpHardwareId::SMDS, "14 (SMDS)"), (ArpHardwareId::DLCI, "15 (Frame Relay DLCI)"), + ( + ArpHardwareId::ATM_JXB2, + "16 (Asynchronous Transmission Mode (ATM) JXB2)", + ), + (ArpHardwareId::HDLC, "17 (HDLC)"), + (ArpHardwareId::FIBRE_CHANNEL, "18 (Fibre Channel)"), (ArpHardwareId::ATM, "19 (ATM)"), + (ArpHardwareId::SERIAL_LINE, "20 (Serial Line)"), + ( + ArpHardwareId::ATM_21, + "21 (Asynchronous Transmission Mode (ATM))", + ), + (ArpHardwareId::MIL_STD_188_220, "22 (MIL-STD-188-220)"), (ArpHardwareId::METRICOM, "23 (Metricom STRIP (new IANA id))"), (ArpHardwareId::IEEE1394, "24 (IEEE 1394 IPv4 - RFC 2734)"), + (ArpHardwareId::MAPOS, "25 (MAPOS)"), + (ArpHardwareId::TWINAXIAL, "26 (Twinaxial)"), (ArpHardwareId::EUI64, "27 (EUI-64)"), + (ArpHardwareId::HIPARP, "28 (HIPARP)"), + ( + ArpHardwareId::IP_AND_ARP_OVER_ISO_7816_3, + "29 (IP and ARP over ISO 7816-3)", + ), + (ArpHardwareId::ARPSEC, "30 (ARPSec)"), + (ArpHardwareId::IPSEC_TUNNEL, "31 (IPsec tunnel)"), (ArpHardwareId::INFINIBAND, "32 (InfiniBand)"), + ( + ArpHardwareId::CAI, + "33 (TIA-102 Project 25 Common Air Interface (CAI))", + ), + (ArpHardwareId::WIEGAND_INTERFACE, "34 (Wiegand Interface)"), + (ArpHardwareId::PURE_IP, "35 (Pure IP)"), + (ArpHardwareId::HW_EXP1, "36 (HW_EXP1)"), + (ArpHardwareId::HFI, "37 (HFI)"), + (ArpHardwareId::UNIFIED_BUS, "38 (Unified Bus (UB))"), (ArpHardwareId::SLIP, "256 (SLIP)"), (ArpHardwareId::CSLIP, "257 (CSLIP)"), (ArpHardwareId::SLIP6, "258 (SLIP6)"), @@ -433,9 +607,8 @@ mod test { (ArpHardwareId::from(0x1234), "0x1234"), ]; - for (ether_type, str_value) in pairs { - assert_eq!(str_value, &format!("{}", ether_type)); - assert_eq!(str_value, &format!("{:?}", ether_type)); + for (arp_hw_id, str_value) in pairs { + assert_eq!(str_value, &format!("{:?}", arp_hw_id)); } } @@ -449,7 +622,7 @@ mod test { fn clone_eq() { let values = &[ ArpHardwareId::NETROM, - ArpHardwareId::ETHER, + ArpHardwareId::ETHERNET, ArpHardwareId::EETHER, ArpHardwareId::AX25, ArpHardwareId::PRONET, diff --git a/etherparse/src/net/arp_operation.rs b/etherparse/src/net/arp_operation.rs new file mode 100644 index 00000000..a8c9f739 --- /dev/null +++ b/etherparse/src/net/arp_operation.rs @@ -0,0 +1,25 @@ +/// Operation field value in an ARP packet. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct ArpOperation(pub u16); + +impl ArpOperation { + pub const REQUEST: ArpOperation = ArpOperation(1); + pub const REPLY: ArpOperation = ArpOperation(2); +} + +impl From for ArpOperation { + #[inline] + fn from(raw: u16) -> Self { + ArpOperation(raw) + } +} + +#[cfg(test)] +mod tests { + use crate::ArpOperation; + + #[test] + pub fn from_u16() { + assert_eq!(ArpOperation::from(12), ArpOperation(12)) + } +} diff --git a/etherparse/src/net/arp_packet.rs b/etherparse/src/net/arp_packet.rs new file mode 100644 index 00000000..efbc0be0 --- /dev/null +++ b/etherparse/src/net/arp_packet.rs @@ -0,0 +1,1100 @@ +use arrayvec::ArrayVec; +use err::arp::{ArpHwAddrError, ArpNewError, ArpProtoAddrError}; + +use crate::*; +use core::mem::MaybeUninit; + +/// "Address Resolution Protocol" Packet. +#[derive(Clone)] +pub struct ArpPacket { + /// Network link protocol type (e.g. `ArpHardwareId::ETHERNET`). + pub hw_addr_type: ArpHardwareId, + + /// Protocol for which the ARP request is intended (e.g. `EtherType::IPV4`). + pub proto_addr_type: EtherType, + + /// Length (in octets) of a hardware address (e.g. 6 for Ethernet). + hw_addr_size: u8, + + /// Length (in octets) of internetwork addresses (e.g. 4 for IPv4 or 16 for IPv6). + proto_addr_size: u8, + + /// Specifies the operation that the sender is performing + pub operation: ArpOperation, + + /// Buffer containing the sender hardware address (e.g. MAC address). + sender_hw_addr_buf: [MaybeUninit; 0xff], + + /// Buffer containing the sender protocol address (e.g. IPv4 address). + sender_protocol_addr_buf: [MaybeUninit; 0xff], + + /// Buffer containing the target hardware address (e.g. MAC address). + target_hw_addr_buf: [MaybeUninit; 0xff], + + /// Buffer containing the target protocol address (e.g. IPv4 address).. + target_protocol_addr_buf: [MaybeUninit; 0xff], +} + +impl ArpPacket { + /// Maximum length of an ARP packet in bytes/octets. + /// + /// This number is calculated by taking the maximum values + /// that `hw_addr_size`(255/u8::MAX) & `proto_addr_size` (255/u8::MAX) + /// can take and calculate the maximum packet size from that. + pub const MAX_LEN: usize = 8 + 2 * 255 + 2 * 255; + + /// Create a new ARP packet with the given values. + pub const fn new( + hw_addr_type: ArpHardwareId, + proto_addr_type: EtherType, + operation: ArpOperation, + sender_hw_addr: &[u8], + sender_protocol_addr: &[u8], + target_hw_addr: &[u8], + target_protocol_addr: &[u8], + ) -> Result { + if sender_hw_addr.len() != target_hw_addr.len() { + return Err(ArpNewError::HwAddr(ArpHwAddrError::LenNonMatching( + sender_hw_addr.len(), + target_hw_addr.len(), + ))); + } + if sender_protocol_addr.len() != target_protocol_addr.len() { + return Err(ArpNewError::ProtoAddr(ArpProtoAddrError::LenNonMatching( + sender_protocol_addr.len(), + target_protocol_addr.len(), + ))); + } + if sender_hw_addr.len() > 255 { + return Err(ArpNewError::HwAddr(ArpHwAddrError::LenTooBig( + sender_hw_addr.len(), + ))); + } + if sender_protocol_addr.len() > 255 { + return Err(ArpNewError::ProtoAddr(ArpProtoAddrError::LenTooBig( + sender_protocol_addr.len(), + ))); + } + Ok(ArpPacket { + hw_addr_type, + proto_addr_type, + // cast ok as we verfied the len to be less equal then 255. + hw_addr_size: sender_hw_addr.len() as u8, + // cast ok as we verfied the len to be less equal then 255. + proto_addr_size: sender_protocol_addr.len() as u8, + operation, + sender_hw_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * sender_hw_addr.len() is guranteed to be <= 255 (checked in if above) + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + sender_hw_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + sender_hw_addr.len(), + ); + } + buf + }, + sender_protocol_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * sender_protocol_addr.len() is guranteed to be <= 255 (checked in if above) + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + sender_protocol_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + sender_protocol_addr.len(), + ); + } + buf + }, + target_hw_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * target_hw_addr.len() is guranteed to be <= 255 (checked in if above) + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + target_hw_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + target_hw_addr.len(), + ); + } + buf + }, + target_protocol_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * target_protocol_addr.len() is guranteed to be <= 255 (checked in if above) + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + target_protocol_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + target_protocol_addr.len(), + ); + } + buf + }, + }) + } + + /// Create a new ARP packet with the given values without checking + /// hardware & protocol address sizes. + /// + /// # Safety + /// + /// The caller must gurantee that + /// + /// * `sender_hw_addr` & `target_hw_addr` have the same length and the length must be smaller or equal than 255. + /// * `sender_protocol_addr` & `target_protocol_addr` have the same length and the length must be smaller or equal than 255. + /// + /// The gurantees the caller must fullfill are equal to the following + /// preconditions: + /// + /// * `sender_hw_addr.len() == target_hw_addr.len()` + /// * `sender_hw_addr.len() <= 255` + /// * `target_hw_addr.len() <= 255` + /// * `sender_protocol_addr.len() == target_protocol_addr.len()` + /// * `sender_protocol_addr.len() <= 255` + /// * `target_protocol_addr.len() <= 255` + pub const unsafe fn new_unchecked( + hw_addr_type: ArpHardwareId, + proto_addr_type: EtherType, + operation: ArpOperation, + sender_hw_addr: &[u8], + sender_protocol_addr: &[u8], + target_hw_addr: &[u8], + target_protocol_addr: &[u8], + ) -> ArpPacket { + debug_assert!(sender_hw_addr.len() == target_hw_addr.len()); + debug_assert!(sender_protocol_addr.len() == target_protocol_addr.len()); + debug_assert!(sender_hw_addr.len() <= 255); + debug_assert!(sender_protocol_addr.len() <= 255); + + ArpPacket { + hw_addr_type, + proto_addr_type, + // cast ok as we verfied the len to be less equal then 255. + hw_addr_size: sender_hw_addr.len() as u8, + // cast ok as we verfied the len to be less equal then 255. + proto_addr_size: sender_protocol_addr.len() as u8, + operation, + sender_hw_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * the caller must gurantee that sender_hw_addr.len() is <= 255 + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + sender_hw_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + sender_hw_addr.len(), + ); + } + buf + }, + sender_protocol_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * the caller must gurantee that sender_protocol_addr.len() is <= 255 + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + sender_protocol_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + sender_protocol_addr.len(), + ); + } + buf + }, + target_hw_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * the caller must gurantee that target_hw_addr.len() is <= 255 + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + target_hw_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + target_hw_addr.len(), + ); + } + buf + }, + target_protocol_addr_buf: { + let mut buf: [MaybeUninit; 255] = [const { MaybeUninit::uninit() }; 255]; + // SAFETY: Safe as + // * the caller must gurantee that target_protocol_addr.len() is <= 255 + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + target_protocol_addr.as_ptr(), + buf.as_mut_ptr() as *mut u8, + target_protocol_addr.len(), + ); + } + buf + }, + } + } + + /// Reads an ARP packet from a slice. + pub fn from_slice(slice: &[u8]) -> Result { + ArpPacketSlice::from_slice(slice).map(|v| v.to_packet()) + } + + /// Length (in octets) of a hardware address (e.g. 6 for Ethernet). + #[inline] + pub const fn hw_addr_size(&self) -> u8 { + self.hw_addr_size + } + + /// Length (in octets) of internetwork addresses (e.g. 4 for IPv4 or 16 for IPv6). + #[inline] + pub const fn protocol_addr_size(&self) -> u8 { + self.proto_addr_size + } + + /// Sender hardware address (e.g. MAC address). + #[inline] + pub const fn sender_hw_addr(&self) -> &[u8] { + unsafe { + core::slice::from_raw_parts( + self.sender_hw_addr_buf.as_ptr() as *const u8, + self.hw_addr_size as usize, + ) + } + } + + /// Sender protocol address (e.g. IPv4 address). + #[inline] + pub const fn sender_protocol_addr(&self) -> &[u8] { + unsafe { + core::slice::from_raw_parts( + self.sender_protocol_addr_buf.as_ptr() as *const u8, + self.proto_addr_size as usize, + ) + } + } + + /// Target hardware address (e.g. MAC address). + #[inline] + pub const fn target_hw_addr(&self) -> &[u8] { + unsafe { + core::slice::from_raw_parts( + self.target_hw_addr_buf.as_ptr() as *const u8, + self.hw_addr_size as usize, + ) + } + } + + /// Target protocol address (e.g. IPv4 address). + #[inline] + pub const fn target_protocol_addr(&self) -> &[u8] { + unsafe { + core::slice::from_raw_parts( + self.target_protocol_addr_buf.as_ptr() as *const u8, + self.proto_addr_size as usize, + ) + } + } + + /// Set the sender & target hardware addresses (e.g. MAC address). + #[inline] + pub const fn set_hw_addrs( + &mut self, + sender_hw_addr: &[u8], + target_hw_addr: &[u8], + ) -> Result<(), ArpHwAddrError> { + if sender_hw_addr.len() != target_hw_addr.len() { + return Err(ArpHwAddrError::LenNonMatching( + sender_hw_addr.len(), + target_hw_addr.len(), + )); + } + if sender_hw_addr.len() > 255 { + return Err(ArpHwAddrError::LenTooBig(sender_hw_addr.len())); + } + { + // SAFETY: Safe as + // * the caller must gurantee that sender_hw_addr.len() is <= 255 + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + sender_hw_addr.as_ptr(), + self.sender_hw_addr_buf.as_mut_ptr() as *mut u8, + sender_hw_addr.len(), + ); + } + } + { + // SAFETY: Safe as + // * the caller must gurantee that target_hw_addr.len() is <= 255 + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + target_hw_addr.as_ptr(), + self.target_hw_addr_buf.as_mut_ptr() as *mut u8, + target_hw_addr.len(), + ); + } + } + self.hw_addr_size = sender_hw_addr.len() as u8; + Ok(()) + } + + /// Set the sender & target protocol addresses (e.g. IPv4 address). + #[inline] + pub const fn set_protocol_addrs( + &mut self, + sender_protocol_addr: &[u8], + target_protocol_addr: &[u8], + ) -> Result<(), ArpProtoAddrError> { + if sender_protocol_addr.len() != target_protocol_addr.len() { + return Err(ArpProtoAddrError::LenNonMatching( + sender_protocol_addr.len(), + target_protocol_addr.len(), + )); + } + if sender_protocol_addr.len() > 255 { + return Err(ArpProtoAddrError::LenTooBig(sender_protocol_addr.len())); + } + { + // SAFETY: Safe as + // * sender_protocol_addr.len() is guranteed to be <= 255 (checked in if above) + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + sender_protocol_addr.as_ptr(), + self.sender_protocol_addr_buf.as_mut_ptr() as *mut u8, + sender_protocol_addr.len(), + ); + } + } + { + // SAFETY: Safe as + // * target_protocol_addr.len() is guranteed to be <= 255 (checked in if above) + // * memory areas guranteed to be non overlapping (buf created in this function). + unsafe { + core::ptr::copy_nonoverlapping( + target_protocol_addr.as_ptr(), + self.target_protocol_addr_buf.as_mut_ptr() as *mut u8, + target_protocol_addr.len(), + ); + } + } + self.proto_addr_size = sender_protocol_addr.len() as u8; + Ok(()) + } + + /// Serialized length of this ARP packet. + #[inline] + pub fn packet_len(&self) -> usize { + 8 + usize::from(self.hw_addr_size) * 2 + usize::from(self.proto_addr_size) * 2 + } + + /// Returns the serialized header. + #[inline] + pub fn to_bytes(&self) -> ArrayVec { + let hw_addr_type = self.hw_addr_type.0.to_be_bytes(); + let proto_addr_type = self.proto_addr_type.0.to_be_bytes(); + let operation = self.operation.0.to_be_bytes(); + let mut result = ArrayVec::::new_const(); + result.extend([ + hw_addr_type[0], + hw_addr_type[1], + proto_addr_type[0], + proto_addr_type[1], + self.hw_addr_size, + self.proto_addr_size, + operation[0], + operation[1], + ]); + result.try_extend_from_slice(self.sender_hw_addr()).unwrap(); + result + .try_extend_from_slice(self.sender_protocol_addr()) + .unwrap(); + result.try_extend_from_slice(self.target_hw_addr()).unwrap(); + result + .try_extend_from_slice(self.target_protocol_addr()) + .unwrap(); + result + } + + /// Writes the header to the given writer. + #[cfg(feature = "std")] + pub fn write(&self, writer: &mut T) -> Result<(), std::io::Error> { + writer.write_all(&self.to_bytes())?; + Ok(()) + } + + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + pub fn read( + reader: &mut T, + ) -> Result { + let mut start = [0u8; 8]; + reader.read_exact(&mut start[..])?; + + let mut result = ArpPacket { + hw_addr_type: ArpHardwareId(u16::from_be_bytes([start[0], start[1]])), + proto_addr_type: EtherType(u16::from_be_bytes([start[2], start[3]])), + hw_addr_size: start[4], + proto_addr_size: start[5], + operation: ArpOperation(u16::from_be_bytes([start[6], start[7]])), + sender_hw_addr_buf: [const { MaybeUninit::uninit() }; 255], + sender_protocol_addr_buf: [const { MaybeUninit::uninit() }; 255], + target_hw_addr_buf: [const { MaybeUninit::uninit() }; 255], + target_protocol_addr_buf: [const { MaybeUninit::uninit() }; 255], + }; + + { + // SAFETY: Safe as the maximum u8 value is equal to the array size 255. + let sender_hw_addr_slice = unsafe { + core::slice::from_raw_parts_mut( + result.sender_hw_addr_buf.as_mut_ptr() as *mut u8, + result.hw_addr_size as usize, + ) + }; + reader.read_exact(sender_hw_addr_slice)?; + } + { + // SAFETY: Safe as the maximum u8 value is equal to the array size 255. + let sender_protocol_addr = unsafe { + core::slice::from_raw_parts_mut( + result.sender_protocol_addr_buf.as_mut_ptr() as *mut u8, + result.proto_addr_size as usize, + ) + }; + reader.read_exact(sender_protocol_addr)?; + } + { + // SAFETY: Safe as the maximum u8 value is equal to the array size 255. + let target_hw_addr = unsafe { + core::slice::from_raw_parts_mut( + result.target_hw_addr_buf.as_mut_ptr() as *mut u8, + result.hw_addr_size as usize, + ) + }; + reader.read_exact(target_hw_addr)?; + } + { + // SAFETY: Safe as the maximum u8 value is equal to the array size 255. + let target_protocol_addr = unsafe { + core::slice::from_raw_parts_mut( + result.target_protocol_addr_buf.as_mut_ptr() as *mut u8, + result.proto_addr_size as usize, + ) + }; + reader.read_exact(target_protocol_addr)?; + } + + Ok(result) + } + + /// Returns an [`ArpEthIpv4Packet`] if the current packet + /// is an ethernet & IPv4 ARP packet. + pub fn try_eth_ipv4(&self) -> Result { + use err::arp::ArpEthIpv4FromError::*; + if self.hw_addr_type != ArpHardwareId::ETHERNET { + return Err(NonMatchingHwType(self.hw_addr_type)); + } + if self.proto_addr_type != EtherType::IPV4 { + return Err(NonMatchingProtocolType(self.proto_addr_type)); + } + if self.hw_addr_size != 6 { + return Err(NonMatchingHwAddrSize(self.hw_addr_size)); + } + if self.proto_addr_size != 4 { + return Err(NonMatchingProtoAddrSize(self.proto_addr_size)); + } + Ok(ArpEthIpv4Packet { + operation: self.operation, + sender_mac: unsafe { + // SAFE as we check above that hw_addr_size is 6 + [ + self.sender_hw_addr_buf[0].assume_init(), + self.sender_hw_addr_buf[1].assume_init(), + self.sender_hw_addr_buf[2].assume_init(), + self.sender_hw_addr_buf[3].assume_init(), + self.sender_hw_addr_buf[4].assume_init(), + self.sender_hw_addr_buf[5].assume_init(), + ] + }, + sender_ipv4: unsafe { + // SAFE as we check above that proto_addr_size is 6 + [ + self.sender_protocol_addr_buf[0].assume_init(), + self.sender_protocol_addr_buf[1].assume_init(), + self.sender_protocol_addr_buf[2].assume_init(), + self.sender_protocol_addr_buf[3].assume_init(), + ] + }, + target_mac: unsafe { + // SAFE as we check above that hw_addr_size is 6 + [ + self.target_hw_addr_buf[0].assume_init(), + self.target_hw_addr_buf[1].assume_init(), + self.target_hw_addr_buf[2].assume_init(), + self.target_hw_addr_buf[3].assume_init(), + self.target_hw_addr_buf[4].assume_init(), + self.target_hw_addr_buf[5].assume_init(), + ] + }, + target_ipv4: unsafe { + // SAFE as we check above that proto_addr_size is 6 + [ + self.target_protocol_addr_buf[0].assume_init(), + self.target_protocol_addr_buf[1].assume_init(), + self.target_protocol_addr_buf[2].assume_init(), + self.target_protocol_addr_buf[3].assume_init(), + ] + }, + }) + } +} + +impl core::fmt::Debug for ArpPacket { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ArpPacket") + .field("hw_addr_type", &self.hw_addr_type) + .field("proto_addr_type", &self.proto_addr_type) + .field("hw_addr_size", &self.hw_addr_size) + .field("proto_addr_size", &self.proto_addr_size) + .field("operation", &self.operation) + .field("sender_hw_addr", &self.sender_hw_addr()) + .field("sender_protocol_addr", &self.sender_protocol_addr()) + .field("target_hw_addr", &self.target_hw_addr()) + .field("target_protocol_addr", &self.target_protocol_addr()) + .finish() + } +} + +impl core::cmp::PartialEq for ArpPacket { + fn eq(&self, other: &Self) -> bool { + self.hw_addr_type == other.hw_addr_type + && self.proto_addr_type == other.proto_addr_type + && self.hw_addr_size == other.hw_addr_size + && self.proto_addr_size == other.proto_addr_size + && self.operation == other.operation + && self.sender_hw_addr() == other.sender_hw_addr() + && self.sender_protocol_addr() == other.sender_protocol_addr() + && self.target_hw_addr() == other.target_hw_addr() + && self.target_protocol_addr() == other.target_protocol_addr() + } +} + +impl core::cmp::Eq for ArpPacket {} + +impl core::hash::Hash for ArpPacket { + fn hash(&self, state: &mut H) { + self.hw_addr_type.hash(state); + self.proto_addr_type.hash(state); + self.hw_addr_size.hash(state); + self.proto_addr_size.hash(state); + self.operation.hash(state); + self.sender_hw_addr().hash(state); + self.sender_protocol_addr().hash(state); + self.target_hw_addr().hash(state); + self.target_protocol_addr().hash(state); + } +} + +#[cfg(test)] +mod tests { + use crate::{test_gens::*, *}; + use err::arp::{ArpHwAddrError, ArpNewError, ArpProtoAddrError}; + use proptest::prelude::*; + + #[test] + fn new() { + // ok case + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3], + &[4, 5, 6, 7, 8], + &[9, 10, 11], + &[12, 13, 14, 15, 16], + ) + .unwrap(); + assert_eq!(3, actual.hw_addr_size()); + assert_eq!(5, actual.protocol_addr_size()); + assert_eq!(ArpHardwareId::ASH, actual.hw_addr_type); + assert_eq!(EtherType::PROVIDER_BRIDGING, actual.proto_addr_type); + assert_eq!(ArpOperation::REQUEST, actual.operation); + assert_eq!(&[1, 2, 3], actual.sender_hw_addr()); + assert_eq!(&[4, 5, 6, 7, 8], actual.sender_protocol_addr()); + assert_eq!(&[9, 10, 11], actual.target_hw_addr()); + assert_eq!(&[12, 13, 14, 15, 16], actual.target_protocol_addr()); + } + + // ok case (upper hw size) + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1; 255], + &[4, 5, 6, 7, 8], + &[2; 255], + &[12, 13, 14, 15, 16], + ) + .unwrap(); + assert_eq!(255, actual.hw_addr_size()); + assert_eq!(5, actual.protocol_addr_size()); + assert_eq!(ArpHardwareId::ASH, actual.hw_addr_type); + assert_eq!(EtherType::PROVIDER_BRIDGING, actual.proto_addr_type); + assert_eq!(ArpOperation::REQUEST, actual.operation); + assert_eq!(&[1; 255], actual.sender_hw_addr()); + assert_eq!(&[4, 5, 6, 7, 8], actual.sender_protocol_addr()); + assert_eq!(&[2; 255], actual.target_hw_addr()); + assert_eq!(&[12, 13, 14, 15, 16], actual.target_protocol_addr()); + } + + // ok case (protocol hw size) + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[3, 4, 5], + &[1; 255], + &[6, 7, 8], + &[2; 255], + ) + .unwrap(); + assert_eq!(3, actual.hw_addr_size()); + assert_eq!(255, actual.protocol_addr_size()); + assert_eq!(ArpHardwareId::ASH, actual.hw_addr_type); + assert_eq!(EtherType::PROVIDER_BRIDGING, actual.proto_addr_type); + assert_eq!(ArpOperation::REQUEST, actual.operation); + assert_eq!(&[3, 4, 5], actual.sender_hw_addr()); + assert_eq!(&[1; 255], actual.sender_protocol_addr()); + assert_eq!(&[6, 7, 8], actual.target_hw_addr()); + assert_eq!(&[2; 255], actual.target_protocol_addr()); + } + + // hw slice len differ error + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3], + &[], + &[4, 5, 6, 7], + &[], + ); + assert_eq!( + Err(ArpNewError::HwAddr(ArpHwAddrError::LenNonMatching(3, 4))), + actual + ); + } + // protocol slice len differ error + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[], + &[1, 2, 3], + &[], + &[4, 5, 6, 7], + ); + assert_eq!( + Err(ArpNewError::ProtoAddr(ArpProtoAddrError::LenNonMatching( + 3, 4 + ))), + actual + ); + } + + // hardware length error + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[0; 256], + &[1, 2, 3, 4], + &[0; 256], + &[5, 6, 7, 8], + ); + assert_eq!( + Err(ArpNewError::HwAddr(ArpHwAddrError::LenTooBig(256))), + actual + ); + } + + // protocol length error + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3, 4], + &[0; 256], + &[5, 6, 7, 8], + &[0; 256], + ); + assert_eq!( + Err(ArpNewError::ProtoAddr(ArpProtoAddrError::LenTooBig(256))), + actual + ); + } + } + + #[test] + fn new_unchecked() { + // ok case + { + let actual = unsafe { + ArpPacket::new_unchecked( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3], + &[4, 5, 6, 7, 8], + &[9, 10, 11], + &[12, 13, 14, 15, 16], + ) + }; + assert_eq!(3, actual.hw_addr_size()); + assert_eq!(5, actual.protocol_addr_size()); + assert_eq!(ArpHardwareId::ASH, actual.hw_addr_type); + assert_eq!(EtherType::PROVIDER_BRIDGING, actual.proto_addr_type); + assert_eq!(ArpOperation::REQUEST, actual.operation); + assert_eq!(&[1, 2, 3], actual.sender_hw_addr()); + assert_eq!(&[4, 5, 6, 7, 8], actual.sender_protocol_addr()); + assert_eq!(&[9, 10, 11], actual.target_hw_addr()); + assert_eq!(&[12, 13, 14, 15, 16], actual.target_protocol_addr()); + } + + // ok case (upper hw size) + { + let actual = unsafe { + ArpPacket::new_unchecked( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[0; 255], + &[4, 5, 6, 7, 8], + &[0; 255], + &[12, 13, 14, 15, 16], + ) + }; + assert_eq!(255, actual.hw_addr_size()); + assert_eq!(5, actual.protocol_addr_size()); + assert_eq!(ArpHardwareId::ASH, actual.hw_addr_type); + assert_eq!(EtherType::PROVIDER_BRIDGING, actual.proto_addr_type); + assert_eq!(ArpOperation::REQUEST, actual.operation); + assert_eq!(&[0; 255], actual.sender_hw_addr()); + assert_eq!(&[4, 5, 6, 7, 8], actual.sender_protocol_addr()); + assert_eq!(&[0; 255], actual.target_hw_addr()); + assert_eq!(&[12, 13, 14, 15, 16], actual.target_protocol_addr()); + } + + // ok case (protocol hw size) + { + let actual = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3], + &[0; 255], + &[9, 10, 11], + &[0; 255], + ) + .unwrap(); + assert_eq!(3, actual.hw_addr_size()); + assert_eq!(255, actual.protocol_addr_size()); + assert_eq!(ArpHardwareId::ASH, actual.hw_addr_type); + assert_eq!(EtherType::PROVIDER_BRIDGING, actual.proto_addr_type); + assert_eq!(ArpOperation::REQUEST, actual.operation); + assert_eq!(&[1, 2, 3], actual.sender_hw_addr()); + assert_eq!(&[0; 255], actual.sender_protocol_addr()); + assert_eq!(&[9, 10, 11], actual.target_hw_addr()); + assert_eq!(&[0; 255], actual.target_protocol_addr()); + } + } + + proptest! { + #[test] + fn debug(arp in arp_packet_any()) { + use std::format; + assert_eq!( + format!("{:?}", arp), + format!( + "ArpPacket {{ hw_addr_type: {:?}, proto_addr_type: {:?}, hw_addr_size: {:?}, proto_addr_size: {:?}, operation: {:?}, sender_hw_addr: {:?}, sender_protocol_addr: {:?}, target_hw_addr: {:?}, target_protocol_addr: {:?} }}", + arp.hw_addr_type, + arp.proto_addr_type, + arp.hw_addr_size(), + arp.protocol_addr_size(), + arp.operation, + arp.sender_hw_addr(), + arp.sender_protocol_addr(), + arp.target_hw_addr(), + arp.target_protocol_addr() + ) + ); + } + } + + proptest! { + #[test] + fn clone_eq(arp in arp_packet_any()) { + assert_eq!(&arp.clone(), &arp); + } + } + + proptest! { + #[test] + fn hash(arp in arp_packet_any()) { + use core::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + let expected_hash = { + let mut s = DefaultHasher::new(); + + arp.hw_addr_type.hash(&mut s); + arp.proto_addr_type.hash(&mut s); + arp.hw_addr_size().hash(&mut s); + arp.protocol_addr_size().hash(&mut s); + arp.operation.hash(&mut s); + arp.sender_hw_addr().hash(&mut s); + arp.sender_protocol_addr().hash(&mut s); + arp.target_hw_addr().hash(&mut s); + arp.target_protocol_addr().hash(&mut s); + + s.finish() + }; + + let actual_hash = { + let mut s = DefaultHasher::new(); + arp.hash(&mut s); + s.finish() + }; + + assert_eq!(expected_hash, actual_hash); + } + } + + #[test] + fn arp_packet_works() { + let bytes = [ + 0, 1, // hardware type + 8, 0, // proto type + 6, 4, // sizes + 0, 1, // arp operation + 0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b, // src mac + 10, 10, 1, 135, // src ip + 0xde, 0xad, 0xc0, 0x00, 0xff, 0xee, // dest mac + 192, 168, 1, 253, // dest ip + ]; + + let expected = ArpPacket::new( + ArpHardwareId::ETHERNET, + EtherType::IPV4, + ArpOperation::REQUEST, + &[0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b], + &[10, 10, 1, 135], + &[0xde, 0xad, 0xc0, 0x00, 0xff, 0xee], + &[192, 168, 1, 253], + ) + .unwrap(); + + let actual = ArpPacket::from_slice(&bytes).unwrap(); + + assert_eq!(expected, actual); + } + + proptest! { + #[test] + fn read( + arp in arp_packet_any() + ) { + use std::vec::Vec; + use std::io::Cursor; + + // ok case + let mut buf = Vec::with_capacity(arp.packet_len()); + arp.write(&mut buf).unwrap(); + { + let mut cursor = Cursor::new(&buf); + let actual = ArpPacket::read(&mut cursor).unwrap(); + assert_eq!(arp, actual); + } + + // len io error + for len in 0..arp.packet_len() { + let mut cursor = Cursor::new(&buf[..len]); + let actual = ArpPacket::read(&mut cursor); + assert!(actual.is_err()); + } + } + } + + proptest! { + #[test] + fn write_error( + arp in arp_packet_any() + ) { + use std::vec::Vec; + use std::io::Cursor; + + let mut buf = Vec::with_capacity(arp.packet_len()); + buf.resize(arp.packet_len(), 0u8); + + // check that the write produces an error if not enough memory is present + for len in 0..arp.packet_len() { + let mut cursor = Cursor::new(&mut buf[..len]); + let actual = arp.write(&mut cursor); + assert!(actual.is_err()); + } + } + } + + #[test] + fn set_hw_addrs() { + let start = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3], + &[4, 5, 6, 7, 8], + &[9, 10, 11], + &[12, 13, 14, 15, 16], + ) + .unwrap(); + + // ok case + { + let mut arp = start.clone(); + arp.set_hw_addrs(&[17, 18], &[19, 20]).unwrap(); + assert_eq!(2, arp.hw_addr_size()); + assert_eq!(&[17, 18], arp.sender_hw_addr()); + assert_eq!(&[19, 20], arp.target_hw_addr()); + } + + // non matching error + { + let mut arp = start.clone(); + assert_eq!( + arp.set_hw_addrs(&[17, 18], &[19]), + Err(ArpHwAddrError::LenNonMatching(2, 1)) + ); + } + + // above 255 error + { + let mut arp = start.clone(); + assert_eq!( + arp.set_hw_addrs(&[0; 260], &[0; 260]), + Err(ArpHwAddrError::LenTooBig(260)) + ); + } + } + + #[test] + fn set_proto_addrs() { + let start = ArpPacket::new( + ArpHardwareId::ASH, + EtherType::PROVIDER_BRIDGING, + ArpOperation::REQUEST, + &[1, 2, 3], + &[4, 5, 6, 7, 8], + &[9, 10, 11], + &[12, 13, 14, 15, 16], + ) + .unwrap(); + + // ok case + { + let mut arp = start.clone(); + arp.set_protocol_addrs(&[17, 18], &[19, 20]).unwrap(); + assert_eq!(2, arp.protocol_addr_size()); + assert_eq!(&[17, 18], arp.sender_protocol_addr()); + assert_eq!(&[19, 20], arp.target_protocol_addr()); + } + + // non matching error + { + let mut arp = start.clone(); + assert_eq!( + arp.set_protocol_addrs(&[17, 18], &[19]), + Err(ArpProtoAddrError::LenNonMatching(2, 1)) + ); + } + + // above 255 error + { + let mut arp = start.clone(); + assert_eq!( + arp.set_protocol_addrs(&[0; 260], &[0; 260]), + Err(ArpProtoAddrError::LenTooBig(260)) + ); + } + } + + proptest! { + #[test] + fn try_eth_ipv4( + arp_eth_ipv4 in arp_eth_ipv4_packet_any() + ) { + use err::arp::ArpEthIpv4FromError::*; + + // ok case + { + let arp: ArpPacket = arp_eth_ipv4.clone().into(); + assert_eq!(arp.try_eth_ipv4(), Ok(arp_eth_ipv4.clone())); + } + + // hw type error + { + let mut arp: ArpPacket = arp_eth_ipv4.clone().into(); + arp.hw_addr_type = ArpHardwareId::AX25; + assert_eq!( + arp.try_eth_ipv4(), + Err(NonMatchingHwType(ArpHardwareId::AX25)) + ); + } + + // proto type error + { + let mut arp: ArpPacket = arp_eth_ipv4.clone().into(); + arp.proto_addr_type = EtherType::IPV6; + assert_eq!( + arp.try_eth_ipv4(), + Err(NonMatchingProtocolType(EtherType::IPV6)) + ); + } + + // hw address size error + { + let mut arp: ArpPacket = arp_eth_ipv4.clone().into(); + arp.set_hw_addrs(&[1], &[2]).unwrap(); + assert_eq!( + arp.try_eth_ipv4(), + Err(NonMatchingHwAddrSize(1)) + ); + } + + // protocol address size error + { + let mut arp: ArpPacket = arp_eth_ipv4.clone().into(); + arp.set_protocol_addrs(&[1], &[2]).unwrap(); + assert_eq!( + arp.try_eth_ipv4(), + Err(NonMatchingProtoAddrSize(1)) + ); + } + } + } +} diff --git a/etherparse/src/net/arp_packet_slice.rs b/etherparse/src/net/arp_packet_slice.rs new file mode 100644 index 00000000..87f51bf8 --- /dev/null +++ b/etherparse/src/net/arp_packet_slice.rs @@ -0,0 +1,231 @@ +use super::{ArpHardwareId, ArpOperation}; +use crate::{ + err::{Layer, LenError}, + ArpPacket, EtherType, LenSource, +}; + +/// Slice containing an "Address Resolution Protocol" Packet. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ArpPacketSlice<'a> { + slice: &'a [u8], +} + +impl<'a> ArpPacketSlice<'a> { + /// Creates an `ArpPacketSlice` from a slice and verfies that the + /// given slice has enough data to contain an complete ARP packet. + pub fn from_slice(slice: &'a [u8]) -> Result, LenError> { + if slice.len() < 8 { + return Err(LenError { + required_len: 8, + len: slice.len(), + len_source: LenSource::Slice, + layer: Layer::Arp, + layer_start_offset: 0, + }); + } + + // validate the rest length based on the hardware & protocol lengths + let hw_addr_size = unsafe { *slice.as_ptr().add(4) }; + let protocol_addr_size = unsafe { *slice.as_ptr().add(5) }; + let min_len = 8 + (hw_addr_size as usize) * 2 + (protocol_addr_size as usize) * 2; + + if slice.len() < min_len { + return Err(LenError { + required_len: min_len, + len: slice.len(), + len_source: LenSource::ArpAddrLengths, + layer: Layer::Arp, + layer_start_offset: 0, + }); + } + + Ok(Self { + slice: unsafe { + // SAFETY: Safe as slice was verified above to have a + // length of at least min_len. + core::slice::from_raw_parts(slice.as_ptr(), min_len) + }, + }) + } + + /// Slice containing the ARP packet. + #[inline] + pub fn slice(&self) -> &'a [u8] { + self.slice + } + + /// Network link protocol type (e.g. `ArpHardwareId::ETHERNET`). + #[inline] + pub const fn hw_addr_type(&self) -> ArpHardwareId { + ArpHardwareId(u16::from_be_bytes( + // SAFE: As the constructor verified the length + // of the slice to be at least 8. + unsafe { [*self.slice.as_ptr(), *self.slice.as_ptr().add(1)] }, + )) + } + + /// Protocol for which the ARP request is intended (e.g. `EtherType::IPV4`). + #[inline] + pub const fn proto_addr_type(&self) -> EtherType { + EtherType(u16::from_be_bytes( + // SAFE: As the constructor verified the length + // of the slice to be at least 8. + unsafe { [*self.slice.as_ptr().add(2), *self.slice.as_ptr().add(3)] }, + )) + } + + /// Length (in octets) of a hardware address (e.g. 6 for Ethernet). + #[inline] + pub const fn hw_addr_size(&self) -> u8 { + // SAFE: As the constructor verified the length + // of the slice to be at least 8. + unsafe { *self.slice.as_ptr().add(4) } + } + + /// Length (in octets) of internetwork addresses (e.g. 4 for IPv4 or 16 for IPv6). + #[inline] + pub const fn proto_addr_size(&self) -> u8 { + // SAFE: As the constructor verified the length + // of the slice to be at least 8. + unsafe { *self.slice.as_ptr().add(5) } + } + + /// Specifies the operation that the sender is performing + #[inline] + pub const fn operation(&self) -> ArpOperation { + ArpOperation(u16::from_be_bytes( + // SAFE: As the constructor verified the length + // of the slice to be at least 8. + unsafe { [*self.slice.as_ptr().add(6), *self.slice.as_ptr().add(7)] }, + )) + } + + /// Sender hardware address (e.g. MAC address). + #[inline] + pub const fn sender_hw_addr(&self) -> &[u8] { + // SAFETY: Safe as the constructor verfies the + // the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2 + unsafe { + core::slice::from_raw_parts(self.slice.as_ptr().add(8), self.hw_addr_size() as usize) + } + } + + /// Sender protocol address (e.g. IPv4 address). + #[inline] + pub const fn sender_protocol_addr(&self) -> &[u8] { + // SAFETY: Safe as the constructor verfies the + // the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2 + unsafe { + core::slice::from_raw_parts( + self.slice.as_ptr().add(8 + (self.hw_addr_size() as usize)), + self.proto_addr_size() as usize, + ) + } + } + + /// Target hardware address (e.g. MAC address). + #[inline] + pub const fn target_hw_addr(&self) -> &[u8] { + // SAFETY: Safe as the constructor verfies the + // the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2 + unsafe { + core::slice::from_raw_parts( + self.slice + .as_ptr() + .add(8 + (self.hw_addr_size() as usize) + (self.proto_addr_size() as usize)), + self.hw_addr_size() as usize, + ) + } + } + + /// Buffer containing the target protocol address (e.g. IPv4 address).. + #[inline] + pub const fn target_protocol_addr(&self) -> &[u8] { + // SAFETY: Safe as the constructor verfies the + // the slice to be at least 8 + hw_addr_size*2 + protocol_addr_size*2 + unsafe { + core::slice::from_raw_parts( + self.slice.as_ptr().add( + 8 + (self.hw_addr_size() as usize) * 2 + (self.proto_addr_size() as usize), + ), + self.proto_addr_size() as usize, + ) + } + } + + /// Decode fields and return results in an [`ArpPacket`]. + #[inline] + pub fn to_packet(&self) -> ArpPacket { + // SAFETY: Safe as all preconditions of new unchecked + // are fullfilled by the fact that the on the wire packets already + // fullfill them. + unsafe { + ArpPacket::new_unchecked( + self.hw_addr_type(), + self.proto_addr_type(), + self.operation(), + self.sender_hw_addr(), + self.sender_protocol_addr(), + self.target_hw_addr(), + self.target_protocol_addr(), + ) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_gens::*; + use proptest::prelude::*; + + proptest! { + #[test] + fn from_slice_with_payload( + packet in arp_packet_any() + ) { + // build slice data + let data = packet.to_bytes(); + + // happy path + { + let actual = ArpPacketSlice::from_slice(&data).unwrap(); + + assert_eq!(actual.hw_addr_type(), packet.hw_addr_type); + assert_eq!(actual.proto_addr_type(), packet.proto_addr_type); + assert_eq!(actual.hw_addr_size(), packet.hw_addr_size()); + assert_eq!(actual.proto_addr_size(), packet.protocol_addr_size()); + assert_eq!(actual.operation(), packet.operation); + + assert_eq!(actual.sender_hw_addr(), packet.sender_hw_addr()); + assert_eq!(actual.sender_protocol_addr(), packet.sender_protocol_addr()); + assert_eq!(actual.target_hw_addr(), packet.target_hw_addr()); + assert_eq!(actual.target_protocol_addr(), packet.target_protocol_addr()); + + assert_eq!(&actual.to_packet(), &packet); + } + + // length error + for len in 0..(8 + (packet.hw_addr_size() as usize)*2 + (packet.protocol_addr_size() as usize)*2) { + let err = ArpPacketSlice::from_slice(&data[..len]).unwrap_err(); + if len < 8 { + assert_eq!(err, LenError{ + required_len: 8, + len, + len_source: LenSource::Slice, + layer: Layer::Arp, + layer_start_offset: 0, + }); + } else { + assert_eq!(err, LenError{ + required_len: 8 + (packet.hw_addr_size() as usize)*2 + (packet.protocol_addr_size() as usize)*2, + len, + len_source: LenSource::ArpAddrLengths, + layer: Layer::Arp, + layer_start_offset: 0, + }); + } + } + } + } +} diff --git a/etherparse/src/net/ip_headers.rs b/etherparse/src/net/ip_headers.rs index 7b901bc0..e8df69a7 100644 --- a/etherparse/src/net/ip_headers.rs +++ b/etherparse/src/net/ip_headers.rs @@ -1096,16 +1096,16 @@ impl IpHeaders { /// /// The given number will be set as the last "next_header" or /// protocol number. - pub fn set_next_headers(&mut self, last_next_header: IpNumber) -> u16 { + pub fn set_next_headers(&mut self, last_next_header: IpNumber) -> EtherType { use IpHeaders::*; match self { Ipv4(ref mut header, ref mut extensions) => { header.protocol = extensions.set_next_headers(last_next_header); - EtherType::IPV4.0 + EtherType::IPV4 } Ipv6(ref mut header, ref mut extensions) => { header.next_header = extensions.set_next_headers(last_next_header); - EtherType::IPV4.0 + EtherType::IPV4 } } } diff --git a/etherparse/src/net/ipv6_ext_slice_iter.rs b/etherparse/src/net/ipv6_ext_slice_iter.rs index cbf720d3..8ac0de1b 100644 --- a/etherparse/src/net/ipv6_ext_slice_iter.rs +++ b/etherparse/src/net/ipv6_ext_slice_iter.rs @@ -8,7 +8,7 @@ pub struct Ipv6ExtensionSliceIter<'a> { pub(crate) rest: &'a [u8], } -impl<'a> Default for Ipv6ExtensionSliceIter<'a> { +impl Default for Ipv6ExtensionSliceIter<'_> { fn default() -> Self { Ipv6ExtensionSliceIter { // don't use 0 as this is the reserved value diff --git a/etherparse/src/net/lax_ip_slice.rs b/etherparse/src/net/lax_ip_slice.rs index 97477dc8..491bf602 100644 --- a/etherparse/src/net/lax_ip_slice.rs +++ b/etherparse/src/net/lax_ip_slice.rs @@ -99,7 +99,7 @@ impl<'a> LaxIpSlice<'a> { /// as far as possible without encountering an error and with less strict length checks. /// This function is usefull for cut off packet or for packets with unset length fields. /// - /// If you want to only receive correct IpPayloads use [`IpSlice::from_ip_slice`] + /// If you want to only receive correct IpPayloads use [`IpSlice::from_slice`] /// instead. /// /// The main usecases for this functions are: diff --git a/etherparse/src/net/lax_ipv4_slice.rs b/etherparse/src/net/lax_ipv4_slice.rs index 2c73f58c..d9359c75 100644 --- a/etherparse/src/net/lax_ipv4_slice.rs +++ b/etherparse/src/net/lax_ipv4_slice.rs @@ -68,7 +68,6 @@ impl<'a> LaxIpv4Slice<'a> { /// if the `len_source` value in the returned [`LaxIpPayloadSlice`] is set to /// [`LenSource::Slice`]. If a substitution was not needed `len_source` /// is set to [`LenSource::Ipv4HeaderTotalLen`]. - pub fn from_slice( slice: &[u8], ) -> Result<(LaxIpv4Slice, Option), err::ipv4::HeaderSliceError> diff --git a/etherparse/src/net/lax_net_slice.rs b/etherparse/src/net/lax_net_slice.rs index 69523f22..9ee2917f 100644 --- a/etherparse/src/net/lax_net_slice.rs +++ b/etherparse/src/net/lax_net_slice.rs @@ -16,10 +16,12 @@ use crate::*; /// operating system set the length fields). #[derive(Clone, Debug, Eq, PartialEq)] pub enum LaxNetSlice<'a> { - /// The ipv4 header & the decoded extension headers. + /// IPv4 header & the decoded extension headers. Ipv4(LaxIpv4Slice<'a>), - /// The ipv6 header & the decoded extension headers. + /// IPv6 header & the decoded extension headers. Ipv6(LaxIpv6Slice<'a>), + /// "Address Resolution Protocol" Packet, + Arp(ArpPacketSlice<'a>), } impl<'a> LaxNetSlice<'a> { @@ -30,6 +32,7 @@ impl<'a> LaxNetSlice<'a> { match self { LaxNetSlice::Ipv4(s) => Some(&s.payload), LaxNetSlice::Ipv6(s) => Some(&s.payload), + LaxNetSlice::Arp(_) => None, } } } diff --git a/etherparse/src/net/mod.rs b/etherparse/src/net/mod.rs index cee996fc..676f9655 100644 --- a/etherparse/src/net/mod.rs +++ b/etherparse/src/net/mod.rs @@ -1,3 +1,15 @@ +mod arp_eth_ipv4_packet; +pub use arp_eth_ipv4_packet::*; + +mod arp_hardware_id; +pub use arp_hardware_id::*; + +mod arp_packet; +pub use arp_packet::*; + +mod arp_operation; +pub use arp_operation::*; + mod ip_auth_header; pub use ip_auth_header::*; @@ -102,3 +114,6 @@ pub use net_headers::*; mod net_slice; pub use net_slice::*; + +mod arp_packet_slice; +pub use arp_packet_slice::*; diff --git a/etherparse/src/net/net_headers.rs b/etherparse/src/net/net_headers.rs index f2af1f44..3389fd78 100644 --- a/etherparse/src/net/net_headers.rs +++ b/etherparse/src/net/net_headers.rs @@ -12,9 +12,17 @@ pub enum NetHeaders { Ipv4(Ipv4Header, Ipv4Extensions), /// IPv6 header & extension headers. Ipv6(Ipv6Header, Ipv6Extensions), + /// Address Resolution Protocol packet. + Arp(ArpPacket), } impl NetHeaders { + /// Returns true if the NetHeaders contains either IPv4 or IPv6. + pub fn is_ip(&self) -> bool { + use NetHeaders::*; + matches!(self, Ipv4(_, _) | Ipv6(_, _)) + } + /// Returns references to the IPv4 header & extensions if the header contains IPv4 values. pub fn ipv4_ref(&self) -> Option<(&Ipv4Header, &Ipv4Extensions)> { if let NetHeaders::Ipv4(header, exts) = self { @@ -33,12 +41,37 @@ impl NetHeaders { } } + /// Sets all the next_header fields in the ipv4 & ipv6 header + /// as well as in all extension headers and returns the ether + /// type number. + /// + /// The given number will be set as the last "next_header" or + /// protocol number. + pub fn try_set_next_headers( + &mut self, + last_next_header: IpNumber, + ) -> Result { + use NetHeaders::*; + match self { + Ipv4(ref mut header, ref mut extensions) => { + header.protocol = extensions.set_next_headers(last_next_header); + Ok(EtherType::IPV4) + } + Ipv6(ref mut header, ref mut extensions) => { + header.next_header = extensions.set_next_headers(last_next_header); + Ok(EtherType::IPV4) + } + Arp(_) => Err(err::net::NetSetNextHeaderError::ArpHeader), + } + } + /// Returns the size when the header & extension headers are serialized pub fn header_len(&self) -> usize { use crate::NetHeaders::*; match *self { Ipv4(ref header, ref extensions) => header.header_len() + extensions.header_len(), Ipv6(_, ref extensions) => Ipv6Header::LEN + extensions.header_len(), + Arp(ref arp) => arp.packet_len(), } } } @@ -53,6 +86,13 @@ impl From for NetHeaders { } } +impl From for NetHeaders { + #[inline] + fn from(value: ArpPacket) -> Self { + NetHeaders::Arp(value) + } +} + #[cfg(test)] mod tests { use crate::*; diff --git a/etherparse/src/net/net_slice.rs b/etherparse/src/net/net_slice.rs index 3ab85421..c0a1c1be 100644 --- a/etherparse/src/net/net_slice.rs +++ b/etherparse/src/net/net_slice.rs @@ -15,9 +15,18 @@ pub enum NetSlice<'a> { Ipv4(Ipv4Slice<'a>), /// The ipv6 header & the decoded extension headers. Ipv6(Ipv6Slice<'a>), + /// The arp header & the decoded extension headers. + Arp(ArpPacketSlice<'a>), } impl<'a> NetSlice<'a> { + /// Returns true if the NetSlice contains either IPv4 or IPv6. + #[inline] + pub fn is_ip(&self) -> bool { + use NetSlice::*; + matches!(self, Ipv4(_) | Ipv6(_)) + } + /// Returns a reference to ip payload if the net slice contains /// an ipv4 or ipv6 slice. #[inline] @@ -25,6 +34,7 @@ impl<'a> NetSlice<'a> { match self { NetSlice::Ipv4(s) => Some(&s.payload), NetSlice::Ipv6(s) => Some(&s.payload), + NetSlice::Arp(_) => None, } } } diff --git a/etherparse/src/packet_builder.rs b/etherparse/src/packet_builder.rs index ee92031d..50db0f60 100644 --- a/etherparse/src/packet_builder.rs +++ b/etherparse/src/packet_builder.rs @@ -49,6 +49,7 @@ use std::{io, marker}; /// * [`PacketBuilder::ipv4`] /// * [`PacketBuilder::ipv6`] /// * Options after an Ethernet2 header was added: +/// * [`PacketBuilderStep::arp`] /// * [`PacketBuilderStep::vlan`] /// * [`PacketBuilderStep::single_vlan`] /// * [`PacketBuilderStep::double_vlan`] @@ -140,7 +141,7 @@ impl PacketBuilder { ether_type: EtherType(0), //the type identifier })), vlan_header: None, - ip_header: None, + net_header: None, transport_header: None, }, _marker: marker::PhantomData:: {}, @@ -185,13 +186,13 @@ impl PacketBuilder { state: PacketImpl { link_header: Some(LinkHeader::LinuxSll(LinuxSllHeader { packet_type, - arp_hrd_type: ArpHardwareId::ETHER, + arp_hrd_type: ArpHardwareId::ETHERNET, sender_address_valid_length, sender_address, protocol_type: LinuxSllProtocolType::EtherType(EtherType(0)), // Will be overwitten when writing depending on the net layer })), vlan_header: None, - ip_header: None, + net_header: None, transport_header: None, }, _marker: marker::PhantomData:: {}, @@ -233,7 +234,7 @@ impl PacketBuilder { state: PacketImpl { link_header: None, vlan_header: None, - ip_header: None, + net_header: None, transport_header: None, }, _marker: marker::PhantomData:: {}, @@ -280,7 +281,7 @@ impl PacketBuilder { state: PacketImpl { link_header: None, vlan_header: None, - ip_header: None, + net_header: None, transport_header: None, }, _marker: marker::PhantomData:: {}, @@ -357,7 +358,7 @@ impl PacketBuilder { state: PacketImpl { link_header: None, vlan_header: None, - ip_header: None, + net_header: None, transport_header: None, }, _marker: marker::PhantomData:: {}, @@ -368,7 +369,7 @@ impl PacketBuilder { struct PacketImpl { link_header: Option, - ip_header: Option, + net_header: Option, vlan_header: Option, transport_header: Option, } @@ -417,7 +418,7 @@ impl PacketBuilderStep { time_to_live: u8, ) -> PacketBuilderStep { //add ip header - self.state.ip_header = Some(IpHeaders::Ipv4( + self.state.net_header = Some(NetHeaders::Ipv4( Ipv4Header { source, destination, @@ -479,7 +480,10 @@ impl PacketBuilderStep { /// ``` pub fn ip(mut self, ip_header: IpHeaders) -> PacketBuilderStep { //add ip header - self.state.ip_header = Some(ip_header); + self.state.net_header = Some(match ip_header { + IpHeaders::Ipv4(header, exts) => NetHeaders::Ipv4(header, exts), + IpHeaders::Ipv6(header, exts) => NetHeaders::Ipv6(header, exts), + }); //return for next step PacketBuilderStep { state: self.state, @@ -525,7 +529,7 @@ impl PacketBuilderStep { destination: [u8; 16], hop_limit: u8, ) -> PacketBuilderStep { - self.state.ip_header = Some(IpHeaders::Ipv6( + self.state.net_header = Some(NetHeaders::Ipv6( Ipv6Header { traffic_class: 0, flow_label: Ipv6FlowLabel::ZERO, @@ -687,6 +691,43 @@ impl PacketBuilderStep { _marker: marker::PhantomData:: {}, } } + + /// Adds an ARP packet. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use etherparse::*; + /// + /// let builder = PacketBuilder:: + /// ethernet2([1,2,3,4,5,6], // source mac + /// [7,8,9,10,11,12]) // destination mac + /// .arp(ArpPacket::new( + /// ArpHardwareId::ETHERNET, + /// EtherType::IPV4, + /// ArpOperation::REQUEST, + /// &[1,2,3,4,5,6], // sender_hw_addr + /// &[7,6,8,9], // sender_protocol_addr + /// &[10,11,12,14,15,16], // target_hw_addr + /// &[17,18,19,20] // target_protocol_addr + /// ).unwrap()); + /// + /// // get some memory to store the result + /// let mut result = Vec::::with_capacity(builder.size()); + /// + /// // serialize + /// builder.write(&mut result).unwrap(); + /// ``` + pub fn arp(mut self, arp_packet: ArpPacket) -> PacketBuilderStep { + self.state.net_header = Some(NetHeaders::Arp(arp_packet)); + //return for next step + PacketBuilderStep { + state: self.state, + _marker: marker::PhantomData:: {}, + } + } } #[cfg_attr(docsrs, doc(cfg(feature = "std")))] @@ -833,6 +874,44 @@ impl PacketBuilderStep { } .ipv4(source, destination, time_to_live) } + + /// Adds an ARP packet. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use etherparse::*; + /// + /// let builder = PacketBuilder:: + /// linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// 6, //sender address valid length + /// [1,2,3,4,5,6,0,0]) //sender address with padding + /// .arp(ArpPacket::new( + /// ArpHardwareId::ETHERNET, + /// EtherType::IPV4, + /// ArpOperation::REQUEST, + /// &[1,2,3,4,5,6], // sender_hw_addr + /// &[7,6,8,9], // sender_protocol_addr + /// &[10,11,12,14,15,16], // target_hw_addr + /// &[17,18,19,20] // target_protocol_addr + /// ).unwrap()); + /// + /// // get some memory to store the result + /// let mut result = Vec::::with_capacity(builder.size()); + /// + /// // serialize + /// builder.write(&mut result).unwrap(); + /// ``` + pub fn arp(mut self, arp_packet: ArpPacket) -> PacketBuilderStep { + self.state.net_header = Some(NetHeaders::Arp(arp_packet)); + // return for next step + PacketBuilderStep { + state: self.state, + _marker: marker::PhantomData:: {}, + } + } } #[cfg_attr(docsrs, doc(cfg(feature = "std")))] @@ -979,6 +1058,44 @@ impl PacketBuilderStep { } .ipv4(source, destination, time_to_live) } + + /// Adds an ARP packet. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use etherparse::*; + /// + /// let builder = PacketBuilder:: + /// ethernet2([1,2,3,4,5,6], // source mac + /// [7,8,9,10,11,12]) // destination mac + /// .single_vlan(0x123.try_into().unwrap()) // vlan identifier + /// .arp(ArpPacket::new( + /// ArpHardwareId::ETHERNET, + /// EtherType::IPV4, + /// ArpOperation::REQUEST, + /// &[1,2,3,4,5,6], // sender_hw_addr + /// &[7,6,8,9], // sender_protocol_addr + /// &[10,11,12,14,15,16], // target_hw_addr + /// &[17,18,19,20] // target_protocol_addr + /// ).unwrap()); + /// + /// // get some memory to store the result + /// let mut result = Vec::::with_capacity(builder.size()); + /// + /// // serialize + /// builder.write(&mut result).unwrap(); + /// ``` + pub fn arp(mut self, arp_packet: ArpPacket) -> PacketBuilderStep { + self.state.net_header = Some(NetHeaders::Arp(arp_packet)); + //return for next step + PacketBuilderStep { + state: self.state, + _marker: marker::PhantomData:: {}, + } + } } #[cfg_attr(docsrs, doc(cfg(feature = "std")))] @@ -1525,12 +1642,16 @@ impl PacketBuilderStep { last_next_header_ip_number: IpNumber, payload: &[u8], ) -> Result<(), BuildWriteError> { - self.state - .ip_header - .as_mut() - .unwrap() - .set_next_headers(last_next_header_ip_number); - final_write(self, writer, payload) + match &mut (self.state.net_header) { + Some(NetHeaders::Ipv4(ref mut ip, ref mut exts)) => { + ip.protocol = exts.set_next_headers(last_next_header_ip_number); + } + Some(NetHeaders::Ipv6(ref mut ip, ref mut exts)) => { + ip.next_header = exts.set_next_headers(last_next_header_ip_number); + } + _ => {} + } + final_write_with_net(self, writer, payload) } ///Returns the size of the packet when it is serialized @@ -1547,7 +1668,7 @@ impl PacketBuilderStep { writer: &mut T, payload: &[u8], ) -> Result<(), BuildWriteError> { - final_write(self, writer, payload) + final_write_with_net(self, writer, payload) } /// Returns the size of the packet when it is serialized @@ -1564,7 +1685,7 @@ impl PacketBuilderStep { writer: &mut T, payload: &[u8], ) -> Result<(), BuildWriteError> { - final_write(self, writer, payload) + final_write_with_net(self, writer, payload) } ///Returns the size of the packet when it is serialized @@ -1581,7 +1702,7 @@ impl PacketBuilderStep { writer: &mut T, payload: &[u8], ) -> Result<(), BuildWriteError> { - final_write(self, writer, payload) + final_write_with_net(self, writer, payload) } ///Returns the size of the packet when it is serialized @@ -1742,7 +1863,7 @@ impl PacketBuilderStep { writer: &mut T, payload: &[u8], ) -> Result<(), BuildWriteError> { - final_write(self, writer, payload) + final_write_with_net(self, writer, payload) } ///Returns the size of the packet when it is serialized @@ -1751,35 +1872,53 @@ impl PacketBuilderStep { } } +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl PacketBuilderStep { + pub fn write(self, writer: &mut T) -> Result<(), BuildWriteError> { + final_write_with_net(self, writer, &[])?; + Ok(()) + } + + pub fn size(&self) -> usize { + final_size(self, 0) + } +} + /// Write all the headers and the payload. -fn final_write( +fn final_write_with_net( builder: PacketBuilderStep, writer: &mut T, payload: &[u8], ) -> Result<(), BuildWriteError> { use BuildWriteError::*; - - let ip_ether_type = { - use crate::IpHeaders::*; - match builder.state.ip_header { - Some(Ipv4(_, _)) => ether_type::IPV4, - Some(Ipv6(_, _)) => ether_type::IPV6, - None => panic!("Missing ip header"), - } + use NetHeaders::*; + + // unpack builder (makes things easier with the borrow checker) + let link = builder.state.link_header; + let vlan = builder.state.vlan_header; + let net = builder.state.net_header; + let mut transport = builder.state.transport_header; + + // determine + let net_ether_type = match &net { + Some(Ipv4(_, _)) => ether_type::IPV4, + Some(Ipv6(_, _)) => ether_type::IPV6, + Some(Arp(_)) => ether_type::ARP, + None => unreachable!(), }; - //link header - if let Some(link) = builder.state.link_header { + // link header + if let Some(link) = link { match link { LinkHeader::Ethernet2(mut eth) => { eth.ether_type = { use crate::VlanHeader::*; //determine the ether type depending on if there is a vlan tagging header - match builder.state.vlan_header { + match &vlan { Some(Single(_)) => ether_type::VLAN_TAGGED_FRAME, Some(Double(_)) => ether_type::PROVIDER_BRIDGING, //if no vlan header exists, the id is purely defined by the ip type - None => ip_ether_type, + None => net_ether_type, } }; eth.write(writer).map_err(Io)?; @@ -1787,168 +1926,140 @@ fn final_write( LinkHeader::LinuxSll(mut linux_sll) => { // Assumes that next layers are ether based. If more types of // layers are supported, this should be updated - debug_assert_eq!(linux_sll.arp_hrd_type, ArpHardwareId::ETHER); + debug_assert_eq!(linux_sll.arp_hrd_type, ArpHardwareId::ETHERNET); - linux_sll.protocol_type.change_value(ip_ether_type.into()); + linux_sll.protocol_type.change_value(net_ether_type.into()); linux_sll.write(writer).map_err(Io)?; } } } - //write the vlan header if it exists + // write the vlan header if it exists use crate::VlanHeader::*; - match builder.state.vlan_header { + match vlan { Some(Single(mut value)) => { //set ether types - value.ether_type = ip_ether_type; + value.ether_type = net_ether_type; //serialize value.write(writer).map_err(Io)?; } Some(Double(mut value)) => { //set ether types value.outer.ether_type = ether_type::VLAN_TAGGED_FRAME; - value.inner.ether_type = ip_ether_type; + value.inner.ether_type = net_ether_type; //serialize value.write(writer).map_err(Io)?; } None => {} } - //ip header - use crate::IpHeaders::*; - let ip_header = builder.state.ip_header.unwrap(); - - //transport header - let transport = builder.state.transport_header; - match transport { - None => { - // in case no transport header is present the protocol - // number and next_header fields are set in the write call - // directly and don't need to be set here again. - match ip_header { - Ipv4(mut ip, ext) => { - ip.set_payload_len(ext.header_len() + payload.len()) - .map_err(PayloadLen)?; - ip.write(writer).map_err(Io)?; - ext.write(writer, ip.protocol).map_err(|err| { - use err::ipv4_exts::HeaderWriteError as I; - match err { - I::Io(err) => Io(err), - I::Content(err) => Ipv4Exts(err), - } - })?; - } - Ipv6(mut ip, ext) => { - ip.set_payload_length(ext.header_len() + payload.len()) - .map_err(PayloadLen)?; - ip.write(writer).map_err(Io)?; - ext.write(writer, ip.next_header).map_err(|err| { - use err::ipv6_exts::HeaderWriteError as I; - match err { - I::Io(err) => Io(err), - I::Content(err) => Ipv6Exts(err), - } - })?; - } - } + // set transport header length (needs to be done here + // so following steps can correctly calculate the checksum) + use TransportHeader::*; + match &mut transport { + Some(Udp(ref mut udp)) => { + udp.length = (UdpHeader::LEN + payload.len()) as u16; } - Some(mut transport) => { - match ip_header { - Ipv4(mut ip, mut ext) => { - //set total length & udp payload length (ip checks that the payload length is ok) - let transport_size = transport.header_len() + payload.len(); - ip.set_payload_len(ext.header_len() + transport_size) - .map_err(PayloadLen)?; - use crate::TransportHeader::*; - match transport { - Icmpv4(_) => {} - Icmpv6(_) => {} - Udp(ref mut udp) => { - udp.length = transport_size as u16; - } - Tcp(_) => {} - } + Some(Tcp(_)) => {} + Some(Icmpv4(_)) => {} + Some(Icmpv6(_)) => {} + None => {} + } - //ip protocol number & next header values of the extension header - ip.protocol = ext.set_next_headers(match transport { - Icmpv4(_) => ip_number::ICMP, - Icmpv6(_) => ip_number::IPV6_ICMP, - Udp(_) => ip_number::UDP, - Tcp(_) => ip_number::TCP, - }); + // net header + match net { + Some(NetHeaders::Ipv4(mut ip, mut ip_exts)) => { + // set payload length & ip number + ip.set_payload_len( + ip_exts.header_len() + + transport.as_ref().map(|v| v.header_len()).unwrap_or(0) + + payload.len(), + ) + .map_err(PayloadLen)?; + + if let Some(transport) = &transport { + ip.protocol = ip_exts.set_next_headers(match &transport { + Icmpv4(_) => ip_number::ICMP, + Icmpv6(_) => ip_number::IPV6_ICMP, + Udp(_) => ip_number::UDP, + Tcp(_) => ip_number::TCP, + }); + } - //calculate the udp checksum - transport - .update_checksum_ipv4(&ip, payload) - .map_err(|err| { - use err::packet::TransportChecksumError as I; - match err { - I::PayloadLen(err) => PayloadLen(err), - I::Icmpv6InIpv4 => Icmpv6InIpv4, - } - })?; - - //write (will automatically calculate the checksum) - ip.write(writer).map_err(Io)?; - ext.write(writer, ip.protocol).map_err(|err| { - use err::ipv4_exts::HeaderWriteError as I; - match err { - I::Io(err) => Io(err), - I::Content(err) => Ipv4Exts(err), - } - })?; + // write ip header & extensions + ip.write(writer).map_err(Io)?; + ip_exts.write(writer, ip.protocol).map_err(|err| { + use err::ipv4_exts::HeaderWriteError as I; + match err { + I::Io(err) => Io(err), + I::Content(err) => Ipv4Exts(err), } - Ipv6(mut ip, mut ext) => { - //set total length - let transport_size = transport.header_len() + payload.len(); - ip.set_payload_length(ext.header_len() + transport_size) - .map_err(PayloadLen)?; - use crate::TransportHeader::*; - match transport { - Icmpv4(_) => {} - Icmpv6(_) => {} - Udp(ref mut udp) => { - udp.length = transport_size as u16; - } - Tcp(_) => {} + })?; + + // update the transport layer checksum + if let Some(t) = &mut transport { + t.update_checksum_ipv4(&ip, payload).map_err(|err| { + use err::packet::TransportChecksumError as I; + match err { + I::PayloadLen(err) => PayloadLen(err), + I::Icmpv6InIpv4 => Icmpv6InIpv4, } + })?; + } + } + Some(NetHeaders::Ipv6(mut ip, mut ip_exts)) => { + // set payload length & ip number + ip.set_payload_length( + ip_exts.header_len() + + transport.as_ref().map(|v| v.header_len()).unwrap_or(0) + + payload.len(), + ) + .map_err(PayloadLen)?; + + if let Some(transport) = &transport { + ip.next_header = ip_exts.set_next_headers(match &transport { + Icmpv4(_) => ip_number::ICMP, + Icmpv6(_) => ip_number::IPV6_ICMP, + Udp(_) => ip_number::UDP, + Tcp(_) => ip_number::TCP, + }); + } - //set the protocol - ip.next_header = ext.set_next_headers(match transport { - Icmpv4(_) => ip_number::ICMP, - Icmpv6(_) => ip_number::IPV6_ICMP, - Udp(_) => ip_number::UDP, - Tcp(_) => ip_number::TCP, - }); - - //calculate the udp checksum - transport - .update_checksum_ipv6(&ip, payload) - .map_err(PayloadLen)?; - - //write (will automatically calculate the checksum) - ip.write(writer).map_err(Io)?; - ext.write(writer, ip.next_header).map_err(|err| { - use err::ipv6_exts::HeaderWriteError as I; - match err { - I::Io(err) => Io(err), - I::Content(err) => Ipv6Exts(err), - } - })?; + // write ip header & extensions + ip.write(writer).map_err(Io)?; + ip_exts.write(writer, ip.next_header).map_err(|err| { + use err::ipv6_exts::HeaderWriteError as I; + match err { + I::Io(err) => Io(err), + I::Content(err) => Ipv6Exts(err), } - } + })?; - //finally write the udp header & payload - transport.write(writer).map_err(Io)?; + // update the transport layer checksum + if let Some(t) = &mut transport { + t.update_checksum_ipv6(&ip, payload).map_err(PayloadLen)?; + } } + Some(NetHeaders::Arp(arp)) => { + writer.write_all(&arp.to_bytes()).map_err(Io)?; + } + None => {} + } + + // write transport header + if let Some(transport) = transport { + transport.write(writer).map_err(Io)?; } + + // and finally the payload writer.write_all(payload).map_err(Io)?; + Ok(()) } ///Returns the size of the packet when it is serialized fn final_size(builder: &PacketBuilderStep, payload_size: usize) -> usize { - use crate::IpHeaders::*; + use crate::NetHeaders::*; use crate::TransportHeader::*; use crate::VlanHeader::*; (match builder.state.link_header { @@ -1958,9 +2069,10 @@ fn final_size(builder: &PacketBuilderStep, payload_size: usize) -> usize { Some(Single(_)) => SingleVlanHeader::LEN, Some(Double(_)) => DoubleVlanHeader::LEN, None => 0, - } + match builder.state.ip_header { + } + match builder.state.net_header { Some(Ipv4(ref value, ref ext)) => value.header_len() + ext.header_len(), Some(Ipv6(_, ref ext)) => Ipv6Header::LEN + ext.header_len(), + Some(Arp(ref packet)) => packet.packet_len(), None => 0, } + match builder.state.transport_header { Some(Icmpv4(ref value)) => value.header_len(), @@ -1984,9 +2096,9 @@ mod white_box_tests { PacketBuilderStep:: { state: PacketImpl { link_header: None, - ip_header: None, + net_header: None, vlan_header: None, - transport_header: None + transport_header: None, }, _marker: marker::PhantomData:: {} } @@ -1998,11 +2110,11 @@ mod white_box_tests { #[should_panic] fn final_write_panic_missing_ip() { let mut writer = Vec::new(); - final_write( + final_write_with_net( PacketBuilderStep:: { state: PacketImpl { link_header: None, - ip_header: None, + net_header: None, vlan_header: None, transport_header: None, }, @@ -2023,6 +2135,108 @@ mod test { use proptest::prelude::*; use std::io::Read; + #[test] + fn eth_arp() { + let expected_header = ArpPacket::new( + ArpHardwareId::ETHERNET, + EtherType::IPV4, + ArpOperation::REQUEST, + &[20, 30, 40, 50, 60, 70], + &[10, 1, 1, 5], + &[00, 01, 02, 03, 04, 05], + &[192, 168, 1, 2], + ) + .unwrap(); + + let mut serialized = Vec::new(); + + let pkg = PacketBuilder::ethernet2( + [0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b], + [0xde, 0xad, 0xc0, 0x00, 0xff, 0xee], + ) + .arp(expected_header.clone()); + + let target_size = pkg.size(); + pkg.write(&mut serialized).unwrap(); + + // validate that the predicted size was matching + assert_eq!(serialized.len(), target_size); + + // deserialize each part of the message and check it + use std::io::Cursor; + let mut cursor = Cursor::new(&serialized); + + // ethernet 2 header + assert_eq!( + Ethernet2Header::read(&mut cursor).unwrap(), + Ethernet2Header { + source: [0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b], + destination: [0xde, 0xad, 0xc0, 0x00, 0xff, 0xee], + ether_type: ether_type::ARP + } + ); + + // arp packet + assert_eq!(ArpPacket::read(&mut cursor).unwrap(), expected_header); + } + + #[test] + fn eth_vlan_arp() { + let expected_arp = ArpPacket::new( + ArpHardwareId::ETHERNET, + EtherType::IPV4, + ArpOperation::REQUEST, + &[20, 30, 40, 50, 60, 70], + &[10, 1, 1, 5], + &[00, 01, 02, 03, 04, 05], + &[192, 168, 1, 2], + ) + .unwrap(); + let vlan = SingleVlanHeader { + pcp: VlanPcp::ZERO, + drop_eligible_indicator: false, + vlan_id: VlanId::try_new(123).unwrap(), + ether_type: EtherType(0), // should get overwritten + }; + + let mut serialized = Vec::new(); + + let pkg = PacketBuilder::ethernet2( + [0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b], + [0xde, 0xad, 0xc0, 0x00, 0xff, 0xee], + ) + .vlan(VlanHeader::Single(vlan.clone())) + .arp(expected_arp.clone()); + + let target_size = pkg.size(); + pkg.write(&mut serialized).unwrap(); + + // validate that the predicted size was matching + assert_eq!(serialized.len(), target_size); + + // deserialize each part of the message and check it + use std::io::Cursor; + let mut cursor = Cursor::new(&serialized); + + // ethernet 2 header + assert_eq!( + Ethernet2Header::read(&mut cursor).unwrap(), + Ethernet2Header { + source: [0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b], + destination: [0xde, 0xad, 0xc0, 0x00, 0xff, 0xee], + ether_type: ether_type::VLAN_TAGGED_FRAME + } + ); + + // vlan header + let mut expected_vlan = vlan.clone(); + expected_vlan.ether_type = EtherType::ARP; + assert_eq!(SingleVlanHeader::read(&mut cursor).unwrap(), expected_vlan); + + // arp packet + assert_eq!(ArpPacket::read(&mut cursor).unwrap(), expected_arp); + } + #[test] fn eth_ipv4_udp() { //generate @@ -2109,7 +2323,7 @@ mod test { LinuxSllHeader::read(&mut cursor).unwrap(), LinuxSllHeader { packet_type: LinuxSllPacketType::OUTGOING, - arp_hrd_type: ArpHardwareId::ETHER, + arp_hrd_type: ArpHardwareId::ETHERNET, sender_address_valid_length: 6, sender_address: [7, 8, 9, 10, 11, 12, 0, 0], protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV4) @@ -2141,6 +2355,52 @@ mod test { assert_eq!(actual_payload, in_payload); } + #[test] + fn linuxsll_arp() { + let expected_arp = ArpPacket::new( + ArpHardwareId::ETHERNET, + EtherType::IPV4, + ArpOperation::REQUEST, + &[20, 30, 40, 50, 60, 70], + &[10, 1, 1, 5], + &[00, 01, 02, 03, 04, 05], + &[192, 168, 1, 2], + ) + .unwrap(); + + // build packet + let builder = + PacketBuilder::linux_sll(LinuxSllPacketType::OUTGOING, 6, [7, 8, 9, 10, 11, 12, 0, 0]) + .arp(expected_arp.clone()); + + let predicted_size = builder.size(); + + let mut serialized = Vec::with_capacity(builder.size()); + builder.write(&mut serialized).unwrap(); + + // validate predicted size + assert_eq!(predicted_size, serialized.len()); + + // deserialize each part of the message and check it + use std::io::Cursor; + let mut cursor = Cursor::new(&serialized); + + // linux sll header + assert_eq!( + LinuxSllHeader::read(&mut cursor).unwrap(), + LinuxSllHeader { + packet_type: LinuxSllPacketType::OUTGOING, + arp_hrd_type: ArpHardwareId::ETHERNET, + sender_address_valid_length: 6, + sender_address: [7, 8, 9, 10, 11, 12, 0, 0], + protocol_type: LinuxSllProtocolType::EtherType(EtherType::ARP) + } + ); + + // arp + assert_eq!(ArpPacket::read(&mut cursor).unwrap(), expected_arp); + } + #[test] fn ipv4() { let auth_ext = IpAuthHeader::new(0.into(), 1, 2, &[3, 4, 5, 6]).unwrap(); @@ -2470,7 +2730,7 @@ mod test { } #[test] - fn udp_builder_eth_ipv6_udp() { + fn eth_ipv6_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -2540,7 +2800,7 @@ mod test { } #[test] - fn udp_builder_linuxsll_ipv6_udp() { + fn linuxsll_ipv6_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -2575,7 +2835,7 @@ mod test { LinuxSllHeader::read(&mut cursor).unwrap(), LinuxSllHeader { packet_type: LinuxSllPacketType::OUTGOING, - arp_hrd_type: ArpHardwareId::ETHER, + arp_hrd_type: ArpHardwareId::ETHERNET, sender_address_valid_length: 6, sender_address: [7, 8, 9, 10, 11, 12, 0, 0], protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV6) @@ -2612,7 +2872,7 @@ mod test { } #[test] - fn udp_builder_eth_single_vlan_ipv4_udp() { + fn eth_single_vlan_ipv4_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -2685,7 +2945,7 @@ mod test { } #[test] - fn udp_builder_eth_double_vlan_ipv6_udp() { + fn eth_double_vlan_ipv6_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -2783,7 +3043,7 @@ mod test { } #[test] - fn udp_builder_eth_ip_udp() { + fn eth_ip_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -2861,7 +3121,7 @@ mod test { } #[test] - fn udp_builder_linuxsll_ip_udp() { + fn linuxsll_ip_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -2904,7 +3164,7 @@ mod test { LinuxSllHeader::read(&mut cursor).unwrap(), LinuxSllHeader { packet_type: LinuxSllPacketType::OUTGOING, - arp_hrd_type: ArpHardwareId::ETHER, + arp_hrd_type: ArpHardwareId::ETHERNET, sender_address_valid_length: 6, sender_address: [7, 8, 9, 10, 11, 12, 0, 0], protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV6) @@ -2941,7 +3201,7 @@ mod test { } #[test] - fn udp_builder_eth_vlan_ip_udp() { + fn eth_vlan_ip_udp() { //generate let in_payload = [50, 51, 52, 53]; let mut serialized = Vec::new(); @@ -3260,7 +3520,7 @@ mod test { } #[test] - fn tcp_options() { + fn eth_ipv4_tcp_options() { let mut serialized = Vec::new(); use crate::TcpOptionElement::*; @@ -3285,6 +3545,34 @@ mod test { assert_eq!(&[Ok(MaximumSegmentSize(1234)), Ok(Noop)], &dec_options[..]); } + #[test] + fn eth_ipv4_tcp_header() { + let mut serialized = Vec::new(); + + let tcp_header = TcpHeader { + source_port: 1234, + destination_port: 2345, + sequence_number: 3456, + acknowledgment_number: 4567, + ..Default::default() + }; + + PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]) + .ipv4([13, 14, 15, 16], [17, 18, 19, 20], 21) + .tcp_header(tcp_header.clone()) + .write(&mut serialized, &[]) + .unwrap(); + + let decoded = PacketHeaders::from_ethernet_slice(&serialized[..]).unwrap(); + + let mut expected = tcp_header; + expected.checksum = expected + .calc_checksum_ipv4_raw([13, 14, 15, 16], [17, 18, 19, 20], &[]) + .unwrap(); + + assert_eq!(decoded.transport, Some(TransportHeader::Tcp(expected))); + } + #[test] fn size() { //ipv4 no vlan ethernet diff --git a/etherparse/src/packet_headers.rs b/etherparse/src/packet_headers.rs index a14f805f..2f0ba58c 100644 --- a/etherparse/src/packet_headers.rs +++ b/etherparse/src/packet_headers.rs @@ -92,6 +92,7 @@ impl<'a> PacketHeaders<'a> { /// The result is returned as a [`PacketHeaders`] struct. Currently supported /// ether type numbers are: /// + /// * `ether_type::ARP` /// * `ether_type::IPV4` /// * `ether_type::IPV6` /// * `ether_type::VLAN_TAGGED_FRAME` @@ -166,7 +167,6 @@ impl<'a> PacketHeaders<'a> { }), }; - //parse vlan header(s) use ether_type::*; result.vlan = match ether_type { @@ -265,6 +265,13 @@ impl<'a> PacketHeaders<'a> { result.transport = transport; result.payload = payload; } + ARP => { + result.net = Some(NetHeaders::Arp( + ArpPacket::from_slice(rest).map_err(|err| Len(add_offset(err, rest)))?, + )); + + result.payload = PayloadSlice::Empty; + } _ => {} }; @@ -936,6 +943,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::UDP); ip.into() @@ -965,6 +973,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: err::Layer::UdpHeader, layer_start_offset: base_len, @@ -986,6 +995,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::TCP); ip.into() @@ -1013,6 +1023,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: err::Layer::TcpHeader, layer_start_offset: base_len, @@ -1047,6 +1058,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::ICMP); ip.into() @@ -1072,6 +1084,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: err::Layer::Icmpv4, layer_start_offset: base_len, @@ -1094,6 +1107,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::IPV6_ICMP); ip.into() @@ -1119,6 +1133,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: err::Layer::Icmpv6, layer_start_offset: base_len, @@ -1185,6 +1200,7 @@ mod test { match ip { NetHeaders::Ipv4(_, _) => ether_type::IPV4, NetHeaders::Ipv6(_, _) => ether_type::IPV6, + NetHeaders::Arp(_) => ether_type::ARP, }, &data, ) @@ -1241,6 +1257,7 @@ mod test { match ip { NetHeaders::Ipv4(_, _) => ether_type::IPV4, NetHeaders::Ipv6(_, _) => ether_type::IPV6, + NetHeaders::Arp(_) => ether_type::ARP, }, &data, ) diff --git a/etherparse/src/payload_slice.rs b/etherparse/src/payload_slice.rs index 3715e542..07fa7022 100644 --- a/etherparse/src/payload_slice.rs +++ b/etherparse/src/payload_slice.rs @@ -3,6 +3,8 @@ use crate::*; /// Payload together with an identifier the type of content. #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum PayloadSlice<'a> { + /// No specific payload (e.g. ARP packet). + Empty, /// Payload with it's type identified by an ether type number /// (e.g. after an ethernet II or vlan header). Ether(EtherPayloadSlice<'a>), @@ -24,6 +26,7 @@ pub enum PayloadSlice<'a> { impl<'a> PayloadSlice<'a> { pub fn slice(&self) -> &'a [u8] { match self { + PayloadSlice::Empty => &[], PayloadSlice::Ether(s) => s.payload, PayloadSlice::Ip(s) => s.payload, PayloadSlice::Udp(s) => s, diff --git a/etherparse/src/sliced_packet.rs b/etherparse/src/sliced_packet.rs index 63c73825..e9756020 100644 --- a/etherparse/src/sliced_packet.rs +++ b/etherparse/src/sliced_packet.rs @@ -142,6 +142,7 @@ impl<'a> SlicedPacket<'a> { /// The result is returned as a [`SlicedPacket`] struct. Currently supported /// ether type numbers are: /// + /// * `ether_type::ARP` /// * `ether_type::IPV4` /// * `ether_type::IPV6` /// * `ether_type::VLAN_TAGGED_FRAME` @@ -202,6 +203,7 @@ impl<'a> SlicedPacket<'a> { IPV4 => cursor.slice_ipv4(), IPV6 => cursor.slice_ipv6(), VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => cursor.slice_vlan(), + ARP => cursor.slice_arp(), _ => Ok(cursor.result), } } @@ -332,6 +334,7 @@ impl<'a> SlicedPacket<'a> { match net { Ipv4(v) => Some(v.payload()), Ipv6(v) => Some(v.payload()), + Arp(_) => None, } } else { None @@ -344,7 +347,7 @@ impl<'a> SlicedPacket<'a> { match &self.net { Some(Ipv4(v)) => v.is_payload_fragmented(), Some(Ipv6(v)) => v.is_payload_fragmented(), - None => false, + Some(Arp(_)) | None => false, } } } @@ -457,7 +460,7 @@ mod test { buf.extend_from_slice( &LinuxSllHeader { packet_type: LinuxSllPacketType::HOST, - arp_hrd_type: ArpHardwareId::ETHER, + arp_hrd_type: ArpHardwareId::ETHERNET, sender_address_valid_length: 6, sender_address: [1, 2, 3, 4, 5, 6, 0, 0], protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN), @@ -575,6 +578,33 @@ mod test { None ); + // arp + { + let mut buf = Vec::with_capacity(Ethernet2Header::LEN + ArpEthIpv4Packet::LEN); + buf.extend_from_slice( + &Ethernet2Header { + source: [0; 6], + destination: [0; 6], + ether_type: EtherType::ARP, + } + .to_bytes(), + ); + buf.extend_from_slice( + &ArpEthIpv4Packet { + operation: ArpOperation::REPLY, + sender_mac: [0; 6], + sender_ipv4: [0; 4], + target_mac: [0; 6], + target_ipv4: [0; 4], + } + .to_bytes(), + ); + assert_eq!( + SlicedPacket::from_ethernet(&buf).unwrap().ip_payload(), + None + ); + } + // ipv4 { let payload = [1, 2, 3, 4]; @@ -624,6 +654,141 @@ mod test { } } + #[test] + fn is_ip_payload_fragmented() { + use alloc::vec::*; + + // no content + assert_eq!( + SlicedPacket { + link: None, + vlan: None, + net: None, + transport: None, + } + .is_ip_payload_fragmented(), + false + ); + + // arp + { + let mut buf = Vec::with_capacity(Ethernet2Header::LEN + ArpEthIpv4Packet::LEN); + buf.extend_from_slice( + &Ethernet2Header { + source: [0; 6], + destination: [0; 6], + ether_type: EtherType::ARP, + } + .to_bytes(), + ); + buf.extend_from_slice( + &ArpEthIpv4Packet { + operation: ArpOperation::REPLY, + sender_mac: [0; 6], + sender_ipv4: [0; 4], + target_mac: [0; 6], + target_ipv4: [0; 4], + } + .to_bytes(), + ); + assert_eq!( + SlicedPacket::from_ethernet(&buf) + .unwrap() + .is_ip_payload_fragmented(), + false + ); + } + + // ipv4 (non fragmented) + { + let payload = [1, 2, 3, 4]; + let mut buf = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); + buf.extend_from_slice( + &Ipv4Header { + protocol: IpNumber::ARIS, + total_len: Ipv4Header::MIN_LEN_U16 + 4, + ..Default::default() + } + .to_bytes(), + ); + buf.extend_from_slice(&payload); + assert_eq!( + SlicedPacket::from_ip(&buf) + .unwrap() + .is_ip_payload_fragmented(), + false + ); + } + + // ipv4 (fragmented) + { + let payload = [1, 2, 3, 4]; + let mut buf = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); + buf.extend_from_slice( + &Ipv4Header { + protocol: IpNumber::ARIS, + total_len: Ipv4Header::MIN_LEN_U16 + 4, + more_fragments: true, + fragment_offset: IpFragOffset::ZERO, + ..Default::default() + } + .to_bytes(), + ); + buf.extend_from_slice(&payload); + assert!(SlicedPacket::from_ip(&buf) + .unwrap() + .is_ip_payload_fragmented()); + } + + // ipv6 (non fragmented) + { + let payload = [1, 2, 3, 4]; + let mut buf = Vec::with_capacity(Ipv6Header::LEN + 4); + buf.extend_from_slice( + &Ipv6Header { + payload_length: 4, + next_header: IpNumber::ARGUS, + ..Default::default() + } + .to_bytes(), + ); + buf.extend_from_slice(&payload); + assert_eq!( + SlicedPacket::from_ip(&buf) + .unwrap() + .is_ip_payload_fragmented(), + false + ); + } + + // ipv6 (fragmented) + { + let payload = [1, 2, 3, 4]; + let mut buf = Vec::with_capacity(Ipv6Header::LEN + 4); + buf.extend_from_slice( + &Ipv6Header { + payload_length: Ipv6FragmentHeader::LEN as u16 + 4, + next_header: IpNumber::IPV6_FRAGMENTATION_HEADER, + ..Default::default() + } + .to_bytes(), + ); + buf.extend_from_slice( + &Ipv6FragmentHeader { + next_header: IpNumber::ARGUS, + fragment_offset: IpFragOffset::ZERO, + more_fragments: true, + identification: 0, + } + .to_bytes(), + ); + buf.extend_from_slice(&payload); + assert!(SlicedPacket::from_ip(&buf) + .unwrap() + .is_ip_payload_fragmented()); + } + } + #[test] fn from_x_slice() { // no eth @@ -690,7 +855,7 @@ mod test { { let linux_sll = LinuxSllHeader { packet_type: LinuxSllPacketType::HOST, - arp_hrd_type: ArpHardwareId::ETHER, + arp_hrd_type: ArpHardwareId::ETHERNET, sender_address_valid_length: 6, sender_address: [1, 2, 3, 4, 5, 6, 0, 0], protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN), @@ -1165,6 +1330,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::UDP); ip.into() @@ -1194,6 +1360,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::UdpHeader, layer_start_offset: base_len, @@ -1215,6 +1382,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::TCP); ip.into() @@ -1243,6 +1411,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::TcpHeader, layer_start_offset: base_len, @@ -1278,6 +1447,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::ICMP); ip.into() @@ -1304,6 +1474,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::Icmpv4, layer_start_offset: base_len, @@ -1326,6 +1497,7 @@ mod test { let mut ip = match ip { NetHeaders::Ipv4(h, e) => IpHeaders::Ipv4(h.clone(), e.clone()), NetHeaders::Ipv6(h, e) => IpHeaders::Ipv6(h.clone(), e.clone()), + NetHeaders::Arp(_) => unreachable!(), }; ip.set_next_headers(ip_number::IPV6_ICMP); ip.into() @@ -1352,6 +1524,7 @@ mod test { len_source: match test.net.as_ref().unwrap() { NetHeaders::Ipv4(_, _) => LenSource::Ipv4HeaderTotalLen, NetHeaders::Ipv6(_, _) => LenSource::Ipv6HeaderPayloadLen, + NetHeaders::Arp(_) => unreachable!(), }, layer: Layer::Icmpv6, layer_start_offset: base_len, @@ -1403,6 +1576,7 @@ mod test { .unwrap() .0, ), + NetSlice::Arp(arp) => NetHeaders::Arp(arp.to_packet()), } }) ); @@ -1473,6 +1647,7 @@ mod test { let ether_type = match ip { NetHeaders::Ipv4(_, _) => ether_type::IPV4, NetHeaders::Ipv6(_, _) => ether_type::IPV6, + NetHeaders::Arp(_) => ether_type::ARP, }; let result = SlicedPacket::from_ether_type(ether_type, &data).unwrap(); assert_eq!( @@ -1523,6 +1698,7 @@ mod test { match ip { NetHeaders::Ipv4(_, _) => ether_type::IPV4, NetHeaders::Ipv6(_, _) => ether_type::IPV6, + NetHeaders::Arp(_) => ether_type::ARP, }, &data, ) diff --git a/etherparse/src/sliced_packet_cursor.rs b/etherparse/src/sliced_packet_cursor.rs index fb1a364e..b6db3787 100644 --- a/etherparse/src/sliced_packet_cursor.rs +++ b/etherparse/src/sliced_packet_cursor.rs @@ -48,6 +48,7 @@ impl<'a> SlicedPacketCursor<'a> { //continue parsing (if required) match ether_type { + ARP => self.slice_arp(), IPV4 => self.slice_ipv4(), IPV6 => self.slice_ipv6(), VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => self.slice_vlan(), @@ -74,6 +75,7 @@ impl<'a> SlicedPacketCursor<'a> { //continue parsing (if required) match protocol_type { + LinuxSllProtocolType::EtherType(EtherType::ARP) => self.slice_arp(), LinuxSllProtocolType::EtherType(EtherType::IPV4) => self.slice_ipv4(), LinuxSllProtocolType::EtherType(EtherType::IPV6) => self.slice_ipv6(), _ => Ok(self.result), @@ -107,11 +109,13 @@ impl<'a> SlicedPacketCursor<'a> { })); match inner_ether_type { + ARP => self.slice_arp(), IPV4 => self.slice_ipv4(), IPV6 => self.slice_ipv6(), _ => Ok(self.result), } } + ARP => self.slice_arp(), IPV4 => self.slice_ipv4(), IPV6 => self.slice_ipv6(), _ => Ok(self.result), @@ -274,6 +278,19 @@ impl<'a> SlicedPacketCursor<'a> { } } + pub fn slice_arp(mut self) -> Result, err::packet::SliceError> { + let result = ArpPacketSlice::from_slice(self.slice).map_err(|mut err| { + err.layer_start_offset += self.offset; + err::packet::SliceError::Len(err) + })?; + + //set the new data + self.move_by(result.slice().len()); + self.result.net = Some(NetSlice::Arp(result.clone())); + + Ok(self.result) + } + pub fn slice_icmp4(mut self) -> Result, err::LenError> { use crate::TransportSlice::*; diff --git a/etherparse/src/test_gens/mod.rs b/etherparse/src/test_gens/mod.rs index c677a354..48ddeb60 100644 --- a/etherparse/src/test_gens/mod.rs +++ b/etherparse/src/test_gens/mod.rs @@ -150,6 +150,7 @@ prop_compose! { } pub static ETHERNET_KNOWN_ETHER_TYPES: &'static [EtherType] = &[ + ether_type::ARP, ether_type::IPV4, ether_type::IPV6, ether_type::VLAN_TAGGED_FRAME, @@ -225,6 +226,54 @@ prop_compose! { } } +prop_compose! { + pub fn arp_packet_any() + ( + hw_addr_size in any::(), + proto_addr_size in any::() + ) + ( + hw_addr_type in any::(), + proto_addr_type in any::(), + operation in any::(), + sender_hw_addr in prop::collection::vec(any::(), hw_addr_size as usize), + sender_protocol_addr in prop::collection::vec(any::(), proto_addr_size as usize), + target_hw_addr in prop::collection::vec(any::(), hw_addr_size as usize), + target_protocol_addr in prop::collection::vec(any::(), proto_addr_size as usize) + ) -> ArpPacket + { + ArpPacket::new( + ArpHardwareId(hw_addr_type), + EtherType(proto_addr_type), + ArpOperation(operation), + &sender_hw_addr[..], + &sender_protocol_addr[..], + &target_hw_addr[..], + &target_protocol_addr[..] + ).unwrap() + } +} + +prop_compose! { + pub fn arp_eth_ipv4_packet_any() + ( + operation in any::(), + sender_mac in prop::array::uniform6(any::()), + sender_ipv4 in prop::array::uniform4(any::()), + target_mac in prop::array::uniform6(any::()), + target_ipv4 in prop::array::uniform4(any::()) + ) -> ArpEthIpv4Packet + { + ArpEthIpv4Packet { + operation: ArpOperation(operation), + sender_mac, + sender_ipv4, + target_mac, + target_ipv4, + } + } +} + prop_compose! { pub fn ipv4_options_any() ( diff --git a/etherparse/src/test_packet.rs b/etherparse/src/test_packet.rs index 13691d6f..73b16fbe 100644 --- a/etherparse/src/test_packet.rs +++ b/etherparse/src/test_packet.rs @@ -26,8 +26,8 @@ impl TestPacket { if let Some(vlan) = &self.vlan { vlan.write(&mut result).unwrap(); } - if let Some(ip) = &self.net { - match ip { + if let Some(net) = &self.net { + match net { NetHeaders::Ipv4(ipv4, exts) => { ipv4.write_raw(&mut result).unwrap(); exts.write(&mut result, ipv4.protocol).unwrap(); @@ -36,6 +36,9 @@ impl TestPacket { ipv6.write(&mut result).unwrap(); exts.write(&mut result, ipv6.next_header).unwrap(); } + NetHeaders::Arp(arp) => { + arp.write(&mut result).unwrap(); + } } } if let Some(transport) = &self.transport { @@ -88,6 +91,7 @@ impl TestPacket { ) .unwrap(); } + Some(Arp(_)) => {} } use TransportHeader::*; @@ -118,6 +122,7 @@ impl TestPacket { ) .unwrap(); } + Arp(_) => {} } } @@ -125,6 +130,7 @@ impl TestPacket { self.net.as_ref().map_or(false, |net| match net { NetHeaders::Ipv4(h, _) => h.is_fragmenting_payload(), NetHeaders::Ipv6(_, e) => e.is_fragmenting_payload(), + NetHeaders::Arp(_) => false, }) } } diff --git a/etherparse/src/transport/mod.rs b/etherparse/src/transport/mod.rs index c09d57f6..45e36b1a 100644 --- a/etherparse/src/transport/mod.rs +++ b/etherparse/src/transport/mod.rs @@ -1,25 +1,68 @@ -pub mod icmp_echo_header; /// Module containing ICMPv4 related types and constants. pub mod icmpv4; -pub mod icmpv4_header; -pub mod icmpv4_slice; -pub mod icmpv4_type; + /// Module containing ICMPv6 related types and constants pub mod icmpv6; -pub mod icmpv6_header; -pub mod icmpv6_slice; -pub mod icmpv6_type; -pub mod tcp_header; -pub mod tcp_header_slice; -pub mod tcp_option_element; -pub mod tcp_option_impl; -pub mod tcp_option_read_error; -pub mod tcp_option_write_error; -pub mod tcp_options; -pub mod tcp_options_iterator; -pub mod tcp_slice; -pub mod transport_header; -pub mod transport_slice; -pub mod udp_header; -pub mod udp_header_slice; -pub mod udp_slice; + +mod icmp_echo_header; +pub use icmp_echo_header::*; + +mod icmpv4_header; +pub use icmpv4_header::*; + +mod icmpv4_slice; +pub use icmpv4_slice::*; + +mod icmpv4_type; +pub use icmpv4_type::*; + +mod icmpv6_header; +pub use icmpv6_header::*; + +mod icmpv6_slice; +pub use icmpv6_slice::*; + +mod icmpv6_type; +pub use icmpv6_type::*; + +mod tcp_header; +pub use tcp_header::*; + +mod tcp_header_slice; +pub use tcp_header_slice::*; + +mod tcp_option_element; +pub use tcp_option_element::*; + +mod tcp_option_impl; +pub use tcp_option_impl::*; + +mod tcp_option_read_error; +pub use tcp_option_read_error::*; + +mod tcp_option_write_error; +pub use tcp_option_write_error::*; + +mod tcp_options; +pub use tcp_options::*; + +mod tcp_options_iterator; +pub use tcp_options_iterator::*; + +mod tcp_slice; +pub use tcp_slice::*; + +mod transport_header; +pub use transport_header::*; + +mod transport_slice; +pub use transport_slice::*; + +mod udp_header; +pub use udp_header::*; + +mod udp_header_slice; +pub use udp_header_slice::*; + +mod udp_slice; +pub use udp_slice::*; diff --git a/etherparse/src/transport/tcp_options_iterator.rs b/etherparse/src/transport/tcp_options_iterator.rs index defc2fff..e1321369 100644 --- a/etherparse/src/transport/tcp_options_iterator.rs +++ b/etherparse/src/transport/tcp_options_iterator.rs @@ -18,7 +18,7 @@ impl<'a> TcpOptionsIterator<'a> { } } -impl<'a> Iterator for TcpOptionsIterator<'a> { +impl Iterator for TcpOptionsIterator<'_> { type Item = Result; fn next(&mut self) -> Option { @@ -181,7 +181,7 @@ impl<'a> Iterator for TcpOptionsIterator<'a> { } } -impl<'a> core::fmt::Debug for TcpOptionsIterator<'a> { +impl core::fmt::Debug for TcpOptionsIterator<'_> { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { let mut list = fmt.debug_list(); diff --git a/etherparse/src/transport/tcp_slice.rs b/etherparse/src/transport/tcp_slice.rs index c867a721..f25479f4 100644 --- a/etherparse/src/transport/tcp_slice.rs +++ b/etherparse/src/transport/tcp_slice.rs @@ -408,7 +408,7 @@ impl<'a> TcpSlice<'a> { } } -impl<'a> core::fmt::Debug for TcpSlice<'a> { +impl core::fmt::Debug for TcpSlice<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("TcpSlice") .field("header", &self.to_header()) diff --git a/etherparse/src/transport/udp_slice.rs b/etherparse/src/transport/udp_slice.rs index 28937f9e..f839745d 100644 --- a/etherparse/src/transport/udp_slice.rs +++ b/etherparse/src/transport/udp_slice.rs @@ -456,4 +456,30 @@ mod test { } } } + + proptest! { + #[test] + fn header_len( + udp in udp_any() + ) { + let mut udp = udp.clone(); + udp.length = UdpHeader::LEN_U16; + let bytes = udp.to_bytes(); + let slice = UdpSlice::from_slice(&bytes).unwrap(); + assert_eq!(UdpHeader::LEN, slice.header_len()); + } + } + + proptest! { + #[test] + fn header_len_u16( + udp in udp_any() + ) { + let mut udp = udp.clone(); + udp.length = UdpHeader::LEN_U16; + let bytes = udp.to_bytes(); + let slice = UdpSlice::from_slice(&bytes).unwrap(); + assert_eq!(UdpHeader::LEN_U16, slice.header_len_u16()); + } + } } diff --git a/etherparse_proptest_generators/src/lib.rs b/etherparse_proptest_generators/src/lib.rs index b0c83101..cd10ddd8 100644 --- a/etherparse_proptest_generators/src/lib.rs +++ b/etherparse_proptest_generators/src/lib.rs @@ -185,6 +185,34 @@ prop_compose! { } } +prop_compose! { + pub fn arp_packet_any() + ( + hw_addr_size in any::(), + proto_addr_size in any::() + ) + ( + hw_addr_type in any::(), + proto_addr_type in any::(), + operation in any::(), + sender_hw_addr in prop::collection::vec(any::(), hw_addr_size as usize), + sender_protocol_addr in prop::collection::vec(any::(), proto_addr_size as usize), + target_hw_addr in prop::collection::vec(any::(), hw_addr_size as usize), + target_protocol_addr in prop::collection::vec(any::(), proto_addr_size as usize) + ) -> ArpPacket + { + ArpPacket::new( + ArpHardwareId(hw_addr_type), + EtherType(proto_addr_type), + ArpOperation(operation), + &sender_hw_addr[..], + &sender_protocol_addr[..], + &target_hw_addr[..], + &target_protocol_addr[..] + ).unwrap() + } +} + prop_compose! { pub fn ipv4_options_any() (