Skip to content

Instantly share code, notes, and snippets.

@hroi
Forked from anonymous/playground.rs
Created February 15, 2016 00:56
Show Gist options
  • Save hroi/7ff6d3438b03e469bd01 to your computer and use it in GitHub Desktop.
Save hroi/7ff6d3438b03e469bd01 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
#![allow(dead_code)]
use std::result;
use std::net::Ipv4Addr;
use std::fmt;
const BGP_MARKER: [u8; 16] = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,];
#[derive(Debug)]
struct AutNum(u32);
impl fmt::Display for AutNum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AS{}", self.0)
}
}
#[derive(Debug)]
struct Open<'a> {
inner: &'a[u8],
}
#[derive(Debug)]
struct OpenParams<'a> {
inner: &'a [u8],
}
#[derive(Debug)]
enum OpenParam<'a> {
Capability(Capability<'a>),
Unknown(u8)
}
#[derive(Debug)]
struct Capability<'a> {
inner: &'a [u8],
}
struct Afi(u16);
impl fmt::Debug for Afi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
1 => write!(f, "ipv4"),
2 => write!(f, "ipv6"),
n => write!(f, "unknown({})", n),
}
}
}
struct Safi(u8);
impl fmt::Debug for Safi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
1 => write!(f, "unicast"),
2 => write!(f, "multicast"),
n => write!(f, "unknown({})", n),
}
}
}
struct AddPathDirection(u8);
impl fmt::Debug for AddPathDirection {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
1 => write!(f, "receive"),
2 => write!(f, "send"),
3 => write!(f, "both"),
n => write!(f, "unknown({})", n),
}
}
}
#[derive(Debug)]
enum CapabilityType {
Reserved,
MultiProtocol(Afi, Safi),
RouteRefresh,
Orf,
MultipleRoutes,
ExtendedNextHopEncoding,
GracefulRestart,
FourByteASN,
DynamicCapability,
MultiSession,
AddPath(Afi, Safi, AddPathDirection),
EnhancedRouteRefresh,
Private(u8),
Other(u8),
}
impl<'a> Capability<'a> {
fn capability_type(&self) -> CapabilityType {
match self.inner[0] {
0 => CapabilityType::Reserved,
1 => CapabilityType::MultiProtocol(Afi((self.inner[2] as u16) << 8 | (self.inner[3] as u16)), Safi(self.inner[5])),
2 => CapabilityType::RouteRefresh,
3 => CapabilityType::Orf,
4 => CapabilityType::MultipleRoutes,
5 => CapabilityType::ExtendedNextHopEncoding,
64 => CapabilityType::GracefulRestart,
65 => CapabilityType::FourByteASN,
67 => CapabilityType::DynamicCapability,
68 => CapabilityType::MultiSession,
69 => CapabilityType::AddPath(Afi((self.inner[2] as u16) << 8 | (self.inner[3] as u16)), Safi(self.inner[4]), AddPathDirection(self.inner[5])),
70 => CapabilityType::EnhancedRouteRefresh,
n @ 128...255 => CapabilityType::Private(n),
n => CapabilityType::Other(n),
}
}
}
#[derive(Debug)]
enum BgpError {
BadLength,
Invalid
}
impl<'a> Iterator for OpenParams<'a> {
type Item = OpenParam<'a>;
fn next(&mut self) -> Option<OpenParam<'a>> {
if self.inner.len() == 0 {
return None;
}
let param_type = self.inner[0];
let param_len = self.inner[1] as usize;
let param_value = &self.inner[2..param_len+2];
self.inner = &self.inner[param_len+2..];
match param_type {
2 => Some(OpenParam::Capability(Capability{ inner: param_value })),
n => Some(OpenParam::Unknown(n)),
}
}
}
type Result<T> = result::Result<T,BgpError>;
impl<'a> Open<'a> {
fn new(raw: &'a [u8]) -> Result<Open> {
if raw.len() < 10 {
return Err(BgpError::BadLength);
} else {
Ok(Open { inner: raw })
}
}
fn version(&self) -> u8 {
self.inner[0]
}
fn aut_num(&self) -> AutNum {
AutNum((self.inner[1] as u32) << 8 | self.inner[2] as u32)
}
fn hold_time(&self) -> u16 {
(self.inner[3] as u16) << 8 | self.inner[4] as u16
}
fn ident(&self) -> Ipv4Addr {
Ipv4Addr::from((self.inner[5] as u32) << 24
| (self.inner[6] as u32) << 16
| (self.inner[7] as u32) << 8
| (self.inner[8] as u32))
}
fn params(&self) -> OpenParams {
OpenParams{ inner: &self.inner[10..] }
}
}
#[derive(Debug)]
enum Message<'a> {
Open(Open<'a>),
Update,
Notification,
KeepAlive,
Refresh,
}
impl<'a> Message<'a> {
fn from_bytes(raw: &'a [u8]) -> Result<Message> {
if raw.len() < 19 || raw.len() > 4096 {
return Err(BgpError::BadLength);
}
let (marker, message) = raw.split_at(16);
if marker != BGP_MARKER {
return Err(BgpError::Invalid);
}
let (length, msg_type) = message[..3].split_at(2);
let length = (length[0] as u16) << 8 | (length[1] as u16);
if length as usize != raw.len() {
return Err(BgpError::Invalid);
}
match msg_type[0] {
1 => Ok(Message::Open(try!(Open::new(&message[3..])))),
2 => Ok(Message::Update),
3 => Ok(Message::Notification),
4 => Ok(Message::KeepAlive),
5 => Ok(Message::Refresh),
_ => Err(BgpError::Invalid),
}
}
}
fn main () {
let bytes = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x41, 0x01, 0x04, 0xfc, 0x00, 0x00, 0xb4, 0x0a, 0x00, 0x00, 0x06, 0x24, 0x02, 0x06, 0x01,
0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x46,
0x00, 0x02, 0x06, 0x45, 0x04, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0xfc, 0x00];
let msg = Message::from_bytes(bytes);
match msg {
Ok(Message::Open(open)) => {
println!("version: {}", open.version());
println!("aut_num: {}", open.aut_num());
println!("hold_time: {}", open.hold_time());
println!("ident: {}", open.ident());
println!("params:");
//println!("{:#?}", open.params().collect::<Vec<OpenParam>>());
for param in open.params() {
match param {
OpenParam::Capability(cap) => println!("\t{:?}", cap.capability_type()),
_ => println!("\t{:?}", param),
}
}
}
_ => (),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment