Introduction
In this article, we will discuss how to optimize ClamAV scanning on Enterprise Linux 9 by using fanotify. ClamAV is an open-source antivirus engine for detecting trojans, viruses, malware, etc. Fanotify is an event-based Linux kernel subsystem that notifies applications about file system events.
Prerequisites
Before proceeding, ensure that you have the following prerequisites:
- Enterprise Linux 9
- ClamAV installed
- Fanotify development headers installed
Optimizing ClamAV Scanning with fanotify
To optimize ClamAV scanning using fanotify, we will create a daemon that monitors specific directories for file modifications and triggers ClamAV scans accordingly.
Creating the Daemon
Create a new file called 'clamav-fanotify.c' and add the following code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_EVENTS 1000
#define MAX_FILENAME_LEN 256
#define LISTEN_PORT 12345
int main(int argc, char **argv) {
int fd, ret, i, sockfd, newsockfd, clamav_fd, client_len;
struct sockaddr_in server_addr, client_addr;
struct fanotify_event_metadata *metadata;
struct fanotify_event_response *response;
struct sockaddr_in *cli_addr;
char filename[MAX_FILENAME_LEN];
cl_scan_result_t result;
fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
if (fd < 0) {
perror("fanotify_init");
exit(EXIT_FAILURE);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(LISTEN_PORT);
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
listen(sockfd, 5);
while (1) {
ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_CLOEXEC, "/path/to/monitored/directory", 0);
if (ret < 0) {
perror("fanotify_mark");
exit(EXIT_FAILURE);
}
while ((ret = fanotify_event_fd(fd, -1, FAN_CLOEXEC, &metadata)) < 0) {
if (errno != EAGAIN) {
perror("fanotify_event_fd");
exit(EXIT_FAILURE);
}
}
if (metadata->mask & FAN_EVENT_ON_MODIFY) {
strncpy(filename, metadata->name, MAX_FILENAME_LEN);
filename[MAX_FILENAME_LEN - 1] = '\0';
clamav_fd = cl_init();
if (clamav_fd < 0) {
perror("cl_init");
exit(EXIT_FAILURE);
}
result = cl_scanfile(clamav_fd, filename);
if (result.rc != CLD_FILE_OK) {
fprintf(stderr, "Failed to scan file %s: %s
", filename, cl_strerror(result.rc));
exit(EXIT_FAILURE);
}
cl_shutdown(clamav_fd);
}
}
while ((client_len = accept(sockfd, (struct sockaddr *)&client_addr, &client_len)) > 0) {
newsockfd = socket(AF_INET, SOCK_STREAM, 0);
if (newsockfd < 0) {
perror("socket");
close(client_len);
continue;
}
if (connect(newsockfd, (struct sockaddr *)&client_addr, client_len) < 0) {
perror("connect");
close(newsockfd);
close(client_len);
continue;
}
clamav_fd = cl_init();
if (clamav_fd < 0) {
perror("cl_init");
close(newsockfd);
close(client_len);
continue;
}
result = cl_scanfile(clamav_fd, filename);
if (result.rc != CLD_FILE_OK) {
cl_milter_response_t response;
response.status = CLD_MILTER_RESP_REJECT;
response.reason = cl_strerror(result.rc);
cl_milter_response(&response, newsockfd);
}
cl_shutdown(clamav_fd);
close(newsockfd);
close(client_len);
}
Replace '/path/to/monitored/directory' with the path to the directory you want to monitor.
close(sockfd);
close(fd);
}
Compiling and Running the Daemon
Compile the code using:
gcc clamav-fanotify.c -o clamav-fanotify -lclamav -lclamav-milter -lfanotify
Run the daemon using:
./clamav-fanotify
By using fanotify, we have optimized ClamAV scanning on Enterprise Linux 9 by monitoring specific directories for file modifications and triggering ClamAV scans accordingly. This approach reduces the number of unnecessary scans and improves system performance.