bgpkit-parser 0.16.0

MRT/BGP/BMP data processing library
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
//! BGP Link-State attribute parsing - RFC 7752

use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::net::{Ipv4Addr, Ipv6Addr};

use crate::error::ParserError;
use crate::models::*;
use crate::parser::ReadUtils;

/// Parse BGP Link-State attribute (type 29)
pub fn parse_link_state_attribute(mut data: Bytes) -> Result<AttributeValue, ParserError> {
    let mut attr = LinkStateAttribute::new();

    while data.remaining() >= 4 {
        let tlv_type = data.read_u16()?;
        let tlv_length = data.read_u16()?;

        if data.remaining() < tlv_length as usize {
            return Err(ParserError::TruncatedMsg(format!(
                "Expected {} bytes for TLV, but only {} remaining",
                tlv_length,
                data.remaining()
            )));
        }

        let tlv_data = data.read_n_bytes(tlv_length as usize)?;

        // Parse based on TLV type
        match tlv_type {
            // Node Attribute TLVs (1024-1039)
            1024..=1039 => {
                let node_attr_type = NodeAttributeType::from(tlv_type);
                if node_attr_type == NodeAttributeType::Reserved {
                    attr.add_unknown_attribute(Tlv::new(tlv_type, tlv_data.to_vec()));
                } else {
                    attr.add_node_attribute(node_attr_type, tlv_data.to_vec());
                }
            }
            // Link Attribute TLVs (1088-1103)
            1088..=1103 => {
                let link_attr_type = LinkAttributeType::from(tlv_type);
                if link_attr_type == LinkAttributeType::Reserved {
                    attr.add_unknown_attribute(Tlv::new(tlv_type, tlv_data.to_vec()));
                } else {
                    attr.add_link_attribute(link_attr_type, tlv_data.to_vec());
                }
            }
            // Link Attribute TLVs (1114-1120, 1122) - RFC 8571, RFC 9294
            1114..=1120 | 1122 => {
                let link_attr_type = LinkAttributeType::from(tlv_type);
                if link_attr_type == LinkAttributeType::Reserved {
                    attr.add_unknown_attribute(Tlv::new(tlv_type, tlv_data.to_vec()));
                } else {
                    attr.add_link_attribute(link_attr_type, tlv_data.to_vec());
                }
            }
            // Link Attribute TLVs (1172) - RFC 9085
            1172 => {
                let link_attr_type = LinkAttributeType::from(tlv_type);
                if link_attr_type == LinkAttributeType::Reserved {
                    attr.add_unknown_attribute(Tlv::new(tlv_type, tlv_data.to_vec()));
                } else {
                    attr.add_link_attribute(link_attr_type, tlv_data.to_vec());
                }
            }
            // Prefix Attribute TLVs (1152-1163, 1170-1171, 1174)
            1152..=1163 | 1170..=1171 | 1174 => {
                let prefix_attr_type = PrefixAttributeType::from(tlv_type);
                if prefix_attr_type == PrefixAttributeType::Reserved {
                    attr.add_unknown_attribute(Tlv::new(tlv_type, tlv_data.to_vec()));
                } else {
                    attr.add_prefix_attribute(prefix_attr_type, tlv_data.to_vec());
                }
            }
            // Unknown/Reserved TLVs
            _ => {
                attr.add_unknown_attribute(Tlv::new(tlv_type, tlv_data.to_vec()));
            }
        }
    }

    Ok(AttributeValue::LinkState(attr))
}

/// Parse BGP Link-State NLRI
pub fn parse_link_state_nlri(
    mut data: Bytes,
    _afi: Afi,
    safi: Safi,
    next_hop: Option<NextHopAddress>,
    is_reachable: bool,
) -> Result<Nlri, ParserError> {
    let mut nlri_list = Vec::new();

    while data.remaining() >= 4 {
        let nlri_type = data.read_u16()?;
        let nlri_len = data.read_u16()?;

        if data.remaining() < nlri_len as usize {
            return Err(ParserError::TruncatedMsg(format!(
                "Expected {} bytes for NLRI, but only {} remaining",
                nlri_len,
                data.remaining()
            )));
        }

        let nlri_data = data.read_n_bytes(nlri_len as usize)?;
        let parsed_nlri = parse_single_link_state_nlri(nlri_type, nlri_data.into())?;
        nlri_list.push(parsed_nlri);
    }

    let nlri = if is_reachable {
        Nlri::new_link_state_reachable(next_hop.map(|nh| nh.addr()), safi, nlri_list)
    } else {
        Nlri::new_link_state_unreachable(safi, nlri_list)
    };

    Ok(nlri)
}

/// Parse a single Link-State NLRI entry
fn parse_single_link_state_nlri(
    nlri_type: u16,
    mut data: Bytes,
) -> Result<LinkStateNlri, ParserError> {
    let nlri_type = NlriType::from(nlri_type);

    // Parse Protocol-ID (1 byte) and Identifier (8 bytes)
    if data.remaining() < 9 {
        return Err(ParserError::TruncatedMsg(format!(
            "Expected at least 9 bytes for Link-State NLRI header, but only {} remaining",
            data.remaining()
        )));
    }

    let protocol_id = ProtocolId::from(data.read_u8()?);
    let identifier = data.read_u64()?;

    // Parse descriptors based on NLRI type
    let (local_node_descriptors, remote_node_descriptors, link_descriptors, prefix_descriptors) =
        match nlri_type {
            NlriType::Node => {
                let local_desc = parse_node_descriptors(&mut data)?;
                (local_desc, None, None, None)
            }
            NlriType::Link => {
                let local_desc = parse_node_descriptors(&mut data)?;
                let remote_desc = parse_node_descriptors(&mut data)?;
                let link_desc = parse_link_descriptors(&mut data)?;
                (local_desc, Some(remote_desc), Some(link_desc), None)
            }
            NlriType::Ipv4TopologyPrefix | NlriType::Ipv6TopologyPrefix => {
                let local_desc = parse_node_descriptors(&mut data)?;
                let prefix_desc = parse_prefix_descriptors(&mut data)?;
                (local_desc, None, None, Some(prefix_desc))
            }
            _ => {
                // For other NLRI types, just parse local node descriptors
                let local_desc = parse_node_descriptors(&mut data)?;
                (local_desc, None, None, None)
            }
        };

    Ok(LinkStateNlri {
        nlri_type,
        protocol_id,
        identifier,
        local_node_descriptors,
        remote_node_descriptors,
        link_descriptors,
        prefix_descriptors,
    })
}

/// Parse Node Descriptor TLVs
fn parse_node_descriptors(data: &mut Bytes) -> Result<NodeDescriptor, ParserError> {
    let mut node_desc = NodeDescriptor::default();

    // Parse TLV length first
    if data.remaining() < 2 {
        return Ok(node_desc);
    }
    let desc_len = data.read_u16()?;

    if data.remaining() < desc_len as usize {
        return Err(ParserError::TruncatedMsg(format!(
            "Expected {} bytes for node descriptors, but only {} remaining",
            desc_len,
            data.remaining()
        )));
    }

    let mut desc_data: Bytes = data.read_n_bytes(desc_len as usize)?.into();

    while desc_data.remaining() >= 4 {
        let sub_tlv_type = desc_data.read_u16()?;
        let sub_tlv_len = desc_data.read_u16()?;

        if desc_data.remaining() < sub_tlv_len as usize {
            break;
        }

        let sub_tlv_data = desc_data.split_to(sub_tlv_len as usize);
        match NodeDescriptorType::from(sub_tlv_type) {
            NodeDescriptorType::AutonomousSystem => {
                if sub_tlv_len == 4 && sub_tlv_data.len() >= 4 {
                    let bytes = sub_tlv_data.as_ref();
                    node_desc.autonomous_system =
                        Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]));
                }
            }
            NodeDescriptorType::BgpLsIdentifier => {
                if sub_tlv_len == 4 && sub_tlv_data.len() >= 4 {
                    let bytes = sub_tlv_data.as_ref();
                    node_desc.bgp_ls_identifier =
                        Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]));
                }
            }
            NodeDescriptorType::OspfAreaId => {
                if sub_tlv_len == 4 && sub_tlv_data.len() >= 4 {
                    let bytes = sub_tlv_data.as_ref();
                    node_desc.ospf_area_id =
                        Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]));
                }
            }
            NodeDescriptorType::IgpRouterId => {
                node_desc.igp_router_id = Some(sub_tlv_data.to_vec());
            }
            _ => {
                node_desc
                    .unknown_tlvs
                    .push(Tlv::new(sub_tlv_type, sub_tlv_data.to_vec()));
            }
        }
    }

    Ok(node_desc)
}

/// Parse Link Descriptor TLVs
fn parse_link_descriptors(data: &mut Bytes) -> Result<LinkDescriptor, ParserError> {
    let mut link_desc = LinkDescriptor::default();

    // Parse TLV length first
    if data.remaining() < 2 {
        return Ok(link_desc);
    }
    let desc_len = data.read_u16()?;

    if data.remaining() < desc_len as usize {
        return Err(ParserError::TruncatedMsg(format!(
            "Expected {} bytes for link descriptors, but only {} remaining",
            desc_len,
            data.remaining()
        )));
    }

    let mut desc_data: Bytes = data.read_n_bytes(desc_len as usize)?.into();

    while desc_data.remaining() >= 4 {
        let sub_tlv_type = desc_data.read_u16()?;
        let sub_tlv_len = desc_data.read_u16()?;

        if desc_data.remaining() < sub_tlv_len as usize {
            break;
        }

        let sub_tlv_data = desc_data.split_to(sub_tlv_len as usize);

        match LinkDescriptorType::from(sub_tlv_type) {
            LinkDescriptorType::LinkLocalRemoteIdentifiers => {
                if sub_tlv_len == 8 && sub_tlv_data.len() >= 8 {
                    let bytes = sub_tlv_data.as_ref();
                    let local_id = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
                    let remote_id = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
                    link_desc.link_local_remote_identifiers = Some((local_id, remote_id));
                }
            }
            LinkDescriptorType::Ipv4InterfaceAddress => {
                if sub_tlv_len == 4 && sub_tlv_data.len() >= 4 {
                    let bytes = sub_tlv_data.as_ref();
                    link_desc.ipv4_interface_address =
                        Some(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]));
                }
            }
            LinkDescriptorType::Ipv4NeighborAddress => {
                if sub_tlv_len == 4 && sub_tlv_data.len() >= 4 {
                    let bytes = sub_tlv_data.as_ref();
                    link_desc.ipv4_neighbor_address =
                        Some(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]));
                }
            }
            LinkDescriptorType::Ipv6InterfaceAddress => {
                if sub_tlv_len == 16 && sub_tlv_data.len() >= 16 {
                    let bytes = sub_tlv_data.as_ref();
                    let mut addr_bytes = [0u8; 16];
                    addr_bytes.copy_from_slice(&bytes[..16]);
                    link_desc.ipv6_interface_address = Some(Ipv6Addr::from(addr_bytes));
                }
            }
            LinkDescriptorType::Ipv6NeighborAddress => {
                if sub_tlv_len == 16 && sub_tlv_data.len() >= 16 {
                    let bytes = sub_tlv_data.as_ref();
                    let mut addr_bytes = [0u8; 16];
                    addr_bytes.copy_from_slice(&bytes[..16]);
                    link_desc.ipv6_neighbor_address = Some(Ipv6Addr::from(addr_bytes));
                }
            }
            LinkDescriptorType::MultiTopologyId => {
                if sub_tlv_len == 2 && sub_tlv_data.len() >= 2 {
                    let bytes = sub_tlv_data.as_ref();
                    link_desc.multi_topology_id = Some(u16::from_be_bytes([bytes[0], bytes[1]]));
                }
            }
            _ => {
                link_desc
                    .unknown_tlvs
                    .push(Tlv::new(sub_tlv_type, sub_tlv_data.to_vec()));
            }
        }
    }

    Ok(link_desc)
}

/// Parse Prefix Descriptor TLVs
fn parse_prefix_descriptors(data: &mut Bytes) -> Result<PrefixDescriptor, ParserError> {
    let mut prefix_desc = PrefixDescriptor::default();

    // Parse TLV length first
    if data.remaining() < 2 {
        return Ok(prefix_desc);
    }
    let desc_len = data.read_u16()?;

    if data.remaining() < desc_len as usize {
        return Err(ParserError::TruncatedMsg(format!(
            "Expected {} bytes for prefix descriptors, but only {} remaining",
            desc_len,
            data.remaining()
        )));
    }

    let mut desc_data: Bytes = data.read_n_bytes(desc_len as usize)?.into();

    while desc_data.remaining() >= 4 {
        let sub_tlv_type = desc_data.read_u16()?;
        let sub_tlv_len = desc_data.read_u16()?;

        if desc_data.remaining() < sub_tlv_len as usize {
            break;
        }

        let sub_tlv_data = desc_data.split_to(sub_tlv_len as usize);

        match PrefixDescriptorType::from(sub_tlv_type) {
            PrefixDescriptorType::MultiTopologyId => {
                if sub_tlv_len == 2 && sub_tlv_data.len() >= 2 {
                    let bytes = sub_tlv_data.as_ref();
                    prefix_desc.multi_topology_id = Some(u16::from_be_bytes([bytes[0], bytes[1]]));
                }
            }
            PrefixDescriptorType::OspfRouteType => {
                if sub_tlv_len == 1 && !sub_tlv_data.is_empty() {
                    let bytes = sub_tlv_data.as_ref();
                    prefix_desc.ospf_route_type = Some(bytes[0]);
                }
            }
            PrefixDescriptorType::IpReachabilityInformation => {
                // Parse IP prefix from the TLV data
                if let Ok(prefix) = parse_ip_prefix_from_bytes(&sub_tlv_data) {
                    prefix_desc.ip_reachability_information = Some(prefix);
                }
            }
            _ => {
                prefix_desc
                    .unknown_tlvs
                    .push(Tlv::new(sub_tlv_type, sub_tlv_data.to_vec()));
            }
        }
    }

    Ok(prefix_desc)
}

/// Parse IP prefix from bytes (prefix length + address bytes)
fn parse_ip_prefix_from_bytes(data: &[u8]) -> Result<NetworkPrefix, ParserError> {
    if data.is_empty() {
        return Err(ParserError::TruncatedMsg("Empty prefix data".to_string()));
    }

    let prefix_len = data[0];
    let addr_bytes = &data[1..];

    if prefix_len <= 32 {
        // IPv4 prefix
        let needed_bytes = prefix_len.div_ceil(8) as usize;
        if addr_bytes.len() < needed_bytes {
            return Err(ParserError::TruncatedMsg(format!(
                "Expected {} bytes for IPv4 prefix, but only {} available",
                needed_bytes,
                addr_bytes.len()
            )));
        }

        let mut ipv4_bytes = [0u8; 4];
        ipv4_bytes[..needed_bytes.min(4)].copy_from_slice(&addr_bytes[..needed_bytes.min(4)]);
        let addr = Ipv4Addr::from(ipv4_bytes);

        let ipnet = ipnet::Ipv4Net::new(addr, prefix_len)
            .map_err(|_| ParserError::ParseError("Invalid IPv4 prefix".to_string()))?;
        Ok(NetworkPrefix::new(ipnet::IpNet::V4(ipnet), None))
    } else {
        // IPv6 prefix
        let needed_bytes = prefix_len.div_ceil(8) as usize;
        if addr_bytes.len() < needed_bytes {
            return Err(ParserError::TruncatedMsg(format!(
                "Expected {} bytes for IPv6 prefix, but only {} available",
                needed_bytes,
                addr_bytes.len()
            )));
        }

        let mut ipv6_bytes = [0u8; 16];
        ipv6_bytes[..needed_bytes.min(16)].copy_from_slice(&addr_bytes[..needed_bytes.min(16)]);
        let addr = Ipv6Addr::from(ipv6_bytes);

        let ipnet = ipnet::Ipv6Net::new(addr, prefix_len)
            .map_err(|_| ParserError::ParseError("Invalid IPv6 prefix".to_string()))?;
        Ok(NetworkPrefix::new(ipnet::IpNet::V6(ipnet), None))
    }
}

/// Encode BGP Link-State attribute
pub fn encode_link_state_attribute(attr: &LinkStateAttribute) -> Bytes {
    let mut bytes = BytesMut::new();

    // Encode node attributes
    for (attr_type, value) in &attr.node_attributes {
        let type_code = u16::from(*attr_type);
        bytes.put_u16(type_code);
        bytes.put_u16(value.len() as u16);
        bytes.extend_from_slice(value);
    }

    // Encode link attributes
    for (attr_type, value) in &attr.link_attributes {
        let type_code = u16::from(*attr_type);
        bytes.put_u16(type_code);
        bytes.put_u16(value.len() as u16);
        bytes.extend_from_slice(value);
    }

    // Encode prefix attributes
    for (attr_type, value) in &attr.prefix_attributes {
        let type_code = u16::from(*attr_type);
        bytes.put_u16(type_code);
        bytes.put_u16(value.len() as u16);
        bytes.extend_from_slice(value);
    }

    // Encode unknown attributes
    for tlv in &attr.unknown_attributes {
        bytes.put_u16(tlv.tlv_type);
        bytes.put_u16(tlv.length());
        bytes.extend_from_slice(&tlv.value);
    }

    bytes.freeze()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_node_descriptors() {
        let mut data = BytesMut::new();
        // Length = 16 bytes (8 + 8) = 2 TLVs with headers and data
        data.put_u16(16);
        // AS Number TLV (512)
        data.put_u16(512);
        data.put_u16(4);
        data.put_u32(65001);
        // OSPF Area ID TLV (514)
        data.put_u16(514);
        data.put_u16(4);
        data.put_u32(0);

        let mut bytes = data.freeze();
        let result = parse_node_descriptors(&mut bytes).unwrap();

        assert_eq!(result.autonomous_system, Some(65001));
        assert_eq!(result.ospf_area_id, Some(0));
    }

    #[test]
    fn test_parse_link_descriptors() {
        let mut data = BytesMut::new();
        // Length = 12 bytes
        data.put_u16(12);
        // Link Local/Remote Identifiers TLV (258)
        data.put_u16(258);
        data.put_u16(8);
        data.put_u32(1); // Local ID
        data.put_u32(2); // Remote ID

        let mut bytes = data.freeze();
        let result = parse_link_descriptors(&mut bytes).unwrap();

        assert_eq!(result.link_local_remote_identifiers, Some((1, 2)));
    }

    #[test]
    fn test_parse_ip_prefix_from_bytes() {
        // Test IPv4 prefix 192.168.1.0/24
        let data = vec![24, 192, 168, 1];
        let result = parse_ip_prefix_from_bytes(&data).unwrap();

        match result.prefix {
            ipnet::IpNet::V4(net) => {
                assert_eq!(net.addr(), std::net::Ipv4Addr::new(192, 168, 1, 0));
                assert_eq!(net.prefix_len(), 24);
            }
            _ => panic!("Expected IPv4 prefix"),
        }
    }

    #[test]
    fn test_link_state_attribute_encoding() {
        let mut attr = LinkStateAttribute::new();
        attr.add_node_attribute(NodeAttributeType::NodeName, b"router1".to_vec());

        let encoded = encode_link_state_attribute(&attr);
        assert!(!encoded.is_empty());

        // Should contain the node name TLV
        // Type (1026) + Length (7) + "router1"
        assert!(encoded.len() >= 11);
    }
}