use bgp_models::bgp::*;
use bgp_models::network::*;
use num_traits::FromPrimitive;
use crate::error::ParserError;
use crate::parser::{AttributeParser, DataBytes};
use log::warn;
pub fn parse_bgp_message(input: &mut DataBytes, add_path: bool, asn_len: &AsnLength, total_size: usize) -> Result<BgpMessage, ParserError> {
input.read_32b()?;
input.read_32b()?;
input.read_32b()?;
input.read_32b()?;
let length = input.read_16b()?;
if !(19..=4096).contains(&length) {
return Err(ParserError::ParseError(format!("invalid BGP message length {}", length)))
}
let bgp_msg_length =
if (length as usize) > total_size {
(total_size-19) as u64
} else {
(length - 19) as u64
};
let msg_type: BgpMessageType = match BgpMessageType::from_u8(input.read_8b()?){
Some(t) => t,
None => {
return Err(ParserError::ParseError("Unknown BGP Message Type".to_string()))
}
};
Ok(
match msg_type{
BgpMessageType::OPEN => {
BgpMessage::Open(parse_bgp_open_message(input)?)
}
BgpMessageType::UPDATE => {
BgpMessage::Update(parse_bgp_update_message(input, add_path, asn_len, bgp_msg_length)?)
}
BgpMessageType::NOTIFICATION => {
BgpMessage::Notification(parse_bgp_notification_message(input, bgp_msg_length)?)
}
BgpMessageType::KEEPALIVE => {
BgpMessage::KeepAlive(BgpKeepAliveMessage{})
}
}
)
}
pub fn parse_bgp_notification_message(input: &mut DataBytes, bgp_msg_length: u64) -> Result<BgpNotificationMessage, ParserError> {
let error_code = input.read_8b()?;
let error_subcode = input.read_8b()?;
let data = input.read_n_bytes((bgp_msg_length - 2) as usize)?;
Ok(
BgpNotificationMessage{
error_code,
error_subcode,
error_type: None,
data
})
}
pub fn parse_bgp_open_message(input: &mut DataBytes) -> Result<BgpOpenMessage, ParserError> {
let version = input.read_8b()?;
let asn = Asn{asn: input.read_16b()? as u32, len: AsnLength::Bits16};
let hold_time = input.read_16b()?;
let sender_ip = input.read_ipv4_address()?;
let opt_params_len = input.read_8b()?;
let pos_end = input.pos + opt_params_len as usize;
let mut extended_length = false;
let mut first= true;
let mut params: Vec<OptParam> = vec![];
while input.pos < pos_end {
let param_type = input.read_8b()?;
if first {
if opt_params_len == 255 && param_type == 255 {
extended_length = true;
break
} else {
first = false;
}
}
let parm_length = input.read_8b()?;
let param_value = match param_type{
2 => {
let code = input.read_8b()?;
let len = input.read_8b()?;
let value = input.read_n_bytes(len as usize)?;
ParamValue::Capability(
Capability{
code,
len,
value,
capability_type: None
}
)
}
_ => {
let bytes = input.read_n_bytes(parm_length as usize)?;
ParamValue::Raw(bytes)
}
};
params.push(
OptParam{
param_type,
param_len: parm_length as u16,
param_value
}
);
}
Ok(
BgpOpenMessage{
version,
asn,
hold_time,
sender_ip,
extended_length,
opt_params: params
})
}
fn read_nlri(input: &mut DataBytes, length: usize, afi: &Afi, add_path: bool) -> Result<Vec<NetworkPrefix>, ParserError> {
if length==0{
return Ok(vec![])
}
if length==1 {
warn!("seeing strange one-byte NLRI field");
input.read_8b().unwrap();
return Ok(vec![])
}
let prefixes = input.parse_nlri_list(add_path, afi, length)?;
Ok(prefixes)
}
pub fn parse_bgp_update_message(input: &mut DataBytes, add_path:bool, asn_len: &AsnLength, bgp_msg_length: u64) -> Result<BgpUpdateMessage, ParserError> {
let afi = Afi::Ipv4;
let withdrawn_length = input.read_16b()? as u64;
let withdrawn_prefixes = read_nlri(input, withdrawn_length as usize, &afi, add_path)?;
let attribute_length = input.read_16b()? as usize;
let attr_parser = AttributeParser::new(add_path);
let attributes = attr_parser.parse_attributes(input, asn_len, None, None, None, attribute_length)?;
let nlri_length = bgp_msg_length - 4 - withdrawn_length - attribute_length as u64;
let announced_prefixes = read_nlri(input, nlri_length as usize, &afi, add_path)?;
Ok(
BgpUpdateMessage{
withdrawn_prefixes,
attributes,
announced_prefixes
}
)
}