1#![allow(unused)]
2
3use self::field::*;
4use smoltcp::wire::{IpAddress, Ipv4Address, Ipv6Address};
5use std::convert::TryFrom;
6use std::ops::Deref;
7
8use crate::{Error, Protocol};
9
10pub const ETHERNET_HDR_SIZE: usize = 14;
11pub const IP4_HDR_SIZE: usize = 20;
12pub const IP6_HDR_SIZE: usize = 40;
13pub const TCP_HDR_SIZE: usize = 20;
14pub const UDP_HDR_SIZE: usize = 20;
15
16mod field {
17 pub type Field = std::ops::Range<usize>;
19 pub type BitField = (usize, std::ops::Range<usize>);
21 pub type Rest = std::ops::RangeFrom<usize>;
23}
24
25pub struct EtherField;
26impl EtherField {
27 pub const DST_MAC: Field = 0..6;
28 pub const SRC_MAC: Field = 6..12;
29 pub const ETHER_TYPE: Field = 12..14;
30 pub const PAYLOAD: Rest = 14..;
31}
32
33#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
34#[non_exhaustive]
35pub enum EtherType {
36 Ip,
37 Arp,
38}
39
40#[non_exhaustive]
41pub enum EtherFrame {
42 Ip(Box<[u8]>),
44 Arp(Box<[u8]>),
46}
47
48impl EtherFrame {
49 pub fn peek_type(data: &[u8]) -> Result<EtherType, Error> {
50 if data.len() < ETHERNET_HDR_SIZE {
51 return Err(Error::PacketMalformed("Ethernet: frame too short".into()));
52 }
53
54 let proto = &data[EtherField::ETHER_TYPE];
55 match proto {
56 &[0x08, 0x00] | &[0x86, 0xdd] => {
57 IpPacket::peek(&data[ETHERNET_HDR_SIZE..])?;
58 Ok(EtherType::Ip)
59 }
60 &[0x08, 0x06] => {
61 ArpPacket::peek(&data[ETHERNET_HDR_SIZE..])?;
62 Ok(EtherType::Arp)
63 }
64 _ => Err(Error::ProtocolNotSupported(format!("0x{:02x?}", proto))),
65 }
66 }
67
68 pub fn peek_payload(data: &[u8]) -> Result<&[u8], Error> {
69 if data.len() < ETHERNET_HDR_SIZE {
70 return Err(Error::PacketMalformed("Ethernet: frame too short".into()));
71 }
72 Ok(&data[EtherField::PAYLOAD])
73 }
74
75 pub const fn payload_off() -> usize {
76 ETHERNET_HDR_SIZE
77 }
78
79 pub fn payload(&self) -> &[u8] {
80 &self.as_ref()[EtherField::PAYLOAD]
81 }
82}
83
84impl TryFrom<Box<[u8]>> for EtherFrame {
85 type Error = Error;
86
87 fn try_from(data: Box<[u8]>) -> Result<Self, Self::Error> {
88 match Self::peek_type(&data)? {
89 EtherType::Ip => Ok(EtherFrame::Ip(data)),
90 EtherType::Arp => Ok(EtherFrame::Arp(data)),
91 }
92 }
93}
94
95impl TryFrom<Vec<u8>> for EtherFrame {
96 type Error = Error;
97
98 #[inline]
99 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
100 Self::try_from(value.into_boxed_slice())
101 }
102}
103
104impl From<EtherFrame> for Box<[u8]> {
105 fn from(frame: EtherFrame) -> Self {
106 match frame {
107 EtherFrame::Ip(b) | EtherFrame::Arp(b) => b,
108 }
109 }
110}
111
112impl From<EtherFrame> for Vec<u8> {
113 fn from(frame: EtherFrame) -> Self {
114 Into::<Box<[u8]>>::into(frame).into()
115 }
116}
117
118impl AsRef<Box<[u8]>> for EtherFrame {
119 fn as_ref(&self) -> &Box<[u8]> {
120 match self {
121 Self::Ip(b) | Self::Arp(b) => b,
122 }
123 }
124}
125
126impl std::fmt::Display for EtherFrame {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 match self {
129 EtherFrame::Ip(_) => write!(f, "IP"),
130 EtherFrame::Arp(_) => write!(f, "ARP"),
131 }
132 }
133}
134
135pub trait PeekPacket<'a> {
136 fn peek(data: &'a [u8]) -> Result<(), Error>;
137 fn packet(data: &'a [u8]) -> Self;
138}
139
140pub enum IpPacket<'a> {
141 V4(IpV4Packet<'a>),
142 V6(IpV6Packet<'a>),
143}
144
145impl<'a> IpPacket<'a> {
146 pub fn protocol(&self) -> u8 {
147 match self {
148 Self::V4(ip) => ip.protocol,
149 Self::V6(ip) => ip.protocol,
150 }
151 }
152
153 pub fn src_address(&self) -> &'a [u8] {
154 match self {
155 Self::V4(ip) => ip.src_address,
156 Self::V6(ip) => ip.src_address,
157 }
158 }
159
160 pub fn dst_address(&self) -> &'a [u8] {
161 match self {
162 Self::V4(ip) => ip.dst_address,
163 Self::V6(ip) => ip.inferred_dst_address(),
164 }
165 }
166
167 pub fn payload(&self) -> &'a [u8] {
168 match self {
169 Self::V4(ip) => ip.payload,
170 Self::V6(ip) => ip.payload,
171 }
172 }
173
174 pub fn payload_off(&self) -> usize {
175 match self {
176 Self::V4(ip) => ip.payload_off(),
177 Self::V6(ip) => ip.payload_off(),
178 }
179 }
180
181 pub fn to_tcp(&self) -> Option<TcpPacket> {
182 match self.protocol() {
183 6 => Some(TcpPacket::packet(self.payload())),
184 _ => None,
185 }
186 }
187
188 pub fn is_broadcast(&self) -> bool {
189 match self {
190 Self::V4(ip) => ip.dst_address[0..4] == [255, 255, 255, 255],
191 Self::V6(_) => false,
192 }
193 }
194
195 pub fn is_multicast(&self) -> bool {
196 match self {
197 Self::V4(ip) => ip.dst_address[0] & 0xf0 == 224,
198 Self::V6(ip) => ip.dst_address[0] == 0xff,
199 }
200 }
201}
202
203impl<'a> PeekPacket<'a> for IpPacket<'a> {
204 fn peek(data: &'a [u8]) -> Result<(), Error> {
205 match data[0] >> 4 {
206 4 => IpV4Packet::peek(data),
207 6 => IpV6Packet::peek(data),
208 _ => Err(Error::PacketMalformed("IP: invalid version".into())),
209 }
210 }
211
212 fn packet(data: &'a [u8]) -> Self {
213 if data[0] >> 4 == 4 {
214 Self::V4(IpV4Packet::packet(data))
215 } else {
216 Self::V6(IpV6Packet::packet(data))
217 }
218 }
219}
220
221pub struct IpV4Field;
222impl IpV4Field {
223 pub const IHL: BitField = (0, 4..8);
224 pub const TOTAL_LEN: Field = 2..4;
225 pub const PROTOCOL: Field = 9..10;
226 pub const SRC_ADDR: Field = 12..16;
227 pub const DST_ADDR: Field = 16..20;
228}
229
230pub struct IpV4Packet<'a> {
231 pub src_address: &'a [u8],
232 pub dst_address: &'a [u8],
233 pub protocol: u8,
234 pub payload: &'a [u8],
235 pub payload_off: usize,
236}
237
238impl<'a> IpV4Packet<'a> {
239 pub const MIN_HEADER_LEN: usize = 20;
240
241 #[inline]
242 pub fn payload_off(&self) -> usize {
243 self.payload_off
244 }
245
246 fn read_header_len(data: &'a [u8]) -> usize {
247 let ihl = get_bit_field(data, IpV4Field::IHL) as usize;
248 if ihl >= 5 {
249 4 * ihl
250 } else {
251 Self::MIN_HEADER_LEN
252 }
253 }
254}
255
256impl<'a> PeekPacket<'a> for IpV4Packet<'a> {
257 fn peek(data: &'a [u8]) -> Result<(), Error> {
258 let data_len = data.len();
259 if data_len < Self::MIN_HEADER_LEN {
260 return Err(Error::PacketMalformed("IPv4: header too short".into()));
261 }
262
263 let len = ntoh_u16(&data[IpV4Field::TOTAL_LEN]).unwrap() as usize;
264 let payload_off = Self::read_header_len(data);
265
266 if len < payload_off {
267 return Err(Error::PacketMalformed("IPv4: payload too short".into()));
268 }
269 Ok(())
270 }
271
272 fn packet(data: &'a [u8]) -> Self {
273 let payload_off = Self::read_header_len(data);
274
275 Self {
276 src_address: &data[IpV4Field::SRC_ADDR],
277 dst_address: &data[IpV4Field::DST_ADDR],
278 protocol: data[IpV4Field::PROTOCOL][0],
279 payload: &data[payload_off..],
280 payload_off,
281 }
282 }
283}
284
285pub struct IpV6Field;
286impl IpV6Field {
287 pub const PAYLOAD_LEN: Field = 4..6;
288 pub const PROTOCOL: Field = 6..7;
289 pub const SRC_ADDR: Field = 8..24;
290 pub const DST_ADDR: Field = 24..40;
291 pub const PAYLOAD: Rest = 40..; }
293
294pub struct IpV6Packet<'a> {
295 pub src_address: &'a [u8],
296 dst_address: &'a [u8],
297 pub protocol: u8,
298 pub payload: &'a [u8],
299 pub next_header: IpV6NextHeader<'a>,
300}
301
302impl<'a> IpV6Packet<'a> {
303 pub const MIN_HEADER_LEN: usize = 40;
304
305 #[inline]
306 pub fn payload_off(&self) -> usize {
307 IpV6Field::PAYLOAD.start
308 }
309
310 pub fn inferred_dst_address(&self) -> &'a [u8] {
311 match &self.next_header {
312 IpV6NextHeader::IcmpV6(icmp_v6) => icmp_v6.dst_address().unwrap_or(self.dst_address),
313 IpV6NextHeader::Other => self.dst_address,
314 }
315 }
316}
317
318impl<'a> PeekPacket<'a> for IpV6Packet<'a> {
319 fn peek(data: &'a [u8]) -> Result<(), Error> {
320 let data_len = data.len();
321 if data_len < Self::MIN_HEADER_LEN {
322 return Err(Error::PacketMalformed("IPv6: header too short".into()));
323 }
324
325 let len = Self::MIN_HEADER_LEN + ntoh_u16(&data[IpV6Field::PAYLOAD_LEN]).unwrap() as usize;
326 if data_len < len {
327 return Err(Error::PacketMalformed("IPv6: payload too short".into()));
328 } else if len == Self::MIN_HEADER_LEN {
329 return Err(Error::ProtocolNotSupported("IPv6: jumbogram".into()));
330 }
331
332 if data[IpV6Field::PROTOCOL][0] == 58 {
333 IcmpV6Packet::peek(&data[IpV6Field::PAYLOAD])?;
334 };
335
336 Ok(())
337 }
338
339 fn packet(data: &'a [u8]) -> Self {
340 let payload = &data[IpV6Field::PAYLOAD];
341 let protocol = data[IpV6Field::PROTOCOL][0];
342 let next_header = match protocol {
343 58 => IpV6NextHeader::IcmpV6(IcmpV6Packet::packet(payload)),
344 _ => IpV6NextHeader::Other,
345 };
346
347 Self {
348 src_address: &data[IpV6Field::SRC_ADDR],
349 dst_address: &data[IpV6Field::DST_ADDR],
350 protocol,
351 payload,
352 next_header,
353 }
354 }
355}
356
357pub enum IpV6NextHeader<'a> {
358 IcmpV6(IcmpV6Packet<'a>),
359 Other,
360}
361
362pub struct IcmpV6Field;
363impl IcmpV6Field {
364 pub const TYPE: Field = 0..1;
365 pub const CODE: Field = 1..2;
366 pub const CHECKSUM: Field = 2..4;
367 pub const PAYLOAD: Rest = 4..;
368}
369
370pub struct IcmpV6Packet<'a> {
371 pub type_: u8,
372 pub message: IcmpV6Message<'a>,
373}
374
375impl<'a> IcmpV6Packet<'a> {
376 pub const MIN_HEADER_SIZE: usize = 4;
377
378 pub fn dst_address(&self) -> Option<&'a [u8]> {
379 match &self.message {
380 IcmpV6Message::NdpNeighborSolicitation { dst_address, .. } => Some(dst_address),
381 _ => None,
382 }
383 }
384}
385
386impl<'a> PeekPacket<'a> for IcmpV6Packet<'a> {
387 fn peek(data: &'a [u8]) -> Result<(), Error> {
388 let data_len = data.len();
389 if data_len < Self::MIN_HEADER_SIZE {
390 return Err(Error::PacketMalformed("ICMPv6: packet too short".into()));
391 }
392
393 match data[IcmpV6Field::TYPE][0] {
394 135 => {
395 if data_len < Self::MIN_HEADER_SIZE + 16 {
396 return Err(Error::PacketMalformed("ICMPv6: payload too short".into()));
397 }
398 }
399 _ => {
400 if data_len < Self::MIN_HEADER_SIZE {
401 return Err(Error::PacketMalformed("ICMPv6: payload too short".into()));
402 }
403 }
404 }
405
406 Ok(())
407 }
408
409 fn packet(data: &'a [u8]) -> Self {
410 let type_ = data[IcmpV6Field::TYPE][0];
411 let payload = &data[IcmpV6Field::PAYLOAD];
412 Self {
413 type_,
414 message: match type_ {
415 IcmpV6Message::NDP_ROUTER_SOLICITATION => IcmpV6Message::NdpRouterSolicitation {},
416 IcmpV6Message::NDP_ROUTER_ADVERTISEMENT => IcmpV6Message::NdpRouterAdvertisement {},
417 IcmpV6Message::NDP_NEIGHBOR_SOLICITATION => {
418 IcmpV6Message::NdpNeighborSolicitation {
419 dst_address: &payload[NdpNeighborSolicitationField::TARGET_ADDRESS],
420 }
421 }
422 IcmpV6Message::NDP_NEIGHBOR_ADVERTISEMENT => {
423 IcmpV6Message::NdpNeighborAdvertisement {}
424 }
425 IcmpV6Message::NDP_REDIRECT => IcmpV6Message::NdpRedirect {},
426 _ => IcmpV6Message::Other,
427 },
428 }
429 }
430}
431
432pub enum IcmpV6Message<'a> {
433 NdpRouterSolicitation {},
434 NdpRouterAdvertisement {},
435 NdpNeighborSolicitation { dst_address: &'a [u8] },
436 NdpNeighborAdvertisement {},
437 NdpRedirect {},
438 Other,
439}
440
441impl<'a> IcmpV6Message<'a> {
442 pub const NDP_ROUTER_SOLICITATION: u8 = 133;
443 pub const NDP_ROUTER_ADVERTISEMENT: u8 = 134;
444 pub const NDP_NEIGHBOR_SOLICITATION: u8 = 135;
445 pub const NDP_NEIGHBOR_ADVERTISEMENT: u8 = 136;
446 pub const NDP_REDIRECT: u8 = 137;
447}
448
449pub struct NdpNeighborSolicitationField;
450impl NdpNeighborSolicitationField {
451 pub const TARGET_ADDRESS: Field = 4..20;
452}
453
454pub struct NdpRouterAdvertisementField;
455impl NdpRouterAdvertisementField {
456 pub const CUR_HOP_LIMIT: Field = 0..1;
458 pub const M: BitField = (1, 0..1);
460 pub const O: BitField = (1, 1..2);
462 pub const ROUTER_LIFETIME: Field = 2..4;
464 pub const REACHABLE_TIME: Field = 4..8;
467 pub const RETRANS_TIMER: Field = 8..16;
469}
470
471pub struct NdpNeighborAdvertisementField;
472impl NdpNeighborAdvertisementField {
473 pub const R: BitField = (0, 0..1);
475 pub const S: BitField = (0, 1..2);
477 pub const O: BitField = (0, 2..3);
479 pub const TARGET_ADDRESS: Field = 4..20;
481}
482
483pub struct ArpField;
484impl ArpField {
485 pub const HTYPE: Field = 0..2;
487 pub const PTYPE: Field = 2..4;
489 pub const HLEN: Field = 4..5;
491 pub const PLEN: Field = 5..6;
493 pub const OP: Field = 6..8;
495 pub const SHA: Field = 8..14;
497 pub const SPA: Field = 14..18;
499 pub const THA: Field = 18..24;
501 pub const TPA: Field = 24..28;
503}
504
505pub struct ArpPacket<'a> {
506 inner: &'a [u8],
507}
508
509impl<'a> ArpPacket<'a> {
510 #[inline(always)]
511 pub fn get_field(&self, field: Field) -> &[u8] {
512 &self.inner[field]
513 }
514}
515
516impl<'a> PeekPacket<'a> for ArpPacket<'a> {
517 fn peek(data: &'a [u8]) -> Result<(), Error> {
518 if data.len() < 28 {
519 return Err(Error::PacketMalformed("ARP: packet too short".into()));
520 }
521 Ok(())
522 }
523
524 fn packet(data: &'a [u8]) -> Self {
525 Self { inner: data }
526 }
527}
528
529pub struct ArpPacketMut<'a> {
530 inner: &'a mut [u8],
531}
532
533impl<'a> ArpPacketMut<'a> {
534 pub fn set_field(&mut self, field: Field, value: &[u8]) {
535 let value = &value[..field.end];
536 self.inner[field].copy_from_slice(value);
537 }
538
539 pub fn freeze(self) -> ArpPacket<'a> {
540 ArpPacket { inner: self.inner }
541 }
542}
543
544pub struct TcpField;
545impl TcpField {
546 pub const SRC_PORT: Field = 0..2;
547 pub const DST_PORT: Field = 2..4;
548 pub const DATA_OFF: BitField = (12, 0..4);
549}
550
551pub struct TcpPacket<'a> {
552 pub src_port: &'a [u8],
553 pub dst_port: &'a [u8],
554 pub payload_off: usize,
555 pub payload_size: usize,
556}
557
558impl<'a> TcpPacket<'a> {
559 pub fn src_port(&self) -> u16 {
560 ntoh_u16(self.src_port).unwrap()
561 }
562
563 pub fn dst_port(&self) -> u16 {
564 ntoh_u16(self.dst_port).unwrap()
565 }
566}
567
568impl<'a> PeekPacket<'a> for TcpPacket<'a> {
569 fn peek(data: &'a [u8]) -> Result<(), Error> {
570 if data.len() < 20 {
571 return Err(Error::PacketMalformed("TCP: packet too short".into()));
572 }
573
574 let payload_off = get_bit_field(data, TcpField::DATA_OFF) as usize;
575 if data.len() < payload_off {
576 return Err(Error::PacketMalformed("TCP: packet too short".into()));
577 }
578
579 Ok(())
580 }
581
582 fn packet(data: &'a [u8]) -> Self {
583 let payload_off = get_bit_field(data, TcpField::DATA_OFF) as usize;
584 let payload_size = data.len().saturating_sub(payload_off);
585 Self {
586 src_port: &data[TcpField::SRC_PORT],
587 dst_port: &data[TcpField::DST_PORT],
588 payload_off,
589 payload_size,
590 }
591 }
592}
593
594pub struct UdpField;
595impl UdpField {
596 pub const SRC_PORT: Field = 0..2;
597 pub const DST_PORT: Field = 2..4;
598 pub const LEN: Field = 4..6;
599 pub const PAYLOAD: Rest = 8..;
600}
601
602pub struct UdpPacket<'a> {
603 pub src_port: &'a [u8],
604 pub dst_port: &'a [u8],
605 pub payload_size: usize,
606}
607
608impl<'a> UdpPacket<'a> {
609 pub fn src_port(&self) -> u16 {
610 ntoh_u16(self.src_port).unwrap()
611 }
612
613 pub fn dst_port(&self) -> u16 {
614 ntoh_u16(self.dst_port).unwrap()
615 }
616}
617
618impl<'a> PeekPacket<'a> for UdpPacket<'a> {
619 fn peek(data: &'a [u8]) -> Result<(), Error> {
620 if data.len() < 8 {
621 return Err(Error::PacketMalformed("UDP: packet too short".into()));
622 }
623
624 let len = ntoh_u16(&data[UdpField::LEN]).unwrap() as usize;
625 if data.len() < len {
626 return Err(Error::PacketMalformed("UDP: packet too short".into()));
627 }
628
629 Ok(())
630 }
631
632 fn packet(data: &'a [u8]) -> Self {
633 let payload_size = data.len().saturating_sub(UdpField::PAYLOAD.start);
634 Self {
635 src_port: &data[UdpField::SRC_PORT],
636 dst_port: &data[UdpField::DST_PORT],
637 payload_size,
638 }
639 }
640}
641
642#[inline(always)]
644pub fn ip_hton(ip: IpAddress) -> Box<[u8]> {
645 match ip {
646 IpAddress::Ipv4(ip) => ip.as_bytes().into(),
647 IpAddress::Ipv6(ip) => ip.as_bytes().into(),
648 _ => vec![0, 0, 0, 0].into(),
649 }
650}
651
652#[inline(always)]
654pub fn ip_ntoh(data: &[u8]) -> Option<IpAddress> {
655 if data.len() == 4 {
656 Some(IpAddress::v4(data[0], data[1], data[2], data[3]))
657 } else if data.len() == 16 {
658 Some(IpAddress::Ipv6(Ipv6Address::from_bytes(data)))
659 } else {
660 None
661 }
662}
663
664pub fn write_field(data: &mut [u8], field: Field, value: &[u8]) -> bool {
665 if value.len() == field.len() && data.len() >= field.end {
666 data[field].copy_from_slice(value);
667 true
668 } else {
669 false
670 }
671}
672
673#[inline(always)]
675pub fn read_bit_field(data: &[u8], bit_field: BitField) -> Option<u8> {
676 if data.len() >= bit_field.0 && bit_field.1.len() <= 8 {
677 Some(get_bit_field(data, bit_field))
678 } else {
679 None
680 }
681}
682
683#[inline(always)]
685pub fn write_bit_field(data: &mut [u8], bit_field: BitField, value: u8) -> bool {
686 if data.len() >= bit_field.0 && bit_field.1.len() <= 8 {
687 set_bit_field(data, bit_field, value);
688 true
689 } else {
690 false
691 }
692}
693
694#[inline(always)]
695fn get_bit_field(data: &[u8], bit_field: BitField) -> u8 {
696 (data[bit_field.0] << bit_field.1.start) >> (8 - bit_field.1.len())
697}
698
699#[inline(always)]
700fn set_bit_field(data: &mut [u8], bit_field: BitField, value: u8) {
701 let bit_len = bit_field.1.len();
702 let mask = (0xff_u8 << (8 - bit_len)) >> bit_field.1.start;
703 data[bit_field.0] &= !mask;
704 data[bit_field.0] |= (value << (8 - bit_len)) >> bit_field.1.start;
705}
706
707macro_rules! impl_ntoh_n {
708 ($ident:ident, $ty:ty, $n:tt) => {
709 fn $ident(data: &[u8]) -> Option<$ty> {
710 match data.len() {
711 $n => {
712 let mut result = [0u8; $n];
713 result.copy_from_slice(&data[0..$n]);
714 Some(<$ty>::from_be_bytes(result))
715 }
716 _ => None,
717 }
718 }
719 };
720}
721
722impl_ntoh_n!(ntoh_u16, u16, 2);
723impl_ntoh_n!(ntoh_u32, u32, 4);
724impl_ntoh_n!(ntoh_u64, u64, 8);
725
726#[cfg(test)]
727mod tests {
728 use crate::packet::{get_bit_field, set_bit_field};
729
730 #[test]
731 fn change_bit_field() {
732 for len in 1..8 {
733 for off in 0..8 {
734 let mut bytes = [0u8; 1];
735 let range = off..8.min(off + len);
736 println!("range: {:?}", range);
737
738 set_bit_field(&mut bytes, (0, range.clone()), 0xff);
739 println!("byte: {:#010b}", bytes[0]);
740
741 assert_eq!(
742 get_bit_field(&bytes, (0, range.clone())),
743 0xff_u8 >> (8 - range.len())
744 );
745 }
746 }
747 }
748}