Skip to content

Instantly share code, notes, and snippets.

@thepacketgeek
Created May 8, 2019 01:16
Show Gist options
  • Save thepacketgeek/9339ec221703dd21673af5e37d36cb49 to your computer and use it in GitHub Desktop.
Save thepacketgeek/9339ec221703dd21673af5e37d36cb49 to your computer and use it in GitHub Desktop.
extern crate pcarp;
use std::fs::File;
use std::io::{Cursor, Read};
use std::net::IpAddr;
use std::path::Path;
use std::result::Result;
use bgp_rs::{Header, Message, Reader};
use byteorder::{NetworkEndian, ReadBytesExt};
use etherparse::InternetSlice::{Ipv4, Ipv6};
use etherparse::SlicedPacket;
use pcarp::{Capture, Packet};
use twoway::find_bytes;
#[derive(Debug)]
struct MsgRange {
start: u16,
end: u16,
}
#[derive(Debug)]
pub struct BGPMessage {
pub header: Header,
pub message: Message,
}
#[derive(Debug)]
pub struct PeerMessages {
pub peer_addr: IpAddr,
pub messages: Vec<BGPMessage>,
}
/// Given a byte stream, find the BGP Message range between
/// start: 0xff x 16 BGP marker
/// end: 16 + length field
fn find_msg_range(data: &[u8]) -> Option<MsgRange> {
if let Some(marker_loc) = find_bytes(&data, &[255; 16]) {
let mut buf = data.clone().split_at(marker_loc).1;
let mut _preamble: [u8; 16] = [0; 16];
let _ = buf.read_exact(&mut _preamble);
let start = marker_loc as u16;
let length = buf.read_u16::<NetworkEndian>().unwrap();
Some(MsgRange {
start,
end: start + length,
})
} else {
None
}
}
pub fn parse_packet(pkt: Packet) -> Result<PeerMessages, String> {
let mut messages: Vec<BGPMessage> = Vec::new();
let mut buf: Vec<u8> = Vec::from(pkt.data);
// Get & save TCP/IP Header info (Source IP, port)
let peer_addr = match SlicedPacket::from_ethernet(&pkt.data) {
Err(e) => return Err(format!("Err {:?}", e)),
Ok(value) => match value.ip.unwrap() {
Ipv4(header) => format!("{}", header.source_addr()).parse().unwrap(),
Ipv6(header, _) => format!("{}", header.source_addr()).parse().unwrap(),
},
};
// Split at 0xff x 16, then for each message:
loop {
let msg_range = find_msg_range(&buf);
match msg_range {
Some(range) => {
let segment: Vec<_> = buf
.drain(range.start as usize..range.end as usize)
.collect();
let cursor = Cursor::new(segment);
let mut buf = Reader { stream: cursor };
for (header, message) in buf.read() {
messages.push(BGPMessage { header, message });
}
}
None => break,
}
}
Ok(PeerMessages {
peer_addr,
messages,
})
}
fn main() -> std::io::Result<()> {
let file = File::open(Path::new("pcaps/iBGP_single.pcapng")).unwrap();
let mut pcap = Capture::new(file).unwrap();
while let Some(pkt) = pcap.next() {
let pkt = pkt.unwrap();
if pkt.data.len() > 60 {
let res = parse_packet(pkt);
match res {
Ok(res) => {
for msg in res.messages {
if msg.header.record_type == 2 {
if let Message::Update(x) = msg.message {
println!("{:#?}", x);
}
}
}
}
Err(err) => eprintln!("ERROR: {}", err),
}
}
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment