Skip to content

Commit

Permalink
feat: icmp extensions (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
fujiapple852 committed Oct 15, 2023
1 parent 753c794 commit 4118634
Show file tree
Hide file tree
Showing 22 changed files with 1,432 additions and 89 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ windows-sys = { version = "0.48.0", features = [
] }

[dev-dependencies]
hex-literal = "0.4.1"
rand = "0.8.5"
test-case = "3.2.1"

Expand Down
12 changes: 10 additions & 2 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use std::sync::Arc;
use std::time::Duration;
use tracing::instrument;
use trippy::tracing::{
Probe, ProbeStatus, SocketImpl, Tracer, TracerChannel, TracerChannelConfig, TracerConfig,
TracerRound,
Extensions, Probe, ProbeStatus, SocketImpl, Tracer, TracerChannel, TracerChannelConfig,
TracerConfig, TracerRound,
};

/// The state of all hops in a trace.
Expand Down Expand Up @@ -115,6 +115,8 @@ impl Trace {
}
let host = probe.host.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
*hop.addrs.entry(host).or_default() += 1;
// TODO should we combine extensions across rounds?
hop.extensions = probe.extensions.clone();
}
ProbeStatus::Awaited => {
let index = usize::from(probe.ttl.0) - 1;
Expand Down Expand Up @@ -165,6 +167,7 @@ pub struct Hop {
mean: f64,
m2: f64,
samples: Vec<Duration>,
extensions: Option<Extensions>,
}

impl Hop {
Expand All @@ -187,6 +190,10 @@ impl Hop {
self.addrs.len()
}

pub fn extensions(&self) -> Option<&Extensions> {
self.extensions.as_ref()
}

/// The total number of probes sent.
pub fn total_sent(&self) -> usize {
self.total_sent
Expand Down Expand Up @@ -260,6 +267,7 @@ impl Default for Hop {
mean: 0f64,
m2: 0f64,
samples: Vec::default(),
extensions: None,
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ pub struct TrippyConfig {
pub max_inflight: u8,
pub initial_sequence: u16,
pub tos: u8,
pub icmp_extensions: bool,
pub read_timeout: Duration,
pub packet_size: u16,
pub payload_pattern: u8,
Expand Down Expand Up @@ -340,6 +341,13 @@ impl TryFrom<(Args, u16)> for TrippyConfig {
cfg_file_strategy.tos,
constants::DEFAULT_STRATEGY_TOS,
);

let icmp_extensions = cfg_layer_bool_flag(
args.icmp_extensions,
cfg_file_strategy.icmp_extensions,
false,
);

let read_timeout = cfg_layer(
args.read_timeout,
cfg_file_strategy.read_timeout,
Expand Down Expand Up @@ -510,6 +518,7 @@ impl TryFrom<(Args, u16)> for TrippyConfig {
packet_size,
payload_pattern,
tos,
icmp_extensions,
source_addr,
interface,
port_direction,
Expand Down
4 changes: 4 additions & 0 deletions src/config/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ pub struct Args {
#[arg(short = 'Q', long)]
pub tos: Option<u8>,

/// Parse ICMP extensions
#[arg(short = 'e', long)]
pub icmp_extensions: bool,

/// The socket read timeout [default: 10ms]
#[arg(long)]
pub read_timeout: Option<String>,
Expand Down
1 change: 1 addition & 0 deletions src/config/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ pub struct ConfigStrategy {
pub packet_size: Option<u16>,
pub payload_pattern: Option<u8>,
pub tos: Option<u8>,
pub icmp_extensions: Option<bool>,
pub read_timeout: Option<String>,
}

Expand Down
24 changes: 23 additions & 1 deletion src/frontend/render/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use ratatui::widgets::{Block, BorderType, Borders, Cell, Row, Table};
use ratatui::Frame;
use std::net::IpAddr;
use std::rc::Rc;
use trippy::tracing::Extension;

/// Render the table of data about the hops.
///
Expand Down Expand Up @@ -233,12 +234,33 @@ fn format_address(
let addr_fmt = match config.address_mode {
AddressMode::IP => addr.to_string(),
AddressMode::Host => {
if config.lookup_as_info {
let hostname = if config.lookup_as_info {
let entry = dns.lazy_reverse_lookup_with_asinfo(*addr);
format_dns_entry(entry, true, config.as_mode)
} else {
let entry = dns.lazy_reverse_lookup(*addr);
format_dns_entry(entry, false, config.as_mode)
};

// TODO just a hack for now...
if let Some(extensions) = hop.extensions() {
let mpls = extensions
.extensions
.iter()
.map(|ext| match ext {
Extension::Unknown => todo!(),
Extension::Mpls(mpls) => mpls
.members
.iter()
.map(|member| {
format!("[MPLS label: {}, ttl: {}]", member.label, member.ttl)
})
.join("\n"),
})
.join("\n");
format!("{hostname} {mpls}")
} else {
hostname
}
}
AddressMode::Both => {
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ fn make_channel_config(
args.payload_pattern,
args.multipath_strategy,
args.tos,
args.icmp_extensions,
args.read_timeout,
args.min_round_duration,
)
Expand Down
2 changes: 1 addition & 1 deletion src/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ pub use config::{
pub use net::channel::TracerChannel;
pub use net::source::SourceAddr;
pub use net::SocketImpl;
pub use probe::{IcmpPacketType, Probe, ProbeStatus};
pub use probe::{Extension, Extensions, IcmpPacketType, Probe, ProbeStatus};
pub use tracer::{Tracer, TracerRound};
3 changes: 3 additions & 0 deletions src/tracing/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ pub struct TracerChannelConfig {
pub payload_pattern: PayloadPattern,
pub multipath_strategy: MultipathStrategy,
pub tos: TypeOfService,
pub icmp_extensions: bool,
pub read_timeout: Duration,
pub tcp_connect_timeout: Duration,
}
Expand All @@ -173,6 +174,7 @@ impl TracerChannelConfig {
payload_pattern: u8,
multipath_strategy: MultipathStrategy,
tos: u8,
icmp_extensions: bool,
read_timeout: Duration,
tcp_connect_timeout: Duration,
) -> Self {
Expand All @@ -185,6 +187,7 @@ impl TracerChannelConfig {
payload_pattern: PayloadPattern(payload_pattern),
multipath_strategy,
tos: TypeOfService(tos),
icmp_extensions,
read_timeout,
tcp_connect_timeout,
}
Expand Down
3 changes: 3 additions & 0 deletions src/tracing/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ mod ipv4;
/// IPv6 implementation.
mod ipv6;

/// ICMP extensions.
mod extension;

/// Platform specific network code.
mod platform;

Expand Down
20 changes: 15 additions & 5 deletions src/tracing/net/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct TracerChannel<S: Socket> {
payload_pattern: PayloadPattern,
multipath_strategy: MultipathStrategy,
tos: TypeOfService,
icmp_extensions: bool,
read_timeout: Duration,
tcp_connect_timeout: Duration,
send_socket: Option<S>,
Expand Down Expand Up @@ -63,6 +64,7 @@ impl<S: Socket> TracerChannel<S> {
payload_pattern: config.payload_pattern,
multipath_strategy: config.multipath_strategy,
tos: config.tos,
icmp_extensions: config.icmp_extensions,
read_timeout: config.read_timeout,
tcp_connect_timeout: config.tcp_connect_timeout,
send_socket,
Expand Down Expand Up @@ -90,7 +92,7 @@ impl<S: Socket> Network for TracerChannel<S> {
resp => Ok(resp),
},
}?;
if let Some(resp) = prob_response {
if let Some(resp) = &prob_response {
tracing::debug!(?resp);
}
Ok(prob_response)
Expand Down Expand Up @@ -162,10 +164,10 @@ impl<S: Socket> TracerChannel<S> {
fn dispatch_tcp_probe(&mut self, probe: Probe) -> TraceResult<()> {
let socket = match (self.src_addr, self.dest_addr) {
(IpAddr::V4(src_addr), IpAddr::V4(dest_addr)) => {
ipv4::dispatch_tcp_probe(probe, src_addr, dest_addr, self.tos)
ipv4::dispatch_tcp_probe(&probe, src_addr, dest_addr, self.tos)
}
(IpAddr::V6(src_addr), IpAddr::V6(dest_addr)) => {
ipv6::dispatch_tcp_probe(probe, src_addr, dest_addr)
ipv6::dispatch_tcp_probe(&probe, src_addr, dest_addr)
}
_ => unreachable!(),
}?;
Expand All @@ -179,8 +181,16 @@ impl<S: Socket> TracerChannel<S> {
fn recv_icmp_probe(&mut self) -> TraceResult<Option<ProbeResponse>> {
if self.recv_socket.is_readable(self.read_timeout)? {
match self.dest_addr {
IpAddr::V4(_) => ipv4::recv_icmp_probe(&mut self.recv_socket, self.protocol),
IpAddr::V6(_) => ipv6::recv_icmp_probe(&mut self.recv_socket, self.protocol),
IpAddr::V4(_) => ipv4::recv_icmp_probe(
&mut self.recv_socket,
self.protocol,
self.icmp_extensions,
),
IpAddr::V6(_) => ipv6::recv_icmp_probe(
&mut self.recv_socket,
self.protocol,
self.icmp_extensions,
),
}
} else {
Ok(None)
Expand Down
58 changes: 58 additions & 0 deletions src/tracing/net/extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use crate::tracing::error::TracerError;
use crate::tracing::packet::icmp_extension::extension_object::{ClassNum, ExtensionObjectPacket};
use crate::tracing::packet::icmp_extension::extension_structure::ExtensionsPacket;
use crate::tracing::packet::icmp_extension::mpls_label_stack::MplsLabelStackPacket;
use crate::tracing::packet::icmp_extension::mpls_label_stack_member::MplsLabelStackMemberPacket;
use crate::tracing::probe::{Extension, Extensions, MplsLabelStack, MplsLabelStackMember};
use crate::tracing::util::Required;

impl TryFrom<&[u8]> for Extensions {
type Error = TracerError;

fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
Self::try_from(ExtensionsPacket::new_view(value).req()?)
}
}

impl TryFrom<ExtensionsPacket<'_>> for Extensions {
type Error = TracerError;

fn try_from(value: ExtensionsPacket<'_>) -> Result<Self, Self::Error> {
let extensions = value
.objects()
.flat_map(|obj| ExtensionObjectPacket::new_view(obj).req())
.map(|obj| match obj.get_class_num() {
ClassNum::MultiProtocolLabelSwitchingLabelStack => {
MplsLabelStackPacket::new_view(obj.payload())
.req()
.map(|mpls| Extension::Mpls(MplsLabelStack::from(mpls)))
}
_ => Ok(Extension::Unknown),
})
.collect::<Result<_, _>>()?;
Ok(Self { extensions })
}
}

impl From<MplsLabelStackPacket<'_>> for MplsLabelStack {
fn from(value: MplsLabelStackPacket<'_>) -> Self {
Self {
members: value
.members()
.flat_map(|member| MplsLabelStackMemberPacket::new_view(member).req())
.map(MplsLabelStackMember::from)
.collect(),
}
}
}

impl From<MplsLabelStackMemberPacket<'_>> for MplsLabelStackMember {
fn from(value: MplsLabelStackMemberPacket<'_>) -> Self {
Self {
label: value.get_label(),
exp: value.get_exp(),
bos: value.get_bos(),
ttl: value.get_ttl(),
}
}
}
Loading

0 comments on commit 4118634

Please sign in to comment.