1use alloc::vec;
4use alloc::vec::Vec;
5use core::net::Ipv6Addr;
6
7use crate::types::IpProtocol;
8use crate::util::{internet_checksum, pseudo_header_checksum, seal_internet_checksum, seal_transport_checksum, read_u16be, read_u32be, write_u16be, PacketBuilder};
9
10pub const ICMP_HEADER_LEN: usize = 8;
15
16pub const ICMP_TYPE_ECHO_REPLY: u8 = 0;
17pub const ICMP_TYPE_DEST_UNREACH: u8 = 3;
18pub const ICMP_TYPE_ECHO_REQUEST: u8 = 8;
19pub const ICMP_TYPE_TIME_EXCEEDED: u8 = 11;
20
21pub const ICMPV6_HEADER_LEN: usize = 8;
26
27pub const ICMPV6_TYPE_ECHO_REQUEST: u8 = 128;
28pub const ICMPV6_TYPE_ECHO_REPLY: u8 = 129;
29pub const ICMPV6_TYPE_ROUTER_SOLICIT: u8 = 133;
30pub const ICMPV6_TYPE_ROUTER_ADVERT: u8 = 134;
31pub const ICMPV6_TYPE_NEIGHBOR_SOLICIT: u8 = 135;
32pub const ICMPV6_TYPE_NEIGHBOR_ADVERT: u8 = 136;
33
34#[derive(Debug, Clone)]
40pub enum IcmpMessage<'a> {
41 EchoReply {
42 identifier: u16,
43 sequence_number: u16,
44 data: &'a [u8],
45 },
46 EchoRequest {
47 identifier: u16,
48 sequence_number: u16,
49 data: &'a [u8],
50 },
51 DestUnreachable {
52 code: u8,
53 data: &'a [u8],
54 },
55 TimeExceeded {
56 code: u8,
57 data: &'a [u8],
58 },
59 Unknown {
60 type_: u8,
61 code: u8,
62 data: &'a [u8],
63 },
64}
65
66#[derive(Debug, Clone)]
68pub struct IcmpPacket<'a> {
69 buf: &'a [u8],
70}
71
72impl<'a> IcmpPacket<'a> {
73 crate::parser_new!(ICMP_HEADER_LEN);
74
75 #[inline]
77 pub fn as_bytes(&self) -> &'a [u8] { self.buf }
78
79 #[inline]
80 pub fn type_(&self) -> u8 {
81 self.buf[0]
82 }
83
84 #[inline]
85 pub fn code(&self) -> u8 {
86 self.buf[1]
87 }
88
89 #[inline]
90 pub fn checksum(&self) -> u16 {
91 read_u16be(&self.buf[2..4])
92 }
93
94 #[inline]
96 pub fn rest_of_header(&self) -> u32 {
97 read_u32be(&self.buf[4..8])
98 }
99
100 #[inline]
102 pub fn payload(&self) -> &'a [u8] {
103 &self.buf[ICMP_HEADER_LEN..]
104 }
105
106 pub fn verify_checksum(&self) -> bool {
108 internet_checksum(self.buf) == 0
109 }
110
111 pub fn message(&self) -> IcmpMessage<'a> {
113 let payload = self.payload();
114 let roh = self.rest_of_header();
115 match self.type_() {
116 ICMP_TYPE_ECHO_REPLY => IcmpMessage::EchoReply {
117 identifier: (roh >> 16) as u16,
118 sequence_number: roh as u16,
119 data: payload,
120 },
121 ICMP_TYPE_ECHO_REQUEST => IcmpMessage::EchoRequest {
122 identifier: (roh >> 16) as u16,
123 sequence_number: roh as u16,
124 data: payload,
125 },
126 ICMP_TYPE_DEST_UNREACH => IcmpMessage::DestUnreachable {
127 code: self.code(),
128 data: payload,
129 },
130 ICMP_TYPE_TIME_EXCEEDED => IcmpMessage::TimeExceeded {
131 code: self.code(),
132 data: payload,
133 },
134 _ => IcmpMessage::Unknown {
135 type_: self.type_(),
136 code: self.code(),
137 data: payload,
138 },
139 }
140 }
141}
142
143pub struct IcmpPacketBuilder {
148 buf: Vec<u8>,
149 payload: Option<Vec<u8>>,
150}
151
152impl Default for IcmpPacketBuilder {
153 fn default() -> Self {
154 Self::new(ICMP_TYPE_ECHO_REQUEST, 0)
155 }
156}
157
158impl IcmpPacketBuilder {
159 pub fn new(type_: u8, code: u8) -> Self {
160 let mut buf = vec![0u8; ICMP_HEADER_LEN];
161 buf[0] = type_;
162 buf[1] = code;
163 Self { buf, payload: None }
164 }
165
166 pub fn echo_request() -> Self {
168 Self::new(ICMP_TYPE_ECHO_REQUEST, 0)
169 }
170
171 pub fn echo_reply() -> Self {
173 Self::new(ICMP_TYPE_ECHO_REPLY, 0)
174 }
175
176 pub fn code(mut self, code: u8) -> Self {
177 self.buf[1] = code;
178 self
179 }
180
181 pub fn identifier(mut self, id: u16) -> Self {
182 write_u16be(&mut self.buf[4..6], id);
183 self
184 }
185
186 pub fn sequence_number(mut self, seq: u16) -> Self {
187 write_u16be(&mut self.buf[6..8], seq);
188 self
189 }
190
191 pub fn payload(mut self, data: &[u8]) -> Self {
192 self.payload = Some(data.to_vec());
193 self
194 }
195
196 pub fn build(self) -> Vec<u8> {
197 <Self as PacketBuilder>::build(self)
198 }
199}
200
201impl PacketBuilder for IcmpPacketBuilder {
202 type Output = Vec<u8>;
203
204 fn build(self) -> Vec<u8> {
205 let mut packet = self.buf;
206 if let Some(ref p) = self.payload {
207 packet.extend_from_slice(p);
208 }
209 seal_internet_checksum(&mut packet, 2);
210 packet
211 }
212}
213
214#[derive(Debug, Clone)]
220pub enum Icmpv6Message<'a> {
221 EchoRequest {
222 identifier: u16,
223 sequence_number: u16,
224 data: &'a [u8],
225 },
226 EchoReply {
227 identifier: u16,
228 sequence_number: u16,
229 data: &'a [u8],
230 },
231 NeighborSolicitation {
232 target_address: Ipv6Addr,
233 options: &'a [u8],
234 },
235 NeighborAdvertisement {
236 flags: u8,
237 target_address: Ipv6Addr,
238 options: &'a [u8],
239 },
240 RouterSolicitation {
241 options: &'a [u8],
242 },
243 RouterAdvertisement {
244 hop_limit: u8,
245 flags: u8,
246 router_lifetime: u16,
247 reachable_time: u32,
248 retrans_timer: u32,
249 options: &'a [u8],
250 },
251 Unknown {
252 type_: u8,
253 code: u8,
254 data: &'a [u8],
255 },
256}
257
258#[derive(Debug, Clone)]
260pub struct Icmpv6Packet<'a> {
261 buf: &'a [u8],
262}
263
264impl<'a> Icmpv6Packet<'a> {
265 crate::parser_new!(ICMPV6_HEADER_LEN);
266
267 #[inline]
269 pub fn as_bytes(&self) -> &'a [u8] { self.buf }
270
271 #[inline]
272 pub fn type_(&self) -> u8 {
273 self.buf[0]
274 }
275
276 #[inline]
277 pub fn code(&self) -> u8 {
278 self.buf[1]
279 }
280
281 #[inline]
282 pub fn checksum(&self) -> u16 {
283 read_u16be(&self.buf[2..4])
284 }
285
286 #[inline]
288 pub fn body(&self) -> &'a [u8] {
289 &self.buf[ICMPV6_HEADER_LEN..]
290 }
291
292 pub fn verify_checksum(&self, src: Ipv6Addr, dst: Ipv6Addr) -> bool {
294 let csum = pseudo_header_checksum(
295 &src.octets(),
296 &dst.octets(),
297 u8::from(IpProtocol::Icmpv6),
298 self.buf,
299 );
300 csum == 0
301 }
302
303 pub fn message(&self) -> Icmpv6Message<'a> {
305 let buf = self.buf;
306 match self.type_() {
307 ICMPV6_TYPE_ECHO_REQUEST => {
308 let id = if buf.len() >= 6 { read_u16be(&buf[4..6]) } else { 0 };
309 let seq = if buf.len() >= 8 { read_u16be(&buf[6..8]) } else { 0 };
310 let data = if buf.len() > 8 { &buf[8..] } else { &[] };
311 Icmpv6Message::EchoRequest { identifier: id, sequence_number: seq, data }
312 }
313 ICMPV6_TYPE_ECHO_REPLY => {
314 let id = if buf.len() >= 6 { read_u16be(&buf[4..6]) } else { 0 };
315 let seq = if buf.len() >= 8 { read_u16be(&buf[6..8]) } else { 0 };
316 let data = if buf.len() > 8 { &buf[8..] } else { &[] };
317 Icmpv6Message::EchoReply { identifier: id, sequence_number: seq, data }
318 }
319 ICMPV6_TYPE_NEIGHBOR_SOLICIT => {
320 let target = if buf.len() >= 24 {
321 let b: [u8; 16] = buf[8..24].try_into().unwrap();
322 Ipv6Addr::from(b)
323 } else {
324 Ipv6Addr::UNSPECIFIED
325 };
326 let options = if buf.len() > 24 { &buf[24..] } else { &[] };
327 Icmpv6Message::NeighborSolicitation { target_address: target, options }
328 }
329 ICMPV6_TYPE_NEIGHBOR_ADVERT => {
330 let flags = if buf.len() >= 8 { buf[4] } else { 0 };
331 let target = if buf.len() >= 24 {
332 let b: [u8; 16] = buf[8..24].try_into().unwrap();
333 Ipv6Addr::from(b)
334 } else {
335 Ipv6Addr::UNSPECIFIED
336 };
337 let options = if buf.len() > 24 { &buf[24..] } else { &[] };
338 Icmpv6Message::NeighborAdvertisement { flags, target_address: target, options }
339 }
340 ICMPV6_TYPE_ROUTER_SOLICIT => {
341 let options = if buf.len() > 8 { &buf[8..] } else { &[] };
342 Icmpv6Message::RouterSolicitation { options }
343 }
344 ICMPV6_TYPE_ROUTER_ADVERT => {
345 let hop_limit = if buf.len() >= 8 { buf[4] } else { 0 };
346 let flags = if buf.len() >= 8 { buf[5] } else { 0 };
347 let router_lifetime = if buf.len() >= 8 { read_u16be(&buf[6..8]) } else { 0 };
348 let reachable_time = if buf.len() >= 12 { read_u32be(&buf[8..12]) } else { 0 };
349 let retrans_timer = if buf.len() >= 16 { read_u32be(&buf[12..16]) } else { 0 };
350 let options = if buf.len() > 16 { &buf[16..] } else { &[] };
351 Icmpv6Message::RouterAdvertisement {
352 hop_limit, flags, router_lifetime, reachable_time, retrans_timer, options,
353 }
354 }
355 _ => Icmpv6Message::Unknown {
356 type_: self.type_(),
357 code: self.code(),
358 data: if buf.len() > 8 { &buf[8..] } else { &[] },
359 },
360 }
361 }
362}
363
364pub struct Icmpv6PacketBuilder {
369 buf: Vec<u8>,
370 body: Vec<u8>,
371}
372
373impl Default for Icmpv6PacketBuilder {
374 fn default() -> Self {
375 Self::new(ICMPV6_TYPE_ECHO_REQUEST, 0)
376 }
377}
378
379impl Icmpv6PacketBuilder {
380 pub fn new(type_: u8, code: u8) -> Self {
381 let mut buf = vec![0u8; ICMPV6_HEADER_LEN];
382 buf[0] = type_;
383 buf[1] = code;
384 Self { buf, body: Vec::new() }
385 }
386
387 pub fn echo_request() -> Self {
388 Self::new(ICMPV6_TYPE_ECHO_REQUEST, 0)
389 }
390
391 pub fn echo_reply() -> Self {
392 Self::new(ICMPV6_TYPE_ECHO_REPLY, 0)
393 }
394
395 pub fn code(mut self, code: u8) -> Self {
396 self.buf[1] = code;
397 self
398 }
399
400 pub fn identifier(mut self, id: u16) -> Self {
402 write_u16be(&mut self.buf[4..6], id);
403 self
404 }
405
406 pub fn sequence_number(mut self, seq: u16) -> Self {
408 write_u16be(&mut self.buf[6..8], seq);
409 self
410 }
411
412 pub fn body(mut self, data: &[u8]) -> Self {
414 self.body = data.to_vec();
415 self
416 }
417
418 pub fn build(self, src: Ipv6Addr, dst: Ipv6Addr) -> Vec<u8> {
420 let mut packet = self.buf;
421 packet.extend_from_slice(&self.body);
422 seal_transport_checksum(&mut packet, 2, &src.octets(), &dst.octets(), IpProtocol::Icmpv6.into());
423 packet
424 }
425}
426
427#[cfg(test)]
432mod tests {
433 use super::*;
434 use core::net::Ipv6Addr;
435
436 #[test]
439 fn parse_icmp_echo_request() {
440 let data: &[u8] = &[
442 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x41, 0x42, 0x43, 0x44, ];
446 let pkt = IcmpPacket::new(data).unwrap();
447 assert_eq!(pkt.type_(), 8);
448 assert_eq!(pkt.code(), 0);
449 assert_eq!(pkt.payload(), &[0x41, 0x42, 0x43, 0x44]);
450
451 match pkt.message() {
452 IcmpMessage::EchoRequest { identifier, sequence_number, data } => {
453 assert_eq!(identifier, 1);
454 assert_eq!(sequence_number, 2);
455 assert_eq!(data, &[0x41, 0x42, 0x43, 0x44]);
456 }
457 _ => panic!("expected EchoRequest"),
458 }
459 }
460
461 #[test]
462 fn parse_icmp_echo_reply() {
463 let data: &[u8] = &[
464 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, ];
467 let pkt = IcmpPacket::new(data).unwrap();
468 match pkt.message() {
469 IcmpMessage::EchoReply { identifier, sequence_number, .. } => {
470 assert_eq!(identifier, 3);
471 assert_eq!(sequence_number, 4);
472 }
473 _ => panic!("expected EchoReply"),
474 }
475 }
476
477 #[test]
478 fn parse_icmp_dest_unreachable() {
479 let data: &[u8] = &[
480 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, ];
484 let pkt = IcmpPacket::new(data).unwrap();
485 match pkt.message() {
486 IcmpMessage::DestUnreachable { code, data: d } => {
487 assert_eq!(code, 1);
488 assert_eq!(d, &[0x11, 0x22]);
489 }
490 _ => panic!("expected DestUnreachable"),
491 }
492 }
493
494 #[test]
495 fn parse_icmp_time_exceeded() {
496 let data: &[u8] = &[
497 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 ];
500 let pkt = IcmpPacket::new(data).unwrap();
501 match pkt.message() {
502 IcmpMessage::TimeExceeded { code, .. } => {
503 assert_eq!(code, 0);
504 }
505 _ => panic!("expected TimeExceeded"),
506 }
507 }
508
509 #[test]
510 fn parse_icmp_too_short() {
511 assert!(IcmpPacket::new(&[]).is_none());
512 assert!(IcmpPacket::new(&[0u8; 7]).is_none());
513 assert!(IcmpPacket::new(&[0u8; 8]).is_some());
514 }
515
516 #[test]
517 fn icmp_echo_build_and_verify_checksum() {
518 let pkt_bytes = IcmpPacketBuilder::echo_request()
519 .identifier(0x1234)
520 .sequence_number(1)
521 .payload(&[0xAA, 0xBB, 0xCC, 0xDD])
522 .build();
523
524 let pkt = IcmpPacket::new(&pkt_bytes).unwrap();
525 assert!(pkt.verify_checksum());
526 match pkt.message() {
527 IcmpMessage::EchoRequest { identifier, sequence_number, .. } => {
528 assert_eq!(identifier, 0x1234);
529 assert_eq!(sequence_number, 1);
530 }
531 _ => panic!("expected EchoRequest"),
532 }
533 }
534
535 #[test]
538 fn parse_icmpv6_echo_request() {
539 let data: &[u8] = &[
540 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0xDE, 0xAD, ];
544 let pkt = Icmpv6Packet::new(data).unwrap();
545 assert_eq!(pkt.type_(), 128);
546 match pkt.message() {
547 Icmpv6Message::EchoRequest { identifier, sequence_number, data } => {
548 assert_eq!(identifier, 5);
549 assert_eq!(sequence_number, 6);
550 assert_eq!(data, &[0xDE, 0xAD]);
551 }
552 _ => panic!("expected EchoRequest"),
553 }
554 }
555
556 #[test]
557 fn parse_icmpv6_echo_reply() {
558 let data: &[u8] = &[
559 0x81, 0x00, 0x00, 0x00,
560 0x00, 0x07, 0x00, 0x08,
561 ];
562 let pkt = Icmpv6Packet::new(data).unwrap();
563 match pkt.message() {
564 Icmpv6Message::EchoReply { identifier, sequence_number, .. } => {
565 assert_eq!(identifier, 7);
566 assert_eq!(sequence_number, 8);
567 }
568 _ => panic!("expected EchoReply"),
569 }
570 }
571
572 #[test]
573 fn parse_icmpv6_neighbor_solicitation() {
574 let target = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
575 let mut data = vec![0x87u8, 0x00, 0x00, 0x00]; data.extend_from_slice(&[0u8; 4]); data.extend_from_slice(&target.octets()); data.extend_from_slice(&[0x01, 0x01, 0x02, 0x03]); let pkt = Icmpv6Packet::new(&data).unwrap();
581 match pkt.message() {
582 Icmpv6Message::NeighborSolicitation { target_address, options } => {
583 assert_eq!(target_address, target);
584 assert_eq!(options.len(), 4);
585 }
586 _ => panic!("expected NeighborSolicitation"),
587 }
588 }
589
590 #[test]
591 fn parse_icmpv6_neighbor_advertisement() {
592 let target = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
593 let mut data = vec![0x88u8, 0x00, 0x00, 0x00]; data.push(0x60); data.extend_from_slice(&[0u8; 3]); data.extend_from_slice(&target.octets()); let pkt = Icmpv6Packet::new(&data).unwrap();
599 match pkt.message() {
600 Icmpv6Message::NeighborAdvertisement { flags, target_address, .. } => {
601 assert_eq!(flags, 0x60);
602 assert_eq!(target_address, target);
603 }
604 _ => panic!("expected NeighborAdvertisement"),
605 }
606 }
607
608 #[test]
609 fn parse_icmpv6_router_solicitation() {
610 let data: &[u8] = &[
611 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, ];
615 let pkt = Icmpv6Packet::new(data).unwrap();
616 match pkt.message() {
617 Icmpv6Message::RouterSolicitation { options } => {
618 assert_eq!(options.len(), 2);
619 }
620 _ => panic!("expected RouterSolicitation"),
621 }
622 }
623
624 #[test]
625 fn parse_icmpv6_router_advertisement() {
626 let mut data = vec![0x86u8, 0x00, 0x00, 0x00]; data.push(64); data.push(0x08); data.extend_from_slice(&0x0E10u16.to_be_bytes()); data.extend_from_slice(&0x0000EA60u32.to_be_bytes()); data.extend_from_slice(&0x00002710u32.to_be_bytes()); data.extend_from_slice(&[0x01, 0x01]); let pkt = Icmpv6Packet::new(&data).unwrap();
635 match pkt.message() {
636 Icmpv6Message::RouterAdvertisement {
637 hop_limit, flags, router_lifetime,
638 reachable_time, retrans_timer, options,
639 } => {
640 assert_eq!(hop_limit, 64);
641 assert_eq!(flags, 0x08);
642 assert_eq!(router_lifetime, 3600);
643 assert_eq!(reachable_time, 60000);
644 assert_eq!(retrans_timer, 10000);
645 assert_eq!(options.len(), 2);
646 }
647 _ => panic!("expected RouterAdvertisement"),
648 }
649 }
650
651 #[test]
652 fn parse_icmpv6_too_short() {
653 assert!(Icmpv6Packet::new(&[]).is_none());
654 assert!(Icmpv6Packet::new(&[0u8; 7]).is_none());
655 assert!(Icmpv6Packet::new(&[0u8; 8]).is_some());
656 }
657
658 #[test]
659 fn icmpv6_echo_build_and_verify_checksum() {
660 let src = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
661 let dst = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2);
662 let pkt_bytes = Icmpv6PacketBuilder::echo_request()
663 .identifier(0x42)
664 .sequence_number(1)
665 .build(src, dst);
666
667 let pkt = Icmpv6Packet::new(&pkt_bytes).unwrap();
668 assert!(pkt.verify_checksum(src, dst));
669 match pkt.message() {
670 Icmpv6Message::EchoRequest { identifier, sequence_number, .. } => {
671 assert_eq!(identifier, 0x42);
672 assert_eq!(sequence_number, 1);
673 }
674 _ => panic!("expected EchoRequest"),
675 }
676 }
677}