Created
May 8, 2019 01:16
-
-
Save thepacketgeek/9339ec221703dd21673af5e37d36cb49 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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