agentsight_capture/
binary_extractor.rs1use std::fs;
5use std::io::Write;
6use std::os::unix::fs::PermissionsExt;
7use std::path::{Path, PathBuf};
8use std::sync::{Mutex, OnceLock};
9use tempfile::TempDir;
10use tokio::time::{Duration, sleep};
11
12const PROCESS_BINARY: &[u8] = include_bytes!("../vendor/bpf/process");
13const SSLSNIFF_BINARY: &[u8] = include_bytes!("../vendor/bpf/sslsniff");
14const STDIOCAP_BINARY: &[u8] = include_bytes!("../vendor/bpf/stdiocap");
15
16pub struct BinaryExtractor {
17 _temp_dir: TempDir, pub process_path: PathBuf,
19 pub sslsniff_path: PathBuf,
20 stdiocap_init_lock: Mutex<()>,
21 stdiocap_path: OnceLock<PathBuf>,
22}
23
24impl BinaryExtractor {
25 pub async fn new() -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
26 let temp_dir = TempDir::new()?;
27 let temp_path = temp_dir.path();
28
29 log::debug!("Created temporary directory: {}", temp_path.display());
30
31 let process_path = temp_path.join("process");
33 Self::extract_binary(&process_path, PROCESS_BINARY, "process").await?;
34
35 let sslsniff_path = temp_path.join("sslsniff");
37 Self::extract_binary(&sslsniff_path, SSLSNIFF_BINARY, "sslsniff").await?;
38
39 sleep(Duration::from_millis(100)).await;
41
42 Ok(Self {
43 _temp_dir: temp_dir,
44 process_path,
45 sslsniff_path,
46 stdiocap_init_lock: Mutex::new(()),
47 stdiocap_path: OnceLock::new(),
48 })
49 }
50
51 async fn extract_binary(
52 path: &Path,
53 binary_data: &[u8],
54 name: &str,
55 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
56 {
57 let mut file = fs::File::create(path)?;
58 file.write_all(binary_data)?;
59 file.flush()?;
60 } let mut perms = fs::metadata(path)?.permissions();
64 perms.set_mode(0o755);
65 fs::set_permissions(path, perms)?;
66
67 log::debug!("Extracted {} binary to: {}", name, path.display());
68
69 Ok(())
70 }
71
72 pub fn get_process_path(&self) -> &Path {
73 &self.process_path
74 }
75
76 pub fn get_sslsniff_path(&self) -> &Path {
77 &self.sslsniff_path
78 }
79
80 pub fn get_stdiocap_path(&self) -> Result<&Path, Box<dyn std::error::Error + Send + Sync>> {
81 if let Some(path) = self.stdiocap_path.get() {
82 return Ok(path.as_path());
83 }
84
85 let _guard = self
86 .stdiocap_init_lock
87 .lock()
88 .map_err(|_| std::io::Error::other("stdiocap extraction lock poisoned"))?;
89
90 if let Some(path) = self.stdiocap_path.get() {
91 return Ok(path.as_path());
92 }
93
94 let stdiocap_path = self._temp_dir.path().join("stdiocap");
95 {
96 let mut file = fs::File::create(&stdiocap_path)?;
97 file.write_all(STDIOCAP_BINARY)?;
98 file.flush()?;
99 }
100
101 let mut perms = fs::metadata(&stdiocap_path)?.permissions();
102 perms.set_mode(0o755);
103 fs::set_permissions(&stdiocap_path, perms)?;
104 log::debug!("Extracted stdiocap binary to: {}", stdiocap_path.display());
105
106 self.stdiocap_path
107 .set(stdiocap_path)
108 .map_err(|_| std::io::Error::other("stdiocap path initialized concurrently"))?;
109
110 Ok(self
111 .stdiocap_path
112 .get()
113 .expect("stdiocap path should be initialized")
114 .as_path())
115 }
116}