1use wireforge_core::arp::ArpPacket;
8use wireforge_core::ether::EthernetPacket;
9use wireforge_core::icmp::{IcmpPacket, Icmpv6Packet};
10use wireforge_core::ipv4::Ipv4Packet;
11use wireforge_core::ipv6::Ipv6Packet;
12use wireforge_core::tcp::TcpPacket;
13use wireforge_core::udp::UdpPacket;
14use wireforge_core::types::{EtherType, IpProtocol};
15
16#[derive(Debug, Clone)]
18pub enum Packet<'a> {
19 Ethernet(EthernetPacket<'a>),
20 Arp(ArpPacket<'a>),
21 Ipv4(Ipv4Packet<'a>),
22 Ipv6(Ipv6Packet<'a>),
23 Tcp(TcpPacket<'a>),
24 Udp(UdpPacket<'a>),
25 Icmp(IcmpPacket<'a>),
26 Icmpv6(Icmpv6Packet<'a>),
27}
28
29impl<'a> From<EthernetPacket<'a>> for Packet<'a> {
31 fn from(p: EthernetPacket<'a>) -> Self { Packet::Ethernet(p) }
32}
33
34impl<'a> From<ArpPacket<'a>> for Packet<'a> {
35 fn from(p: ArpPacket<'a>) -> Self { Packet::Arp(p) }
36}
37
38impl<'a> From<Ipv4Packet<'a>> for Packet<'a> {
39 fn from(p: Ipv4Packet<'a>) -> Self { Packet::Ipv4(p) }
40}
41
42impl<'a> From<Ipv6Packet<'a>> for Packet<'a> {
43 fn from(p: Ipv6Packet<'a>) -> Self { Packet::Ipv6(p) }
44}
45
46impl<'a> From<TcpPacket<'a>> for Packet<'a> {
47 fn from(p: TcpPacket<'a>) -> Self { Packet::Tcp(p) }
48}
49
50impl<'a> From<UdpPacket<'a>> for Packet<'a> {
51 fn from(p: UdpPacket<'a>) -> Self { Packet::Udp(p) }
52}
53
54impl<'a> From<IcmpPacket<'a>> for Packet<'a> {
55 fn from(p: IcmpPacket<'a>) -> Self { Packet::Icmp(p) }
56}
57
58impl<'a> From<Icmpv6Packet<'a>> for Packet<'a> {
59 fn from(p: Icmpv6Packet<'a>) -> Self { Packet::Icmpv6(p) }
60}
61
62pub fn parse_ethernet_frame(buf: &[u8]) -> Option<(EthernetPacket<'_>, Option<Packet<'_>>)> {
67 let eth = EthernetPacket::new(buf)?;
68 let inner = match eth.ethertype() {
69 EtherType::Arp => ArpPacket::new(eth.payload()).map(Packet::Arp),
70 EtherType::Ipv4 => Ipv4Packet::new(eth.payload()).map(Packet::Ipv4),
71 EtherType::Ipv6 => Ipv6Packet::new(eth.payload()).map(Packet::Ipv6),
72 _ => None,
73 };
74 Some((eth, inner))
75}
76
77pub fn parse_ipv4_payload<'a>(ip: &Ipv4Packet<'a>) -> Option<Packet<'a>> {
79 match ip.protocol() {
80 IpProtocol::Icmp => IcmpPacket::new(ip.payload()).map(Packet::Icmp),
81 IpProtocol::Tcp => TcpPacket::new(ip.payload()).map(Packet::Tcp),
82 IpProtocol::Udp => UdpPacket::new(ip.payload()).map(Packet::Udp),
83 _ => None,
84 }
85}
86
87pub fn parse_ipv6_payload<'a>(ip: &Ipv6Packet<'a>) -> Option<Packet<'a>> {
89 match ip.final_protocol() {
90 IpProtocol::Icmpv6 => Icmpv6Packet::new(ip.payload()).map(Packet::Icmpv6),
91 IpProtocol::Tcp => TcpPacket::new(ip.payload()).map(Packet::Tcp),
92 IpProtocol::Udp => UdpPacket::new(ip.payload()).map(Packet::Udp),
93 _ => None,
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use wireforge_core::ipv4::Ipv4PacketBuilder;
101 use wireforge_core::udp::UdpPacketBuilder;
102
103 #[test]
104 fn dispatch_ethernet_to_ipv4_to_tcp() {
105 let ip_bytes = Ipv4PacketBuilder::new()
106 .source(std::net::Ipv4Addr::new(10, 0, 0, 1))
107 .destination(std::net::Ipv4Addr::new(10, 0, 0, 2))
108 .protocol(IpProtocol::Tcp)
109 .ttl(64)
110 .build();
111
112 let mut frame = vec![0xFFu8; 12]; frame.extend_from_slice(&[0x08, 0x00]); frame.extend_from_slice(&ip_bytes);
115
116 let (eth, inner) = parse_ethernet_frame(&frame).unwrap();
117 assert_eq!(eth.ethertype(), EtherType::Ipv4);
118 assert!(matches!(inner, Some(Packet::Ipv4(_))));
119 }
120
121 #[test]
122 fn dispatch_ethernet_to_arp() {
123 let mut arp_bytes = vec![0x00u8, 0x01]; arp_bytes.extend_from_slice(&[0x08, 0x00]); arp_bytes.push(6); arp_bytes.push(4); arp_bytes.extend_from_slice(&[0x00, 0x01]); arp_bytes.extend_from_slice(&[0x00u8; 20]); let mut frame = vec![0xFFu8; 12];
132 frame.extend_from_slice(&[0x08, 0x06]); frame.extend_from_slice(&arp_bytes);
134
135 let (eth, inner) = parse_ethernet_frame(&frame).unwrap();
136 assert_eq!(eth.ethertype(), EtherType::Arp);
137 assert!(matches!(inner, Some(Packet::Arp(_))));
138 }
139
140 #[test]
141 fn dispatch_ethernet_to_ipv6() {
142 let mut frame = vec![0xFFu8; 12];
144 frame.extend_from_slice(&[0x86, 0xDD]); let mut ip6 = vec![0x60u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x40]; ip6.extend_from_slice(&[0u8; 32]); frame.extend_from_slice(&ip6);
148
149 let (eth, inner) = parse_ethernet_frame(&frame).unwrap();
150 assert_eq!(eth.ethertype(), EtherType::Ipv6);
151 assert!(matches!(inner, Some(Packet::Ipv6(_))));
152 }
153
154 #[test]
155 fn dispatch_ipv4_to_udp() {
156 let udp_bytes = UdpPacketBuilder::new()
157 .source_port(12345)
158 .destination_port(53)
159 .payload(&[0x01])
160 .build(std::net::Ipv4Addr::new(10, 0, 0, 1), std::net::Ipv4Addr::new(10, 0, 0, 2));
161
162 let ip_bytes = Ipv4PacketBuilder::new()
163 .source(std::net::Ipv4Addr::new(10, 0, 0, 1))
164 .destination(std::net::Ipv4Addr::new(10, 0, 0, 2))
165 .protocol(IpProtocol::Udp)
166 .ttl(64)
167 .payload(&udp_bytes).unwrap()
168 .build();
169
170 let ip = Ipv4Packet::new(&ip_bytes).unwrap();
171 let inner = parse_ipv4_payload(&ip);
172 assert!(matches!(inner, Some(Packet::Udp(_))));
173 }
174
175 #[test]
176 fn dispatch_ipv4_to_icmp() {
177 use wireforge_core::icmp::IcmpPacketBuilder;
178 let icmp_bytes = IcmpPacketBuilder::echo_request()
179 .identifier(1).sequence_number(1)
180 .payload(b"ping")
181 .build();
182
183 let ip_bytes = Ipv4PacketBuilder::new()
184 .source(std::net::Ipv4Addr::new(10, 0, 0, 1))
185 .destination(std::net::Ipv4Addr::new(10, 0, 0, 2))
186 .protocol(IpProtocol::Icmp)
187 .ttl(64)
188 .payload(&icmp_bytes).unwrap()
189 .build();
190
191 let ip = Ipv4Packet::new(&ip_bytes).unwrap();
192 let inner = parse_ipv4_payload(&ip);
193 assert!(matches!(inner, Some(Packet::Icmp(_))));
194 }
195}