#[cfg(feature = "serialization")]
extern crate serde;
pub mod afi;
pub mod bmp;
pub mod error;
pub mod message;
pub mod prelude;
pub mod util;
use error::*;
use message::open::*;
use util::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BgpTransportMode {
IPv4,
IPv6,
}
impl From<std::net::IpAddr> for BgpTransportMode {
#[inline]
fn from(addr: std::net::IpAddr) -> Self {
match addr {
std::net::IpAddr::V4(_) => BgpTransportMode::IPv4,
std::net::IpAddr::V6(_) => BgpTransportMode::IPv6,
}
}
}
pub trait BgpAddrItem<T: std::marker::Sized> {
fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(T, usize), BgpError>;
fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result<usize, BgpError>;
}
pub trait BgpMessage {
fn decode_from(&mut self, peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError>;
fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result<usize, BgpError>;
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MacAddress {
pub mac_address: [u8; 6],
}
impl MacAddress {
pub fn new() -> MacAddress {
MacAddress {
mac_address: [0 as u8; 6],
}
}
pub fn from(b: &[u8]) -> MacAddress {
let mut bf = [0 as u8; 6];
bf.clone_from_slice(&b[0..6]);
MacAddress { mac_address: bf }
}
}
impl std::fmt::Display for MacAddress {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.mac_address[0],
self.mac_address[1],
self.mac_address[2],
self.mac_address[3],
self.mac_address[4],
self.mac_address[5],
)
}
}
impl std::fmt::Debug for MacAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.mac_address[0],
self.mac_address[1],
self.mac_address[2],
self.mac_address[3],
self.mac_address[4],
self.mac_address[5]
))
}
}
#[cfg(feature = "serialization")]
impl serde::Serialize for MacAddress {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.to_string().as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BgpCapability {
SafiIPv4u,
SafiIPv4m,
SafiIPv4mvpn,
SafiIPv4fu,
SafiVPNv4u,
SafiVPNv4fu,
SafiVPNv4m,
SafiIPv4lu,
SafiIPv6u,
SafiIPv6lu,
SafiIPv6fu,
SafiVPNv6u,
SafiVPNv6m,
SafiVPLS,
SafiEVPN,
CapASN32(u32),
CapRR,
}
impl BgpCapability {
fn bytes_len(&self) -> usize {
match self {
BgpCapability::SafiIPv4u => 6,
BgpCapability::SafiIPv4fu => 6,
BgpCapability::SafiIPv4m => 6,
BgpCapability::SafiIPv4mvpn => 6,
BgpCapability::SafiVPNv4u => 6,
BgpCapability::SafiVPNv4fu => 6,
BgpCapability::SafiVPNv4m => 6,
BgpCapability::SafiIPv4lu => 6,
BgpCapability::SafiIPv6u => 6,
BgpCapability::SafiIPv6lu => 6,
BgpCapability::SafiIPv6fu => 6,
BgpCapability::SafiVPNv6u => 6,
BgpCapability::SafiVPNv6m => 6,
BgpCapability::SafiVPLS => 6,
BgpCapability::SafiEVPN => 6,
BgpCapability::CapASN32(_) => 6,
BgpCapability::CapRR => 2,
}
}
fn fill_buffer(&self, buf: &mut [u8]) {
match self {
BgpCapability::SafiIPv4u => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 1]);
}
BgpCapability::SafiIPv4fu => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 133]);
}
BgpCapability::SafiIPv4m => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 4]);
}
BgpCapability::SafiIPv4mvpn => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 5]);
}
BgpCapability::SafiVPNv4u => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 128]);
}
BgpCapability::SafiVPNv4fu => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 134]);
}
BgpCapability::SafiVPNv4m => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 129]);
}
BgpCapability::SafiIPv4lu => {
buf.clone_from_slice(&[1, 4, 0, 1, 0, 2]);
}
BgpCapability::SafiIPv6u => {
buf.clone_from_slice(&[1, 4, 0, 2, 0, 1]);
}
BgpCapability::SafiIPv6fu => {
buf.clone_from_slice(&[1, 4, 0, 2, 0, 133]);
}
BgpCapability::SafiIPv6lu => {
buf.clone_from_slice(&[1, 4, 0, 2, 0, 4]);
}
BgpCapability::SafiVPNv6u => {
buf.clone_from_slice(&[1, 4, 0, 2, 0, 128]);
}
BgpCapability::SafiVPNv6m => {
buf.clone_from_slice(&[1, 4, 0, 2, 0, 129]);
}
BgpCapability::SafiVPLS => {
buf.clone_from_slice(&[1, 4, 0, 25, 0, 65]);
}
BgpCapability::SafiEVPN => {
buf.clone_from_slice(&[1, 4, 0, 25, 0, 70]);
}
BgpCapability::CapASN32(as_num) => {
buf.clone_from_slice(&[
65,
4,
(as_num >> 24) as u8,
((as_num >> 16) & 0xff) as u8,
((as_num >> 8) & 0xff) as u8,
(as_num & 0xff) as u8,
]);
}
BgpCapability::CapRR => {
buf.clone_from_slice(&[2, 0]);
}
};
}
fn from_buffer(buf: &[u8]) -> Result<(BgpCapability, usize), BgpError> {
if buf.len() >= 6 && buf[0] == 1 && buf[1] == 4 && buf[2] == 0 {
if buf[3] == 1 && buf[4] == 0 {
match buf[5] {
1 => Ok((BgpCapability::SafiIPv4u, 6)),
2 => Ok((BgpCapability::SafiIPv4lu, 6)),
4 => Ok((BgpCapability::SafiIPv4m, 6)),
5 => Ok((BgpCapability::SafiIPv4mvpn, 6)),
128 => Ok((BgpCapability::SafiVPNv4u, 6)),
129 => Ok((BgpCapability::SafiVPNv4m, 6)),
133 => Ok((BgpCapability::SafiIPv4fu, 6)),
134 => Ok((BgpCapability::SafiVPNv4fu, 6)),
_ => Err(BgpError::static_str("Invalid ipv4 safi capability")),
}
} else if buf[3] == 2 && buf[4] == 0 {
match buf[5] {
1 => Ok((BgpCapability::SafiIPv6u, 6)),
4 => Ok((BgpCapability::SafiIPv6lu, 6)),
128 => Ok((BgpCapability::SafiVPNv6u, 6)),
129 => Ok((BgpCapability::SafiVPNv6m, 6)),
133 => Ok((BgpCapability::SafiIPv6fu, 6)),
_ => Err(BgpError::static_str("Invalid ipv6 safi capability")),
}
} else if buf[3] == 25 && buf[4] == 0 && buf[5] == 65 {
match buf[5] {
65 => Ok((BgpCapability::SafiVPLS, 6)),
70 => Ok((BgpCapability::SafiEVPN, 6)),
_ => Err(BgpError::static_str("Invalid vpls safi capability")),
}
} else {
Err(BgpError::static_str("Invalid capability"))
}
} else if buf.len() >= 6 && buf[0] == 65 && buf[1] == 4 {
Ok((BgpCapability::CapASN32(getn_u32(&buf[2..6])), 6))
} else if buf.len() >= 2 && buf[0] == 2 && buf[1] == 0 {
Ok((BgpCapability::CapRR, 2))
} else {
Err(BgpError::static_str("Invalid capability"))
}
}
}
#[derive(Debug, Clone)]
pub struct BgpSessionParams {
pub as_num: u32,
pub hold_time: u16,
pub peer_mode: BgpTransportMode,
pub has_as32bit: bool,
pub router_id: std::net::Ipv4Addr,
pub caps: std::collections::HashSet<BgpCapability>,
}
impl BgpSessionParams {
pub fn new(
asnum: u32,
holdtime: u16,
peermode: BgpTransportMode,
routerid: std::net::Ipv4Addr,
cps: std::collections::HashSet<BgpCapability>,
) -> BgpSessionParams {
BgpSessionParams {
as_num: asnum,
hold_time: holdtime,
peer_mode: peermode,
has_as32bit: true,
router_id: routerid,
caps: cps,
}
}
pub fn open_message(&self) -> BgpOpenMessage {
let mut bom = BgpOpenMessage::new();
bom.as_num = self.as_num;
bom.router_id = self.router_id;
bom.caps = self.caps.iter().copied().collect();
bom.hold_time = self.hold_time;
bom
}
pub fn check_caps(&mut self) {
self.has_as32bit = false;
for cap in self.caps.iter() {
match cap {
BgpCapability::CapASN32(n) => {
self.has_as32bit = true;
if self.as_num != 0 && self.as_num != 23456 && self.as_num != *n {
eprintln!(
"Warning: Capability 32-bit AS mismatch AS number: {:?}!={:?}",
self.as_num, *n
);
}
self.as_num = *n;
}
_ => {}
}
}
}
pub fn decode_message_head(
&self,
buf: &[u8],
) -> Result<(message::BgpMessageType, usize), BgpError> {
if buf.len() < 19 {
return Err(BgpError::static_str("Invalid message header size!"));
}
for q in buf[0..16].iter() {
if (*q) != 255 {
return Err(BgpError::static_str(
"Invalid header content, MD5 is not supported!",
));
}
}
let messagetype = message::BgpMessageType::decode_from(buf[18])?;
Ok((messagetype, (getn_u16(&buf[16..18]) - 19) as usize))
}
pub fn recv_message_head(
&mut self,
rdsrc: &mut impl std::io::Read,
) -> Result<(message::BgpMessageType, usize), BgpError> {
let mut buf = [0 as u8; 19];
rdsrc.read_exact(&mut buf)?;
self.decode_message_head(&buf)
}
pub fn prepare_message_buf(
&self,
buf: &mut [u8],
messagetype: message::BgpMessageType,
messagelen: usize,
) -> Result<usize, BgpError> {
if buf.len() < (messagelen + 19) {
return Err(BgpError::insufficient_buffer_size());
}
buf[0..16].clone_from_slice(&[255 as u8; 16]);
let lng: u16 = (messagelen as u16) + 19;
buf[16] = (lng >> 8) as u8;
buf[17] = (lng & 0xff) as u8;
buf[18] = messagetype.encode();
Ok(lng as usize)
}
pub fn send_message_buf(
&mut self,
wrdst: &mut impl std::io::Write,
buf: &mut [u8],
messagetype: message::BgpMessageType,
messagelen: usize,
) -> Result<(), BgpError> {
if buf.len() < (messagelen + 19) {
return Err(BgpError::insufficient_buffer_size());
}
buf[0..16].clone_from_slice(&[255 as u8; 16]);
let lng: u16 = (messagelen as u16) + 19;
buf[16] = (lng >> 8) as u8;
buf[17] = (lng & 0xff) as u8;
buf[18] = messagetype.encode();
match wrdst.write_all(&buf[0..(lng as usize)]) {
Ok(_) => Ok(()),
Err(e) => Err(e.into()),
}
}
}