FAUN — Developer Community 🐾

We help developers learn and grow by keeping them up with what matters. 👉 www.faun.dev

Follow publication

Part 1 — Virus Detection Service using ClamAV and Java

In most of the web or desktop applications, we work with files or streams. Nowadays virus attacks have increased significantly it’s also required to scan files before we perform any operations on them. We had the same requirement and I searched on the internet what all open-source choices are available and what other companies are using.

ClamAV® is an open-source antivirus engine for detecting trojans, viruses, malware & other malicious threats. It has enough documentation and you can also find an active community on StackOverflow. It is also compatible with most operating systems.

https://www.clamav.net/documents/clam-antivirus-user-manual

It comes with 2 processes one is the main process which we can also call as virus detection service ClamAV and another is freshclam. Freshclam is responsible for updating ClamAV local database to support the scanning of more types of files. In this blog, we will run all services inside docker and also learn how we can start multiple services inside a single docker container.

If you want to test ClamAV it’s better to use a docker image which you can find https://hub.docker.com/r/mkodockx/docker-clamav/. The current ClamAV version is “0.102.1” but when you install in different OS using package not binary you might get older version as well. As this is an open-source you have to keep an eye on changelog and accordingly update your ClamAV version.

Setting up ClamAV using Docker

By default, ClamAV runs on 3310 port. It provides a configuration in “clamd.conf” where you can tune many parameters like Port, File Size, etc.

Pulling ClamAV Docker Image

bash-3.2$ docker pull mkodockx/docker-clamav Using default tag: latest
latest: Pulling from mkodockx/docker-clamav
Digest: sha256:b8e343e005e6475e52eabb4966803d2d7e7ee1800693a8be82e85be14714252b
Status: Image is up to date for mkodockx/docker-clamav:latest
docker.io/mkodockx/docker-clamav:latest
bash-3.2$ docker image ls -a | grep docker-clamav mkodockx/docker-clamav latest b0a33e6a0b6b 3 weeks ago 319MB

Running ClamAV Docker using image

bash-3.2$ docker run -d -p 3310:3310 b0a33e6a0b6b f2276b656e96656493132b507d0e6386e8aa75220bc1b06ce309cffed5d6c1cc bash-3.2$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f2276b656e96 b0a33e6a0b6b "/bootstrap.sh" 5 seconds ago Up 3 seconds 0.0.0.0:3310->3310/tcp lucid_brahmagupta

Checking if clamd process is running inside docker

bash-3.2$ docker exec -it f2276b656e96 bash root@f2276b656e96:/# ps -ef | grep clamd clamav 16 1 65 07:40 ? 00:01:22 clamd
root 31 20 0 07:42 pts/0 00:00:00 grep clamd

Clamd.conf configuration inside docker

root@f2276b656e96:/# ls -lrt /etc/clamav/clamd.conf -rw-r - r - 1 root root 2004 Nov 24 15:42 /etc/clamav/clamd.conf root@f2276b656e96:/# cat /etc/clamav/clamd.conf ReadTimeout 180
MaxThreads 12
MaxConnectionQueueLength 15
MaxScanTime 120000
MaxScanSize 100M
MaxFileSize 25M

Docker and ClamAV Details

root@f2276b656e96:/# (cat /etc/os-release;clamd - version ) | cat PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
VERSION_CODENAME=stretch
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
ClamAV 0.101.4/25667/Wed Dec 18 09:53:32 2019

We can connect to ClamAV on localhost:3310 using TCP and send file data in the input stream format. In the below code, we are sending an input stream to ClamAV. We can also create File Hash from input Stream.

public static void scanStream(InputStream inputStream) throws IOException, NoSuchAlgorithmException {
Socket socket = null;
OutputStream outStream = null;
InputStream inStream = null;
try {
socket = new Socket("localhost",3310);
outStream = new BufferedOutputStream(socket.getOutputStream());
socket.setSoTimeout(2000);
outStream.write("zINSTREAM\0".getBytes(StandardCharsets.));
outStream.flush();
byte[] buffer = new byte[2048];
try {
inStream = socket.getInputStream();
int read = inputStream.read(buffer);
while (read >= 0) {
byte[] chunkSize = ByteBuffer.allocate(4).putInt(read).array();
outStream.write(chunkSize);
outStream.write(buffer, 0, read);
if (inStream.available() > 0) {
byte[] reply = IOUtils.toByteArray(inStream);
throw new IOException("Reply from server: " + new String(reply, StandardCharsets.));
}
read = inputStream.read(buffer);
}
outStream.write(new byte[]{0,0,0,0});
outStream.flush();
System..println(new String(IOUtils.toByteArray(inStream)));
} finally { }
}finally {
try {
if(socket != null)
socket.close();
} catch (IOException e) {
System..println("Exception occurred while closing socket = {} "+ e.getMessage());
}
try {
if(inStream != null)
inStream.close();
} catch(IOException e) {
System..println("Exception occurred while closing input streams = {} "+ e.getMessage());
}
try {
if(outStream != null)
outStream.close();
} catch(IOException e) {
System..println("Exception occurred while closing output streams = {} "+ e.getMessage());
}
}
}

Output

For Stream containing virusFor Stream with no virus
stream: OK�
stream: Eicar-Test-Signature FOUND�

In the next part, I will integrate the same with Sample Spring Boot Application and create APIs.

You can cross-check ClamAV’s scan results with https://virustotal.com/.

Subscribe to FAUN topics and get your weekly curated email of the must-read tech stories, news, and tutorials 🗞️

Follow us on Twitter 🐦 and Facebook 👥 and Instagram 📷 and join our Facebook and Linkedin Groups 💬

If this post was helpful, please click the clap 👏 button below a few times to show your support for the author! ⬇

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in FAUN — Developer Community 🐾

We help developers learn and grow by keeping them up with what matters. 👉 www.faun.dev

Written by Raghunandan Gupta

I am a coder by heart and try to learn new things along with sharpening existing skills. https://www.linkedin.com/in/raghunitb/

Responses (1)

Write a response

Hi Raghunandan,
I have implemented the poc as mentioned by you, but for all file I am getting output as stream ok.
Am I missing anything here?
Thanks,
Shivananda S.