bgpkit_parser/models/bgp/flowspec/
nlri.rs

1use super::*;
2use crate::models::NetworkPrefix;
3use ipnet::IpNet;
4
5#[cfg(test)]
6use std::str::FromStr;
7
8/// Parse Flow-Spec NLRI from byte data according to RFC 8955/8956
9pub fn parse_flowspec_nlri(data: &[u8]) -> Result<FlowSpecNlri, FlowSpecError> {
10    let mut offset = 0;
11    let length = parse_length(data, &mut offset)?;
12
13    if offset + length as usize > data.len() {
14        return Err(FlowSpecError::InsufficientData);
15    }
16
17    let end_offset = offset + length as usize;
18    let mut components = Vec::new();
19    let mut last_type = 0u8;
20
21    while offset < end_offset {
22        let component_type = data[offset];
23        offset += 1;
24
25        // Verify ordering
26        if component_type <= last_type {
27            return Err(FlowSpecError::InvalidComponentOrder {
28                expected_greater_than: last_type,
29                found: component_type,
30            });
31        }
32        last_type = component_type;
33
34        let component = match component_type {
35            1 => parse_destination_prefix(data, &mut offset)?,
36            2 => parse_source_prefix(data, &mut offset)?,
37            3 => parse_ip_protocol(data, &mut offset)?,
38            4 => parse_port(data, &mut offset)?,
39            5 => parse_destination_port(data, &mut offset)?,
40            6 => parse_source_port(data, &mut offset)?,
41            7 => parse_icmp_type(data, &mut offset)?,
42            8 => parse_icmp_code(data, &mut offset)?,
43            9 => parse_tcp_flags(data, &mut offset)?,
44            10 => parse_packet_length(data, &mut offset)?,
45            11 => parse_dscp(data, &mut offset)?,
46            12 => parse_fragment(data, &mut offset)?,
47            13 => parse_flow_label(data, &mut offset)?,
48            _ => return Err(FlowSpecError::InvalidComponentType(component_type)),
49        };
50
51        components.push(component);
52    }
53
54    Ok(FlowSpecNlri { components })
55}
56
57/// Encode Flow-Spec NLRI to byte data
58pub fn encode_flowspec_nlri(nlri: &FlowSpecNlri) -> Vec<u8> {
59    let mut data = Vec::new();
60
61    // Encode each component
62    for component in &nlri.components {
63        data.push(component.component_type());
64
65        match component {
66            FlowSpecComponent::DestinationPrefix(prefix)
67            | FlowSpecComponent::SourcePrefix(prefix) => {
68                encode_prefix(prefix, &mut data);
69            }
70            FlowSpecComponent::DestinationIpv6Prefix { offset, prefix }
71            | FlowSpecComponent::SourceIpv6Prefix { offset, prefix } => {
72                encode_ipv6_prefix(*offset, prefix, &mut data);
73            }
74            FlowSpecComponent::IpProtocol(ops)
75            | FlowSpecComponent::Port(ops)
76            | FlowSpecComponent::DestinationPort(ops)
77            | FlowSpecComponent::SourcePort(ops)
78            | FlowSpecComponent::IcmpType(ops)
79            | FlowSpecComponent::IcmpCode(ops)
80            | FlowSpecComponent::PacketLength(ops)
81            | FlowSpecComponent::Dscp(ops)
82            | FlowSpecComponent::FlowLabel(ops) => {
83                encode_numeric_operators(ops, &mut data);
84            }
85            FlowSpecComponent::TcpFlags(ops) | FlowSpecComponent::Fragment(ops) => {
86                encode_bitmask_operators(ops, &mut data);
87            }
88        }
89    }
90
91    // Prepend length
92    let mut result = Vec::new();
93    encode_length(data.len() as u16, &mut result);
94    result.extend(data);
95    result
96}
97
98/// Parse length field (1 or 2 octets)
99pub(crate) fn parse_length(data: &[u8], offset: &mut usize) -> Result<u16, FlowSpecError> {
100    if *offset >= data.len() {
101        return Err(FlowSpecError::InsufficientData);
102    }
103
104    let first_byte = data[*offset];
105    *offset += 1;
106
107    if first_byte < 240 {
108        Ok(first_byte as u16)
109    } else {
110        if *offset >= data.len() {
111            return Err(FlowSpecError::InsufficientData);
112        }
113        let second_byte = data[*offset];
114        *offset += 1;
115        Ok(((first_byte & 0x0F) as u16) << 8 | second_byte as u16)
116    }
117}
118
119/// Encode length field (1 or 2 octets)
120pub(crate) fn encode_length(length: u16, data: &mut Vec<u8>) {
121    if length < 240 {
122        data.push(length as u8);
123    } else {
124        data.push(0xF0 | ((length >> 8) as u8));
125        data.push(length as u8);
126    }
127}
128
129/// Parse prefix component (Types 1 & 2)
130fn parse_prefix_component(data: &[u8], offset: &mut usize) -> Result<NetworkPrefix, FlowSpecError> {
131    if *offset >= data.len() {
132        return Err(FlowSpecError::InsufficientData);
133    }
134
135    let prefix_len = data[*offset];
136    *offset += 1;
137
138    let prefix_bytes = prefix_len.div_ceil(8);
139    if *offset + prefix_bytes as usize > data.len() {
140        return Err(FlowSpecError::InsufficientData);
141    }
142
143    let prefix_data = &data[*offset..*offset + prefix_bytes as usize];
144    *offset += prefix_bytes as usize;
145
146    // Construct prefix based on address family
147    let prefix = if prefix_bytes <= 4 {
148        // IPv4
149        let mut addr_bytes = [0u8; 4];
150        addr_bytes[..prefix_data.len()].copy_from_slice(prefix_data);
151        let addr = std::net::Ipv4Addr::from(addr_bytes);
152        let ipnet = IpNet::V4(
153            ipnet::Ipv4Net::new(addr, prefix_len).map_err(|_| FlowSpecError::InvalidPrefix)?,
154        );
155        NetworkPrefix::new(ipnet, None)
156    } else {
157        // IPv6
158        let mut addr_bytes = [0u8; 16];
159        addr_bytes[..prefix_data.len()].copy_from_slice(prefix_data);
160        let addr = std::net::Ipv6Addr::from(addr_bytes);
161        let ipnet = IpNet::V6(
162            ipnet::Ipv6Net::new(addr, prefix_len).map_err(|_| FlowSpecError::InvalidPrefix)?,
163        );
164        NetworkPrefix::new(ipnet, None)
165    };
166
167    Ok(prefix)
168}
169
170/// Parse destination prefix (Type 1)
171fn parse_destination_prefix(
172    data: &[u8],
173    offset: &mut usize,
174) -> Result<FlowSpecComponent, FlowSpecError> {
175    let prefix = parse_prefix_component(data, offset)?;
176    Ok(FlowSpecComponent::DestinationPrefix(prefix))
177}
178
179/// Parse source prefix (Type 2)
180fn parse_source_prefix(
181    data: &[u8],
182    offset: &mut usize,
183) -> Result<FlowSpecComponent, FlowSpecError> {
184    let prefix = parse_prefix_component(data, offset)?;
185    Ok(FlowSpecComponent::SourcePrefix(prefix))
186}
187
188/// Parse numeric operators sequence
189fn parse_numeric_operators(
190    data: &[u8],
191    offset: &mut usize,
192) -> Result<Vec<NumericOperator>, FlowSpecError> {
193    let mut operators = Vec::new();
194
195    loop {
196        if *offset >= data.len() {
197            return Err(FlowSpecError::InsufficientData);
198        }
199
200        let operator_byte = data[*offset];
201        *offset += 1;
202
203        let value_length = match (operator_byte >> 4) & 0x03 {
204            0 => 1,
205            1 => 2,
206            2 => 4,
207            3 => 8,
208            _ => {
209                return Err(FlowSpecError::InvalidValueLength(
210                    (operator_byte >> 4) & 0x03,
211                ))
212            }
213        };
214
215        if *offset + value_length > data.len() {
216            return Err(FlowSpecError::InsufficientData);
217        }
218
219        let value = read_value(&data[*offset..*offset + value_length]);
220        *offset += value_length;
221
222        let operator = NumericOperator::from_byte_and_value(operator_byte, value)?;
223        let is_end = operator.end_of_list;
224        operators.push(operator);
225
226        if is_end {
227            break;
228        }
229    }
230
231    Ok(operators)
232}
233
234/// Parse bitmask operators sequence
235fn parse_bitmask_operators(
236    data: &[u8],
237    offset: &mut usize,
238) -> Result<Vec<BitmaskOperator>, FlowSpecError> {
239    let mut operators = Vec::new();
240
241    loop {
242        if *offset >= data.len() {
243            return Err(FlowSpecError::InsufficientData);
244        }
245
246        let operator_byte = data[*offset];
247        *offset += 1;
248
249        let value_length = match (operator_byte >> 4) & 0x03 {
250            0 => 1,
251            1 => 2,
252            2 => 4,
253            3 => 8,
254            _ => {
255                return Err(FlowSpecError::InvalidValueLength(
256                    (operator_byte >> 4) & 0x03,
257                ))
258            }
259        };
260
261        if *offset + value_length > data.len() {
262            return Err(FlowSpecError::InsufficientData);
263        }
264
265        let bitmask = read_value(&data[*offset..*offset + value_length]);
266        *offset += value_length;
267
268        let operator = BitmaskOperator::from_byte_and_value(operator_byte, bitmask)?;
269        let is_end = operator.end_of_list;
270        operators.push(operator);
271
272        if is_end {
273            break;
274        }
275    }
276
277    Ok(operators)
278}
279
280/// Read value from bytes (big-endian)
281fn read_value(bytes: &[u8]) -> u64 {
282    let mut value = 0u64;
283    for &byte in bytes {
284        value = (value << 8) | byte as u64;
285    }
286    value
287}
288
289/// Write value to bytes (big-endian)
290fn write_value(value: u64, length: usize, data: &mut Vec<u8>) {
291    for i in (0..length).rev() {
292        data.push((value >> (i * 8)) as u8);
293    }
294}
295
296// Component parsers
297fn parse_ip_protocol(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
298    let operators = parse_numeric_operators(data, offset)?;
299    Ok(FlowSpecComponent::IpProtocol(operators))
300}
301
302fn parse_port(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
303    let operators = parse_numeric_operators(data, offset)?;
304    Ok(FlowSpecComponent::Port(operators))
305}
306
307fn parse_destination_port(
308    data: &[u8],
309    offset: &mut usize,
310) -> Result<FlowSpecComponent, FlowSpecError> {
311    let operators = parse_numeric_operators(data, offset)?;
312    Ok(FlowSpecComponent::DestinationPort(operators))
313}
314
315fn parse_source_port(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
316    let operators = parse_numeric_operators(data, offset)?;
317    Ok(FlowSpecComponent::SourcePort(operators))
318}
319
320fn parse_icmp_type(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
321    let operators = parse_numeric_operators(data, offset)?;
322    Ok(FlowSpecComponent::IcmpType(operators))
323}
324
325fn parse_icmp_code(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
326    let operators = parse_numeric_operators(data, offset)?;
327    Ok(FlowSpecComponent::IcmpCode(operators))
328}
329
330fn parse_tcp_flags(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
331    let operators = parse_bitmask_operators(data, offset)?;
332    Ok(FlowSpecComponent::TcpFlags(operators))
333}
334
335fn parse_packet_length(
336    data: &[u8],
337    offset: &mut usize,
338) -> Result<FlowSpecComponent, FlowSpecError> {
339    let operators = parse_numeric_operators(data, offset)?;
340    Ok(FlowSpecComponent::PacketLength(operators))
341}
342
343fn parse_dscp(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
344    let operators = parse_numeric_operators(data, offset)?;
345    Ok(FlowSpecComponent::Dscp(operators))
346}
347
348fn parse_fragment(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
349    let operators = parse_bitmask_operators(data, offset)?;
350    Ok(FlowSpecComponent::Fragment(operators))
351}
352
353fn parse_flow_label(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
354    let operators = parse_numeric_operators(data, offset)?;
355    Ok(FlowSpecComponent::FlowLabel(operators))
356}
357
358// Encoding functions
359fn encode_prefix(prefix: &NetworkPrefix, data: &mut Vec<u8>) {
360    let prefix_len = prefix.prefix.prefix_len();
361    data.push(prefix_len);
362
363    let prefix_bytes = prefix_len.div_ceil(8);
364    let addr_bytes = match prefix.prefix.addr() {
365        std::net::IpAddr::V4(addr) => addr.octets().to_vec(),
366        std::net::IpAddr::V6(addr) => addr.octets().to_vec(),
367    };
368
369    data.extend(&addr_bytes[..prefix_bytes as usize]);
370}
371
372fn encode_ipv6_prefix(offset: u8, prefix: &NetworkPrefix, data: &mut Vec<u8>) {
373    data.push(prefix.prefix.prefix_len());
374    data.push(offset);
375
376    let prefix_bytes = prefix.prefix.prefix_len().div_ceil(8);
377    if let std::net::IpAddr::V6(addr) = prefix.prefix.addr() {
378        let addr_bytes = addr.octets();
379        data.extend(&addr_bytes[..prefix_bytes as usize]);
380    }
381}
382
383fn encode_numeric_operators(operators: &[NumericOperator], data: &mut Vec<u8>) {
384    for operator in operators {
385        data.push(operator.to_byte());
386        write_value(operator.value, operator.value_length as usize, data);
387    }
388}
389
390fn encode_bitmask_operators(operators: &[BitmaskOperator], data: &mut Vec<u8>) {
391    for operator in operators {
392        data.push(operator.to_byte());
393        write_value(operator.bitmask, operator.value_length as usize, data);
394    }
395}
396
397#[cfg(test)]
398mod tests {
399    use super::*;
400
401    #[test]
402    fn test_length_encoding() {
403        // Test short length
404        let mut data = Vec::new();
405        encode_length(100, &mut data);
406        assert_eq!(data, vec![100]);
407
408        let mut offset = 0;
409        let parsed_len = parse_length(&data, &mut offset).unwrap();
410        assert_eq!(parsed_len, 100);
411        assert_eq!(offset, 1);
412
413        // Test extended length
414        let mut data = Vec::new();
415        encode_length(1000, &mut data);
416        assert_eq!(data, vec![0xF3, 0xE8]); // 1000 = 0x3E8
417
418        let mut offset = 0;
419        let parsed_len = parse_length(&data, &mut offset).unwrap();
420        assert_eq!(parsed_len, 1000);
421        assert_eq!(offset, 2);
422    }
423
424    #[test]
425    fn test_read_write_value() {
426        // Test 1 byte
427        assert_eq!(read_value(&[0x25]), 0x25);
428
429        // Test 2 bytes
430        assert_eq!(read_value(&[0x01, 0xBB]), 443);
431
432        // Test 4 bytes
433        assert_eq!(read_value(&[0x00, 0x00, 0x00, 0x50]), 80);
434
435        // Test writing
436        let mut data = Vec::new();
437        write_value(443, 2, &mut data);
438        assert_eq!(data, vec![0x01, 0xBB]);
439    }
440
441    #[test]
442    fn test_simple_nlri_parsing() {
443        // Packets to 192.0.2.0/24 and TCP (protocol 6)
444        let data = vec![
445            0x08, // Length: 8 bytes (the actual NLRI content length)
446            0x01, // Type 1: Destination Prefix
447            0x18, // /24
448            0xC0, 0x00, 0x02, // 192.0.2.0
449            0x03, // Type 3: IP Protocol
450            0x81, // end=1, and=0, len=00, eq=1
451            0x06, // TCP
452        ];
453
454        let nlri = parse_flowspec_nlri(&data).unwrap();
455        assert_eq!(nlri.components.len(), 2);
456
457        match &nlri.components[0] {
458            FlowSpecComponent::DestinationPrefix(prefix) => {
459                assert_eq!(prefix.to_string(), "192.0.2.0/24");
460            }
461            _ => panic!("Expected destination prefix"),
462        }
463
464        match &nlri.components[1] {
465            FlowSpecComponent::IpProtocol(ops) => {
466                assert_eq!(ops.len(), 1);
467                assert_eq!(ops[0].value, 6);
468                assert!(ops[0].equal);
469            }
470            _ => panic!("Expected IP protocol"),
471        }
472    }
473
474    #[test]
475    fn test_nlri_round_trip() {
476        let original_nlri = FlowSpecNlri::new(vec![
477            FlowSpecComponent::DestinationPrefix(NetworkPrefix::from_str("192.0.2.0/24").unwrap()),
478            FlowSpecComponent::IpProtocol(vec![NumericOperator::equal_to(6)]),
479            FlowSpecComponent::DestinationPort(vec![NumericOperator::equal_to(80)]),
480        ]);
481
482        let encoded = encode_flowspec_nlri(&original_nlri);
483        let parsed_nlri = parse_flowspec_nlri(&encoded).unwrap();
484
485        assert_eq!(original_nlri, parsed_nlri);
486    }
487}