bgpkit-parser 0.9.0-alpha-3

A library to parse MRT/BGP/BMP binary data.
Documentation
use crate::parser::bgp::parse_bgp_message;
use crate::parser::rislive::error::ParserRisliveError;
use crate::{BgpElem, Elementor};
use bgp_models::mrt::{Bgp4MpType, CommonHeader, EntryType, MrtMessage, MrtRecord};
use bgp_models::network::{Afi, AsnLength};
use serde_json::Value;
use std::net::IpAddr;
use std::str::FromStr;

pub fn parse_raw_bytes(msg_str: &str) -> Result<Vec<BgpElem>, ParserRisliveError> {
    let msg: Value = serde_json::from_str(msg_str)?;
    let msg_type = match msg.get("type") {
        None => return Err(ParserRisliveError::IrregularRisLiveFormat),
        Some(t) => t.as_str().unwrap(),
    };

    match msg_type {
        "ris_message" => {}
        "ris_error" | "ris_rrc_list" | "ris_subscribe_ok" | "pong" => {
            return Err(ParserRisliveError::UnsupportedMessage)
        }
        _ => return Err(ParserRisliveError::IrregularRisLiveFormat),
    }

    let data = msg.get("data").unwrap().as_object().unwrap();

    let bytes = hex::decode(data.get("raw").unwrap().as_str().unwrap()).unwrap();

    let timestamp = data.get("timestamp").unwrap().as_f64().unwrap();
    let peer_str = data.get("peer").unwrap().as_str().unwrap().to_owned();

    let peer_ip = peer_str.parse::<IpAddr>().unwrap();
    let afi = match peer_ip.is_ipv4() {
        true => Afi::Ipv4,
        false => Afi::Ipv6,
    };

    let peer_asn_str = data.get("peer_asn").unwrap().as_str().unwrap().to_owned();

    let peer_asn = peer_asn_str.parse::<i32>().unwrap().into();

    let bgp_msg = match parse_bgp_message(bytes.as_slice(), false, &AsnLength::Bits32) {
        Ok(m) => m,
        Err(_) => match parse_bgp_message(bytes.as_slice(), false, &AsnLength::Bits16) {
            Ok(m) => m,
            Err(_) => return Err(ParserRisliveError::IncorrectRawBytes),
        },
    };

    let t_sec = timestamp as u32;
    let t_msec = get_micro_seconds(timestamp);

    let header = CommonHeader {
        timestamp: t_sec,
        microsecond_timestamp: Some(t_msec),
        entry_type: EntryType::BGP4MP,
        entry_subtype: 4, // Bgp4MpMessageAs4
        length: 0,
    };

    let record = MrtRecord {
        common_header: header,
        message: MrtMessage::Bgp4Mp(bgp_models::mrt::bgp4mp::Bgp4Mp::Bgp4MpMessage(
            bgp_models::mrt::bgp4mp::Bgp4MpMessage {
                msg_type: Bgp4MpType::Bgp4MpMessageAs4,
                peer_asn,
                local_asn: 0.into(),
                interface_index: 0,
                afi,
                peer_ip,
                local_ip: IpAddr::from_str("0.0.0.0").unwrap(),
                bgp_message: bgp_msg,
            },
        )),
    };
    Ok(Elementor::new().record_to_elems(record))
}

fn get_micro_seconds(sec: f64) -> u32 {
    format!("{:.6}", sec).split('.').collect::<Vec<&str>>()[1]
        .to_owned()
        .parse::<u32>()
        .unwrap()
}

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

    #[test]
    fn ris_live_message() {
        let message = r#"
        {
  "type": "ris_message",
  "data": {
    "timestamp": 1636245154.8,
    "peer": "2001:7f8:b:100:1d1:a520:1333:74",
    "peer_asn": "201333",
    "id": "10-183678-175313836",
    "host": "rrc10",
    "type": "UPDATE",
    "path": [
      201333,
      6762,
      174,
      20473
    ],
    "community": [
      [
        6762,
        30
      ],
      [
        6762,
        14400
      ]
    ],
    "origin": "igp",
    "announcements": [
      {
        "next_hop": "2001:7f8:b:100:1d1:a520:1333:74",
        "prefixes": [
          "2a0e:97c7::/48",
          "2a0e:97c6:fe::/48",
          "2a10:cc42:17b7::/48",
          "2a10:cc42:1feb::/48"
        ]
      },
      {
        "next_hop": "fe80::217:a3ff:fefe:2905",
        "prefixes": [
          "2a0e:97c7::/48",
          "2a0e:97c6:fe::/48",
          "2a10:cc42:17b7::/48",
          "2a10:cc42:1feb::/48"
        ]
      }
    ],
    "raw": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0086020000006F4001010040021202040003127500001A6A000000AE00004FF980040400000000C008081A6A001E1A6A3840800E4100020120200107F8000B010001D1A52013330074FE800000000000000217A3FFFEFE290500302A0E97C70000302A0E97C600FE302A10CC4217B7302A10CC421FEB"
  }
}
        "#;

        let res = parse_raw_bytes(message);
        dbg!(&res);
        for elem in res.unwrap() {
            println!("{}", elem);
        }
    }
}