Skip to content
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
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ RUN mkdir -p /etc/ssl/clamav-rest
# Install ClamAV
RUN apk --no-cache add clamav clamav-libunrar \
&& mkdir /run/clamav \
&& chown clamav:clamav /run/clamav
&& chown clamav:clamav /run/clamav


# Configure clamAV to run in foreground with port 3310
Expand All @@ -47,11 +47,11 @@ COPY entrypoint.sh /usr/bin/

RUN mkdir -p /clamav/etc \
&& mkdir -p /clamav/data \
&& mkdir -p /clamav/tmp
&& mkdir -p /clamav/tmp

RUN chown -R clamav:clamav /clamav \
&& chown -R clamav:clamav /var/log/clamav \
&& chown -R clamav:clamav /run/clamav
&& chown -R clamav:clamav /run/clamav


ENV PORT=9000
Expand All @@ -71,6 +71,7 @@ ENV MAX_RECONNECT_TIME=30
ENV PCRE_MATCHLIMIT=100000
ENV PCRE_RECMATCHLIMIT=2000
ENV SIGNATURE_CHECKS=2
ENV HEALTHCHECK_MAX_SIGNATURE_AGE=48
ENV ALLOW_ORIGINS=*

USER clamav
Expand Down
54 changes: 28 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,12 @@ In order to remain backward compatible, we allow all CORS related origins by set

### Utility endpoints

| Endpoint | Description |
| ---------- | --------------------------------------------------------------------------------------------------------------------------- |
| `/` | Home endpoint, returns stats for the currently running process |
| `/version` | Returns the clamav binary version and also the version of the virus signature databases and the signature last update date. |
| `/metrics` | Prometheus endpoint for scraping metrics. |
| Endpoint | Description |
|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `/` | Home endpoint, returns stats for the currently running process |
| `/version` | Returns the clamav binary version and also the version of the virus signature databases and the signature last update date. |
| `/metrics` | Prometheus endpoint for scraping metrics. |
| `/healthcheck` | If signatures are older than HEALTHCHECK_MAX_SIGNATURE_AGE this endpoint returns status code 420, otherwise it returns 200. If Clamd is not running, it returns 500. |

### Scanning endpoints

Expand All @@ -181,27 +182,28 @@ In order to remain backward compatible, we allow all CORS related origins by set

Below is the complete list of available options that can be used to customize your installation.

| Parameter | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------- |
| `MAX_SCAN_SIZE` | Amount of data scanned for each file. Defaults to `100M` |
| `MAX_FILE_SIZE` | Do not scan files larger than this size. Defaults to `25M` |
| `MAX_RECURSION` | How many nested archives to scan. Defaults to `16` |
| `MAX_FILES` | Number of files to scan within an archive. Defaults to `10000` |
| `MAX_EMBEDDEDPE` | Maximum file size for embedded PE. Defaults to `10M` |
| `MAX_HTMLNORMALIZE` | Maximum size of HTML to normalize. Defaults to `10M` |
| `MAX_HTMLNOTAGS` | Maximum size of normlized HTML file to scan. Defaults to `2M` |
| `MAX_SCRIPTNORMALIZE` | Maximum size of a script to normalize. Defaults to `5M` |
| `MAX_ZIPTYPERCG` | Maximum size of ZIP to reanalyze type recognition. Defaults to `1M` |
| `MAX_PARTITIONS` | How many partitions per raw disk to scan. Defaults to `50` |
| `MAX_ICONSPE` | How many icons in PE to scan. Defaults to `100` |
| `MAX_RECONNECT_TIME` | Maximum timeout while waiting for ClamAV to start. Defaults to `30` |
| `PCRE_MATCHLIMIT` | Maximum PCRE match calls. Defaults to `100000` |
| `PCRE_RECMATCHLIMIT` | Maximum recursive match calls to PCRE. Defaults to `2000` |
| `SIGNATURE_CHECKS` | How many times per day to check for a new database signature. Must be between 1 and 50. Defaults to `2` |
| `PROXY_SERVER` | Specify a proxy for freshclam to utilize. Default disabled (optional) |
| `PROXY_PORT` | The port for the proxy server. Default disabled (optional) |
| `PROXY_USERNAME` | The username for the proxy server. Default disabled (optional) |
| `PROXY_PASSWORD` | The password for the proxy server. Default disabled (optional) |
| Parameter | Description |
|---------------------------------|---------------------------------------------------------------------------------------------------------|
| `MAX_SCAN_SIZE` | Amount of data scanned for each file. Defaults to `100M` |
| `MAX_FILE_SIZE` | Do not scan files larger than this size. Defaults to `25M` |
| `MAX_RECURSION` | How many nested archives to scan. Defaults to `16` |
| `MAX_FILES` | Number of files to scan within an archive. Defaults to `10000` |
| `MAX_EMBEDDEDPE` | Maximum file size for embedded PE. Defaults to `10M` |
| `MAX_HTMLNORMALIZE` | Maximum size of HTML to normalize. Defaults to `10M` |
| `MAX_HTMLNOTAGS` | Maximum size of normlized HTML file to scan. Defaults to `2M` |
| `MAX_SCRIPTNORMALIZE` | Maximum size of a script to normalize. Defaults to `5M` |
| `MAX_ZIPTYPERCG` | Maximum size of ZIP to reanalyze type recognition. Defaults to `1M` |
| `MAX_PARTITIONS` | How many partitions per raw disk to scan. Defaults to `50` |
| `MAX_ICONSPE` | How many icons in PE to scan. Defaults to `100` |
| `MAX_RECONNECT_TIME` | Maximum timeout while waiting for ClamAV to start. Defaults to `30` |
| `PCRE_MATCHLIMIT` | Maximum PCRE match calls. Defaults to `100000` |
| `PCRE_RECMATCHLIMIT` | Maximum recursive match calls to PCRE. Defaults to `2000` |
| `SIGNATURE_CHECKS` | How many times per day to check for a new database signature. Must be between 1 and 50. Defaults to `2` |
| `HEALTHCHECK_MAX_SIGNATURE_AGE` | Max signature age in hours for /healthcheck endpoint to return OK. Defaults to `48` hours. |
| `PROXY_SERVER` | Specify a proxy for freshclam to utilize. Default disabled (optional) |
| `PROXY_PORT` | The port for the proxy server. Default disabled (optional) |
| `PROXY_USERNAME` | The username for the proxy server. Default disabled (optional) |
| `PROXY_PASSWORD` | The password for the proxy server. Default disabled (optional) |

### TLS Certificates

Expand Down
38 changes: 38 additions & 0 deletions clamrest.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,42 @@ func clamversion(w http.ResponseWriter, r *http.Request) {
}
}

func healthcheck(w http.ResponseWriter, r *http.Request) {
maxAgeHours, err := strconv.ParseInt(opts["HEALTHCHECK_MAX_SIGNATURE_AGE"], 10, 64);
c := clamd.NewClamd(opts["CLAMD_PORT"])

version, err := c.Version()
if err != nil {
http.Error(w, "", http.StatusServiceUnavailable)
return
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")
for version_string := range version {
if strings.HasPrefix(version_string.Raw, "ClamAV ") {
version_values := strings.Split(strings.Replace(version_string.Raw, "ClamAV", "", 1), "/")
if len(version_values) == 3 {
signatureDateStr := version_values[2]
signatureDate, err := time.Parse("Mon Jan 2 15:04:05 2006", signatureDateStr)
if err != nil {
http.Error(w, "", http.StatusInternalServerError)
return
}

if time.Since(signatureDate).Hours() > float64(maxAgeHours) {
http.Error(w, "", 420)
return
}

w.WriteHeader(http.StatusOK)
return
}
}
}

http.Error(w, "Unexpected response format", http.StatusInternalServerError)
}

func home(w http.ResponseWriter, r *http.Request) {
c := clamd.NewClamd(opts["CLAMD_PORT"])

Expand Down Expand Up @@ -201,6 +237,7 @@ func scanHandler(w http.ResponseWriter, r *http.Request) {
scanner(w, r, 1)
}


// This is where the action happens.
func scanner(w http.ResponseWriter, r *http.Request, version int) {
switch r.Method {
Expand Down Expand Up @@ -449,6 +486,7 @@ func main() {
mux.HandleFunc("GET /scanPath", scanPathHandler)
mux.HandleFunc("POST /scanHandlerBody", scanHandlerBody)
mux.HandleFunc("GET /version", clamversion)
mux.HandleFunc("GET /healthcheck", healthcheck)
mux.HandleFunc("GET /", home)

// Prometheus metrics
Expand Down