1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
// for nicer doc links
#[allow(unused_imports)]
use crate::ClamdClient;
use std::num::TryFromIntError;
use tracing::trace;
pub type Result<T> = std::result::Result<T, ClamdError>;
/// Errors that can occur when using [`ClamdClient`].
#[derive(Debug, thiserror::Error)]
pub enum ClamdError {
/// Occurs when the custom set chunk size is larger than
/// [`std::u32::MAX`].
#[error("could not send chunk: too large: {0}")]
ChunkSizeError(#[source] TryFromIntError),
/// Occurs when the library cannot connect to the tcp or unix
/// socket. Contains underlying [`std::io::Error`].
#[error("could not connect to socket: {0}")]
ConnectError(#[source] std::io::Error),
/// Occurs when the clamd response is not valid Utf8.
#[error("could not decode clamav response: {0}")]
DecodingUtf8Error(#[source] std::string::FromUtf8Error),
/// Occurs when there was an [`std::io::Error`] while transfering
/// commands or data to/from clamd.
#[error("could not decode / encode clamav response: {0}")]
DecodingIoError(
#[from]
#[source]
std::io::Error,
),
/// Occurs when the response from clamd is not what the library
/// expects. Contains the invalid response.
#[error("invalid response from clamd: {0}")]
InvalidResponse(String),
/// Occurs when there should be a response from clamd but it just
/// closed the connection without sending a response.
#[error("no response from clamd")]
NoResponse,
/// Occurs when we expect a longer response from clamd, but it
/// is somehow malformed. Contains the invalid response.
#[error("incomplete response from clamd: {0}")]
IncompleteResponse(String),
/// Occurs when everything between this library and clamd went
/// well but clamd seems to have found a virus signature. See also
/// [`ClamdError::scan_error`].
#[error("clamd returned error on scan, possible virus: {0}")]
ScanError(String),
}
impl ClamdError {
/// If you want to ignore any error but an actual malignent scan
/// result from clamd. I do not recommend using this without careful thought, as any other error
/// could hide that uploaded bytes are actually a virus.
/// # Example
/// ```rust
/// # use std::net::SocketAddr;
/// # use clamd_client::ClamdClientBuilder;
/// # use eyre::Result;
/// # async fn doc() -> eyre::Result<()> {
/// let address = "127.0.0.1:3310".parse::<SocketAddr>()?;
/// let mut clamd_client = ClamdClientBuilder::tcp_socket(&address).build();
///
/// // This downloads a virus signature that is benign but trips clamd.
/// let eicar_bytes = reqwest::get("https://secure.eicar.org/eicarcom2.zip")
/// .await?
/// .bytes()
/// .await?;
///
/// let err = clamd_client.scan_bytes(&eicar_bytes).await.unwrap_err();
/// let msg = err.scan_error().unwrap();
/// println!("Eicar scan returned that its a virus: {}", msg);
/// # Ok(())
/// # }
/// ```
pub fn scan_error(self) -> Option<String> {
match self {
Self::ScanError(s) => Some(s),
_ => {
trace!("ignoring non-scan error {:?}", self);
None
}
}
}
}