stackforge_core/layer/ipv6/
builder.rs1use std::net::Ipv6Addr;
22
23use super::IPV6_HEADER_LEN;
24
25#[derive(Debug, Clone)]
27pub struct Ipv6Builder {
28 traffic_class: u8,
30 flow_label: u32,
32 next_header: u8,
34 hop_limit: u8,
36 src: Ipv6Addr,
38 dst: Ipv6Addr,
40 payload: Vec<u8>,
42 auto_length: bool,
44 payload_len_override: Option<u16>,
46}
47
48impl Default for Ipv6Builder {
49 fn default() -> Self {
50 Self {
51 traffic_class: 0,
52 flow_label: 0,
53 next_header: 59, hop_limit: 64,
55 src: Ipv6Addr::UNSPECIFIED,
56 dst: Ipv6Addr::UNSPECIFIED,
57 payload: Vec::new(),
58 auto_length: true,
59 payload_len_override: None,
60 }
61 }
62}
63
64impl Ipv6Builder {
65 #[must_use]
67 pub fn new() -> Self {
68 Self::default()
69 }
70
71 #[must_use]
75 pub fn src(mut self, src: Ipv6Addr) -> Self {
76 self.src = src;
77 self
78 }
79
80 #[must_use]
82 pub fn dst(mut self, dst: Ipv6Addr) -> Self {
83 self.dst = dst;
84 self
85 }
86
87 #[must_use]
89 pub fn hop_limit(mut self, hlim: u8) -> Self {
90 self.hop_limit = hlim;
91 self
92 }
93
94 #[must_use]
96 pub fn traffic_class(mut self, tc: u8) -> Self {
97 self.traffic_class = tc;
98 self
99 }
100
101 #[must_use]
103 pub fn flow_label(mut self, fl: u32) -> Self {
104 self.flow_label = fl & 0x000F_FFFF;
105 self
106 }
107
108 #[must_use]
110 pub fn next_header(mut self, nh: u8) -> Self {
111 self.next_header = nh;
112 self
113 }
114
115 pub fn payload<T: Into<Vec<u8>>>(mut self, data: T) -> Self {
117 self.payload = data.into();
118 self
119 }
120
121 #[must_use]
123 pub fn auto_length(mut self, auto: bool) -> Self {
124 self.auto_length = auto;
125 self
126 }
127
128 #[must_use]
132 pub fn payload_len(mut self, len: u16) -> Self {
133 self.payload_len_override = Some(len);
134 self.auto_length = false;
135 self
136 }
137
138 #[must_use]
142 pub fn header_size(&self) -> usize {
143 IPV6_HEADER_LEN
144 }
145
146 #[must_use]
148 pub fn packet_size(&self) -> usize {
149 IPV6_HEADER_LEN + self.payload.len()
150 }
151
152 #[must_use]
167 pub fn build(&self) -> Vec<u8> {
168 let total = self.packet_size();
169 let mut buf = vec![0u8; total];
170
171 buf[0] = 0x60 | ((self.traffic_class >> 4) & 0x0F);
173
174 buf[1] = ((self.traffic_class & 0x0F) << 4) | (((self.flow_label >> 16) & 0x0F) as u8);
176
177 buf[2] = ((self.flow_label >> 8) & 0xFF) as u8;
179 buf[3] = (self.flow_label & 0xFF) as u8;
180
181 let plen: u16 = if self.auto_length {
183 self.payload.len() as u16
184 } else {
185 self.payload_len_override
186 .unwrap_or(self.payload.len() as u16)
187 };
188 buf[4] = (plen >> 8) as u8;
189 buf[5] = (plen & 0xFF) as u8;
190
191 buf[6] = self.next_header;
193
194 buf[7] = self.hop_limit;
196
197 buf[8..24].copy_from_slice(&self.src.octets());
199
200 buf[24..40].copy_from_slice(&self.dst.octets());
202
203 if !self.payload.is_empty() {
205 buf[40..40 + self.payload.len()].copy_from_slice(&self.payload);
206 }
207
208 buf
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_ipv6_builder_basic() {
218 let src = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1);
219 let dst = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2);
220
221 let bytes = Ipv6Builder::new()
222 .src(src)
223 .dst(dst)
224 .hop_limit(64)
225 .next_header(58)
226 .build();
227
228 assert_eq!(bytes.len(), 40);
229 assert_eq!((bytes[0] >> 4) & 0x0F, 6);
231 assert_eq!(bytes[6], 58);
233 assert_eq!(bytes[7], 64);
235 let mut src_bytes = [0u8; 16];
237 src_bytes.copy_from_slice(&bytes[8..24]);
238 assert_eq!(Ipv6Addr::from(src_bytes), src);
239 let mut dst_bytes = [0u8; 16];
241 dst_bytes.copy_from_slice(&bytes[24..40]);
242 assert_eq!(Ipv6Addr::from(dst_bytes), dst);
243 }
244
245 #[test]
246 fn test_ipv6_builder_with_payload() {
247 let payload = b"hello world";
248 let bytes = Ipv6Builder::new()
249 .src(Ipv6Addr::LOCALHOST)
250 .dst(Ipv6Addr::LOCALHOST)
251 .next_header(59)
252 .payload(payload.as_ref())
253 .build();
254
255 assert_eq!(bytes.len(), 40 + payload.len());
256 let plen = u16::from_be_bytes([bytes[4], bytes[5]]);
258 assert_eq!(plen as usize, payload.len());
259 assert_eq!(&bytes[40..], payload.as_ref());
261 }
262
263 #[test]
264 fn test_ipv6_traffic_class() {
265 let bytes = Ipv6Builder::new().traffic_class(0xAB).build();
266
267 assert_eq!(bytes[0], 0x6A);
269 assert_eq!(bytes[1] & 0xF0, 0xB0);
271 let tc = ((bytes[0] & 0x0F) << 4) | ((bytes[1] >> 4) & 0x0F);
273 assert_eq!(tc, 0xAB);
274 }
275
276 #[test]
277 fn test_ipv6_flow_label() {
278 let bytes = Ipv6Builder::new().flow_label(0x12345).build();
279
280 assert_eq!(bytes[1] & 0x0F, 0x01);
282 assert_eq!(bytes[2], 0x23);
284 assert_eq!(bytes[3], 0x45);
286 let fl = ((bytes[1] as u32 & 0x0F) << 16) | ((bytes[2] as u32) << 8) | (bytes[3] as u32);
288 assert_eq!(fl, 0x12345);
289 }
290
291 #[test]
292 fn test_ipv6_manual_payload_len() {
293 let bytes = Ipv6Builder::new()
294 .payload(vec![0u8; 20])
295 .payload_len(100) .build();
297
298 let plen = u16::from_be_bytes([bytes[4], bytes[5]]);
299 assert_eq!(plen, 100);
300 }
301
302 #[test]
303 fn test_ipv6_header_size() {
304 let builder = Ipv6Builder::new();
305 assert_eq!(builder.header_size(), 40);
306 }
307}