Skip to content

Commit

Permalink
feat(net): added dublin tracing strategy support for IPv6/UDP (#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
fujiapple852 committed Mar 17, 2024
1 parent 7e564d1 commit 5e97a47
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 30 deletions.
19 changes: 5 additions & 14 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,20 +585,11 @@ impl TrippyConfig {
(true, _, _, _) => IpAddrFamily::Ipv4Only,
(_, true, _, _) => IpAddrFamily::Ipv6Only,
};

#[allow(clippy::match_same_arms)]
let multipath_strategy = match (multipath_strategy_cfg, addr_family) {
(MultipathStrategyConfig::Classic, _) => Ok(MultipathStrategy::Classic),
(MultipathStrategyConfig::Paris, _) => Ok(MultipathStrategy::Paris),
(
MultipathStrategyConfig::Dublin,
IpAddrFamily::Ipv4Only | IpAddrFamily::Ipv4thenIpv6 | IpAddrFamily::Ipv6thenIpv4,
) => Ok(MultipathStrategy::Dublin),
(MultipathStrategyConfig::Dublin, IpAddrFamily::Ipv6Only) => Err(anyhow!(
"Dublin multipath strategy not implemented for IPv6 yet!"
)),
}?;

let multipath_strategy = match multipath_strategy_cfg {
MultipathStrategyConfig::Classic => MultipathStrategy::Classic,
MultipathStrategyConfig::Paris => MultipathStrategy::Paris,
MultipathStrategyConfig::Dublin => MultipathStrategy::Dublin,
};
let port_direction = match (protocol, source_port, target_port, multipath_strategy_cfg) {
(Protocol::Icmp, _, _, _) => PortDirection::None,
(Protocol::Udp, None, None, _) => PortDirection::new_fixed_src(pid.max(1024)),
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ fn make_channel_config(
target_addr,
args.packet_size,
args.payload_pattern,
args.initial_sequence,
args.tos,
args.icmp_extension_parse_mode,
args.read_timeout,
Expand Down
4 changes: 4 additions & 0 deletions src/tracing/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ pub struct ChannelConfig {
pub target_addr: IpAddr,
pub packet_size: PacketSize,
pub payload_pattern: PayloadPattern,
pub initial_sequence: Sequence,
pub tos: TypeOfService,
pub icmp_extension_mode: IcmpExtensionParseMode,
pub read_timeout: Duration,
Expand All @@ -376,6 +377,7 @@ impl ChannelConfig {
target_addr: IpAddr,
packet_size: u16,
payload_pattern: u8,
initial_sequence: u16,
tos: u8,
icmp_extension_mode: IcmpExtensionParseMode,
read_timeout: Duration,
Expand All @@ -388,6 +390,7 @@ impl ChannelConfig {
target_addr,
packet_size: PacketSize(packet_size),
payload_pattern: PayloadPattern(payload_pattern),
initial_sequence: Sequence(initial_sequence),
tos: TypeOfService(tos),
icmp_extension_mode,
read_timeout,
Expand All @@ -405,6 +408,7 @@ impl Default for ChannelConfig {
target_addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
packet_size: PacketSize(defaults::DEFAULT_STRATEGY_PACKET_SIZE),
payload_pattern: PayloadPattern(defaults::DEFAULT_STRATEGY_PAYLOAD_PATTERN),
initial_sequence: Sequence(defaults::DEFAULT_STRATEGY_INITIAL_SEQUENCE),
tos: TypeOfService(defaults::DEFAULT_STRATEGY_TOS),
icmp_extension_mode: defaults::DEFAULT_ICMP_EXTENSION_PARSE_MODE,
read_timeout: defaults::DEFAULT_STRATEGY_READ_TIMEOUT,
Expand Down
5 changes: 4 additions & 1 deletion src/tracing/net/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::tracing::net::socket::Socket;
use crate::tracing::net::{ipv4, ipv6, platform, Network};
use crate::tracing::probe::{Probe, ProbeResponse};
use crate::tracing::types::{PacketSize, PayloadPattern, TypeOfService};
use crate::tracing::{ChannelConfig, Port, PrivilegeMode, Protocol};
use crate::tracing::{ChannelConfig, Port, PrivilegeMode, Protocol, Sequence};
use arrayvec::ArrayVec;
use std::net::IpAddr;
use std::time::{Duration, SystemTime};
Expand All @@ -25,6 +25,7 @@ pub struct TracerChannel<S: Socket> {
dest_addr: IpAddr,
packet_size: PacketSize,
payload_pattern: PayloadPattern,
initial_sequence: Sequence,
tos: TypeOfService,
icmp_extension_mode: IcmpExtensionParseMode,
read_timeout: Duration,
Expand Down Expand Up @@ -63,6 +64,7 @@ impl<S: Socket> TracerChannel<S> {
dest_addr: config.target_addr,
packet_size: config.packet_size,
payload_pattern: config.payload_pattern,
initial_sequence: config.initial_sequence,
tos: config.tos,
icmp_extension_mode: config.icmp_extension_mode,
read_timeout: config.read_timeout,
Expand Down Expand Up @@ -154,6 +156,7 @@ impl<S: Socket> TracerChannel<S> {
self.privilege_mode,
self.packet_size,
self.payload_pattern,
self.initial_sequence,
)
}
_ => unreachable!(),
Expand Down
6 changes: 5 additions & 1 deletion src/tracing/net/ipv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,13 @@ fn extract_probe_resp_seq(
}
(Protocol::Udp, IpProtocol::Udp) => {
let (src_port, dest_port, checksum, identifier) = extract_udp_packet(ipv4)?;

Some(ProbeResponseSeq::Udp(ProbeResponseSeqUdp::new(
identifier,
IpAddr::V4(ipv4.get_destination()),
src_port,
dest_port,
checksum,
0,
)))
}
(Protocol::Tcp, IpProtocol::Tcp) => {
Expand Down Expand Up @@ -1137,6 +1137,7 @@ mod tests {
src_port,
dest_port,
checksum,
payload_len,
}),
..
},
Expand All @@ -1154,6 +1155,7 @@ mod tests {
assert_eq!(31829, src_port);
assert_eq!(33030, dest_port);
assert_eq!(58571, checksum);
assert_eq!(0, payload_len);
assert_eq!(None, extensions);
Ok(())
}
Expand Down Expand Up @@ -1189,6 +1191,7 @@ mod tests {
src_port,
dest_port,
checksum,
payload_len,
}),
..
},
Expand All @@ -1206,6 +1209,7 @@ mod tests {
assert_eq!(32779, src_port);
assert_eq!(33010, dest_port);
assert_eq!(10913, checksum);
assert_eq!(0, payload_len);
assert_eq!(None, extensions);
Ok(())
}
Expand Down
42 changes: 37 additions & 5 deletions src/tracing/net/ipv6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub fn dispatch_icmp_probe<S: Socket>(
Ok(())
}

#[allow(clippy::too_many_arguments)]
#[instrument(skip(raw_send_socket, probe))]
pub fn dispatch_udp_probe<S: Socket>(
raw_send_socket: &mut S,
Expand All @@ -82,6 +83,7 @@ pub fn dispatch_udp_probe<S: Socket>(
privilege_mode: PrivilegeMode,
packet_size: PacketSize,
payload_pattern: PayloadPattern,
initial_sequence: Sequence,
) -> TraceResult<()> {
let packet_size = usize::from(packet_size.0);
if !(MIN_PACKET_SIZE_UDP..=MAX_PACKET_SIZE).contains(&packet_size) {
Expand All @@ -90,9 +92,14 @@ pub fn dispatch_udp_probe<S: Socket>(
let payload_size = udp_payload_size(packet_size);
let payload = &[payload_pattern.0; MAX_UDP_PAYLOAD_BUF][0..payload_size];
match privilege_mode {
PrivilegeMode::Privileged => {
dispatch_udp_probe_raw(raw_send_socket, probe, src_addr, dest_addr, payload)
}
PrivilegeMode::Privileged => dispatch_udp_probe_raw(
raw_send_socket,
probe,
src_addr,
dest_addr,
payload,
initial_sequence,
),
PrivilegeMode::Unprivileged => {
dispatch_udp_probe_non_raw::<S>(probe, src_addr, dest_addr, payload)
}
Expand All @@ -106,11 +113,16 @@ fn dispatch_udp_probe_raw<S: Socket>(
src_addr: Ipv6Addr,
dest_addr: Ipv6Addr,
payload: &[u8],
initial_sequence: Sequence,
) -> TraceResult<()> {
let mut udp_buf = [0_u8; MAX_UDP_PACKET_BUF];
let dublin_payload = [222_u8; MAX_UDP_PAYLOAD_BUF];
let payload_paris = probe.sequence.0.to_be_bytes();
let payload = if probe.flags.contains(Flags::PARIS_CHECKSUM) {
payload_paris.as_slice()
} else if probe.flags.contains(Flags::DUBLIN_CHECKSUM) {
let payload_len = (probe.sequence.0 - initial_sequence.0) + 1;
&dublin_payload[..usize::from(payload_len)]
} else {
payload
};
Expand Down Expand Up @@ -371,13 +383,14 @@ fn extract_probe_resp_seq(
)))
}
(Protocol::Udp, IpProtocol::Udp) => {
let (src_port, dest_port, checksum) = extract_udp_packet(ipv6)?;
let (src_port, dest_port, checksum, payload_len) = extract_udp_packet(ipv6)?;
Some(ProbeResponseSeq::Udp(ProbeResponseSeqUdp::new(
0,
IpAddr::V6(ipv6.get_destination_address()),
src_port,
dest_port,
checksum,
payload_len,
)))
}
(Protocol::Tcp, IpProtocol::Tcp) => {
Expand All @@ -400,12 +413,13 @@ fn extract_echo_request(ipv6: &Ipv6Packet<'_>) -> TraceResult<(u16, u16)> {
))
}

fn extract_udp_packet(ipv6: &Ipv6Packet<'_>) -> TraceResult<(u16, u16, u16)> {
fn extract_udp_packet(ipv6: &Ipv6Packet<'_>) -> TraceResult<(u16, u16, u16, u16)> {
let udp_packet = UdpPacket::new_view(ipv6.payload())?;
Ok((
udp_packet.get_source(),
udp_packet.get_destination(),
udp_packet.get_checksum(),
udp_packet.get_length() - UdpPacket::minimum_packet_size() as u16,
))
}

Expand Down Expand Up @@ -574,6 +588,7 @@ mod tests {
let privilege_mode = PrivilegeMode::Privileged;
let packet_size = PacketSize(48);
let payload_pattern = PayloadPattern(0x00);
let initial_sequence = Sequence(33000);
let expected_send_to_buf = hex_literal::hex!("00 7b 01 c8 00 08 7a ed");
let expected_send_to_addr = SocketAddr::new(IpAddr::V6(dest_addr), 0);

Expand All @@ -600,6 +615,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)?;
Ok(())
}
Expand All @@ -612,6 +628,7 @@ mod tests {
let privilege_mode = PrivilegeMode::Privileged;
let packet_size = PacketSize(56);
let payload_pattern = PayloadPattern(0xaa);
let initial_sequence = Sequence(33000);
let expected_send_to_buf = hex_literal::hex!(
"
00 7b 01 c8 00 10 d0 32 aa aa aa aa aa aa aa aa
Expand Down Expand Up @@ -642,6 +659,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)?;
Ok(())
}
Expand All @@ -659,6 +677,7 @@ mod tests {
// fixed two byte payload is used to hold the sequence
let packet_size = PacketSize(300);
let payload_pattern = PayloadPattern(0xaa);
let initial_sequence = Sequence(33000);
let expected_send_to_buf = hex_literal::hex!(
"
00 7b 01 c8 00 0a 80 e8 fa 00
Expand Down Expand Up @@ -689,6 +708,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)?;
Ok(())
}
Expand All @@ -702,6 +722,7 @@ mod tests {
let privilege_mode = PrivilegeMode::Unprivileged;
let packet_size = PacketSize(48);
let payload_pattern = PayloadPattern(0x00);
let initial_sequence = Sequence(33000);
let expected_send_to_buf = hex_literal::hex!("");
let expected_send_to_addr = SocketAddr::new(IpAddr::V6(dest_addr), 456);
let expected_bind_addr = SocketAddr::new(IpAddr::V6(src_addr), 123);
Expand Down Expand Up @@ -744,6 +765,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)?;
Ok(())
}
Expand All @@ -757,6 +779,7 @@ mod tests {
let privilege_mode = PrivilegeMode::Unprivileged;
let packet_size = PacketSize(56);
let payload_pattern = PayloadPattern(0x1f);
let initial_sequence = Sequence(33000);
let expected_send_to_buf = hex_literal::hex!("1f 1f 1f 1f 1f 1f 1f 1f");
let expected_send_to_addr = SocketAddr::new(IpAddr::V6(dest_addr), 456);
let expected_bind_addr = SocketAddr::new(IpAddr::V6(src_addr), 123);
Expand Down Expand Up @@ -799,6 +822,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)?;
Ok(())
}
Expand All @@ -811,6 +835,7 @@ mod tests {
let privilege_mode = PrivilegeMode::Privileged;
let packet_size = PacketSize(47);
let payload_pattern = PayloadPattern(0x00);
let initial_sequence = Sequence(33000);
let mut mocket = MockSocket::new();
let err = dispatch_udp_probe(
&mut mocket,
Expand All @@ -820,6 +845,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)
.unwrap_err();
assert!(matches!(err, TracerError::InvalidPacketSize(_)));
Expand All @@ -834,6 +860,7 @@ mod tests {
let privilege_mode = PrivilegeMode::Privileged;
let packet_size = PacketSize(1025);
let payload_pattern = PayloadPattern(0x00);
let initial_sequence = Sequence(33000);
let mut mocket = MockSocket::new();
let err = dispatch_udp_probe(
&mut mocket,
Expand All @@ -843,6 +870,7 @@ mod tests {
privilege_mode,
packet_size,
payload_pattern,
initial_sequence,
)
.unwrap_err();
assert!(matches!(err, TracerError::InvalidPacketSize(_)));
Expand Down Expand Up @@ -1068,6 +1096,7 @@ mod tests {
src_port,
dest_port,
checksum,
payload_len,
}),
..
},
Expand All @@ -1085,6 +1114,7 @@ mod tests {
assert_eq!(22694, src_port);
assert_eq!(33029, dest_port);
assert_eq!(53489, checksum);
assert_eq!(36, payload_len);
assert_eq!(None, extensions);
Ok(())
}
Expand Down Expand Up @@ -1124,6 +1154,7 @@ mod tests {
src_port,
dest_port,
checksum,
payload_len,
}),
..
},
Expand All @@ -1141,6 +1172,7 @@ mod tests {
assert_eq!(26477, src_port);
assert_eq!(33118, dest_port);
assert_eq!(37906, checksum);
assert_eq!(36, payload_len);
assert_eq!(None, extensions);
Ok(())
}
Expand Down
3 changes: 3 additions & 0 deletions src/tracing/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ pub struct ProbeResponseSeqUdp {
pub src_port: u16,
pub dest_port: u16,
pub checksum: u16,
pub payload_len: u16,
}

impl ProbeResponseSeqUdp {
Expand All @@ -240,13 +241,15 @@ impl ProbeResponseSeqUdp {
src_port: u16,
dest_port: u16,
checksum: u16,
payload_len: u16,
) -> Self {
Self {
identifier,
dest_addr,
src_port,
dest_port,
checksum,
payload_len,
}
}
}
Expand Down
Loading

0 comments on commit 5e97a47

Please sign in to comment.