manycastr/worker/outbound/
trace.rs1use crate::custom_module::manycastr::{ProtocolType, Trace};
2use crate::net::packet::{
3 ProbePayload, TraceDnsId, create_icmp, create_tcp_trace, create_udp_trace,
4};
5use crate::worker::outbound::{OutboundConfig, send_packet};
6use crate::worker::trace_codec::TraceTag;
7use log::warn;
8use socket2::Socket;
9use std::time::{SystemTime, UNIX_EPOCH};
10
11pub fn send_trace(config: &OutboundConfig, trace_task: &Trace, socket: &Socket) -> (u32, u32) {
24 let worker_id = config.worker_id as u32;
25 let p_type = config.p_type;
26 let src = &config.src;
27 let info_url = config.info_url.as_deref();
28 let target = &trace_task.dst.unwrap();
29 let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
30 let tx_micros = now.as_micros() as u64;
31 let tag = TraceTag {
32 worker_id,
33 ttl: trace_task.ttl as u8,
34 ts14: (now.as_millis() & 0x3FFF) as u16,
35 };
36 let ttl = tag.ttl;
37 let probe_id = crate::probe_id(config.m_id, 0);
39
40 let packet = match p_type {
41 ProtocolType::Icmp => {
42 let (identifier, sequence_number) = tag.encode_split();
44
45 let payload_fields = ProbePayload {
46 worker_id,
47 probe_id,
48 trace_ttl: Some(ttl),
49 info_url,
50 };
51
52 create_icmp(
53 src,
54 target,
55 identifier,
56 sequence_number,
57 &payload_fields,
58 ttl,
59 )
60 }
61
62 ProtocolType::ADns | ProtocolType::ChaosDns => {
63 let (identifier, desired_checksum) = tag.encode_split();
65
66 create_udp_trace(
67 src,
68 target,
69 config.sport,
70 config.dport,
71 identifier,
72 desired_checksum,
73 &TraceDnsId {
74 tx_id: worker_id,
75 probe_id,
76 tx_micros,
77 ttl,
78 qname: config.qname.as_deref().unwrap_or("example.org"),
79 },
80 )
81 }
82
83 ProtocolType::Tcp => {
84 let seq = tag.encode_tcp_seq();
86
87 create_tcp_trace(src, target, config.sport, config.dport, seq, ttl, info_url)
88 }
89 };
90
91 if src.is_v6()
95 && p_type == ProtocolType::Icmp
96 && let Err(e) = socket.set_unicast_hops_v6(trace_task.ttl)
97 {
98 warn!(
99 "[Worker outbound] Failed to set IPv6 hop limit to {}: {e}",
100 trace_task.ttl
101 );
102 }
103
104 let result = match send_packet(
105 socket,
106 &packet,
107 &trace_task.dst.expect("invalid destination"),
108 ) {
109 Ok(()) => (1, 0),
110 Err(e) => {
111 warn!("[Worker outbound] Failed to send {p_type} traceroute packet: {e}");
112 (0, 1)
113 }
114 };
115
116 if src.is_v6() && p_type == ProtocolType::Icmp {
118 let _ = socket.set_unicast_hops_v6(255);
119 }
120
121 result
122}