📄 clamavscan.java
字号:
/**************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * * or more contributor license agreements. See the NOTICE file * * distributed with this work for additional information * * regarding copyright ownership. The ASF licenses this file * * to you under the Apache License, Version 2.0 (the * * "License"); you may not use this file except in compliance * * with the License. You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * * KIND, either express or implied. See the License for the * * specific language governing permissions and limitations * * under the License. * ****************************************************************/package org.apache.james.transport.mailets;import org.apache.mailet.RFC2822Headers;import org.apache.mailet.GenericMailet;import org.apache.mailet.Mail;import javax.mail.MessagingException;import javax.mail.internet.MimeMessage;import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StringWriter;import java.net.ConnectException;import java.net.InetAddress;import java.net.Socket;import java.net.UnknownHostException;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Iterator;import java.util.Set;/** * <P>Does an antivirus scan check using a ClamAV daemon (CLAMD)</P> * * <P> Interacts directly with the daemon using the "stream" method, * which should have the lowest possible overhead.</P> * <P>The CLAMD daemon will typically reside on <I>localhost</I>, but could reside on a * different host. * It may also consist on a set of multiple daemons, each residing on a different * server and on different IP number. * In such case a DNS host name with multiple IP addresses (round-robin load sharing) * is supported by the mailet (but on the same port number).</P> * * <P>Handles the following init parameters:</P> * <UL> * <LI><CODE><debug></CODE>.</LI> * <LI><CODE><host></CODE>: the host name of the server where CLAMD runs. It can either be * a machine name, such as * "<code>java.sun.com</code>", or a textual representation of its * IP address. If a literal IP address is supplied, only the * validity of the address format is checked. * If the machine name resolves to multiple IP addresses, <I>round-robin load sharing</I> will * be used. * The default is <CODE>localhost</CODE>.</LI> * <LI><CODE><port></CODE>: the port on which CLAMD listens. The default is <I>3310</I>.</LI> * <LI><CODE><maxPings></CODE>: the maximum number of connection retries during startup. * If the value is <I>0</I> no startup test will be done. * The default is <I>6</I>.</LI> * <LI><CODE><pingIntervalMilli></CODE>: the interval (in milliseconds) * between each connection retry during startup. * The default is <I>30000</I> (30 seconds).</LI> * <LI><CODE><streamBufferSize></CODE>: the BufferedOutputStream buffer size to use * writing to the <I>stream connection</I>. The default is <I>8192</I>.</LI> * </UL> * * <P>The actions performed are as follows:</P> * <UL> * <LI>During initialization:</LI> * <OL> * <LI>Gets all <CODE>config.xml</CODE> parameters, handling the defaults;</LI> * <LI>resolves the <CODE><host></CODE> parameter, creating the round-robin IP list;</LI> * <LI>connects to CLAMD at the first IP in the round-robin list, on * the specified <CODE><port></CODE>;</LI> * <LI>if unsuccessful, retries every <CODE><pingIntervalMilli></CODE> milliseconds up to * <CODE><maxPings></CODE> times;</LI> * <LI>sends a <CODE>PING</CODE> request;</LI> * <LI>waits for a <CODE>PONG</CODE> answer;</LI> * <LI>repeats steps 3-6 for every other IP resolved. * </OL> * <LI>For every mail</LI> * <OL> * <LI>connects to CLAMD at the "next" IP in the round-robin list, on * the specified <CODE><port></CODE>, and increments the "next" index; * if the connection request is not accepted tries with the next one * in the list unless all of them have failed;</LI> * <LI>sends a "<CODE>STREAM</CODE>" request;</LI> * <LI>parses the "<CODE>PORT <I>streamPort</I></CODE>" answer obtaining the port number;</LI> * <LI>makes a second connection (the <I>stream connection</I>) to CLAMD at the same host (or IP) * on the <I>streamPort</I> just obtained;</LI> * <LI>sends the mime message to CLAMD (using {@link MimeMessage#writeTo(OutputStream)}) * through the <I>stream connection</I>;</LI> * <LI>closes the <I>stream connection</I>;</LI> * <LI>gets the "<CODE>OK</CODE>" or "<CODE>... FOUND</CODE>" answer from the main connection;</LI> * <LI>closes the main connection;</LI> * <LI>sets the "<CODE>org.apache.james.infected</CODE>" <I>mail attribute</I> to either * "<CODE>true</CODE>" or "<CODE>false</CODE>";</LI> * <LI>adds the "<CODE>X-MessageIsInfected</CODE>" <I>header</I> to either * "<CODE>true</CODE>" or "<CODE>false</CODE>";</LI> * </OL> * </UL> * * <P>Some notes regarding <a href="http://www.clamav.net/">clamav.conf</a>:</p> * <UL> * <LI><CODE>LocalSocket</CODE> must be commented out</LI> * <LI><CODE>TCPSocket</CODE> must be set to a port# (typically 3310)</LI> * <LI><CODE>StreamMaxLength</CODE> must be >= the James config.xml parameter * <<CODE>maxmessagesize</CODE>> in SMTP <<CODE>handler</CODE>></LI> * <LI><CODE>MaxThreads</CODE> should? be >= the James config.xml parameter * <<CODE>threads</CODE>> in <<CODE>spoolmanager</CODE>></LI> * <LI><CODE>ScanMail</CODE> must be uncommented</LI> * </UL> * * <P>Here follows an example of config.xml definitions deploying CLAMD on localhost, * and handling the infected messages:</P> * <PRE><CODE> * * ... * * <!-- Do an antivirus scan --> * <mailet match="All" class="ClamAVScan" onMailetException="ignore"/> * * <!-- If infected go to virus processor --> * <mailet match="HasMailAttributeWithValue=org.apache.james.infected, true" class="ToProcessor"> * <processor> virus </processor> * </mailet> * * <!-- Check attachment extensions for possible viruses --> * <mailet match="AttachmentFileNameIs=-d -z *.exe *.com *.bat *.cmd *.pif *.scr *.vbs *.avi *.mp3 *.mpeg *.shs" class="ToProcessor"> * <processor> bad-extensions </processor> * </mailet> * * ... * * <!-- Messages containing viruses --> * <processor name="virus"> * * <!-- To avoid a loop while bouncing --> * <mailet match="All" class="SetMailAttribute"> * <org.apache.james.infected>true, bouncing</org.apache.james.infected> * </mailet> * * <mailet match="SMTPAuthSuccessful" class="Bounce"> * <sender>bounce-admin@xxx.com</sender> * <inline>heads</inline> * <attachment>none</attachment> * <notice> Warning: We were unable to deliver the message below because it was found infected by virus(es). </notice> * </mailet> * * <!-- * <mailet match="All" class="ToRepository"> * <repositoryPath>file://var/mail/infected/</repositoryPath> * </mailet> * --> * * <mailet match="All" class="Null" /> * </processor> * </CODE></PRE> * * @version 2.2.1 * @since 2.2.1 * @see <a href="http://www.clamav.net/">ClamAV Home Page</a> * @see <a href="http://www.sosdg.org/clamav-win32/">ClamAV For Windows</a> */public class ClamAVScan extends GenericMailet { private static final int DEFAULT_PORT = 3310; private static final int DEFAULT_MAX_PINGS = 6; private static final int DEFAULT_PING_INTERVAL_MILLI = 30000; private static final int DEFAULT_STREAM_BUFFER_SIZE = 8192; private static final int DEFAULT_CONNECTION_TIMEOUT = 20000; private static final String STREAM_PORT_STRING = "PORT "; private static final String FOUND_STRING = "FOUND"; private static final String MAIL_ATTRIBUTE_NAME = "org.apache.james.infected"; private static final String HEADER_NAME = "X-MessageIsInfected"; /** * Holds value of property debug. */ private boolean debug; /** * Holds value of property host. */ private String host; /** * Holds value of property port. */ private int port; /** * Holds value of property maxPings. */ private int maxPings; /** * Holds value of property pingIntervalMilli. */ private int pingIntervalMilli; /** * Holds value of property streamBufferSize. */ private int streamBufferSize; /** * Holds value of property addresses. */ private InetAddress[] addresses; /** * Holds the index of the next address to connect to */ private int nextAddressIndex; /** * Return a string describing this mailet. * * @return a string describing this mailet */ public String getMailetInfo() { return "Antivirus Check using ClamAV (CLAMD)"; } /** Gets the expected init parameters. */ protected String[] getAllowedInitParameters() { String[] allowedArray = { // "static", "debug", "host", "port", "maxPings", "pingIntervalMilli", "streamBufferSize" }; return allowedArray; } /** * Initializer for property debug. */ protected void initDebug() { String debugParam = getInitParameter("debug"); setDebug((debugParam == null) ? false : new Boolean(debugParam).booleanValue()); } /** * Getter for property debug. * @return Value of property debug. */ public boolean isDebug() { return this.debug; } /** * Setter for property debug. * @param debug New value of property debug. */ public void setDebug(boolean debug) { this.debug = debug; } /** * Initializer for property host. * @throws UnknownHostException if unable to resolve the host name, or if invalid */ protected void initHost() throws UnknownHostException { setHost(getInitParameter("host")); if (isDebug()) { log("host: " + getHost()); } } /** * Getter for property host. * @return Value of property host. */ public String getHost() { return this.host; } /** * Setter for property host. * Resolves also the host name into the corresponding IP addresses, issues * a {@link #setAddresses} and resets the <CODE>nextAddressIndex</CODE> * variable to <I>0</I> for dealing with <I>round-robin</I>. * @param host New value of property host. * @throws UnknownHostException if unable to resolve the host name, or if invalid */ public void setHost(String host) throws UnknownHostException { this.host = host;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -