Skip to main content

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    // Reject prefix lengths beyond the IPv6 maximum. Without this,
139    // `prefix_bytes` can reach 32 and the IPv6 branch below would copy past
140    // the fixed 16-byte buffer and panic. The `Ipv6Net::new` validation only
141    // runs *after* the copy, so the check must happen here.
142    if prefix_len > 128 {
143        return Err(FlowSpecError::InvalidPrefix);
144    }
145
146    let prefix_bytes = prefix_len.div_ceil(8);
147    if *offset + prefix_bytes as usize > data.len() {
148        return Err(FlowSpecError::InsufficientData);
149    }
150
151    let prefix_data = &data[*offset..*offset + prefix_bytes as usize];
152    *offset += prefix_bytes as usize;
153
154    // Construct prefix based on address family
155    let prefix = if prefix_bytes <= 4 {
156        // IPv4
157        let mut addr_bytes = [0u8; 4];
158        addr_bytes[..prefix_data.len()].copy_from_slice(prefix_data);
159        let addr = std::net::Ipv4Addr::from(addr_bytes);
160        let ipnet = IpNet::V4(
161            ipnet::Ipv4Net::new(addr, prefix_len).map_err(|_| FlowSpecError::InvalidPrefix)?,
162        );
163        NetworkPrefix::new(ipnet, None)
164    } else {
165        // IPv6
166        let mut addr_bytes = [0u8; 16];
167        addr_bytes[..prefix_data.len()].copy_from_slice(prefix_data);
168        let addr = std::net::Ipv6Addr::from(addr_bytes);
169        let ipnet = IpNet::V6(
170            ipnet::Ipv6Net::new(addr, prefix_len).map_err(|_| FlowSpecError::InvalidPrefix)?,
171        );
172        NetworkPrefix::new(ipnet, None)
173    };
174
175    Ok(prefix)
176}
177
178/// Parse destination prefix (Type 1)
179fn parse_destination_prefix(
180    data: &[u8],
181    offset: &mut usize,
182) -> Result<FlowSpecComponent, FlowSpecError> {
183    let prefix = parse_prefix_component(data, offset)?;
184    Ok(FlowSpecComponent::DestinationPrefix(prefix))
185}
186
187/// Parse source prefix (Type 2)
188fn parse_source_prefix(
189    data: &[u8],
190    offset: &mut usize,
191) -> Result<FlowSpecComponent, FlowSpecError> {
192    let prefix = parse_prefix_component(data, offset)?;
193    Ok(FlowSpecComponent::SourcePrefix(prefix))
194}
195
196/// Parse numeric operators sequence
197fn parse_numeric_operators(
198    data: &[u8],
199    offset: &mut usize,
200) -> Result<Vec<NumericOperator>, FlowSpecError> {
201    let mut operators = Vec::new();
202
203    loop {
204        if *offset >= data.len() {
205            return Err(FlowSpecError::InsufficientData);
206        }
207
208        let operator_byte = data[*offset];
209        *offset += 1;
210
211        let value_length = match (operator_byte >> 4) & 0x03 {
212            0 => 1,
213            1 => 2,
214            2 => 4,
215            3 => 8,
216            _ => {
217                return Err(FlowSpecError::InvalidValueLength(
218                    (operator_byte >> 4) & 0x03,
219                ))
220            }
221        };
222
223        if *offset + value_length > data.len() {
224            return Err(FlowSpecError::InsufficientData);
225        }
226
227        let value = read_value(&data[*offset..*offset + value_length]);
228        *offset += value_length;
229
230        let operator = NumericOperator::from_byte_and_value(operator_byte, value)?;
231        let is_end = operator.end_of_list;
232        operators.push(operator);
233
234        if is_end {
235            break;
236        }
237    }
238
239    Ok(operators)
240}
241
242/// Parse bitmask operators sequence
243fn parse_bitmask_operators(
244    data: &[u8],
245    offset: &mut usize,
246) -> Result<Vec<BitmaskOperator>, FlowSpecError> {
247    let mut operators = Vec::new();
248
249    loop {
250        if *offset >= data.len() {
251            return Err(FlowSpecError::InsufficientData);
252        }
253
254        let operator_byte = data[*offset];
255        *offset += 1;
256
257        let value_length = match (operator_byte >> 4) & 0x03 {
258            0 => 1,
259            1 => 2,
260            2 => 4,
261            3 => 8,
262            _ => {
263                return Err(FlowSpecError::InvalidValueLength(
264                    (operator_byte >> 4) & 0x03,
265                ))
266            }
267        };
268
269        if *offset + value_length > data.len() {
270            return Err(FlowSpecError::InsufficientData);
271        }
272
273        let bitmask = read_value(&data[*offset..*offset + value_length]);
274        *offset += value_length;
275
276        let operator = BitmaskOperator::from_byte_and_value(operator_byte, bitmask)?;
277        let is_end = operator.end_of_list;
278        operators.push(operator);
279
280        if is_end {
281            break;
282        }
283    }
284
285    Ok(operators)
286}
287
288/// Read value from bytes (big-endian)
289fn read_value(bytes: &[u8]) -> u64 {
290    let mut value = 0u64;
291    for &byte in bytes {
292        value = (value << 8) | byte as u64;
293    }
294    value
295}
296
297/// Write value to bytes (big-endian)
298fn write_value(value: u64, length: usize, data: &mut Vec<u8>) {
299    for i in (0..length).rev() {
300        data.push((value >> (i * 8)) as u8);
301    }
302}
303
304// Component parsers
305fn parse_ip_protocol(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
306    let operators = parse_numeric_operators(data, offset)?;
307    Ok(FlowSpecComponent::IpProtocol(operators))
308}
309
310fn parse_port(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
311    let operators = parse_numeric_operators(data, offset)?;
312    Ok(FlowSpecComponent::Port(operators))
313}
314
315fn parse_destination_port(
316    data: &[u8],
317    offset: &mut usize,
318) -> Result<FlowSpecComponent, FlowSpecError> {
319    let operators = parse_numeric_operators(data, offset)?;
320    Ok(FlowSpecComponent::DestinationPort(operators))
321}
322
323fn parse_source_port(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
324    let operators = parse_numeric_operators(data, offset)?;
325    Ok(FlowSpecComponent::SourcePort(operators))
326}
327
328fn parse_icmp_type(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
329    let operators = parse_numeric_operators(data, offset)?;
330    Ok(FlowSpecComponent::IcmpType(operators))
331}
332
333fn parse_icmp_code(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
334    let operators = parse_numeric_operators(data, offset)?;
335    Ok(FlowSpecComponent::IcmpCode(operators))
336}
337
338fn parse_tcp_flags(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
339    let operators = parse_bitmask_operators(data, offset)?;
340    Ok(FlowSpecComponent::TcpFlags(operators))
341}
342
343fn parse_packet_length(
344    data: &[u8],
345    offset: &mut usize,
346) -> Result<FlowSpecComponent, FlowSpecError> {
347    let operators = parse_numeric_operators(data, offset)?;
348    Ok(FlowSpecComponent::PacketLength(operators))
349}
350
351fn parse_dscp(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
352    let operators = parse_numeric_operators(data, offset)?;
353    Ok(FlowSpecComponent::Dscp(operators))
354}
355
356fn parse_fragment(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
357    let operators = parse_bitmask_operators(data, offset)?;
358    Ok(FlowSpecComponent::Fragment(operators))
359}
360
361fn parse_flow_label(data: &[u8], offset: &mut usize) -> Result<FlowSpecComponent, FlowSpecError> {
362    let operators = parse_numeric_operators(data, offset)?;
363    Ok(FlowSpecComponent::FlowLabel(operators))
364}
365
366// Encoding functions
367fn encode_prefix(prefix: &NetworkPrefix, data: &mut Vec<u8>) {
368    let prefix_len = prefix.prefix.prefix_len();
369    data.push(prefix_len);
370
371    let prefix_bytes = prefix_len.div_ceil(8);
372    let addr_bytes = match prefix.prefix.addr() {
373        std::net::IpAddr::V4(addr) => addr.octets().to_vec(),
374        std::net::IpAddr::V6(addr) => addr.octets().to_vec(),
375    };
376
377    data.extend(&addr_bytes[..prefix_bytes as usize]);
378}
379
380fn encode_ipv6_prefix(offset: u8, prefix: &NetworkPrefix, data: &mut Vec<u8>) {
381    data.push(prefix.prefix.prefix_len());
382    data.push(offset);
383
384    let prefix_bytes = prefix.prefix.prefix_len().div_ceil(8);
385    if let std::net::IpAddr::V6(addr) = prefix.prefix.addr() {
386        let addr_bytes = addr.octets();
387        data.extend(&addr_bytes[..prefix_bytes as usize]);
388    }
389}
390
391fn encode_numeric_operators(operators: &[NumericOperator], data: &mut Vec<u8>) {
392    for operator in operators {
393        data.push(operator.to_byte());
394        write_value(operator.value, operator.value_length as usize, data);
395    }
396}
397
398fn encode_bitmask_operators(operators: &[BitmaskOperator], data: &mut Vec<u8>) {
399    for operator in operators {
400        data.push(operator.to_byte());
401        write_value(operator.bitmask, operator.value_length as usize, data);
402    }
403}
404
405#[cfg(test)]
406mod tests {
407    use super::*;
408
409    /// Regression: an oversized prefix length (>128) must be rejected before
410    /// the address bytes are copied, rather than panicking on an out-of-bounds
411    /// copy into the fixed 16-byte buffer.
412    #[test]
413    fn test_parse_prefix_component_oversized_len_no_panic() {
414        // prefix_len = 0xFF (255) → 32 prefix bytes, followed by 32 bytes.
415        let mut data = vec![0xFF];
416        data.extend(std::iter::repeat_n(0u8, 32));
417        let mut offset = 0;
418        assert!(matches!(
419            parse_prefix_component(&data, &mut offset),
420            Err(FlowSpecError::InvalidPrefix)
421        ));
422    }
423
424    #[test]
425    fn test_length_encoding() {
426        // Test short length
427        let mut data = Vec::new();
428        encode_length(100, &mut data);
429        assert_eq!(data, vec![100]);
430
431        let mut offset = 0;
432        let parsed_len = parse_length(&data, &mut offset).unwrap();
433        assert_eq!(parsed_len, 100);
434        assert_eq!(offset, 1);
435
436        // Test extended length
437        let mut data = Vec::new();
438        encode_length(1000, &mut data);
439        assert_eq!(data, vec![0xF3, 0xE8]); // 1000 = 0x3E8
440
441        let mut offset = 0;
442        let parsed_len = parse_length(&data, &mut offset).unwrap();
443        assert_eq!(parsed_len, 1000);
444        assert_eq!(offset, 2);
445    }
446
447    #[test]
448    fn test_read_write_value() {
449        // Test 1 byte
450        assert_eq!(read_value(&[0x25]), 0x25);
451
452        // Test 2 bytes
453        assert_eq!(read_value(&[0x01, 0xBB]), 443);
454
455        // Test 4 bytes
456        assert_eq!(read_value(&[0x00, 0x00, 0x00, 0x50]), 80);
457
458        // Test writing
459        let mut data = Vec::new();
460        write_value(443, 2, &mut data);
461        assert_eq!(data, vec![0x01, 0xBB]);
462    }
463
464    #[test]
465    fn test_simple_nlri_parsing() {
466        // Packets to 192.0.2.0/24 and TCP (protocol 6)
467        let data = vec![
468            0x08, // Length: 8 bytes (the actual NLRI content length)
469            0x01, // Type 1: Destination Prefix
470            0x18, // /24
471            0xC0, 0x00, 0x02, // 192.0.2.0
472            0x03, // Type 3: IP Protocol
473            0x81, // end=1, and=0, len=00, eq=1
474            0x06, // TCP
475        ];
476
477        let nlri = parse_flowspec_nlri(&data).unwrap();
478        assert_eq!(nlri.components.len(), 2);
479
480        match &nlri.components[0] {
481            FlowSpecComponent::DestinationPrefix(prefix) => {
482                assert_eq!(prefix.to_string(), "192.0.2.0/24");
483            }
484            _ => panic!("Expected destination prefix"),
485        }
486
487        match &nlri.components[1] {
488            FlowSpecComponent::IpProtocol(ops) => {
489                assert_eq!(ops.len(), 1);
490                assert_eq!(ops[0].value, 6);
491                assert!(ops[0].equal);
492            }
493            _ => panic!("Expected IP protocol"),
494        }
495    }
496
497    #[test]
498    fn test_nlri_round_trip() {
499        let original_nlri = FlowSpecNlri::new(vec![
500            FlowSpecComponent::DestinationPrefix(NetworkPrefix::from_str("192.0.2.0/24").unwrap()),
501            FlowSpecComponent::IpProtocol(vec![NumericOperator::equal_to(6)]),
502            FlowSpecComponent::DestinationPort(vec![NumericOperator::equal_to(80)]),
503        ]);
504
505        let encoded = encode_flowspec_nlri(&original_nlri);
506        let parsed_nlri = parse_flowspec_nlri(&encoded).unwrap();
507
508        assert_eq!(original_nlri, parsed_nlri);
509    }
510}