1use alloc::vec;
4use alloc::vec::Vec;
5use core::net::Ipv6Addr;
6
7use crate::types::IpProtocol;
8use crate::util::{read_u16be, read_u32be, write_u16be, write_u32be, BuildError};
9
10pub const IPV6_HEADER_LEN: usize = 40;
12
13const MAX_EXTENSION_DEPTH: usize = 8;
15
16#[derive(Debug, Clone)]
18pub struct Ipv6Packet<'a> {
19 buf: &'a [u8],
20}
21
22impl<'a> Ipv6Packet<'a> {
23 pub fn new(buf: &'a [u8]) -> Option<Self> {
24 if buf.len() < IPV6_HEADER_LEN {
25 return None;
26 }
27 Some(Self { buf })
28 }
29
30 #[inline]
31 pub fn version(&self) -> u8 {
32 self.buf[0] >> 4
33 }
34
35 #[inline]
36 pub fn traffic_class(&self) -> u8 {
37 ((self.buf[0] & 0x0F) << 4) | (self.buf[1] >> 4)
38 }
39
40 #[inline]
41 pub fn flow_label(&self) -> u32 {
42 read_u32be(&self.buf[..4]) & 0x000F_FFFF
43 }
44
45 #[inline]
46 pub fn payload_length(&self) -> u16 {
47 read_u16be(&self.buf[4..6])
48 }
49
50 #[inline]
51 pub fn next_header(&self) -> IpProtocol {
52 IpProtocol::from(self.buf[6])
53 }
54
55 #[inline]
56 pub fn hop_limit(&self) -> u8 {
57 self.buf[7]
58 }
59
60 #[inline]
61 pub fn source(&self) -> Ipv6Addr {
62 let b: [u8; 16] = self.buf[8..24].try_into().unwrap();
63 Ipv6Addr::from(b)
64 }
65
66 #[inline]
67 pub fn destination(&self) -> Ipv6Addr {
68 let b: [u8; 16] = self.buf[24..40].try_into().unwrap();
69 Ipv6Addr::from(b)
70 }
71
72 pub fn extension_headers(&self) -> Ipv6ExtensionHeadersIter<'a> {
74 Ipv6ExtensionHeadersIter {
75 next_header: self.next_header(),
76 data: &self.buf[IPV6_HEADER_LEN..],
77 depth: 0,
78 }
79 }
80
81 pub fn final_protocol(&self) -> IpProtocol {
83 let mut next = self.next_header();
84 let mut remaining = &self.buf[IPV6_HEADER_LEN..];
85 for _ in 0..MAX_EXTENSION_DEPTH {
86 if !is_extension_header(next) {
87 return next;
88 }
89 if remaining.len() < 2 {
90 break;
91 }
92 let hdr_len = extension_header_len(next, remaining);
93 if hdr_len == 0 {
94 break;
95 }
96 next = IpProtocol::from(remaining[0]);
97 if remaining.len() < hdr_len {
98 break;
99 }
100 remaining = &remaining[hdr_len..];
101 }
102 next
103 }
104
105 pub fn payload(&self) -> &'a [u8] {
107 let mut remaining = &self.buf[IPV6_HEADER_LEN..];
108 let mut next = self.next_header();
109 for _ in 0..MAX_EXTENSION_DEPTH {
110 if !is_extension_header(next) {
111 return remaining;
112 }
113 if remaining.len() < 2 {
114 return &[];
115 }
116 let hdr_len = extension_header_len(next, remaining);
117 if remaining.len() < hdr_len {
118 return &[];
119 }
120 next = IpProtocol::from(remaining[0]);
121 remaining = &remaining[hdr_len..];
122 }
123 remaining
124 }
125}
126
127fn is_extension_header(proto: IpProtocol) -> bool {
128 matches!(proto, IpProtocol::Unknown(0 | 43 | 44 | 60))
129}
130
131fn extension_header_len(proto: IpProtocol, data: &[u8]) -> usize {
132 match proto {
133 IpProtocol::Unknown(0 | 60) => (data[1] as usize + 1) * 8,
134 IpProtocol::Unknown(43) => (data[1] as usize + 1) * 8,
135 IpProtocol::Unknown(44) => 8,
136 _ => 0,
137 }
138}
139
140#[derive(Debug, Clone)]
142pub enum Ipv6ExtensionHeader<'a> {
143 HopByHop { next_header: IpProtocol, data: &'a [u8] },
144 Routing { next_header: IpProtocol, routing_type: u8, segments_left: u8, data: &'a [u8] },
145 Fragment { next_header: IpProtocol, fragment_offset: u16, more_fragments: bool, id: u32 },
146 Destination { next_header: IpProtocol, data: &'a [u8] },
147}
148
149pub struct Ipv6ExtensionHeadersIter<'a> {
151 next_header: IpProtocol,
152 data: &'a [u8],
153 depth: usize,
154}
155
156impl<'a> Iterator for Ipv6ExtensionHeadersIter<'a> {
157 type Item = Ipv6ExtensionHeader<'a>;
158
159 fn next(&mut self) -> Option<Self::Item> {
160 if self.depth >= MAX_EXTENSION_DEPTH || !is_extension_header(self.next_header) {
161 return None;
162 }
163 if self.data.len() < 2 {
164 return None;
165 }
166
167 let current_next = IpProtocol::from(self.data[0]);
168 let hdr_len = extension_header_len(self.next_header, self.data);
169 if self.data.len() < hdr_len || hdr_len == 0 {
170 return None;
171 }
172
173 let hdr_data = &self.data[..hdr_len];
174 let item = match self.next_header {
175 IpProtocol::Unknown(0) => Ipv6ExtensionHeader::HopByHop {
176 next_header: current_next,
177 data: hdr_data,
178 },
179 IpProtocol::Unknown(43) => Ipv6ExtensionHeader::Routing {
180 next_header: current_next,
181 routing_type: hdr_data[2],
182 segments_left: hdr_data[3],
183 data: hdr_data,
184 },
185 IpProtocol::Unknown(44) => {
186 let offset = read_u16be(&hdr_data[2..4]);
187 Ipv6ExtensionHeader::Fragment {
188 next_header: current_next,
189 fragment_offset: (offset >> 3) & 0x1FFF,
190 more_fragments: offset & 0x01 != 0,
191 id: read_u32be(&hdr_data[4..8]),
192 }
193 }
194 IpProtocol::Unknown(60) => Ipv6ExtensionHeader::Destination {
195 next_header: current_next,
196 data: hdr_data,
197 },
198 _ => return None,
199 };
200
201 self.next_header = current_next;
202 self.data = &self.data[hdr_len..];
203 self.depth += 1;
204
205 Some(item)
206 }
207}
208
209pub struct Ipv6PacketBuilder {
214 buf: Vec<u8>,
215 ext_headers: Vec<(IpProtocol, Vec<u8>)>,
216 payload: Option<Vec<u8>>,
217}
218
219impl Default for Ipv6PacketBuilder {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225impl Ipv6PacketBuilder {
226 pub fn new() -> Self {
227 let mut buf = vec![0u8; IPV6_HEADER_LEN];
228 buf[0] = 0x60; Self { buf, ext_headers: Vec::new(), payload: None }
230 }
231
232 pub fn traffic_class(mut self, tc: u8) -> Self {
233 self.buf[0] = (self.buf[0] & 0xF0) | (tc >> 4);
234 self.buf[1] = (tc & 0x0F) << 4 | (self.buf[1] & 0x0F);
235 self
236 }
237
238 pub fn flow_label(mut self, label: u32) -> Self {
239 let val = read_u32be(&self.buf[..4]);
240 let updated = (val & 0xFFF0_0000) | (label & 0x000F_FFFF);
241 write_u32be(&mut self.buf[..4], updated);
242 self
243 }
244
245 pub fn next_header(mut self, proto: IpProtocol) -> Self {
246 self.buf[6] = proto.into();
247 self
248 }
249
250 pub fn hop_limit(mut self, hl: u8) -> Self {
251 self.buf[7] = hl;
252 self
253 }
254
255 pub fn source(mut self, addr: Ipv6Addr) -> Self {
256 self.buf[8..24].copy_from_slice(&addr.octets());
257 self
258 }
259
260 pub fn destination(mut self, addr: Ipv6Addr) -> Self {
261 self.buf[24..40].copy_from_slice(&addr.octets());
262 self
263 }
264
265 pub fn add_extension_header(mut self, proto: IpProtocol, data: &[u8]) -> Self {
266 if proto == IpProtocol::Unknown(44) && data.len() != 8 {
268 return self;
269 }
270 if data.len() < 2 {
272 return self;
273 }
274 self.ext_headers.push((proto, data.to_vec()));
275 self
276 }
277
278 pub fn payload(mut self, data: &[u8]) -> Result<Self, BuildError> {
279 if data.len() > 65535 {
280 return Err(BuildError::PayloadTooLarge { max: 65535, actual: data.len() });
281 }
282 self.payload = Some(data.to_vec());
283 Ok(self)
284 }
285
286 pub fn build(mut self) -> Vec<u8> {
287 if self.ext_headers.len() > MAX_EXTENSION_DEPTH {
289 self.ext_headers.truncate(MAX_EXTENSION_DEPTH);
290 }
291
292 let final_proto: u8 = self.buf[6];
293
294 let mut total_ext_len = 0usize;
295 let mut ext_data = Vec::new();
296
297 if !self.ext_headers.is_empty() {
300 self.buf[6] = self.ext_headers[0].0.into();
302
303 for i in 0..self.ext_headers.len() {
304 let (_proto, ref data) = self.ext_headers[i];
305 let mut hdr = Vec::with_capacity(data.len());
306 hdr.push(if i + 1 < self.ext_headers.len() {
307 self.ext_headers[i + 1].0.into()
308 } else {
309 final_proto
310 });
311 hdr.extend_from_slice(&data[1..]); ext_data.extend_from_slice(&hdr);
313 total_ext_len += hdr.len();
314 }
315 }
316
317 let payload_len = total_ext_len + self.payload.as_ref().map_or(0, |p| p.len());
318 write_u16be(&mut self.buf[4..6], payload_len as u16);
319
320 let mut packet = self.buf;
321 packet.extend_from_slice(&ext_data);
322 if let Some(p) = self.payload {
323 packet.extend_from_slice(&p);
324 }
325 packet
326 }
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 const SAMPLE_IPV6: &[u8] = &[
335 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ];
344
345 #[test]
346 fn parse_ipv6() {
347 let pkt = Ipv6Packet::new(SAMPLE_IPV6).unwrap();
348 assert_eq!(pkt.version(), 6);
349 assert_eq!(pkt.next_header(), IpProtocol::Icmpv6);
350 assert_eq!(pkt.hop_limit(), 64);
351 assert_eq!(pkt.source(), Ipv6Addr::LOCALHOST);
352 assert_eq!(pkt.destination(), Ipv6Addr::LOCALHOST);
353 assert_eq!(pkt.payload_length(), 8);
354 }
355
356 #[test]
357 fn parse_too_short() {
358 assert!(Ipv6Packet::new(&[0u8; 39]).is_none());
359 assert!(Ipv6Packet::new(&[]).is_none());
360 }
361
362 #[test]
363 fn build_and_parse_roundtrip() {
364 let src = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
365 let dst = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2);
366 let pkt_bytes = Ipv6PacketBuilder::new()
367 .source(src)
368 .destination(dst)
369 .hop_limit(128)
370 .next_header(IpProtocol::Tcp)
371 .payload(&[0xAA, 0xBB])
372 .unwrap()
373 .build();
374
375 let pkt = Ipv6Packet::new(&pkt_bytes).unwrap();
376 assert_eq!(pkt.source(), src);
377 assert_eq!(pkt.destination(), dst);
378 assert_eq!(pkt.hop_limit(), 128);
379 assert_eq!(pkt.next_header(), IpProtocol::Tcp);
380 assert_eq!(pkt.payload(), &[0xAA, 0xBB]);
381 }
382
383 #[test]
384 fn no_ext_headers() {
385 let pkt = Ipv6Packet::new(SAMPLE_IPV6).unwrap();
386 let headers: Vec<_> = pkt.extension_headers().collect();
387 assert!(headers.is_empty());
388 assert_eq!(pkt.final_protocol(), IpProtocol::Icmpv6);
389 }
390
391 #[test]
393 fn single_ext_header_hop_by_hop() {
394 let hbh_data: &[u8] = &[
396 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 ];
398 let payload = &[0xAA, 0xBB, 0xCC, 0xDD];
399 let src = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
400 let dst = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2);
401
402 let pkt_bytes = Ipv6PacketBuilder::new()
403 .source(src)
404 .destination(dst)
405 .hop_limit(64)
406 .next_header(IpProtocol::Icmpv6)
407 .add_extension_header(IpProtocol::Unknown(0), hbh_data)
408 .payload(payload)
409 .unwrap()
410 .build();
411
412 let pkt = Ipv6Packet::new(&pkt_bytes).unwrap();
413 assert_eq!(pkt.next_header(), IpProtocol::Unknown(0));
414 assert_eq!(pkt.final_protocol(), IpProtocol::Icmpv6);
415 assert_eq!(pkt.payload(), payload);
416
417 let ext: Vec<_> = pkt.extension_headers().collect();
418 assert_eq!(ext.len(), 1);
419 match &ext[0] {
420 Ipv6ExtensionHeader::HopByHop { next_header, .. } => {
421 assert_eq!(*next_header, IpProtocol::Icmpv6);
422 }
423 _ => panic!("expected HopByHop"),
424 }
425 }
426
427 #[test]
429 fn multi_ext_header_chain() {
430 let hbh: &[u8] = &[0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let routing: &[u8] = &[0x2C, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00]; let fragment: &[u8] = &[0x06, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x42]; let pkt_bytes = Ipv6PacketBuilder::new()
435 .source(Ipv6Addr::LOCALHOST)
436 .destination(Ipv6Addr::LOCALHOST)
437 .next_header(IpProtocol::Tcp)
438 .add_extension_header(IpProtocol::Unknown(0), hbh)
439 .add_extension_header(IpProtocol::Unknown(43), routing)
440 .add_extension_header(IpProtocol::Unknown(44), fragment)
441 .payload(&[0x01, 0x02])
442 .unwrap()
443 .build();
444
445 let pkt = Ipv6Packet::new(&pkt_bytes).unwrap();
446 assert_eq!(pkt.final_protocol(), IpProtocol::Tcp);
447
448 let ext: Vec<_> = pkt.extension_headers().collect();
449 assert_eq!(ext.len(), 3);
450 assert!(matches!(ext[0], Ipv6ExtensionHeader::HopByHop { .. }));
451 match &ext[1] {
452 Ipv6ExtensionHeader::Routing { routing_type, segments_left, .. } => {
453 assert_eq!(*routing_type, 0);
454 assert_eq!(*segments_left, 2);
455 }
456 _ => panic!("expected Routing"),
457 }
458 match &ext[2] {
459 Ipv6ExtensionHeader::Fragment { fragment_offset, more_fragments, id, .. } => {
460 assert_eq!(*fragment_offset, 1);
461 assert!(more_fragments);
462 assert_eq!(*id, 0x42);
463 }
464 _ => panic!("expected Fragment"),
465 }
466 }
467
468 #[test]
470 fn extension_header_depth_limit() {
471 let mut pkt_bytes = Ipv6PacketBuilder::new()
474 .source(Ipv6Addr::LOCALHOST)
475 .destination(Ipv6Addr::LOCALHOST)
476 .next_header(IpProtocol::Tcp);
477 for _ in 0..9 {
478 pkt_bytes = pkt_bytes.add_extension_header(
479 IpProtocol::Unknown(0),
480 &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
481 );
482 }
483 let pkt_bytes = pkt_bytes.payload(&[0x99]).unwrap().build();
484
485 let pkt = Ipv6Packet::new(&pkt_bytes).unwrap();
486 let count = pkt.extension_headers().count();
488 assert_eq!(count, 8, "iterator should stop at MAX_EXTENSION_DEPTH (8)");
489 }
490
491 #[test]
493 fn builder_rejects_invalid_ext_header_data() {
494 let pkt = Ipv6PacketBuilder::new()
496 .source(Ipv6Addr::LOCALHOST)
497 .destination(Ipv6Addr::LOCALHOST)
498 .next_header(IpProtocol::Tcp)
499 .add_extension_header(IpProtocol::Unknown(44), &[0x06, 0x00, 0x00]) .payload(&[0xAA])
501 .unwrap()
502 .build();
503 let parsed = Ipv6Packet::new(&pkt).unwrap();
504 assert_eq!(parsed.extension_headers().count(), 0);
505
506 let pkt = Ipv6PacketBuilder::new()
508 .source(Ipv6Addr::LOCALHOST)
509 .destination(Ipv6Addr::LOCALHOST)
510 .next_header(IpProtocol::Tcp)
511 .add_extension_header(IpProtocol::Unknown(0), &[0x06]) .payload(&[0xAA])
513 .unwrap()
514 .build();
515 let parsed = Ipv6Packet::new(&pkt).unwrap();
516 assert_eq!(parsed.extension_headers().count(), 0);
517 }
518
519 #[test]
521 fn builder_fragment_ext_header_roundtrip() {
522 let frag: &[u8] = &[0x06, 0x00, 0x00, 0x09, 0x12, 0x34, 0x56, 0x78];
523 let pkt = Ipv6PacketBuilder::new()
524 .source(Ipv6Addr::LOCALHOST)
525 .destination(Ipv6Addr::LOCALHOST)
526 .next_header(IpProtocol::Tcp)
527 .add_extension_header(IpProtocol::Unknown(44), frag)
528 .payload(&[0xCC])
529 .unwrap()
530 .build();
531 let parsed = Ipv6Packet::new(&pkt).unwrap();
532 let ext: Vec<_> = parsed.extension_headers().collect();
533 assert_eq!(ext.len(), 1);
534 match &ext[0] {
535 Ipv6ExtensionHeader::Fragment { fragment_offset, more_fragments, id, .. } => {
536 assert_eq!(*fragment_offset, 1);
537 assert!(more_fragments);
538 assert_eq!(*id, 0x12345678);
539 }
540 _ => panic!("expected Fragment"),
541 }
542 }
543
544 #[test]
546 fn parse_single_ext_header() {
547 let mut data = vec![
549 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
559 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0xAA, 0xBB,
563 ];
564 data[4] = 0x00;
566 data[5] = 10;
567
568 let pkt = Ipv6Packet::new(&data).unwrap();
569 assert_eq!(pkt.next_header(), IpProtocol::Unknown(0));
570 assert_eq!(pkt.final_protocol(), IpProtocol::Icmpv6);
571 assert_eq!(pkt.payload(), &[0xAA, 0xBB]);
572
573 let ext: Vec<_> = pkt.extension_headers().collect();
574 assert_eq!(ext.len(), 1);
575 }
576}