Commit 58a8cc29 authored by Daniel Willmann's avatar Daniel Willmann
Browse files

WIP support for parsing pcap files

parent 3f8de5a8
......@@ -19,4 +19,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
opentelemetry = { version = "0.11.2", features = ["async-std"] }
opentelemetry-jaeger = { version = "0.10.0", features = ["async-std"] }
opentelemetry-semantic-conventions = "0.3.0"
pcap-parser = "0.10.0"
clap = "3.0.0-beta.2"
etherparse = "0.9.0"
mod options;
use clap::Clap;
use eyre::*;
use std::collections::HashMap;
......@@ -6,13 +9,13 @@ use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
}, fs::File,
};
use tracing::{debug, error, info, warn};
use tracing::{trace, debug, error, info, warn, Level};
use tracing_subscriber::EnvFilter;
use async_std::net::{SocketAddr, UdpSocket};
use async_std::{net::{SocketAddr, UdpSocket}};
use opentelemetry::trace::{Span as _, Tracer as _, TracerProvider as _};
use opentelemetry::{
......@@ -74,12 +77,9 @@ fn tracer_from_peer(
KeyValue::new(HOST_NAME, peer.ip().to_string()),
KeyValue::new(HOST_ID, peer.port() as i64),
KeyValue::new(PROCESS_PID, olog.pid as i64),
KeyValue::new(
PROCESS_EXECUTABLE_NAME,
olog.proc_name.clone(),
),
KeyValue::new(PROCESS_EXECUTABLE_NAME, olog.proc_name.clone()),
KeyValue::new(SERVICE_NAME, olog.proc_name.clone()),
KeyValue::new(SERVICE_NAMESPACE, olog.proc_name.clone())
KeyValue::new(SERVICE_NAMESPACE, olog.proc_name.clone()),
];
tracer_from_attrs(olog.proc_name.clone(), attrs, providers)
......@@ -98,13 +98,10 @@ fn tracer_from_osmo_trace(
let attrs = vec![
KeyValue::new(HOST_NAME, peer.to_string()),
KeyValue::new(PROCESS_PID, traceattrs.common.pid as i64),
KeyValue::new(
PROCESS_EXECUTABLE_NAME,
traceattrs.common.proc_name.clone(),
),
KeyValue::new(PROCESS_EXECUTABLE_NAME, traceattrs.common.proc_name.clone()),
KeyValue::new(SERVICE_NAME, fsmid),
KeyValue::new(SERVICE_NAMESPACE, fsmname.clone()),
KeyValue::new(SERVICE_INSTANCE_ID, fsminst)
KeyValue::new(SERVICE_INSTANCE_ID, fsminst),
];
tracer_from_attrs(
......@@ -116,6 +113,124 @@ fn tracer_from_osmo_trace(
#[async_std::main]
async fn main() -> Result<()> {
opentelemetry::global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());
let opts = options::Opts::parse();
let opts = &opts;
let envfilter = {
let mut filter = EnvFilter::from_default_env();
match opts.verbose {
0 => {}
1 => filter = filter.add_directive(Level::INFO.into()),
2 => filter = filter.add_directive(Level::DEBUG.into()),
_ => filter = filter.add_directive(Level::TRACE.into()),
};
filter
};
tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(envfilter)
.init();
debug!("Got options: {:?}", opts);
match &opts.file {
None => listen_socket(&opts.listen).await?,
Some(file) => read_pcap(file).await?,
}
Ok(())
}
async fn read_pcap(path: &std::path::PathBuf) -> Result<()> {
use pcap_parser::*;
let mut linktype = None;
let file = File::open(path)?;
let mut reader = pcap_parser::create_reader(4096, file)?;
loop {
let (num_read, block) = match reader.next() {
Err(PcapError::Eof) | Err(PcapError::Incomplete) => break,
Ok((num_read, block)) => (num_read, block),
Err(err) => bail!(format!("Unable to parse file {:?}: {:?}", path, err)),
};
match block {
PcapBlockOwned::LegacyHeader(hdr) => {
trace!("Got Header: {:?}", hdr);
linktype = Some(hdr.network);
},
PcapBlockOwned::Legacy(pkt) => {
trace!("Pkt: {}", pkt.origlen);
parse_packet(pkt.data, pkt.origlen, linktype).await?;
},
PcapBlockOwned::NG(ngblock) => {
use pcap_parser::pcapng::Block::*;
match ngblock {
SectionHeader(hdr) => trace!("NG Header: {:?}", hdr),
InterfaceDescription(ifdesc) => {
trace!("NG IfDesc: {:?}", ifdesc);
linktype = Some(ifdesc.linktype);
},
SimplePacket(pkt) => {
trace!("NG SPkt: {}", pkt.origlen);
parse_packet(pkt.data, pkt.origlen, linktype).await?;
}
EnhancedPacket(pkt) => {
trace!("NG EPkt: {}", pkt.origlen);
parse_packet(pkt.data, pkt.origlen, linktype).await?;
}
_ => trace!("NG Don't care"),
}
},
}
reader.consume(num_read);
}
Ok(())
}
async fn parse_packet(buf: &[u8], orig_len: u32, linktype: Option<pcap_parser::Linktype>) -> Result<()> {
let orig_len = orig_len as usize;
let linktype = linktype.unwrap_or(pcap_parser::Linktype::ETHERNET);
/* Check if packet was truncated */
if orig_len > buf.len() {
error!("Truncated packet: {} vs {}", orig_len, buf.len());
} else if orig_len < buf.len() {
let pad = &buf[orig_len..];
/* Complain if any pad bytes are != 0 */
if pad.iter().any(|&c| c != 0) {
error!("Padding: {:?}", &buf[orig_len..]);
}
}
let packet = &buf[..orig_len];
trace!("Data: {} {:x?}", linktype, packet);
//TODO
let _udp_pkt = match linktype {
// Ethernet frames
pcap_parser::Linktype::ETHERNET => {},
// Linux cooked capture
pcap_parser::Linktype::LINUX_SLL => {},
// Linux cooked v2
pcap_parser::Linktype(276) => {},
_ => bail!("Unsupported linktype {}", linktype),
};
// Parse UDP for PeerContext
// TODO: Should we limit the dst port?
// Feed data to gsmtap_telemetry
Ok(())
}
async fn listen_socket(listen: &str) -> Result<()> {
let stop = Arc::new(AtomicBool::new(false));
// ctrlc::set_handler({
// let s = stop.clone();
......@@ -123,14 +238,8 @@ async fn main() -> Result<()> {
// s.store(true, Ordering::SeqCst);
// }
// })?;
opentelemetry::global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new());
tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(EnvFilter::from_default_env())
.init();
// Open GSMTAP socket
let socket = UdpSocket::bind("127.0.0.2:4729").await?;
let socket = UdpSocket::bind(listen).await?;
info!("Listening on {:?}", socket.local_addr());
let mut peers = HashMap::new();
......
use clap::Clap;
use std::path::PathBuf;
/// Capture Osmocom GSMTAP trace and log messages and visualize them with opentracing/jaeger
#[derive(Clap, Debug)]
#[clap(version = "0.1", author = "Daniel Willmann <daniel@totalueberwachung.de>")]
pub struct Opts {
/// Verbosity, can be used multiple times
#[clap(short, long, parse(from_occurrences))]
pub verbose: i32,
/// Listen on a socket for GSMTAP packets
#[clap(short, long, conflicts_with("file"), default_value = "0.0.0.0:4729")]
pub listen: String,
/// Read GSMTAP packets from PCAP file
#[clap(short, long, conflicts_with("listen"), parse(from_os_str))]
pub file: Option<PathBuf>,
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment