l3l4kit/
l3.rs

1use smoltcp::phy::ChecksumCapabilities;
2use smoltcp::wire::{
3    IpAddress, IpProtocol, Ipv4Packet, Ipv4Repr, Ipv6Packet, Ipv6Repr, TcpPacket, TcpRepr,
4    UdpPacket, UdpRepr,
5};
6
7use crate::Flow;
8
9pub(crate) fn parse_v4(rx: &[u8]) -> Option<Flow> {
10    if let Ok(pkt) = Ipv4Packet::new_checked(rx) {
11        let nocksum = ChecksumCapabilities::ignored();
12        let pkt = Ipv4Packet::new_unchecked(pkt.into_inner());
13        if let Ok(ipv4) = Ipv4Repr::parse(&pkt, &nocksum) {
14            let source_ip = IpAddress::from(ipv4.src_addr);
15            let dest_ip = IpAddress::from(ipv4.dst_addr);
16            match pkt.next_header() {
17                IpProtocol::Tcp => {
18                    if let Ok(tpkt) = TcpPacket::new_checked(pkt.payload()) {
19                        if let Ok(tcp) = TcpRepr::parse(&tpkt, &source_ip, &dest_ip, &nocksum) {
20                            return Some(Flow {
21                                source_ip,
22                                dest_ip,
23                                source_port: tcp.src_port,
24                                dest_port: tcp.dst_port,
25                                protocol: crate::TCP,
26                            });
27                        }
28                    }
29                }
30                IpProtocol::Udp => {
31                    if let Ok(upkt) = UdpPacket::new_checked(pkt.payload()) {
32                        if let Ok(udp) = UdpRepr::parse(&upkt, &source_ip, &dest_ip, &nocksum) {
33                            return Some(Flow {
34                                source_ip,
35                                dest_ip,
36                                source_port: udp.src_port,
37                                dest_port: udp.dst_port,
38                                protocol: crate::UDP,
39                            });
40                        }
41                    }
42                }
43                _ => {}
44            }
45        }
46    }
47    None
48}
49
50pub(crate) fn parse_v6(rx: &[u8]) -> Option<Flow> {
51    if let Ok(pkt) = Ipv6Packet::new_checked(rx) {
52        let pkt = Ipv6Packet::new_unchecked(pkt.into_inner());
53        let nocksum = ChecksumCapabilities::ignored();
54        if let Ok(ipv6) = Ipv6Repr::parse(&pkt) {
55            let source_ip = IpAddress::from(ipv6.src_addr);
56            let dest_ip = IpAddress::from(ipv6.dst_addr);
57            match pkt.next_header() {
58                IpProtocol::Tcp => {
59                    if let Ok(tpkt) = TcpPacket::new_checked(pkt.payload()) {
60                        if let Ok(tcp) = TcpRepr::parse(&tpkt, &source_ip, &dest_ip, &nocksum) {
61                            return Some(Flow {
62                                source_ip,
63                                dest_ip,
64                                source_port: tcp.src_port,
65                                dest_port: tcp.dst_port,
66                                protocol: crate::TCP,
67                            });
68                        }
69                    }
70                }
71                IpProtocol::Udp => {
72                    if let Ok(upkt) = UdpPacket::new_checked(pkt.payload()) {
73                        if let Ok(udp) = UdpRepr::parse(&upkt, &source_ip, &dest_ip, &nocksum) {
74                            return Some(Flow {
75                                source_ip,
76                                dest_ip,
77                                source_port: udp.src_port,
78                                dest_port: udp.dst_port,
79                                protocol: crate::UDP,
80                            });
81                        }
82                    }
83                }
84                _ => {}
85            }
86        }
87    }
88    None
89}