Commit 8ea67569 authored by Daniel Willmann's avatar Daniel Willmann
Browse files

Use pcap-parser and etherparse to parse pcap packets

We only care for gsmtap packets so only need to handle UDP
parent 58a8cc29
......@@ -19,7 +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"
pcap-parser = { version = "0.10.1", features = ["data"] }
clap = "3.0.0-beta.2"
etherparse = "0.9.0"
......@@ -5,17 +5,18 @@ use eyre::*;
use std::collections::HashMap;
use std::{
fs::File,
rc::Rc,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
}, fs::File,
},
};
use tracing::{trace, debug, error, info, warn, Level};
use tracing::{debug, error, info, trace, 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::{
......@@ -159,32 +160,33 @@ async fn read_pcap(path: &std::path::PathBuf) -> Result<()> {
match block {
PcapBlockOwned::LegacyHeader(hdr) => {
trace!("Got Header: {:?}", hdr);
trace!("Legacy Header: {:?}", hdr);
linktype = Some(hdr.network);
},
}
PcapBlockOwned::Legacy(pkt) => {
trace!("Pkt: {}", pkt.origlen);
trace!("Legacy Pktlen: {}", 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) => {
// FIXME: What if we have multiple if descriptions with different linktypes?
trace!("NG IfDesc: {:?}", ifdesc);
linktype = Some(ifdesc.linktype);
},
}
SimplePacket(pkt) => {
trace!("NG SPkt: {}", pkt.origlen);
trace!("NG SPktlen: {}", pkt.origlen);
parse_packet(pkt.data, pkt.origlen, linktype).await?;
}
EnhancedPacket(pkt) => {
trace!("NG EPkt: {}", pkt.origlen);
trace!("NG EPktlen: {}", pkt.origlen);
parse_packet(pkt.data, pkt.origlen, linktype).await?;
}
_ => trace!("NG Don't care"),
}
},
}
}
reader.consume(num_read);
......@@ -193,14 +195,20 @@ async fn read_pcap(path: &std::path::PathBuf) -> Result<()> {
Ok(())
}
async fn parse_packet(buf: &[u8], orig_len: u32, linktype: Option<pcap_parser::Linktype>) -> Result<()> {
async fn parse_packet(
buf: &[u8],
orig_len: u32,
linktype: Option<pcap_parser::Linktype>,
) -> Result<()> {
use etherparse::{InternetSlice, TransportSlice};
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() {
} 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) {
......@@ -211,23 +219,62 @@ async fn parse_packet(buf: &[u8], orig_len: u32, linktype: Option<pcap_parser::L
let packet = &buf[..orig_len];
trace!("Data: {} {:x?}", linktype, packet);
//TODO
let _udp_pkt = match linktype {
let pkt = get_packet_from(linktype, packet)?;
match (pkt.ip, pkt.transport) {
(Some(InternetSlice::Ipv4(ip4)), Some(TransportSlice::Udp(udp))) => {
debug!(
"Got UDP packet: {}:{} -> {}:{}",
ip4.source_addr(),
udp.source_port(),
ip4.destination_addr(),
udp.destination_port()
);
// Parse UDP for PeerContext
// TODO: Should we limit the dst port?
// Feed data to gsmtap_telemetry
}
(Some(InternetSlice::Ipv6(ip6, _opts)), Some(TransportSlice::Udp(udp))) => {
todo!("IPv6 support")
}
_ => trace!("Packet is not UDP, ignoring"),
}
Ok(())
}
fn get_packet_from(
linktype: pcap_parser::Linktype,
packet: &[u8],
) -> Result<etherparse::SlicedPacket> {
use etherparse::SlicedPacket;
let parsed = match linktype {
// Ethernet frames
pcap_parser::Linktype::ETHERNET => {},
pcap_parser::Linktype::ETHERNET => SlicedPacket::from_ethernet(packet)?,
// Linux cooked capture
pcap_parser::Linktype::LINUX_SLL => {},
pcap_parser::Linktype::LINUX_SLL => {
// Get the linktype
SlicedPacket::from_ip(&packet[16..])?
}
// Linux cooked v2
pcap_parser::Linktype(276) => {},
pcap_parser::Linktype(276) => {
// FIXME: Hardcoded length and offset for now
let mut protobuf = [0u8; 2];
protobuf.clone_from_slice(&packet[0..2]);
let proto = u16::from_be_bytes(protobuf);
match proto {
pcap_parser::data::ETHERTYPE_IPV4 | pcap_parser::data::ETHERTYPE_IPV6 => {
SlicedPacket::from_ip(&packet[20..])?
}
_ => bail!("Unsupported linktype in cooked capture {}", proto),
}
}
_ => bail!("Unsupported linktype {}", linktype),
};
// Parse UDP for PeerContext
// TODO: Should we limit the dst port?
// Feed data to gsmtap_telemetry
Ok(())
Ok(parsed)
}
async fn listen_socket(listen: &str) -> Result<()> {
......
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