Clamd Python Interface
Clamd is a Python interface library for communicating with the ClamAV daemon (`clamd`). It allows Python applications to send files or streams to `clamd` for virus scanning. The current stable version is 1.0.2, with a low release cadence indicating maturity and stability, focusing on Python 3.7+.
Warnings
- gotcha Clamd daemon must be running and accessible. The `clamd` library is merely a client; it does not start or manage the ClamAV daemon. Connection attempts will fail with `clamd.ClamdError` or `FileNotFoundError` if the daemon isn't running or the socket/network address is incorrect.
- gotcha Unix socket permissions can cause 'Permission denied' errors. When using `ClamdUnixSocket`, the user running the Python script needs appropriate read/write permissions for the socket file (e.g., `/var/run/clamav/clamd.ctl`).
- gotcha The `scan()` and `multiscan()` methods return a dictionary where keys are stream names/file paths and values are tuples `(status, virus_name)`.
- gotcha The library primarily uses bytes for scanning inputs, not strings. While Python 3 handles string-to-bytes implicitly in some I/O operations, explicitly encoding input strings to bytes (`my_string.encode()`) is best practice.
Install
-
pip install clamd
Imports
- clamd
import clamd
- ClamdUnixSocket
import clamd cd = clamd.ClamdUnixSocket()
- ClamdNetworkSocket
import clamd cd = clamd.ClamdNetworkSocket(host='127.0.0.1', port=3310)
Quickstart
import clamd
import os
# Assuming clamd is running and accessible via its default Unix socket
# You might need to adjust the socket path or use ClamdNetworkSocket
# if clamd is running on a network port.
def scan_string(text_to_scan: str):
try:
# Common Unix socket paths for clamd:
# /var/run/clamav/clamd.ctl (Ubuntu/Debian)
# /run/clamd.ctl (Arch Linux)
# /var/lib/clamav/clamd.sock
# Use environment variable for socket path or default
clamd_socket_path = os.environ.get('CLAMD_UNIX_SOCKET', '/var/run/clamav/clamd.ctl')
cd = clamd.ClamdUnixSocket(path=clamd_socket_path)
# Test connection
cd.ping()
print(f"Successfully connected to clamd at {clamd_socket_path}")
# Scan the string. The 'stream' key is arbitrary for stream scans.
# 'EICAR_Test_File' is a safe test virus string.
result = cd.scan(b'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*')
print(f"Scan result for string: {result}")
# Interpret result
if 'stream' in result and result['stream'][0] == 'FOUND':
print(f"!!! VIRUS DETECTED: {result['stream'][1]} !!!")
elif 'stream' in result and result['stream'][0] == 'OK':
print("No virus detected.")
else:
print("Unexpected scan result format.")
except clamd.ClamdError as e:
print(f"Error connecting to or communicating with clamd: {e}")
print("Please ensure the clamd daemon is running and accessible at the specified socket path/address, and that your user has permissions.")
except FileNotFoundError:
print(f"Error: Clamd Unix socket not found at {clamd_socket_path}. Please check the path and clamd status.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
# Example usage with the EICAR test string
scan_string("This is a test file for antivirus scanning.")