Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for execution simple MULTISCAN command (only one file) #13

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ MAINTAINER Antti Virtanen <[email protected]>
# update maximum stream length to much smaller than default
# automated tests run smoother this way
RUN sed -i 's/^StreamMaxLength .*$/StreamMaxLength 50100/g' /etc/clamav/clamd.conf

# For testing scan files
ADD src/test/resources /
# av daemon bootstrapping
CMD ["/bootstrap.sh"]
23 changes: 22 additions & 1 deletion src/main/java/fi/solita/clamav/ClamAVClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
Expand Down Expand Up @@ -113,6 +112,28 @@ public byte[] scan(InputStream is) throws IOException {
}
}

/**
* Scan file by the path on the filesystem
* @param filepath the path to file to scan. Example: /share/attachments/virus.txt
* @return server reply
*/
public byte[] scan(String filepath) throws IOException {
try (Socket socket = new Socket(hostName, port);
OutputStream outs = new BufferedOutputStream(socket.getOutputStream())) {
socket.setSoTimeout(timeout);

// handshake
final String multiScanCmd = "MULTISCAN" + " " + filepath;
outs.write(multiScanCmd.getBytes(StandardCharsets.US_ASCII));
outs.flush();

try (InputStream response = socket.getInputStream()) {
return readAll(response);
}

}
}

/**
* Scans bytes for virus by passing the bytes to clamav
*
Expand Down
45 changes: 27 additions & 18 deletions src/test/java/fi/solita/clamav/InstreamTest.java
Original file line number Diff line number Diff line change
@@ -1,66 +1,75 @@
package fi.solita.clamav;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;

import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
* These tests assume clamd is running and responding in the virtual machine.
*/
public class InstreamTest {
private final ClamAVClient client = new ClamAVClient(
TestConfiguration.CLAMAV_HOST, TestConfiguration.CLAMAV_PORT);

private static String CLAMAV_HOST = "localhost";

private byte[] scan(byte[] input) throws UnknownHostException, IOException {
ClamAVClient cl = new ClamAVClient(CLAMAV_HOST, 3310);
return cl.scan(input);
private byte[] scan(byte[] input) throws IOException {
return client.scan(input);
}

private byte[] scan(InputStream input) throws UnknownHostException, IOException {
ClamAVClient cl = new ClamAVClient(CLAMAV_HOST, 3310);
return cl.scan(input);
private byte[] scan(InputStream input) throws IOException {
return client.scan(input);
}

private byte[] scan(String filepath) throws IOException {
return client.scan(filepath);
}

@Test
public void testRandomBytes() throws UnknownHostException, IOException {
public void testRandomBytes() throws IOException {
byte[] r = scan("alsdklaksdla".getBytes("ASCII"));
assertTrue(ClamAVClient.isCleanReply(r));
}

@Test
public void testPositive() throws UnknownHostException, IOException {
public void testPositive() throws IOException {
// http://www.eicar.org/86-0-Intended-use.html
byte[] EICAR = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*".getBytes("ASCII");
byte[] r = scan(EICAR);
assertFalse(ClamAVClient.isCleanReply(r));
}

@Test
public void testStreamChunkingWorks() throws UnknownHostException, IOException {
public void testStreamChunkingWorks() throws IOException {
byte[] multipleChunks = new byte[50000];
byte[] r = scan(multipleChunks);
assertTrue(ClamAVClient.isCleanReply(r));
}

@Test
public void testChunkLimit() throws UnknownHostException, IOException {
public void testChunkLimit() throws IOException {
byte[] maximumChunk = new byte[2048];
byte[] r = scan(maximumChunk);
assertTrue(ClamAVClient.isCleanReply(r));
}

@Test
public void testZeroBytes() throws UnknownHostException, IOException {
public void testZeroBytes() throws IOException {
byte[] r = scan(new byte[]{});
assertTrue(ClamAVClient.isCleanReply(r));
}

@Test(expected = ClamAVSizeLimitException.class)
public void testSizeLimit() throws UnknownHostException, IOException {
public void testSizeLimit() throws IOException {
scan(new SlowInputStream());
}

@Test
public void testHealthyFile() throws IOException {
byte[] response = scan("/healthy.file");
assertTrue(ClamAVClient.isCleanReply(response));
}

}
9 changes: 4 additions & 5 deletions src/test/java/fi/solita/clamav/PingTest.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package fi.solita.clamav;

import static org.junit.Assert.assertTrue;
import org.junit.Test;

import java.io.IOException;
import java.net.UnknownHostException;

import org.junit.Test;
import static org.junit.Assert.assertTrue;

/**
* These tests assume clamd is running and responding in the virtual machine.
*/
public class PingTest {

@Test
public void testPingPong() throws UnknownHostException, IOException {
ClamAVClient cl = new ClamAVClient("localhost", 3310);
public void testPingPong() throws IOException {
ClamAVClient cl = new ClamAVClient(TestConfiguration.CLAMAV_HOST, TestConfiguration.CLAMAV_PORT);
assertTrue(cl.ping());
}
}
6 changes: 6 additions & 0 deletions src/test/java/fi/solita/clamav/TestConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package fi.solita.clamav;

public class TestConfiguration {
public static String CLAMAV_HOST = "localhost";
public static int CLAMAV_PORT = 3310;
}
1 change: 1 addition & 0 deletions src/test/resources/healthy.file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
It's the healthy file