Refactored client binary.

This commit is contained in:
Rayhaan Jaufeerally
2024-07-07 22:34:00 +02:00
parent 75dbfc319a
commit 9be6b1d59d
34 changed files with 452 additions and 296 deletions

View File

@ -0,0 +1,19 @@
[package]
name = "bgp_packet"
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
version.workspace = true
[lints]
workspace = true
[dependencies]
byteorder = "1.4.3"
bytes.workspace = true
nom = "7.1"
serde.workspace = true
tokio-util = { version = "0.7.10", features = ["codec"] }

View File

@ -0,0 +1,741 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::constants::AddressFamilyIdentifier;
use crate::constants::SubsequentAddressFamilyIdentifier;
use crate::traits::BGPParserError;
use crate::traits::ParserContext;
use crate::traits::ReadablePacket;
use crate::traits::WritablePacket;
use byteorder::{ByteOrder, NetworkEndian};
use nom::number::complete::{be_u16, be_u8};
use nom::Err::Failure;
use nom::IResult;
use std::fmt;
/// BGPOpenOptionType represents the option types in the Open message.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
pub struct BGPOpenOptionType(pub u8);
impl BGPOpenOptionType {
pub fn new(val: u8) -> BGPOpenOptionType {
BGPOpenOptionType(val)
}
}
impl Into<u8> for BGPOpenOptionType {
fn into(self) -> u8 {
self.0
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod BGPOpenOptionTypeValues {
use super::BGPOpenOptionType;
pub const CAPABILITIES: BGPOpenOptionType = BGPOpenOptionType(2);
}
/// OpenOptionValue represents something which can be in the payload of OpenOption.
trait OpenOptionValue: ReadablePacket + WritablePacket + fmt::Debug {}
#[derive(Debug, PartialEq)]
pub struct OpenOption {
pub option_type: BGPOpenOptionType,
pub oval: OpenOptions,
}
impl ReadablePacket for OpenOption {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], OpenOption, BGPParserError<&'a [u8]>> {
let (buf, typ) = nom::combinator::complete(be_u8)(buf)?;
let (buf, val) = match BGPOpenOptionType(typ) {
BGPOpenOptionTypeValues::CAPABILITIES => {
let (b, cap) = OpenOptionCapabilities::from_wire(ctx, buf)?;
(b, OpenOptions::Capabilities(cap))
}
_ => {
// TODO: This should gracefully degrrrrade and not fail the parser.
return Err(Failure(BGPParserError::CustomText(
"Unknown BGP OPEN option".to_string(),
)));
}
};
IResult::Ok((
buf,
OpenOption {
option_type: BGPOpenOptionType(typ),
oval: val,
},
))
}
}
impl WritablePacket for OpenOption {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf = Vec::new();
match &self.oval {
OpenOptions::Capabilities(c) => {
buf.push(BGPOpenOptionTypeValues::CAPABILITIES.into());
buf.append(&mut c.to_wire(ctx)?);
}
}
Ok(buf)
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
match &self.oval {
OpenOptions::Capabilities(c) => {
return Ok(2 + c.wire_len(ctx)?);
}
}
}
}
impl fmt::Display for OpenOption {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "OpenOption: {}", self.oval)
}
}
#[derive(Debug, PartialEq)]
pub enum OpenOptions {
Capabilities(OpenOptionCapabilities),
}
impl fmt::Display for OpenOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
return match &self {
OpenOptions::Capabilities(c) => write!(f, "Capabilities: {}", c),
};
}
}
/// CapabilityList represents a list of capabilities which can be present in an OpenOption.
#[derive(Debug, PartialEq)]
pub struct OpenOptionCapabilities {
pub caps: Vec<BGPCapability>,
}
impl ReadablePacket for OpenOptionCapabilities {
// from wire reads the length and value of the TLV.
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], OpenOptionCapabilities, BGPParserError<&'a [u8]>> {
let (buf, caps): (_, Vec<BGPCapability>) = nom::multi::length_value(
be_u8,
nom::multi::many0(|i| BGPCapability::from_wire(ctx, i)),
)(buf)?;
return IResult::Ok((buf, OpenOptionCapabilities { caps }));
}
}
impl WritablePacket for OpenOptionCapabilities {
// to_wire writes the length and value of the TLV.
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = Vec::new();
buf.push(self.wire_len(ctx).unwrap() as u8);
for cap in &self.caps {
let mut result: Vec<u8> = (*cap).to_wire(ctx)?;
buf.append(&mut result);
}
Ok(buf)
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
let mut ttl: u16 = 0;
for cap in &self.caps {
ttl += (*cap).wire_len(ctx)?;
}
Ok(ttl)
}
}
impl fmt::Display for OpenOptionCapabilities {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Capabilities: [")?;
for cap in &self.caps {
std::fmt::Display::fmt(cap, f)?;
}
write!(f, "]")
}
}
/// BGP Capabilities.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
pub struct BGPCapabilityType(pub u8);
impl BGPCapabilityType {
pub fn new(val: u8) -> BGPCapabilityType {
BGPCapabilityType(val)
}
}
impl Into<u8> for BGPCapabilityType {
fn into(self) -> u8 {
return self.0;
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod BGPCapabilityTypeValues {
use super::BGPCapabilityType;
/// Multiprotocol Extensions for BGP-4 [RFC2858]
pub const MULTPROTOCOL_BGP4: BGPCapabilityType = BGPCapabilityType(1);
/// Route Refresh Capability for BGP-4 [RFC2918]
pub const ROUTE_REFRESH_BGP4: BGPCapabilityType = BGPCapabilityType(2);
/// Outbound Route Filtering Capability [RFC5291]
pub const OUTBOUND_ROUTE_FILTERING: BGPCapabilityType = BGPCapabilityType(3);
/// Extended Next Hop Encoding [RFC8950]
pub const EXTENDED_NEXT_HOP: BGPCapabilityType = BGPCapabilityType(5);
/// BGP Extended Message [RFC8654]
pub const EXTENDED_MESSAGE: BGPCapabilityType = BGPCapabilityType(6);
/// BGPsec Capability [RFC8205]
pub const BGPSEC: BGPCapabilityType = BGPCapabilityType(7);
/// Multiple Labels Capability [RFC8277]
pub const MULTILABEL_COMPAT: BGPCapabilityType = BGPCapabilityType(8);
/// Graceful Restart Capability [RFC4724]
pub const GRACEFUL_RESTART: BGPCapabilityType = BGPCapabilityType(64);
/// Support for 4-octet AS number capability [RFC6793]
pub const FOUR_BYTE_ASN: BGPCapabilityType = BGPCapabilityType(65);
/// ADD-PATH Capability [RFC7911]
pub const ADD_PATH: BGPCapabilityType = BGPCapabilityType(69);
/// Enhanced Route Refresh Capability [RFC7313]
pub const ENHANCED_ROUTE_REFRESH: BGPCapabilityType = BGPCapabilityType(70);
}
#[derive(Debug, PartialEq)]
pub struct BGPCapability {
pub cap_type: BGPCapabilityType,
pub val: BGPCapabilityValue,
}
impl ReadablePacket for BGPCapability {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], BGPCapability, BGPParserError<&'a [u8]>> {
let (buf, cap_type) = nom::combinator::peek(be_u8)(buf)?; // Peek the type, if we know it, consume.
let (buf, val): (_, BGPCapabilityValue) =
match BGPCapabilityType(cap_type) {
BGPCapabilityTypeValues::FOUR_BYTE_ASN => {
let (buf, _) = be_u8(buf)?; // Consume type
let (buf, cap) = nom::multi::length_value(be_u8, |i| {
FourByteASNCapability::from_wire(ctx, i)
})(buf)?;
(buf, BGPCapabilityValue::FourByteASN(cap))
}
BGPCapabilityTypeValues::MULTPROTOCOL_BGP4 => {
let (buf, _) = be_u8(buf)?;
let (buf, cap) = nom::multi::length_value(be_u8, |i| {
MultiprotocolCapability::from_wire(ctx, i)
})(buf)?;
(buf, BGPCapabilityValue::Multiprotocol(cap))
}
// TODO: Add extended next hop.
BGPCapabilityTypeValues::ROUTE_REFRESH_BGP4 => {
let (buf, _) = be_u8(buf)?;
let (buf, cap) = nom::multi::length_value(be_u8, |i| {
RouteRefreshCapability::from_wire(ctx, i)
})(buf)?;
(buf, BGPCapabilityValue::RouteRefresh(cap))
}
BGPCapabilityTypeValues::GRACEFUL_RESTART => {
let (buf, _) = be_u8(buf)?;
let (buf, cap) = nom::multi::length_value(be_u8, |i| {
GracefulRestartCapability::from_wire(ctx, i)
})(buf)?;
(buf, BGPCapabilityValue::GracefulRestart(cap))
}
_ => {
// If we do not know what this is, then put the bytes in an UnknownCapability.
let (buf, cap) = UnknownCapability::from_wire(ctx, buf)?;
(buf, BGPCapabilityValue::UnknownCapability(cap))
}
};
IResult::Ok((
buf,
BGPCapability {
cap_type: BGPCapabilityType(cap_type),
val,
},
))
}
}
impl WritablePacket for BGPCapability {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = vec![];
buf.push(self.cap_type.into());
match &self.val {
BGPCapabilityValue::FourByteASN(v) => {
buf.push(v.wire_len(ctx)? as u8);
buf.extend_from_slice(&v.to_wire(ctx)?);
}
BGPCapabilityValue::Multiprotocol(v) => {
buf.push(v.wire_len(ctx)? as u8);
buf.extend_from_slice(&v.to_wire(ctx)?);
}
BGPCapabilityValue::RouteRefresh(v) => {
buf.push(v.wire_len(ctx)? as u8);
buf.extend_from_slice(&v.to_wire(ctx)?);
}
BGPCapabilityValue::GracefulRestart(v) => {
buf.push(v.wire_len(ctx)? as u8);
buf.extend_from_slice(&v.to_wire(ctx)?);
}
BGPCapabilityValue::UnknownCapability(v) => {
buf.push(v.wire_len(ctx)? as u8);
buf.extend_from_slice(&v.to_wire(ctx)?);
}
};
Ok(buf)
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
// BGPCapabilityType(u8) + cap_len(u8) + val
return match &self.val {
BGPCapabilityValue::FourByteASN(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::Multiprotocol(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::RouteRefresh(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::GracefulRestart(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::UnknownCapability(v) => Ok(2 + v.wire_len(ctx)?),
};
}
}
impl fmt::Display for BGPCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
std::fmt::Display::fmt(&self.val, f)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum BGPCapabilityValue {
FourByteASN(FourByteASNCapability),
Multiprotocol(MultiprotocolCapability),
RouteRefresh(RouteRefreshCapability),
GracefulRestart(GracefulRestartCapability),
UnknownCapability(UnknownCapability),
}
impl fmt::Display for BGPCapabilityValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
BGPCapabilityValue::FourByteASN(v) => std::fmt::Display::fmt(v, f),
BGPCapabilityValue::Multiprotocol(v) => std::fmt::Display::fmt(v, f),
BGPCapabilityValue::RouteRefresh(v) => std::fmt::Display::fmt(v, f),
BGPCapabilityValue::GracefulRestart(v) => std::fmt::Display::fmt(v, f),
BGPCapabilityValue::UnknownCapability(v) => std::fmt::Display::fmt(v, f),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct UnknownCapability {
cap_code: u8,
payload: Vec<u8>,
}
impl ReadablePacket for UnknownCapability {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, typ) = be_u8(buf)?;
let (buf, len) = be_u8(buf)?;
let (buf, payload) = nom::bytes::complete::take(len)(buf)?;
Ok((
buf,
UnknownCapability {
cap_code: typ,
payload: payload.to_vec(),
},
))
}
}
impl WritablePacket for UnknownCapability {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf = vec![];
// No need to push the type or length on as that's done at a higher level.
buf.extend(self.payload.to_owned());
Ok(buf)
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(self.payload.len() as u16)
}
}
impl fmt::Display for UnknownCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UnknownCapability type: {}", self.cap_code)
}
}
/// FourByteASNCapability represents the four byte BGP Capability value.
#[derive(Clone, Debug, PartialEq)]
pub struct FourByteASNCapability {
pub asn: u32,
}
impl FourByteASNCapability {
fn new(asn: u32) -> FourByteASNCapability {
FourByteASNCapability { asn }
}
}
impl ReadablePacket for FourByteASNCapability {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, asn) = nom::combinator::complete(nom::number::complete::be_u32)(buf)?;
return IResult::Ok((buf, FourByteASNCapability::new(asn)));
}
}
impl WritablePacket for FourByteASNCapability {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = vec![0; 4];
byteorder::NetworkEndian::write_u32(&mut buf, self.asn);
Ok(buf)
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(4)
}
}
impl fmt::Display for FourByteASNCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FourByteASN: asn: {}", self.asn)
}
}
/// MultiprotocolExtCapability represents support for RFC 4760.
#[derive(Clone, Debug, PartialEq)]
pub struct MultiprotocolCapability {
pub afi: AddressFamilyIdentifier,
pub safi: SubsequentAddressFamilyIdentifier,
}
impl MultiprotocolCapability {
fn new(
afi: AddressFamilyIdentifier,
safi: SubsequentAddressFamilyIdentifier,
) -> MultiprotocolCapability {
MultiprotocolCapability { afi, safi }
}
}
impl ReadablePacket for MultiprotocolCapability {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], MultiprotocolCapability, BGPParserError<&'a [u8]>> {
let (buf, (afi_raw, _, safi_raw)) = nom::combinator::complete(nom::sequence::tuple((
|i| AddressFamilyIdentifier::from_wire(ctx, i),
nom::bytes::complete::take(1u8),
|i| SubsequentAddressFamilyIdentifier::from_wire(ctx, i),
)))(buf)?;
let afi = AddressFamilyIdentifier::try_from(afi_raw)
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
let safi = SubsequentAddressFamilyIdentifier::try_from(safi_raw)
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
IResult::Ok((buf, MultiprotocolCapability::new(afi, safi)))
}
}
impl WritablePacket for MultiprotocolCapability {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
// [ AFI: uint16, 0: uint8, SAFI: uint8 ]
let mut res = [0u8; 4];
byteorder::NetworkEndian::write_u16(&mut res[..2], self.afi.into());
res[3] = self.safi.into();
Ok(res.to_vec())
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(4)
}
}
impl fmt::Display for MultiprotocolCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MultiprotocolCapbility: [ {} {} ]", self.afi, self.safi,)
}
}
// Route refresh capability
#[derive(Clone, Debug, PartialEq)]
pub struct RouteRefreshCapability {}
impl WritablePacket for RouteRefreshCapability {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
Ok(vec![])
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(0)
}
}
impl ReadablePacket for RouteRefreshCapability {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], RouteRefreshCapability, BGPParserError<&'a [u8]>> {
IResult::Ok((buf, RouteRefreshCapability {}))
}
}
impl fmt::Display for RouteRefreshCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RouteRefreshCapability")
}
}
// Graceful restart capability
#[derive(Clone, Debug, PartialEq)]
pub struct GracefulRestartCapability {
pub restart_state: bool, // 4 bits total, most sig bit here, rest reserved.
pub restart_time_sec: u16, // 12 bits.
pub payloads: Vec<GracefulRestartPayload>,
}
// GracefulRestartPayload represents the contents of the graceful restart cap.
#[derive(Clone, Debug, PartialEq)]
pub struct GracefulRestartPayload {
pub afi: AddressFamilyIdentifier,
pub safi: SubsequentAddressFamilyIdentifier,
pub af_flags: bool, // 8 bits total, most significant bit used here.
}
impl ReadablePacket for GracefulRestartPayload {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], GracefulRestartPayload, BGPParserError<&'a [u8]>> {
let (buf, (afi, safi, flags)) = nom::combinator::complete(nom::sequence::tuple((
|i| AddressFamilyIdentifier::from_wire(ctx, i),
|i| SubsequentAddressFamilyIdentifier::from_wire(ctx, i),
be_u8,
)))(buf)?;
IResult::Ok((
buf,
GracefulRestartPayload {
afi,
safi,
af_flags: (0x80 & flags) != 0,
},
))
}
}
impl WritablePacket for GracefulRestartPayload {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let afi: u16 = self.afi.into();
let mut res = vec![0u8; 2];
byteorder::NetworkEndian::write_u16(res.as_mut(), afi.into());
res.push(self.safi.into());
res.push(if self.af_flags { 0x80 } else { 0 });
Ok(res)
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(4)
}
}
impl fmt::Display for GracefulRestartPayload {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GracefulRestartPayload: [afi:{} safi:{} af_flags:{}]",
self.afi, self.safi, self.af_flags
)
}
}
impl ReadablePacket for GracefulRestartCapability {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, state_rt) = nom::combinator::complete(be_u16)(buf)?;
let (buf, payloads): (_, Vec<GracefulRestartPayload>) =
nom::multi::many0(|i| GracefulRestartPayload::from_wire(ctx, i))(buf)?;
let restart_time_sec: u16 = 0x0fff & state_rt; // Lower 14 bits.
let restart_state: bool = (0x8000 & state_rt) != 0; // highest bit
IResult::Ok((
buf,
GracefulRestartCapability {
restart_state,
restart_time_sec,
payloads,
},
))
}
}
impl WritablePacket for GracefulRestartCapability {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = vec![0u8; 2];
let state_rt: u16 = ((self.restart_state as u16) << 15) | (0xfff & self.restart_time_sec);
NetworkEndian::write_u16(&mut buf, state_rt);
for item in &self.payloads {
buf.append(&mut item.to_wire(ctx)?);
}
Ok(buf)
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok((2 + self.payloads.len() * 4) as u16)
}
}
impl fmt::Display for GracefulRestartCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "GracefulRestartCapability: [")?;
for value in &self.payloads {
fmt::Display::fmt(value, f)?;
}
write!(f, " ]")
}
}
// RFC8950 - Advertising IPv4 NLRI with IPv6 next hop.
// GracefulRestartPayload represents the contents of the graceful restart cap.
#[derive(Clone, Debug, PartialEq)]
pub struct ExtendedNextHopEncodingCapability {
pub afi_safi_nhafi: Vec<(
AddressFamilyIdentifier,
SubsequentAddressFamilyIdentifier,
AddressFamilyIdentifier,
)>,
}
impl WritablePacket for ExtendedNextHopEncodingCapability {
fn to_wire(&self, _ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
Ok(self
.afi_safi_nhafi
.iter()
.map(|e| {
Into::<Vec<u8>>::into(e.0)
.into_iter()
.chain(vec![0x00, Into::<u8>::into(e.1)].into_iter())
.chain(Into::<Vec<u8>>::into(e.2).into_iter())
.collect::<Vec<u8>>()
})
.flatten()
.collect::<Vec<u8>>())
}
fn wire_len(&self, _ctx: &ParserContext) -> Result<u16, &'static str> {
Ok((self.afi_safi_nhafi.len() * 6) as u16)
}
}
impl ReadablePacket for ExtendedNextHopEncodingCapability {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>>
where
Self: Sized,
{
let (buf, tuples) = nom::combinator::complete(nom::multi::many0(nom::sequence::tuple((
|i| AddressFamilyIdentifier::from_wire(ctx, i),
|i| {
let (buf, _) = be_u8(i)?; // Eat the 0 byte.
SubsequentAddressFamilyIdentifier::from_wire(ctx, buf)
},
|i| AddressFamilyIdentifier::from_wire(ctx, i),
))))(buf)?;
IResult::Ok((
buf,
Self {
afi_safi_nhafi: tuples,
},
))
}
}
impl fmt::Display for ExtendedNextHopEncodingCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ExtendednextHopEncodingCapability [")?;
for entry in &self.afi_safi_nhafi {
write!(f, "afi: {}, safi: {}, nhafi: {}", entry.0, entry.1, entry.2)?;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use super::BGPCapability;
use super::BGPCapabilityTypeValues;
use super::BGPCapabilityValue;
use super::ExtendedNextHopEncodingCapability;
use super::FourByteASNCapability;
use super::OpenOption;
use crate::constants::AddressFamilyIdentifier::Ipv6;
use crate::traits::ParserContext;
use crate::traits::ReadablePacket;
#[test]
fn test_four_byte_asn_capability() {
let bytes: &[u8] = &[0x41, 0x04, 0x00, 0x00, 0x00, 0x2a];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
let (buf, result) = BGPCapability::from_wire(ctx, bytes).unwrap();
assert_eq!(
result,
BGPCapability {
cap_type: BGPCapabilityTypeValues::FOUR_BYTE_ASN,
val: BGPCapabilityValue::FourByteASN(FourByteASNCapability { asn: 42 })
}
);
assert_eq!(buf.len(), 0);
}
#[test]
fn test_open_options<'a>() {
let option_bytes: &[u8] = &[
0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02,
0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00, 0x2a,
];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
let (_buf, result) =
nom::multi::many0(|buf: &'a [u8]| OpenOption::from_wire(ctx, buf))(option_bytes)
.unwrap();
let expected_str = "[OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(1), val: Multiprotocol(MultiprotocolCapability { afi: Ipv4, safi: Unicast }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(128), val: UnknownCapability(UnknownCapability { cap_code: 128, payload: [] }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(2), val: RouteRefresh(RouteRefreshCapability) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(70), val: UnknownCapability(UnknownCapability { cap_code: 70, payload: [] }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(65), val: FourByteASN(FourByteASNCapability { asn: 42 }) }] }) }]";
assert_eq!(format!("{:?}", result), expected_str);
}
#[test]
fn test_extended_next_hop_encoding_capability() {
let bytes: Vec<u8> = vec![0x00, 0x01, 0x00, 0x01, 0x00, 0x02];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
let (_, cap) = ExtendedNextHopEncodingCapability::from_wire(ctx, &bytes).unwrap();
let expected_str =
"ExtendednextHopEncodingCapability [afi: Ipv4, safi: Unicast, nhafi: Ipv6]";
assert_eq!(expected_str, cap.to_string());
}
}

View File

@ -0,0 +1,153 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use nom::IResult;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::io::ErrorKind;
use super::traits::{BGPParserError, ParserContext, ReadablePacket};
// Address Family Identifiers as per
// https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml
#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize, Hash)]
pub enum AddressFamilyIdentifier {
Ipv4,
Ipv6,
}
impl Into<u16> for AddressFamilyIdentifier {
fn into(self) -> u16 {
match self {
Self::Ipv4 => 1,
Self::Ipv6 => 2,
}
}
}
impl TryFrom<u16> for AddressFamilyIdentifier {
type Error = std::io::Error;
fn try_from(i: u16) -> Result<Self, Self::Error> {
match i {
1 => Ok(Self::Ipv4),
2 => Ok(Self::Ipv6),
_ => Err(std::io::Error::new(
ErrorKind::InvalidInput,
format!("Unknown AFI: {}", i),
)),
}
}
}
impl Into<Vec<u8>> for AddressFamilyIdentifier {
fn into(self) -> Vec<u8> {
match self {
Self::Ipv4 => 1_u16.to_be_bytes().to_vec(),
Self::Ipv6 => 2_u16.to_be_bytes().to_vec(),
}
}
}
/// This parser for AFI makes it easier to write the other message parsers.
impl ReadablePacket for AddressFamilyIdentifier {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], AddressFamilyIdentifier, BGPParserError<&'a [u8]>> {
let (buf, afi_raw) = nom::number::complete::be_u16(buf)?;
let afi = AddressFamilyIdentifier::try_from(afi_raw)
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
IResult::Ok((buf, afi))
}
}
impl fmt::Display for AddressFamilyIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Ipv4 => write!(f, "Ipv4"),
Self::Ipv6 => write!(f, "Ipv6"),
}
}
}
// Subsequent Address Family Identifiers as per
// https://www.iana.org/assignments/safi-namespace/safi-namespace.xhtml
#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize)]
pub enum SubsequentAddressFamilyIdentifier {
Unicast,
Multicast,
NlriWithMpls,
MplsLabeledVPN,
MulticastMplsVpn,
}
impl Into<u8> for SubsequentAddressFamilyIdentifier {
fn into(self) -> u8 {
match self {
Self::Unicast => 1,
Self::Multicast => 2,
Self::NlriWithMpls => 4,
Self::MplsLabeledVPN => 128,
Self::MulticastMplsVpn => 129,
}
}
}
impl TryFrom<u8> for SubsequentAddressFamilyIdentifier {
type Error = std::io::Error;
fn try_from(i: u8) -> Result<Self, Self::Error> {
match i {
1 => Ok(Self::Unicast),
2 => Ok(Self::Multicast),
4 => Ok(Self::NlriWithMpls),
128 => Ok(Self::MplsLabeledVPN),
129 => Ok(Self::MulticastMplsVpn),
_ => Err(std::io::Error::new(
ErrorKind::InvalidInput,
format!("Unknown SAFI value: {} ", i),
)),
}
}
}
/// This parser for SAFI makes it easier to write the other message parsers.
impl ReadablePacket for SubsequentAddressFamilyIdentifier {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], SubsequentAddressFamilyIdentifier, BGPParserError<&'a [u8]>> {
let (buf, safi_raw) = nom::number::complete::be_u8(buf)?;
let safi = SubsequentAddressFamilyIdentifier::try_from(safi_raw)
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
IResult::Ok((buf, safi))
}
}
impl fmt::Display for SubsequentAddressFamilyIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unicast => write!(f, "Unicast"),
Self::Multicast => write!(f, "Multicast"),
Self::NlriWithMpls => write!(f, "NlriWithMpls"),
Self::MulticastMplsVpn => write!(f, "MulticastMplsVpn"),
Self::MplsLabeledVPN => write!(f, "MplsLabeledVpn"),
}
}
}
pub const AS_TRANS: u16 = 23456;

View File

@ -0,0 +1,26 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Implements parsers / serializers for the Border Gateway Protocol wire format.
//! RFC4271
// Meta
pub mod constants;
pub mod traits;
// Parsers
pub mod capabilities;
pub mod messages;
pub mod nlri;
pub mod path_attributes;

View File

@ -0,0 +1,710 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::capabilities::OpenOption;
use crate::constants::AddressFamilyIdentifier;
use crate::constants::SubsequentAddressFamilyIdentifier;
use crate::nlri::NLRI;
use crate::path_attributes::PathAttribute;
use crate::traits::BGPParserError;
use crate::traits::ParserContext;
use crate::traits::ReadablePacket;
use crate::traits::WritablePacket;
use byteorder::{ByteOrder, NetworkEndian};
use bytes::Buf;
use bytes::BufMut;
use bytes::BytesMut;
use nom::number::complete::{be_u16, be_u32, be_u8};
use nom::Err::Failure;
use nom::IResult;
use std::convert::TryInto;
use std::fmt;
use std::fmt::Display;
use std::net::Ipv4Addr;
use tokio_util::codec::{Decoder, Encoder};
/// BGPMessageType represents the type of the top level BGP message.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
pub struct BGPMessageType(pub u8);
impl BGPMessageType {
pub fn new(val: u8) -> BGPMessageType {
BGPMessageType(val)
}
}
impl Into<u8> for BGPMessageType {
fn into(self) -> u8 {
self.0
}
}
impl From<u8> for BGPMessageType {
fn from(i: u8) -> BGPMessageType {
BGPMessageType(i)
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod BGPMessageTypeValues {
use super::BGPMessageType;
pub const OPEN_MESSAGE: BGPMessageType = BGPMessageType(1);
pub const UPDATE_MESSAGE: BGPMessageType = BGPMessageType(2);
pub const NOTIFICATION_MESSAGE: BGPMessageType = BGPMessageType(3);
pub const KEEPALIVE_MESSAGE: BGPMessageType = BGPMessageType(4);
pub const REFRESH_MESSAGE: BGPMessageType = BGPMessageType(5);
}
#[derive(Debug, PartialEq)]
pub enum BGPSubmessage {
OpenMessage(OpenMessage),
UpdateMessage(UpdateMessage),
NotificationMessage(NotificationMessage),
KeepaliveMessage(KeepaliveMessage),
}
impl WritablePacket for BGPSubmessage {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
match &self {
BGPSubmessage::OpenMessage(m) => m.to_wire(ctx),
BGPSubmessage::UpdateMessage(m) => m.to_wire(ctx),
BGPSubmessage::NotificationMessage(m) => m.to_wire(ctx),
BGPSubmessage::KeepaliveMessage(m) => m.to_wire(ctx),
}
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
match &self {
BGPSubmessage::OpenMessage(m) => m.wire_len(ctx),
BGPSubmessage::UpdateMessage(m) => m.wire_len(ctx),
BGPSubmessage::NotificationMessage(m) => m.wire_len(ctx),
BGPSubmessage::KeepaliveMessage(m) => m.wire_len(ctx),
}
}
}
/// KeepaliveMessage implements the KEEPALIVE message as defined in RFC4271.
#[derive(Debug, PartialEq)]
pub struct KeepaliveMessage {}
impl ReadablePacket for KeepaliveMessage {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
Ok((buf, KeepaliveMessage {}))
}
}
impl WritablePacket for KeepaliveMessage {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
Ok(vec![])
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(0)
}
}
impl Display for KeepaliveMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "KeepaliveMessage")
}
}
/// NotificationMessage implements the NOTIFICATION message type as defined in RFC4271.
#[derive(Debug, PartialEq)]
pub struct NotificationMessage {
pub error_code: u8,
pub error_subcode: u8,
pub data: Vec<u8>,
}
impl ReadablePacket for NotificationMessage {
fn from_wire<'a>(
_: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, ec) = be_u8(buf)?;
let (buf, esc) = be_u8(buf)?;
let data = &buf;
Ok((
&[0u8; 0],
NotificationMessage {
error_code: ec,
error_subcode: esc,
data: data.to_vec(),
},
))
}
}
impl WritablePacket for NotificationMessage {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf = vec![];
buf.push(self.error_code);
buf.push(self.error_subcode);
buf.extend(self.data.to_owned());
Ok(buf)
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(2 + self.data.len() as u16)
}
}
impl Display for NotificationMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"NotificationMessage error_code: {}, error_subcode: {}",
self.error_code, self.error_subcode
)
}
}
#[derive(Debug, PartialEq)]
pub struct RouteRefreshMessage {
pub afi: AddressFamilyIdentifier,
pub safi: SubsequentAddressFamilyIdentifier,
}
impl WritablePacket for RouteRefreshMessage {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut res = [0u8; 4];
byteorder::NetworkEndian::write_u16(&mut res[..2], self.afi.into());
res[3] = self.safi.into();
Ok(res.to_vec())
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(4)
}
}
impl ReadablePacket for RouteRefreshMessage {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, (afi, _, safi)) = nom::combinator::complete(nom::sequence::tuple((
|i| AddressFamilyIdentifier::from_wire(ctx, i),
nom::bytes::complete::take(1u8),
|i| SubsequentAddressFamilyIdentifier::from_wire(ctx, i),
)))(buf)?;
IResult::Ok((buf, RouteRefreshMessage { afi, safi }))
}
}
impl Display for RouteRefreshMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RouteRefresh [afi: {}, safi: {}]", self.afi, self.safi)
}
}
/// BGPMessage is the top level message which is transmitted over the wire.
#[derive(Debug, PartialEq)]
pub struct BGPMessage {
pub msg_type: BGPMessageType,
pub payload: BGPSubmessage,
}
/// Codec is a helper for serializing and deserializing BGP messages.
pub struct Codec {
pub ctx: ParserContext,
}
impl Encoder<BGPMessage> for Codec {
type Error = std::io::Error;
fn encode(
&mut self,
msg: BGPMessage,
buf: &mut BytesMut,
) -> Result<(), <Self as Encoder<BGPMessage>>::Error> {
let result = msg.to_wire(&self.ctx);
match result {
Ok(bytes) => {
// XXX: Copying here because the whole write path needs to be updated
// to take a refrence to BytesMut and write to that directly.
let tmp: BytesMut = bytes.as_slice().into();
buf.put(tmp);
Ok(())
}
Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
}
}
}
impl Decoder for Codec {
type Item = BGPMessage;
type Error = std::io::Error;
fn decode(
&mut self,
buf: &mut BytesMut,
) -> Result<std::option::Option<<Self as Decoder>::Item>, <Self as Decoder>::Error> {
// We first check to see if the frame contains the full BGP message before invoking
// the parser on it.
// Expected contents: 16x 0xff, u16 of length.
// The length contains the header length, so we just check that the buf len matches.
if buf.len() < 19 {
// Minimum size is 19 for header + length + type.
return Ok(None);
}
// Read the length
let len: u16 = byteorder::BigEndian::read_u16(&buf[16..18]);
if buf.len() < len.into() {
// Not enough data to read this frame.
return Ok(None);
} else if buf.len() == len as usize {
// Exactly one message here, parse and clear buf.
let parse_result = BGPMessage::from_wire(&self.ctx, buf.as_ref());
match parse_result {
Ok(msg) => {
let result = msg.1;
buf.clear();
Ok(Some(result))
}
Err(e) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to parse message: {:?}", e),
)),
}
} else {
// More than one message here, parse and advance buf.
let parse_result = BGPMessage::from_wire(&self.ctx, buf.as_ref());
match parse_result {
Ok(msg) => {
let result = msg.1;
buf.advance(len as usize);
Ok(Some(result))
}
Err(e) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to parse message: {:?}", e),
)),
}
}
}
}
impl WritablePacket for BGPMessage {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = Vec::new();
// 16 bytes of 0xff according to Section 4.1 of RFC4271.
buf.append(&mut vec![0xff; 16]);
// Length.
{
let mut tmp: [u8; 2] = [0u8; 2];
NetworkEndian::write_u16(&mut tmp, self.wire_len(ctx)?);
buf.extend_from_slice(&mut tmp);
}
// Type
buf.push(self.msg_type.into());
let mut result: Vec<u8> = self.payload.to_wire(ctx)?;
buf.append(&mut result);
Ok(buf)
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
Ok(16 + 2 + 1 + self.payload.wire_len(ctx)?)
}
}
impl ReadablePacket for BGPMessage {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, _) = nom::combinator::complete(nom::bytes::complete::tag(&[0xff; 16]))(buf)?;
let (buf, len) = nom::combinator::complete(be_u16)(buf)?;
let (buf, typ) = nom::combinator::complete(be_u8)(buf)?;
let payload_len = len - 19;
let (buf, payload_bytes) = nom::bytes::complete::take(payload_len)(buf)?;
let (_, payload) = match typ.into() {
BGPMessageTypeValues::OPEN_MESSAGE => {
let (b, omsg) = OpenMessage::from_wire(ctx, payload_bytes)?;
(b, BGPSubmessage::OpenMessage(omsg))
}
BGPMessageTypeValues::UPDATE_MESSAGE => {
let (b, umsg) = UpdateMessage::from_wire(ctx, payload_bytes)?;
(b, BGPSubmessage::UpdateMessage(umsg))
}
BGPMessageTypeValues::NOTIFICATION_MESSAGE => {
let (b, nmsg) = NotificationMessage::from_wire(ctx, payload_bytes)?;
(b, BGPSubmessage::NotificationMessage(nmsg))
}
BGPMessageTypeValues::KEEPALIVE_MESSAGE => {
let (b, kmsg) = KeepaliveMessage::from_wire(ctx, payload_bytes)?;
(b, BGPSubmessage::KeepaliveMessage(kmsg))
}
_ => {
return Err(Failure(BGPParserError::CustomText(
"Unknown BGP message type".to_string(),
)));
}
};
Ok((
buf,
BGPMessage {
msg_type: BGPMessageType(typ),
payload,
},
))
}
}
impl Display for BGPMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.payload {
BGPSubmessage::OpenMessage(m) => fmt::Display::fmt(&m, f),
BGPSubmessage::UpdateMessage(m) => fmt::Display::fmt(&m, f),
BGPSubmessage::KeepaliveMessage(m) => fmt::Display::fmt(&m, f),
BGPSubmessage::NotificationMessage(m) => fmt::Display::fmt(&m, f),
}
}
}
#[derive(Debug, PartialEq)]
pub struct OpenMessage {
pub version: u8,
pub asn: u16,
pub hold_time: u16,
pub identifier: Ipv4Addr,
pub options: Vec<OpenOption>,
}
impl ReadablePacket for OpenMessage {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], OpenMessage, BGPParserError<&'a [u8]>> {
let (buf, (version, asn, hold_time, identifier)) =
nom::combinator::complete(nom::sequence::tuple((be_u8, be_u16, be_u16, be_u32)))(buf)?;
// oplen, [ [OpenOption] ... ]
// OpenOption = [T, L, V]
let (buf, opts): (_, Vec<OpenOption>) = nom::multi::length_value(
be_u8,
nom::multi::many0(|b| OpenOption::from_wire(ctx, b)),
)(buf)?;
Ok((
buf,
OpenMessage {
version,
asn,
hold_time,
identifier: Ipv4Addr::from(identifier),
options: opts,
},
))
}
}
impl WritablePacket for OpenMessage {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = vec![0; 10];
buf[0] = self.version;
NetworkEndian::write_u16(&mut buf.as_mut_slice()[1..3], self.asn);
NetworkEndian::write_u16(&mut buf.as_mut_slice()[3..5], self.hold_time);
buf[5..9].clone_from_slice(&self.identifier.octets());
let mut oplen: u8 = 0;
for opt in &self.options {
buf.append(&mut (*opt).to_wire(ctx)?);
oplen += ((*opt).wire_len(ctx)?) as u8;
}
buf[9] = oplen;
Ok(buf)
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
let mut count: usize = 10;
for opt in &self.options {
count += (*opt).to_wire(ctx)?.len();
}
Ok(count
.try_into()
.map_err(|_| "overflow in wire_len in OpenMessage")?)
}
}
impl Display for OpenMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"OpenMessage: [version: {}, asn: {}, hold_time: {}, identifier: {}, options: [",
self.version, self.asn, self.hold_time, self.identifier
)?;
for option in &self.options {
fmt::Display::fmt(option, f)?;
}
write!(f, "]]")
}
}
/// UPDATE message and subtypes.
#[derive(Debug, PartialEq)]
pub struct UpdateMessage {
pub withdrawn_nlri: Vec<NLRI>,
pub path_attributes: Vec<PathAttribute>,
pub announced_nlri: Vec<NLRI>,
}
impl ReadablePacket for UpdateMessage {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, wd_nlris): (_, Vec<NLRI>) = nom::multi::length_value(
be_u16,
nom::multi::many0(|i| NLRI::from_wire(&ctx.clone(), i)),
)(buf)?;
let (buf, pattrs): (_, Vec<PathAttribute>) = nom::multi::length_value(
be_u16,
nom::multi::many0(|i| PathAttribute::from_wire(ctx, i)),
)(buf)?;
let (buf, ann_nlri): (_, Vec<NLRI>) =
nom::multi::many0(|i| NLRI::from_wire(&ctx.clone(), i))(buf)?;
Ok((
buf,
UpdateMessage {
withdrawn_nlri: wd_nlris,
path_attributes: pattrs,
announced_nlri: ann_nlri,
},
))
}
}
impl WritablePacket for UpdateMessage {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = Vec::new();
let mut tmp: &mut [u8] = &mut [0u8; 2];
let mut wd_len: u16 = 0;
for wd in &self.withdrawn_nlri {
wd_len += wd.wire_len(ctx)?;
}
NetworkEndian::write_u16(&mut tmp, wd_len);
buf.append(&mut tmp.to_vec());
for wd in &self.withdrawn_nlri {
buf.extend(wd.to_wire(ctx)?);
}
let mut pattr_len: u16 = 0;
for pattr in &self.path_attributes {
pattr_len += pattr.wire_len(ctx)?;
}
NetworkEndian::write_u16(&mut tmp, pattr_len);
buf.extend(tmp.to_vec());
for pattr in &self.path_attributes {
buf.extend(pattr.to_wire(ctx)?);
}
for ann in &self.announced_nlri {
buf.extend(ann.to_wire(ctx)?);
}
Ok(buf)
}
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
let mut ctr: u16 = 0;
ctr += 2;
for wd in &self.withdrawn_nlri {
ctr += wd.wire_len(ctx)?;
}
ctr += 2;
for pa in &self.path_attributes {
ctr += pa.wire_len(ctx)?;
}
for ann in &self.announced_nlri {
ctr += ann.wire_len(ctx)?;
}
Ok(ctr)
}
}
impl Display for UpdateMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UpdateMessage [ withdrawn: ")?;
for withdrawn_nlri in &self.withdrawn_nlri {
fmt::Display::fmt(withdrawn_nlri, f)?;
}
for announced_nlri in &self.announced_nlri {
fmt::Display::fmt(announced_nlri, f)?;
}
for path_attr in &self.path_attributes {
fmt::Display::fmt(path_attr, f)?;
}
write!(f, " ]")
}
}
#[cfg(test)]
mod tests {
use super::BGPMessage;
use super::Codec;
use crate::constants::AddressFamilyIdentifier::Ipv6;
use crate::messages::AddressFamilyIdentifier::Ipv4;
use crate::traits::ParserContext;
use crate::traits::ReadablePacket;
use crate::traits::WritablePacket;
use bytes::BufMut;
use tokio_util::codec::{Decoder, Encoder};
#[test]
fn test_open_msg() {
let open_msg_bytes: &[u8] = &[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x39, 0x01, 0x04, 0x00, 0x2a, 0x00, 0xb4, 0xd4, 0x19, 0x16, 0x26,
0x1c, 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02,
0x02, 0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00,
0x2a,
];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap();
assert_eq!(buf.len(), 0);
let want_str = "OpenMessage: [version: 4, asn: 42, hold_time: 180, identifier: 212.25.22.38, options: [OpenOption: Capabilities: Capabilities: [MultiprotocolCapbility: [ Ipv4 Unicast ]]OpenOption: Capabilities: Capabilities: [UnknownCapability type: 128]OpenOption: Capabilities: Capabilities: [RouteRefreshCapability]OpenOption: Capabilities: Capabilities: [UnknownCapability type: 70]OpenOption: Capabilities: Capabilities: [FourByteASN: asn: 42]]]";
assert_eq!(format!("{}", result), want_str);
let wire: Vec<u8> = result.to_wire(ctx).unwrap();
assert_eq!(wire, open_msg_bytes);
}
#[test]
fn test_open_msg_ipv6() {
let open_msg_bytes: &[u8] = &[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x35, 0x01, 0x04, 0x22, 0x36, 0x00, 0xb4, 0xd4, 0x19, 0x1b, 0x2d,
0x18, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02,
0x02, 0x80, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x22, 0x36,
];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap();
assert_eq!(buf.len(), 0);
let want_str = "OpenMessage: [version: 4, asn: 8758, hold_time: 180, identifier: 212.25.27.45, options: [OpenOption: Capabilities: Capabilities: [MultiprotocolCapbility: [ Ipv6 Unicast ]]OpenOption: Capabilities: Capabilities: [RouteRefreshCapability]OpenOption: Capabilities: Capabilities: [UnknownCapability type: 128]OpenOption: Capabilities: Capabilities: [FourByteASN: asn: 8758]]]";
assert_eq!(format!("{}", result), want_str);
let wire: Vec<u8> = result.to_wire(ctx).unwrap();
assert_eq!(wire, open_msg_bytes);
}
#[test]
fn test_update_msg_simple() {
let update_msg_bytes: &[u8] = &[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x79, 0x02, 0x00, 0x00, 0x00, 0x5e, 0x40, 0x01, 0x01, 0x02, 0x40,
0x02, 0x16, 0x02, 0x05, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00,
0x73, 0xfb, 0x00, 0x00, 0x05, 0x13, 0x00, 0x00, 0x12, 0x83, 0x40, 0x03, 0x04, 0xb9,
0x5f, 0xdb, 0x24, 0xc0, 0x08, 0x1c, 0x05, 0x13, 0x88, 0xb8, 0x73, 0xfb, 0x0f, 0xa0,
0x73, 0xfb, 0x0f, 0xb5, 0x9a, 0x74, 0x0f, 0xa0, 0x9a, 0x74, 0x0f, 0xaa, 0xdf, 0x1e,
0x07, 0xd0, 0xdf, 0x1e, 0x07, 0xda, 0xc0, 0x20, 0x18, 0x00, 0x00, 0xdf, 0x1e, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e,
];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
let (buf, result) = BGPMessage::from_wire(ctx, update_msg_bytes).unwrap();
assert_eq!(buf.len(), 0);
let want_str = "UpdateMessage [ withdrawn: 203.1.78.0/24Origin: UnknownAS Path: { Segment [ Type: AS_SEGMENT 39540 57118 29691 1299 4739 ]] }NextHop: 185.95.219.36Communities: [ 1299:35000, 29691:4000, 29691:4021, 39540:4000, 39540:4010, 57118:2000, 57118:2010, ] LargeCommunities: [ 57118:20:0, 57118:20:10, ] ]";
assert_eq!(format!("{}", result), want_str);
let reencoded = result.to_wire(&ctx).unwrap();
assert_eq!(&reencoded, update_msg_bytes);
}
#[test]
fn test_insufficient_decode() {
let update_msg_bytes: &[u8] = &[0xff, 0xff, 0xff, 0xff, 0xff];
let codec = &mut Codec {
ctx: ParserContext {
four_octet_asn: Some(true),
nlri_mode: Some(Ipv6),
},
};
let mut buf = bytes::BytesMut::from(update_msg_bytes);
let result = codec.decode(&mut buf);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
assert_eq!(buf.len(), 5);
}
#[test]
fn test_exact_decode_encode() {
let update_msg_bytes: &[u8] = &[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x79, 0x02, 0x00, 0x00, 0x00, 0x5e, 0x40, 0x01, 0x01, 0x02, 0x40,
0x02, 0x16, 0x02, 0x05, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00,
0x73, 0xfb, 0x00, 0x00, 0x05, 0x13, 0x00, 0x00, 0x12, 0x83, 0x40, 0x03, 0x04, 0xb9,
0x5f, 0xdb, 0x24, 0xc0, 0x08, 0x1c, 0x05, 0x13, 0x88, 0xb8, 0x73, 0xfb, 0x0f, 0xa0,
0x73, 0xfb, 0x0f, 0xb5, 0x9a, 0x74, 0x0f, 0xa0, 0x9a, 0x74, 0x0f, 0xaa, 0xdf, 0x1e,
0x07, 0xd0, 0xdf, 0x1e, 0x07, 0xda, 0xc0, 0x20, 0x18, 0x00, 0x00, 0xdf, 0x1e, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e,
];
let codec = &mut Codec {
ctx: ParserContext {
four_octet_asn: Some(true),
nlri_mode: Some(Ipv6),
},
};
let mut buf = bytes::BytesMut::from(update_msg_bytes);
let result = codec.decode(&mut buf).unwrap();
assert!(result.is_some());
assert_eq!(buf.len(), 0);
codec.encode(result.unwrap(), &mut buf).unwrap();
print!("Output bytes: ");
for b in &buf {
print!("0x{:02x}, ", b);
}
assert_eq!(buf.as_ref(), update_msg_bytes.as_ref());
}
#[test]
fn test_multi_msg_codec_decode() {
let update_msg_bytes: &[u8] = &[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x79, 0x02, 0x00, 0x00, 0x00, 0x5e, 0x40, 0x01, 0x01, 0x02, 0x40,
0x02, 0x16, 0x02, 0x05, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00,
0x73, 0xfb, 0x00, 0x00, 0x05, 0x13, 0x00, 0x00, 0x12, 0x83, 0x40, 0x03, 0x04, 0xb9,
0x5f, 0xdb, 0x24, 0xc0, 0x08, 0x1c, 0x05, 0x13, 0x88, 0xb8, 0x73, 0xfb, 0x0f, 0xa0,
0x73, 0xfb, 0x0f, 0xb5, 0x9a, 0x74, 0x0f, 0xa0, 0x9a, 0x74, 0x0f, 0xaa, 0xdf, 0x1e,
0x07, 0xd0, 0xdf, 0x1e, 0x07, 0xda, 0xc0, 0x20, 0x18, 0x00, 0x00, 0xdf, 0x1e, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e,
// Add part of a second message which is incomplete
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00,
];
let codec = &mut Codec {
ctx: ParserContext {
four_octet_asn: Some(true),
nlri_mode: Some(Ipv6),
},
};
let mut buf = bytes::BytesMut::from(update_msg_bytes);
let result = codec.decode(&mut buf);
assert!(result.is_ok());
assert!(result.unwrap().is_some());
assert_eq!(buf.len(), 17);
// Add the rest of the message into buf.
buf.put_slice(&[
0x79, 0x02, 0x00, 0x00, 0x00, 0x5e, 0x40, 0x01, 0x01, 0x02, 0x40, 0x02, 0x16, 0x02,
0x05, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x73, 0xfb, 0x00,
0x00, 0x05, 0x13, 0x00, 0x00, 0x12, 0x83, 0x40, 0x03, 0x04, 0xb9, 0x5f, 0xdb, 0x24,
0xc0, 0x08, 0x1c, 0x05, 0x13, 0x88, 0xb8, 0x73, 0xfb, 0x0f, 0xa0, 0x73, 0xfb, 0x0f,
0xb5, 0x9a, 0x74, 0x0f, 0xa0, 0x9a, 0x74, 0x0f, 0xaa, 0xdf, 0x1e, 0x07, 0xd0, 0xdf,
0x1e, 0x07, 0xda, 0xc0, 0x20, 0x18, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e,
]);
let result2 = codec.decode(&mut buf);
assert!(result2.is_ok());
assert!(result2.unwrap().is_some());
assert_eq!(buf.len(), 0);
}
}

View File

@ -0,0 +1,353 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::constants::AddressFamilyIdentifier;
use crate::traits::BGPParserError;
use crate::traits::ParserContext;
use crate::traits::ReadablePacket;
use crate::traits::WritablePacket;
use nom::bytes::complete::take;
use nom::number::complete::be_u8;
use nom::Err::Failure;
use nom::IResult;
use serde::Serialize;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::fmt;
use std::io::ErrorKind;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
// NLRI here is the Neighbor Link Reachability Information from RFC 4271.
// Other NLRIs such as MP Reach NLRI are implemented as path attributes.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Hash)]
pub struct NLRI {
pub afi: AddressFamilyIdentifier,
pub prefixlen: u8,
pub prefix: Vec<u8>,
}
impl NLRI {
pub fn from_bytes(
afi: AddressFamilyIdentifier,
prefix: Vec<u8>,
prefixlen: u8,
) -> Result<Self, String> {
// Check that the vector has enough bytes to represent the prefix.
if prefix.len() < ((prefixlen + 7) / 8).into() {
return Err(format!(
"Prefix: {:?}/{} does not have enough bytes in prefix for given prefixlen",
prefix, prefixlen
));
}
Ok(NLRI {
afi,
prefixlen,
prefix,
})
}
}
impl ReadablePacket for NLRI {
fn from_wire<'a>(
ctx: &ParserContext,
buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
// plen is the length in bits of the address.
let (buf, prefixlen) = be_u8(buf)?;
let octet_len = (prefixlen + 7) / 8;
let (buf, prefix) = take(octet_len)(buf)?;
match ctx.nlri_mode {
None => {
return Err(Failure(BGPParserError::CustomText(
"nlri_mode not set in the context for NLRI::from_wire".to_string(),
)));
}
Some(afi) => Ok((
buf,
NLRI {
afi,
prefixlen,
prefix: prefix.to_vec(),
},
)),
}
}
}
impl TryFrom<NLRI> for Ipv6Addr {
type Error = String;
fn try_from(value: NLRI) -> Result<Self, Self::Error> {
match value.afi {
AddressFamilyIdentifier::Ipv6 => {
let mut v: [u8; 16] = [0u8; 16];
if value.prefix.len() > v.len() {
return Err("prefix length greater than IPv6 address length".to_string());
}
for (pos, e) in value.prefix.iter().enumerate() {
v[pos] = *e;
}
let ip6: Ipv6Addr = v.into();
Ok(ip6)
}
_ => Err("Unsupported AFI type".to_string()),
}
}
}
impl TryFrom<NLRI> for Ipv4Addr {
type Error = String;
fn try_from(value: NLRI) -> Result<Self, Self::Error> {
match value.afi {
AddressFamilyIdentifier::Ipv4 => {
let mut v: [u8; 4] = [0u8; 4];
if value.prefix.len() > v.len() {
return Err("prefix length greater than IPv4 address length".to_string());
}
for (pos, e) in value.prefix.iter().enumerate() {
v[pos] = *e;
}
let ip4 = Ipv4Addr::new(v[0], v[1], v[2], v[3]);
Ok(ip4)
}
_ => Err("Unsupported AFI type".to_string()),
}
}
}
impl TryInto<IpAddr> for NLRI {
type Error = std::io::Error;
fn try_into(self) -> Result<IpAddr, Self::Error> {
match self.afi {
AddressFamilyIdentifier::Ipv4 => {
let mut v: [u8; 4] = [0u8; 4];
if self.prefix.len() > v.len() {
return Err(std::io::Error::new(
ErrorKind::InvalidData,
"prefix length greater than IPv4 address length",
));
}
for (pos, e) in self.prefix.iter().enumerate() {
v[pos] = *e;
}
let ip4 = Ipv4Addr::new(v[0], v[1], v[2], v[3]);
Ok(IpAddr::V4(ip4))
}
AddressFamilyIdentifier::Ipv6 => {
let mut v: [u8; 16] = [0u8; 16];
if self.prefix.len() > v.len() {
return Err(std::io::Error::new(
ErrorKind::InvalidData,
"prefix length greater than IPv6 address length",
));
}
for (pos, e) in self.prefix.iter().enumerate() {
v[pos] = *e;
}
let ip6: Ipv6Addr = v.into();
Ok(IpAddr::V6(ip6))
}
}
}
}
impl TryFrom<String> for NLRI {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
let parts: Vec<&str> = value.split("/").collect();
if parts.len() != 2 {
return Err(format!("Expected ip_addr/prefixlen but got: {}", value));
}
let prefixlen: u8 = u8::from_str(parts[1]).map_err(|_| "failed to parse prefixlen")?;
let mut octets: Vec<u8>;
let afi: AddressFamilyIdentifier;
if parts[0].contains(":") {
afi = AddressFamilyIdentifier::Ipv6;
let addr: Ipv6Addr = Ipv6Addr::from_str(parts[0]).map_err(|e| e.to_string())?;
octets = addr.octets().to_vec();
} else if parts[0].contains(".") {
afi = AddressFamilyIdentifier::Ipv4;
let addr: Ipv4Addr = Ipv4Addr::from_str(parts[0]).map_err(|e| e.to_string())?;
octets = addr.octets().to_vec();
} else {
return Err(format!("Could not detect IP address type: {}", parts[0]));
}
// Truncate octets to prefixlen
if prefixlen % 8 == 0 {
// Cleanly truncate.
octets.truncate((prefixlen / 8).into());
} else {
let num_bytes = (prefixlen / 8) + 1;
let mask = u8::MAX << (8 - (prefixlen % 8));
octets.truncate(num_bytes.into());
if octets.len() > 0 {
let last_pos = octets.len() - 1;
octets[last_pos] &= mask;
}
}
Ok(NLRI {
afi,
prefixlen,
prefix: octets,
})
}
}
impl WritablePacket for NLRI {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = Vec::new();
buf.push(self.prefixlen);
buf.extend(self.prefix.as_slice());
Ok(buf)
}
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(1 + self.prefix.len() as u16)
}
}
impl fmt::Display for NLRI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.afi {
AddressFamilyIdentifier::Ipv4 => {
let bytes = &mut self.prefix.clone();
if bytes.len() < 4 {
bytes.extend(std::iter::repeat(0).take(4 - bytes.len()));
}
let four_bytes: [u8; 4] = bytes.as_slice().try_into().map_err(|_| fmt::Error {})?;
let ipv4_addr = Ipv4Addr::from(four_bytes);
write!(f, "{}/{}", ipv4_addr, self.prefixlen)
}
AddressFamilyIdentifier::Ipv6 => {
let bytes = &mut self.prefix.clone();
if bytes.len() < 16 {
bytes.extend(std::iter::repeat(0).take(16 - bytes.len()));
}
let sixteen_bytes: [u8; 16] =
bytes.as_slice().try_into().map_err(|_| fmt::Error {})?;
let ipv6_addr = Ipv6Addr::from(sixteen_bytes);
write!(f, "{}/{}", ipv6_addr, self.prefixlen)
}
}
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use super::NLRI;
use crate::constants::AddressFamilyIdentifier::{Ipv4, Ipv6};
use crate::traits::ParserContext;
use crate::traits::ReadablePacket;
use crate::traits::WritablePacket;
#[test]
fn test_basic_nlri_v6() {
let nlri_bytes: &[u8] = &[0x20, 0x20, 0x01, 0xdb, 0x8];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap();
assert_eq!(nlri_res.1.afi, Ipv6);
assert_eq!(nlri_res.1.prefixlen, 32);
assert_eq!(nlri_res.1.prefix, vec![0x20, 0x01, 0xdb, 0x8]);
assert_eq!(nlri_res.0.len(), 0);
let wire: Vec<u8> = nlri_res.1.to_wire(ctx).unwrap();
assert_eq!(wire.as_slice(), nlri_bytes);
assert_eq!(nlri_res.1.wire_len(ctx).unwrap() as usize, wire.len());
}
#[test]
fn test_basic_nlri_v4() {
let nlri_bytes: &[u8] = &[0x18, 192, 168, 1];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap();
assert_eq!(nlri_res.1.afi, Ipv4);
assert_eq!(nlri_res.1.prefixlen, 24);
assert_eq!(nlri_res.1.prefix, vec![192, 168, 1]);
assert_eq!(nlri_res.0.len(), 0);
let wire: Vec<u8> = nlri_res.1.to_wire(ctx).unwrap();
assert_eq!(wire.as_slice(), nlri_bytes);
assert_eq!(nlri_res.1.wire_len(ctx).unwrap() as usize, wire.len());
}
#[test]
fn test_string_roundtrip() {
let cases: Vec<(String, Vec<u8>, u8, String)> = vec![
(
"2001:db8::/32".into(),
vec![0x20, 0x01, 0xd, 0xb8],
32,
"2001:db8::/32".into(),
),
(
"2001:db8::1/16".into(),
vec![0x20, 0x01],
16,
"2001::/16".into(),
),
(
"2001:db8::/64".into(),
vec![0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0],
64,
"2001:db8::/64".into(),
),
(
"2001:db8::/24".into(),
vec![0x20, 0x01, 0xd],
24,
"2001:d00::/24".into(),
),
("2001:db8::/0".into(), vec![], 0, "::/0".into()),
("::/0".into(), vec![], 0, "::/0".into()),
("10.0.0.0/8".into(), vec![10], 8, "10.0.0.0/8".into()),
];
for (i, case) in cases.iter().enumerate() {
let parsed_nlri = NLRI::try_from(case.0.clone()).unwrap();
assert_eq!(parsed_nlri.prefix, case.1, "Check prefix match ({})", i);
assert_eq!(
parsed_nlri.prefixlen, case.2,
"Check prefixlen match ({})",
i
);
assert_eq!(
case.3,
format!("{}", parsed_nlri),
"Check std::fmt::Display match ({})",
i
);
}
}
// #[test]
// fn test_to_string_invalids() {
// let invalid_v4 = NLRI {
// afi: AddressFamilyIdentifier::Ipv4,
// prefix: vec![1, 2, 3, 4, 5],
// prefixlen: 16,
// };
// assert_eq!(
// "a formatting trait implementation returned an error: Error",
// format!("{}", invalid_v4)
// );
// }
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Implements high level abstractions for use in the BGP parser.
use crate::constants::AddressFamilyIdentifier;
use nom::error::ErrorKind;
use nom::error::ParseError;
use nom::IResult;
// ParserContext contains information pertinent to configurations which affect
// how message parsing is to be handled.
#[derive(Debug, PartialEq, Clone)]
pub struct ParserContext {
// Whether the peer is RFC6793 compliant.
pub four_octet_asn: Option<bool>,
// nlri_mode specifies if a parsed NLRI prefix should be a IPv4 or IPv6 address.
pub nlri_mode: Option<AddressFamilyIdentifier>,
}
impl ParserContext {
pub fn new() -> ParserContext {
ParserContext {
four_octet_asn: None,
nlri_mode: None,
}
}
pub fn four_octet_asn(mut self, v: bool) -> Self {
self.four_octet_asn = Some(v);
self
}
pub fn nlri_mode(mut self, v: AddressFamilyIdentifier) -> Self {
self.nlri_mode = Some(v);
self
}
}
// Custom error type for the parser.
#[derive(Debug, PartialEq)]
pub enum BGPParserError<I> {
CustomText(String),
Nom(I, ErrorKind),
}
impl<I> ParseError<I> for BGPParserError<I> {
fn from_error_kind(input: I, kind: ErrorKind) -> Self {
BGPParserError::Nom(input, kind)
}
fn append(_: I, _: ErrorKind, other: Self) -> Self {
other
}
}
pub trait WritablePacket {
/// to_wire serializes the packet to the wire format bytes.
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str>;
/// wire_len is the length of the message in bytes as would be on the wire.
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str>;
}
pub trait ReadablePacket {
fn from_wire<'a>(
ctx: &ParserContext,
i: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>>
where
Self: Sized;
}