use anyhow::Result; use gethostname::gethostname; use local_ip_address::local_ip; use dns_lookup::lookup_addr; use std::io; use std::io::Write; use std::env; use std::process; use uzers::{get_current_uid, get_current_gid, get_current_username, get_current_groupname}; use crate::common::is_binary; use crate::meta_plugin::MetaPlugin; #[derive(Debug, Clone, Default)] pub struct CwdMetaPlugin { meta_name: String, } #[derive(Debug, Clone, Default)] pub struct BinaryMetaPlugin { meta_name: String, buffer: Vec, max_buffer_size: usize, } impl BinaryMetaPlugin { pub fn new() -> BinaryMetaPlugin { BinaryMetaPlugin { meta_name: "binary".to_string(), buffer: Vec::new(), max_buffer_size: 4096, // 4KB } } } impl MetaPlugin for BinaryMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { let is_binary = is_binary(&self.buffer); Ok(if is_binary { "true".to_string() } else { "false".to_string() }) } fn update(&mut self, data: &[u8]) { // Only collect up to max_buffer_size let remaining_capacity = self.max_buffer_size.saturating_sub(self.buffer.len()); if remaining_capacity > 0 { let bytes_to_copy = std::cmp::min(data.len(), remaining_capacity); self.buffer.extend_from_slice(&data[..bytes_to_copy]); } } fn meta_name(&mut self) -> String { self.meta_name.clone() } } impl CwdMetaPlugin { pub fn new() -> CwdMetaPlugin { CwdMetaPlugin { meta_name: "cwd".to_string(), } } } impl MetaPlugin for CwdMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { match env::current_dir() { Ok(path) => Ok(path.to_string_lossy().to_string()), Err(_) => Ok("unknown".to_string()), } } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct UidMetaPlugin { meta_name: String, } impl UidMetaPlugin { pub fn new() -> UidMetaPlugin { UidMetaPlugin { meta_name: "uid".to_string(), } } } impl MetaPlugin for UidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { Ok(get_current_uid().to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct UserMetaPlugin { meta_name: String, } impl UserMetaPlugin { pub fn new() -> UserMetaPlugin { UserMetaPlugin { meta_name: "user".to_string(), } } } impl MetaPlugin for UserMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { match get_current_username() { Some(username) => Ok(username.to_string_lossy().to_string()), None => Ok("unknown".to_string()), } } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct GidMetaPlugin { meta_name: String, } impl GidMetaPlugin { pub fn new() -> GidMetaPlugin { GidMetaPlugin { meta_name: "gid".to_string(), } } } impl MetaPlugin for GidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { Ok(get_current_gid().to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct GroupMetaPlugin { meta_name: String, } impl GroupMetaPlugin { pub fn new() -> GroupMetaPlugin { GroupMetaPlugin { meta_name: "group".to_string(), } } } impl MetaPlugin for GroupMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { match get_current_groupname() { Some(groupname) => Ok(groupname.to_string_lossy().to_string()), None => Ok("unknown".to_string()), } } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct ShellMetaPlugin { meta_name: String, } impl ShellMetaPlugin { pub fn new() -> ShellMetaPlugin { ShellMetaPlugin { meta_name: "shell".to_string(), } } } impl MetaPlugin for ShellMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { match env::var("SHELL") { Ok(shell) => Ok(shell), Err(_) => Ok("unknown".to_string()), } } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct ShellPidMetaPlugin { meta_name: String, } impl ShellPidMetaPlugin { pub fn new() -> ShellPidMetaPlugin { ShellPidMetaPlugin { meta_name: "shell_pid".to_string(), } } } impl MetaPlugin for ShellPidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { match env::var("PPID") { Ok(ppid) => Ok(ppid), Err(_) => Ok(process::id().to_string()), } } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct KeepPidMetaPlugin { meta_name: String, } impl KeepPidMetaPlugin { pub fn new() -> KeepPidMetaPlugin { KeepPidMetaPlugin { meta_name: "keep_pid".to_string(), } } } impl MetaPlugin for KeepPidMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { Ok(process::id().to_string()) } fn update(&mut self, _data: &[u8]) { // No update needed } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct HostnameMetaPlugin { meta_name: String, } impl HostnameMetaPlugin { pub fn new() -> HostnameMetaPlugin { HostnameMetaPlugin { meta_name: "hostname".to_string(), } } } impl MetaPlugin for HostnameMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { match gethostname().into_string() { Ok(hostname) => Ok(hostname), Err(_) => Ok("unknown".to_string()), } } fn update(&mut self, _data: &[u8]) { // No update needed for hostname } fn meta_name(&mut self) -> String { self.meta_name.clone() } } #[derive(Debug, Clone, Default)] pub struct FullHostnameMetaPlugin { meta_name: String, } impl FullHostnameMetaPlugin { pub fn new() -> FullHostnameMetaPlugin { FullHostnameMetaPlugin { meta_name: "full_hostname".to_string(), } } } impl MetaPlugin for FullHostnameMetaPlugin { fn is_internal(&self) -> bool { true } fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { // Try to get the FQDN through reverse DNS lookup match local_ip() { Ok(my_local_ip) => { match lookup_addr(&my_local_ip) { Ok(hostname) => Ok(hostname), Err(_) => { // Fall back to regular hostname if reverse DNS fails match gethostname().into_string() { Ok(hostname) => Ok(hostname), Err(_) => Ok("unknown".to_string()), } } } } Err(_) => { // Fall back to regular hostname if we can't get local IP match gethostname().into_string() { Ok(hostname) => Ok(hostname), Err(_) => Ok("unknown".to_string()), } } } } fn update(&mut self, _data: &[u8]) { // No update needed for full hostname } fn meta_name(&mut self) -> String { self.meta_name.clone() } }