use std::{ collections::HashMap, net::IpAddr, sync::{Arc, Mutex}, }; use insta::assert_snapshot; use once_cell::sync::Lazy; use packet_builder::*; use pnet::{datalink::DataLinkReceiver, packet::Packet}; use regex::Regex; use crate::{ start, tests::{ cases::test_utils::{ build_tcp_packet, opts_raw, os_input_output_dns, os_input_output_stdout, test_backend_factory, }, fakes::{create_fake_dns_client, NetworkFrames}, }, Opt, }; fn build_ip_tcp_packet( source_ip: &str, destination_ip: &str, source_port: u16, destination_port: u16, payload: &'static [u8], ) -> Vec { let mut pkt_buf = [0u8; 1500]; let pkt = packet_builder!( pkt_buf, ipv4({set_source => ipv4addr!(source_ip), set_destination => ipv4addr!(destination_ip) }) / tcp({set_source => source_port, set_destination => destination_port }) / payload(payload) ); pkt.packet().to_vec() } fn format_raw_stdout(raw: &Mutex>) -> String { static TIMESTAMP_MATCHER: Lazy = Lazy::new(|| Regex::new(r"<\d+>").unwrap()); let stdout = raw.lock().unwrap(); TIMESTAMP_MATCHER .replace_all(std::str::from_utf8(&stdout).unwrap(), "") .into() } #[test] fn one_ip_packet_of_traffic() { let network_frames = vec![NetworkFrames::new(vec![Some(build_ip_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"I am a fake tcp packet", ))]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn one_packet_of_traffic() { let network_frames = vec![NetworkFrames::new(vec![Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"I am a fake tcp packet", ))]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn bi_directional_traffic() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"I am a fake tcp upload packet", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I am a fake tcp download packet", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn multiple_packets_of_traffic_from_different_connections() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "2.2.2.2", "10.0.0.2", 12345, 443, b"I have come from 2.2.2.2", )), Some(build_tcp_packet( "2.2.2.2", "10.0.0.2", 54321, 4434, b"I come from 2.2.2.2", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn multiple_packets_of_traffic_from_single_connection() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I've come from 1.1.1.1 too!", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn one_process_with_multiple_connections() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12346, 443, b"Funny that, I'm from 1.1.1.1", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn multiple_processes_with_multiple_connections() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"Greetings traveller, I'm from 3.3.3.3", )), Some(build_tcp_packet( "2.2.2.2", "10.0.0.2", 54321, 4434, b"You know, 2.2.2.2 is really nice!", )), Some(build_tcp_packet( "4.4.4.4", "10.0.0.2", 1337, 4432, b"I'm partial to 4.4.4.4", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn multiple_connections_from_remote_address() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12346, 443, b"Me too, but on a different port", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 2, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn sustained_traffic_from_one_process() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1", )), None, // sleep Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"Same here, but one second later", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 3, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn sustained_traffic_from_multiple_processes() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"I come from 3.3.3.3", )), None, // sleep Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"I have come from 1.1.1.1 one second later", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"I come 3.3.3.3 one second later", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 3, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn sustained_traffic_from_multiple_processes_bi_directional() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "10.0.0.2", "3.3.3.3", 4435, 1337, b"omw to 3.3.3.3", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"I was just there!", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"Is it nice there? I think 1.1.1.1 is dull", )), Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"Well, I heard 1.1.1.1 is all the rage", )), None, // sleep Some(build_tcp_packet( "10.0.0.2", "3.3.3.3", 4435, 1337, b"Wait for me!", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"They're waiting for you...", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"1.1.1.1 forever!", )), Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"10.0.0.2 forever!", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_stdout(network_frames, 3, Some(stdout.clone())); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn traffic_with_host_names() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "10.0.0.2", "3.3.3.3", 4435, 1337, b"omw to 3.3.3.3", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"I was just there!", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"Is it nice there? I think 1.1.1.1 is dull", )), Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"Well, I heard 1.1.1.1 is all the rage", )), None, // sleep Some(build_tcp_packet( "10.0.0.2", "3.3.3.3", 4435, 1337, b"Wait for me!", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"They're waiting for you...", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"1.1.1.1 forever!", )), Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"10.0.0.2 forever!", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let mut ips_to_hostnames = HashMap::new(); ips_to_hostnames.insert( IpAddr::V4("1.1.1.1".parse().unwrap()), String::from("one.one.one.one"), ); ips_to_hostnames.insert( IpAddr::V4("3.3.3.3".parse().unwrap()), String::from("three.three.three.three"), ); ips_to_hostnames.insert( IpAddr::V4("10.0.0.2".parse().unwrap()), String::from("i-like-cheese.com"), ); let dns_client = create_fake_dns_client(ips_to_hostnames); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_dns(network_frames, 3, Some(stdout.clone()), dns_client); let opts = opts_raw(); start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); } #[test] fn no_resolve_mode() { let network_frames = vec![NetworkFrames::new(vec![ Some(build_tcp_packet( "10.0.0.2", "3.3.3.3", 4435, 1337, b"omw to 3.3.3.3", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"I was just there!", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"Is it nice there? I think 1.1.1.1 is dull", )), Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"Well, I heard 1.1.1.1 is all the rage", )), None, // sleep Some(build_tcp_packet( "10.0.0.2", "3.3.3.3", 4435, 1337, b"Wait for me!", )), Some(build_tcp_packet( "3.3.3.3", "10.0.0.2", 1337, 4435, b"They're waiting for you...", )), Some(build_tcp_packet( "1.1.1.1", "10.0.0.2", 12345, 443, b"1.1.1.1 forever!", )), Some(build_tcp_packet( "10.0.0.2", "1.1.1.1", 443, 12345, b"10.0.0.2 forever!", )), ]) as Box]; let (_, _, backend) = test_backend_factory(190, 50); let mut ips_to_hostnames = HashMap::new(); ips_to_hostnames.insert( IpAddr::V4("1.1.1.1".parse().unwrap()), String::from("one.one.one.one"), ); ips_to_hostnames.insert( IpAddr::V4("3.3.3.3".parse().unwrap()), String::from("three.three.three.three"), ); ips_to_hostnames.insert( IpAddr::V4("10.0.0.2".parse().unwrap()), String::from("i-like-cheese.com"), ); let stdout = Arc::new(Mutex::new(Vec::new())); let os_input = os_input_output_dns(network_frames, 3, Some(stdout.clone()), None); let opts = Opt { interface: Some(String::from("interface_name")), raw: true, no_resolve: true, ..Default::default() }; start(backend, os_input, opts); assert_snapshot!(format_raw_stdout(&stdout)); }