Skip to main content

bgpkit_parser/models/bgp/flowspec/
nlri.rs

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