1use std::ffi::OsStr;
2use std::io::{self, ErrorKind, Read, Write};
3use std::net::{AddrParseError, IpAddr, SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
4use std::path::Path;
5use std::process::{Child, Command, Stdio};
6use std::str::FromStr;
7use std::sync::mpsc::{self, channel};
8use std::thread;
9use std::time::Duration;
10
11use puffin::agent::{AgentDescriptor, AgentName};
12use puffin::algebra::ConcreteMessage;
13use puffin::claims::GlobalClaimList;
14use puffin::codec::Codec;
15use puffin::error::Error;
16use puffin::protocol::ProtocolBehavior;
17use puffin::put::{Put, PutOptions};
18use puffin::put_registry::{Factory, TCP_PUT};
19use puffin::stream::Stream;
20
21use crate::protocol::{AgentType, OpaqueMessageFlight, TLSDescriptorConfig, TLSProtocolBehavior};
22
23pub fn new_tcp_factory() -> Box<dyn Factory<TLSProtocolBehavior>> {
24 struct TCPFactory;
25 impl Factory<TLSProtocolBehavior> for TCPFactory {
26 fn create(
27 &self,
28 agent_descriptor: &AgentDescriptor<TLSDescriptorConfig>,
29 _claims: &GlobalClaimList<<TLSProtocolBehavior as ProtocolBehavior>::Claim>,
30 options: &PutOptions,
31 ) -> Result<Box<dyn Put<TLSProtocolBehavior>>, Error> {
32 if options.get_option("args").is_some() {
33 log::info!("Trace contains TCP running information we shall reuse.");
34 let args = options
35 .get_option("args")
36 .ok_or_else(|| {
37 Error::Agent(format!("{} // {:?}", "Unable to find args", options))
38 })?
39 .to_owned();
40 let prog = options
41 .get_option("prog")
42 .ok_or_else(|| Error::Agent("Unable to find prog".to_string()))?
43 .to_owned();
44 let cwd = options
45 .get_option("cwd")
46 .map(|cwd| Some(cwd.to_owned()))
47 .unwrap_or_default();
48 if agent_descriptor.protocol_config.typ == AgentType::Client {
49 let mut server = TcpServerPut::new(agent_descriptor, options)?;
50 server.set_process(TLSProcess::new(&prog, &args, cwd.as_ref()));
51 Ok(Box::new(server))
52 } else {
53 let process = TLSProcess::new(&prog, &args, cwd);
54 let mut client = TcpClientPut::new(agent_descriptor, options)?;
55 client.set_process(process);
56 Ok(Box::new(client))
57 }
58 } else {
59 log::info!("Trace contains no TCP running information so we fall back to external TCP client and servers.");
60 if agent_descriptor.protocol_config.typ == AgentType::Client {
61 let server = TcpServerPut::new(agent_descriptor, options)?;
62 Ok(Box::new(server))
63 } else {
64 let client = TcpClientPut::new(agent_descriptor, options)?;
65 Ok(Box::new(client))
66 }
67 }
68 }
69
70 fn name(&self) -> String {
71 String::from(TCP_PUT)
72 }
73
74 fn versions(&self) -> Vec<(String, String)> {
75 vec![(
76 "harness".to_string(),
77 format!("{} {}", TCP_PUT, puffin_build::puffin::full_version()),
78 )]
79 }
80
81 fn supports(&self, _capability: &str) -> bool {
82 false
83 }
84
85 fn clone_factory(&self) -> Box<dyn Factory<TLSProtocolBehavior>> {
86 Box::new(TCPFactory)
87 }
88
89 fn rng_reseed(&self) {
90 log::debug!("[RNG] reseed failed ({}): not supported", self.name());
91 }
92 }
93
94 Box::new(TCPFactory)
95}
96
97trait TcpPut {
98 fn write_to_stream(&mut self, buf: &[u8]) -> io::Result<()>;
99
100 fn read_to_flight(&mut self) -> Result<Option<OpaqueMessageFlight>, Error>;
101}
102
103pub struct TcpClientPut {
110 stream: TcpStream,
111 agent_descriptor: AgentDescriptor<TLSDescriptorConfig>,
112 process: Option<TLSProcess>,
113}
114
115impl TcpPut for TcpClientPut {
116 fn write_to_stream(&mut self, buf: &[u8]) -> io::Result<()> {
117 self.stream.write_all(buf)?;
118 self.stream.flush()
119 }
120
121 fn read_to_flight(&mut self) -> Result<Option<OpaqueMessageFlight>, Error> {
122 let mut buf = vec![];
123 let _ = self.stream.read_to_end(&mut buf);
124 let flight = OpaqueMessageFlight::read_bytes(&buf);
125 Ok(flight)
126 }
127}
128
129impl TcpClientPut {
130 fn new(
131 agent_descriptor: &AgentDescriptor<TLSDescriptorConfig>,
132 options: &PutOptions,
133 ) -> Result<Self, Error> {
134 let addr = addr_from_config(options).map_err(|err| Error::Put(err.to_string()))?;
135 let stream = Self::new_stream(addr)?;
136
137 Ok(Self {
138 stream,
139 agent_descriptor: agent_descriptor.clone(),
140 process: None,
141 })
142 }
143
144 fn new_stream<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
145 let mut tries = 500;
146 let stream = loop {
147 if let Ok(stream) = TcpStream::connect(&addr) {
148 stream.set_read_timeout(Some(Duration::from_millis(500)))?;
152 stream.set_nodelay(true)?;
153 break Some(stream);
154 }
155
156 tries -= 1;
157
158 if tries == 0 {
159 break None;
160 }
161
162 thread::sleep(Duration::from_millis(100));
163 };
164
165 stream.ok_or(io::Error::new(
166 ErrorKind::NotConnected,
167 "TcpClientPut failed to connect",
168 ))
169 }
170
171 pub fn set_process(&mut self, process: TLSProcess) {
172 self.process = Some(process)
173 }
174}
175
176pub struct TcpServerPut {
177 stream: Option<(TcpStream, TcpListener)>,
178 stream_receiver: mpsc::Receiver<(TcpStream, TcpListener)>,
179 agent_descriptor: AgentDescriptor<TLSDescriptorConfig>,
180 process: Option<TLSProcess>,
181}
182
183impl TcpServerPut {
184 fn new(
185 agent_descriptor: &AgentDescriptor<TLSDescriptorConfig>,
186 options: &PutOptions,
187 ) -> Result<Self, Error> {
188 let (sender, stream_receiver) = channel();
189 let addr = addr_from_config(options).map_err(|err| Error::Put(err.to_string()))?;
190
191 let listener = TcpListener::bind(addr).unwrap();
192
193 thread::spawn(move || {
194 if let Some(new_stream) = listener.incoming().next() {
195 let stream = new_stream.unwrap();
196 stream
200 .set_read_timeout(Some(Duration::from_millis(500)))
201 .unwrap();
202 stream.set_nodelay(true).unwrap();
203 sender.send((stream, listener)).unwrap();
204 }
205 });
206
207 Ok(Self {
208 stream: None,
209 stream_receiver,
210 agent_descriptor: agent_descriptor.clone(),
211 process: None,
212 })
213 }
214
215 pub fn set_process(&mut self, process: TLSProcess) {
216 self.process = Some(process)
217 }
218
219 pub fn receive_stream(&mut self) {
220 if self.stream.is_some() {
221 return;
222 }
223
224 if let Ok(tuple) = self.stream_receiver.recv_timeout(Duration::from_secs(60)) {
225 self.stream = Some(tuple);
226 } else {
227 panic!("Unable to get stream to client!")
228 }
229 }
230}
231
232impl TcpPut for TcpServerPut {
233 fn write_to_stream(&mut self, buf: &[u8]) -> io::Result<()> {
234 self.receive_stream();
235 let stream = &mut self.stream.as_mut().unwrap().0;
236 stream.write_all(buf)?;
237 stream.flush()?;
238 Ok(())
239 }
240
241 fn read_to_flight(&mut self) -> Result<Option<OpaqueMessageFlight>, Error> {
242 self.receive_stream();
243 let mut buf = vec![];
244 let _ = self.stream.as_mut().unwrap().0.read_to_end(&mut buf);
245 let flight = OpaqueMessageFlight::read_bytes(&buf);
246 Ok(flight)
247 }
248}
249
250impl Stream<TLSProtocolBehavior> for TcpServerPut {
251 fn add_to_inbound(&mut self, message: &ConcreteMessage) {
252 self.write_to_stream(message).unwrap();
253 }
254
255 fn take_message_from_outbound(
256 &mut self,
257 output_flight: &mut Option<OpaqueMessageFlight>,
258 ) -> Result<(), Error> {
259 take_message_from_outbound(self, output_flight)
260 }
261}
262
263impl Stream<TLSProtocolBehavior> for TcpClientPut {
264 fn add_to_inbound(&mut self, message: &ConcreteMessage) {
265 self.write_to_stream(message).unwrap();
266 }
267
268 fn take_message_from_outbound(
269 &mut self,
270 output_flight: &mut Option<OpaqueMessageFlight>,
271 ) -> Result<(), Error> {
272 take_message_from_outbound(self, output_flight)
273 }
274}
275
276fn take_message_from_outbound<P: TcpPut>(
277 put: &mut P,
278 output_flight: &mut Option<OpaqueMessageFlight>,
279) -> Result<(), Error> {
280 *output_flight = put.read_to_flight()?;
281 Ok(())
282}
283
284fn addr_from_config(options: &PutOptions) -> Result<SocketAddr, AddrParseError> {
285 let host = options.get_option("host").unwrap_or("127.0.0.1");
286 let port = options
287 .get_option("port")
288 .and_then(|value| u16::from_str(value).ok())
289 .unwrap_or_else(|| {
290 let port = 44338;
291 log::warn!(
292 "Failed to parse port option (maybe you executed a trace that was not produced in \
293 TCP mode?). We anyway fall back to port {port}."
294 );
295 port
296 });
297
298 Ok(SocketAddr::new(IpAddr::from_str(host)?, port))
299}
300
301impl Put<TLSProtocolBehavior> for TcpServerPut {
302 fn progress(&mut self) -> Result<(), Error> {
303 Ok(())
304 }
305
306 fn reset(&mut self, _new_name: AgentName) -> Result<(), Error> {
307 panic!("Not supported")
308 }
309
310 fn descriptor(&self) -> &AgentDescriptor<TLSDescriptorConfig> {
311 &self.agent_descriptor
312 }
313
314 fn describe_state(&self) -> String {
315 panic!("Not supported")
316 }
317
318 fn is_state_successful(&self) -> bool {
319 false
320 }
321
322 fn shutdown(&mut self) -> String {
323 self.process.as_mut().unwrap().shutdown().unwrap()
324 }
325
326 fn version() -> String
327 where
328 Self: Sized,
329 {
330 "Undefined".to_string()
331 }
332}
333
334impl Put<TLSProtocolBehavior> for TcpClientPut {
335 fn progress(&mut self) -> Result<(), Error> {
336 Ok(())
337 }
338
339 fn reset(&mut self, new_name: AgentName) -> Result<(), Error> {
340 self.agent_descriptor.name = new_name;
341 let address = self.stream.peer_addr()?;
342 self.stream = Self::new_stream(address)?;
343 Ok(())
344 }
345
346 fn descriptor(&self) -> &AgentDescriptor<TLSDescriptorConfig> {
347 &self.agent_descriptor
348 }
349
350 fn describe_state(&self) -> String {
351 panic!("Not supported")
352 }
353
354 fn is_state_successful(&self) -> bool {
355 false
356 }
357
358 fn shutdown(&mut self) -> String {
359 self.process.as_mut().unwrap().shutdown().unwrap()
360 }
361
362 fn version() -> String
363 where
364 Self: Sized,
365 {
366 "Undefined".to_string()
367 }
368}
369
370pub struct TLSProcess {
371 child: Option<Child>,
372 output: Option<String>,
373}
374
375impl TLSProcess {
376 pub fn new<P: AsRef<Path>>(prog: &str, args: &str, cwd: Option<P>) -> Self {
377 Self {
378 child: Some(execute_command(prog, args.split(' '), cwd)),
379 output: None,
380 }
381 }
382
383 pub fn shutdown(&mut self) -> Option<String> {
384 self.output = if let Some(mut child) = self.child.take() {
385 child.kill().expect("failed to stop process");
386
387 Some(collect_output(child))
388 } else {
389 None
390 };
391
392 self.output.clone()
393 }
394}
395
396impl Drop for TLSProcess {
397 fn drop(&mut self) {
398 if let Some(output) = self.shutdown() {
399 println!(
400 "TLSProcess was not shutdown manually. Output of the process: {}",
401 output
402 );
403 }
404 }
405}
406
407pub fn collect_output(child: Child) -> String {
408 let output = child.wait_with_output().expect("failed to wait on child");
409 let mut complete = "--- start stderr\n".to_string();
410
411 complete.push_str(std::str::from_utf8(&output.stderr).unwrap());
412 complete.push_str("\n--- end stderr\n");
413 complete.push_str("--- start stdout\n");
414 complete.push_str(std::str::from_utf8(&output.stdout).unwrap());
415 complete.push_str("\n--- end stdout\n");
416
417 complete
418}
419
420pub fn execute_command<I, S, P: AsRef<Path>>(prog: &str, args: I, cwd: Option<P>) -> Child
421where
422 I: IntoIterator<Item = S>,
423 S: AsRef<OsStr>,
424{
425 let mut cmd = Command::new(prog);
426
427 if let Some(cwd) = cwd {
428 cmd.current_dir(cwd);
429 }
430
431 cmd.args(args)
432 .stdin(Stdio::piped()) .stdout(Stdio::piped())
434 .stderr(Stdio::piped())
435 .spawn()
436 .expect("failed to execute process")
437}
438
439#[cfg(test)]
440mod tests {
441 use puffin::execution::{Runner, TraceRunner};
442 use puffin::put::PutDescriptor;
443 use puffin::put_registry::TCP_PUT;
444 use puffin::trace::Spawner;
445
446 use crate::protocol::TLSVersion;
447 #[allow(unused_imports)]
448 use crate::{test_utils::prelude::*, tls::seeds::*};
449
450 #[test_log::test]
451 fn test_openssl_session_resumption_dhe_full() {
452 let port = 44330;
453 let guard = openssl_server(port, TLSVersion::V1_3);
454 let trace = seed_session_resumption_dhe_full.build_trace();
455 let server = trace.descriptors[0].name;
456 let runner = default_runner_for_desc(PutDescriptor::new(TCP_PUT, guard.build_options()));
457
458 let mut context = runner.execute(trace, &mut 0).unwrap();
459
460 let shutdown = context.find_agent_mut(server).unwrap().shutdown();
461 log::info!("{}", shutdown);
462 assert!(shutdown.contains("Reused session-id"));
463 }
464
465 #[test_log::test]
466 fn test_openssl_seed_client_attacker_full() {
467 let port = 44331;
468 let guard = openssl_server(port, TLSVersion::V1_3);
469 let runner = default_runner_for_desc(PutDescriptor::new(TCP_PUT, guard.build_options()));
470 let trace = seed_client_attacker_full.build_trace();
471 let server = trace.descriptors[0].name;
472
473 let mut context = runner.execute(trace, &mut 0).unwrap();
474
475 let shutdown = context.find_agent_mut(server).unwrap().shutdown();
476 log::info!("{}", shutdown);
477 assert!(shutdown.contains("BEGIN SSL SESSION PARAMETERS"));
478 assert!(!shutdown.contains("Reused session-id"));
479 }
480
481 #[test_log::test]
482 fn test_openssl_openssl_seed_successful12() {
483 let trace = seed_successful12_with_tickets.build_trace();
484
485 let server_port = 44332;
486 let server_agent = trace.descriptors[1].name;
487 let server_guard = openssl_server(server_port, TLSVersion::V1_2);
488 let server = PutDescriptor::new(TCP_PUT, server_guard.build_options());
489
490 let client_port = 44333;
491 let client_agent = trace.descriptors[0].name;
492 let client_guard = openssl_client(client_port, TLSVersion::V1_2);
493 let client = PutDescriptor::new(TCP_PUT, client_guard.build_options());
494
495 let put_registry = tls_registry();
496 let runner = Runner::new(
497 put_registry.clone(),
498 Spawner::new(put_registry)
499 .with_mapping(&[(client_agent, client), (server_agent, server)]),
500 );
501
502 let mut context = runner.execute(trace, &mut 0).unwrap();
503
504 let shutdown = context.find_agent_mut(client_agent).unwrap().shutdown();
505 log::info!("{}", shutdown);
506 assert!(shutdown.contains("Timeout : 7200 (sec)"));
507
508 let shutdown = context.find_agent_mut(server_agent).unwrap().shutdown();
509 log::info!("{}", shutdown);
510 assert!(shutdown.contains("BEGIN SSL SESSION PARAMETERS"));
511 }
512
513 #[test_log::test]
514 #[ignore] fn test_wolfssl_openssl_seed_successful12() {
516 let trace = seed_successful12_with_tickets.build_trace();
517
518 let server_port = 44334;
519 let server_agent = trace.descriptors[1].name;
520 let server_guard = openssl_server(server_port, TLSVersion::V1_2);
521 let server = PutDescriptor::new(TCP_PUT, server_guard.build_options());
522
523 let client_port = 44335;
524 let client_agent = trace.descriptors[0].name;
525 let client_guard = wolfssl_client(client_port, TLSVersion::V1_2, None);
526 let client = PutDescriptor::new(TCP_PUT, client_guard.build_options());
527
528 let put_registry = tls_registry();
529 let runner = Runner::new(
530 put_registry.clone(),
531 Spawner::new(put_registry)
532 .with_mapping(&[(client_agent, client), (server_agent, server)]),
533 );
534
535 let mut context = runner.execute(trace, &mut 0).unwrap();
536
537 let shutdown = context.find_agent_mut(client_agent).unwrap().shutdown();
538 log::info!("{}", shutdown);
539 assert!(!shutdown.contains("fail"));
540
541 let shutdown = context.find_agent_mut(server_agent).unwrap().shutdown();
542 log::info!("{}", shutdown);
543 assert!(shutdown.contains("BEGIN SSL SESSION PARAMETERS"));
544 }
545}