День добрый Victor,
Sunday, November 11, 2007, 7:24:46 PM, Вы пишете:
...
>> А не проще отдельный лог для хелпера?
VS> Пожалуй, это оптимальный вариант, потому что хелпер обладает
VS> информацией от обеих сторон.
В принципе, да, из него это проще сделать.
>> Я к clamav-cgp приделывал логирование как в cgpav по syslog, в логе
>> строчки вида:
>> Nov 7 09:12:09 mx clamav-cgp: Virus: Worm.Nyxem.E From: zavar@yandex.ru To: shpak@rzpost.ru IP: 82.215.66.101
VS> А можно патч посмотреть?
Да, конечно.
В нем логирование в сислог перетащено из cgpav, добавлено ID письма и
дополнительно в лог CGP, правда включается только вместе.
Да, есть в логировании косяк, до которого руки не дойдут ни как, если
получатель письма не один, то в логе пишется только последний :(
Кроме этого я добавлял то к чему привык в cgpav, добавка хедеров на
чистые письма (правда от нее единственная польза по заголовкам увидеть
попадало ли письмо в хелпер), коллекционирование писем в вирусами в
папочку из того же cgpav.
Включается опциями -L -A -C соответственно, все настройки куда
логировать, какой хедер добавлять, и куда складывать письма в
коллекцию меняются только в исходниках, так как делалось первоначально
только для себя.
Адаптация для 1.0.12 ниже, первоначально это все делалось для более
ранней версии clamav-cgp где то с год назад, при переходе на него с
cgpav.
--------------------------------->Cut Here<-------------------------------
--- clamav-cgp.c.ORIG Mon Nov 12 10:11:31 2007
+++ clamav-cgp.c Mon Nov 12 10:13:28 2007
@@ -68,6 +68,7 @@
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <syslog.h>
#ifdef FREEBSD
#include <netinet/in.h>
@@ -80,6 +81,10 @@
#define CGP_CMDARG_LEN 128
#define CGP_ANSWER_LEN 4096
#define CGP_DIR "/var/CommuniGate"
+#define CGP_OK 0
+#define CGP_ADD_HEADER 1
+#define CGP_ADDING_HEADER "X-Virus-Scanned: by clamav-cgp on localhost"
+
#define CLAMD_TIMEOUT 300
#define CLAMD_PORT 3310
@@ -89,6 +94,12 @@
#define TRANSPORT_UNIX 0x03 /* UNIX domain socket */
#define TRANSPORT_MAX_HOSTS 1
+#define VIR_NO 0
+#define VIR_YES 1
+#define VIR_COLLECT_DIR "/var/log/clamav/vir_collection"
+#define VIR_SYSLOG_FACILITY_TEXT "LOCAL0"
+#define VIR_SYSLOG_FACILITY LOG_LOCAL0
+
typedef struct transport
{
int type;
@@ -120,6 +131,18 @@
static void transport_init(transport_t *trans);
static int transport_setup(transport_t *trans);
+static void clear_string(char *pat, char **text);
+static void tr_string(char **text, char from, char to);
+static int copy_infected(char *filename, char *virus_name);
+static int copy_file(char *from_file, char *to_file);
+static char *parse_smtp(char *header_line);
+static char *parse_email(char *header_line);
+
+int add_header = CGP_OK;
+int vir_collect = VIR_NO;
+int vir_log = VIR_NO;
+
+
int
main(int argc, char **argv)
@@ -200,8 +223,11 @@
switch( rc ) {
case CL_CLEAN:
- putline("%u OK\n", req->seqNum);
- break;
+ if( add_header == CGP_ADD_HEADER )
+ putline("%u ADDHEADER \"%s\"\n", req->seqNum,CGP_ADDING_HEADER);
+ else
+ putline("%u OK\n", req->seqNum);
+ break;
case CL_VIRUS:
putline("%u DISCARD\n", req->seqNum);
break;
@@ -334,14 +360,77 @@
static int
cl_reply(req_t *req, char *buf, int len)
{
+ char cmdScan[CGP_CMDARG_LEN], *p, hbuf[384], *rcpt, *sender, *ip, id[CGP_CMDARG_LEN];
+ int fd = -1, len_id;
+ FILE *fin = NULL;
+
buf[len] = '\0';
if( strstr(buf, " OK\n") )
return CL_CLEAN;
- if( strstr(buf, " FOUND\n") )
+ if( strstr(buf, " FOUND\n") ) {
+ p = strchr(buf, ':') + 2;
+ len = len - (p - buf) - 1;
+ memmove(buf, p, len);
+ len -= 6;
+ buf[len]='\0';
+ if( vir_collect ) {
+ if( req->cmdArg[0] == '/' )
+ len = snprintf(cmdScan, sizeof(cmdScan)-1, "%s", req->cmdArg);
+ else
+ len = snprintf(cmdScan, sizeof(cmdScan)-1, "%s/%s", CGP_DIR, req->cmdArg);
+ if( !copy_infected(cmdScan,buf) )
+ putline("* clamav-cgp[%u]: copy to collection fail\n", req->seqNum);
+ }
+ if( vir_log){
+ if( req->cmdArg[0] == '/' )
+ len = snprintf(cmdScan, sizeof(cmdScan)-1, "%s", req->cmdArg);
+ else
+ len = snprintf(cmdScan, sizeof(cmdScan)-1, "%s/%s", CGP_DIR, req->cmdArg);
+ if( (fin = fopen(cmdScan, "r")) == NULL ) {
+ putline("* clamav-cgp[%u]: Can't fopen(fin) %s: errno = %d\n", req->seqNum,cmdScan, errno);
+ goto end;
+ }
+ len_id = snprintf(id, sizeof(id)-1, "%s", req->cmdArg);
+ if ( p = strrchr(id, '/') + 1 )
+ {
+ len_id = len_id - (p - id);
+ memmove(id, p, len_id);
+ id[len_id]='\0';
+ }
+ if ( p = strrchr(id, '.') + 1 )
+ {
+ if ( strcmp(p,"msg") == 0 )
+ {
+ len_id -= 4;
+ id[len_id]='\0';
+ }
+ }
+ while( fgets(hbuf, sizeof(hbuf), fin) != NULL ) {
+ if( strcmp(hbuf, "\n") == 0 ) {
+ goto log;
+ }
+ if( strncmp(hbuf, "R ", 2) == 0 ) {
+ rcpt = strdup(parse_email(hbuf));
+ }
+ if( strncmp(hbuf, "P ", 2) == 0 ) {
+ sender = strdup(parse_email(hbuf));
+ }
+ if( strncmp(hbuf, "S ", 2) == 0 ) {
+ ip = strdup(parse_smtp(hbuf));
+ }
+ }
+ log:
+ fclose(fin);
+ openlog("clamav-cgp", 0, VIR_SYSLOG_FACILITY);
+ syslog(LOG_ERR, "Virus: %s From: %s To: %s IP: %s ID: %s", buf,sender,rcpt,ip,id);
+ closelog();
+ putline("* clamav-cgp[%u]: Virus: %s From: %s To: %s IP: %s ID: %s\n",req->seqNum, buf,sender,rcpt,ip,id);
+ end:
+ }
return CL_VIRUS;
-
+ }
putline("* clamav-cgp[%u]: error: %s\n", req->seqNum, buf);
return -1;
}
@@ -351,14 +440,17 @@
static void
print_usage(void)
{
- printf("Usage: clamav-cgp [options]\n\n");
- printf(" -d <ip addr> : specify ip address to connect to clamd\n");
- printf(" -h : print this help message\n");
- printf(" -p <port> : specify port for connection. default: %u\n", CLAMD_PORT);
- printf(" -t <sec> : timeout in seconds to read from clamd.\n");
- printf(" : 0 disables, default: %u sec\n", CLAMD_TIMEOUT);
- printf(" -s : use STREAM mode. default SCAN mode\n");
- printf(" -U <path> : use UNIX domain socket with path\n\n");
+ printf("Usage: clamav-cgp [options]\n\n");
+ printf(" -d <ip addr> : specify ip address to connect to clamd\n");
+ printf(" -h : print this help message\n");
+ printf(" -p <port> : specify port for connection. default: %u\n", CLAMD_PORT);
+ printf(" -t <sec> : timeout in seconds to read from clamd.\n");
+ printf(" : 0 disables, default: %u sec\n", CLAMD_TIMEOUT);
+ printf(" -s : use STREAM mode. default SCAN mode\n");
+ printf(" -U <path> : use UNIX domain socket with path\n");
+ printf(" -A : add header '%s' for clean\n",CGP_ADDING_HEADER);
+ printf(" -C : Collection virus in '%s'\n",VIR_COLLECT_DIR);
+ printf(" -L : SysLog virus in '%s'\n\n",VIR_SYSLOG_FACILITY_TEXT);
}
@@ -383,8 +475,18 @@
{
int opt;
- while( (opt = getopt(argc,argv,"?hsd:p:t:U:")) != -1 ) {
+ while( (opt = getopt(argc,argv,"?hsd:p:t:U:ALC")) != -1 ) {
switch(opt) {
+ case 'L':
+ vir_log = VIR_YES;
+ break;
+ case 'C':
+ vir_collect = VIR_YES;
+ break;
+ case 'A':
+ add_header = CGP_ADD_HEADER;
+ break;
+
case 'U':
trans->type = TRANSPORT_UNIX;
trans->socketpath = optarg;
@@ -496,3 +598,160 @@
}
return 0;
}
+
+
+/* ----------------------------------------------------------------- */
+static char *parse_email(char *header_line)
+{
+ char *p_start = NULL;
+ char *p_end = NULL;
+
+ p_end = strrchr(header_line, '>');
+ if (p_end)
+ p_start = strrchr(header_line, '<');
+
+ if (!p_end || !p_start || (p_start >= p_end))
+ return NULL;
+ else {
+ *p_end = '\0';
+ p_start++;
+ }
+ return p_start;
+}
+
+
+
+/* ----------------------------------------------------------------- */
+static char *parse_smtp(char *header_line)
+{
+ char *p_start = NULL;
+ char *p_end = NULL;
+
+ p_end = strrchr(header_line, ']');
+ if (p_end)
+ p_start = strrchr(header_line, '[');
+
+ if (!p_end || !p_start || (p_start >= p_end))
+ return NULL;
+ else {
+ *p_end = '\0';
+ p_start++;
+ }
+ return p_start;
+}
+
+
+
+/* ----------------------------------------------------------------- */
+static int copy_infected(char *filename, char *virus_name)
+{
+ char *tmp = NULL;
+ char *outfile = NULL;
+
+ if (!filename || !virus_name)
+ return -1;
+
+ tmp = strdup(virus_name);
+ if (!tmp)
+ return -1;
+
+ clear_string(" ", &tmp);
+ tr_string(&tmp, '/', '.');
+ tr_string(&tmp, ',', '_');
+ if (!(outfile = (char *)malloc(strlen(VIR_COLLECT_DIR) + 1
+ + strlen(tmp) + 1)))
+ return -1;
+
+
+ strcpy(outfile, VIR_COLLECT_DIR);
+ strcat(outfile, "/");
+ strncat(outfile, tmp, 256);
+
+ copy_file(filename, outfile);
+
+ if (outfile)
+ free(outfile);
+ if (tmp)
+ free(tmp);
+
+ return 1;
+
+}
+
+/* this procedure removes the given pattern from the text */
+static void clear_string(char *pat, char **text)
+{
+ int p_end;
+ int pat_len;
+ char *p;
+
+ if (!pat || !text)
+ return;
+
+ pat_len = strlen(pat);
+ p = *text;
+
+ for (; *p != '\0'; p++) {
+ if (strncmp(pat, p, pat_len) == 0) {
+ p_end = strlen(p) - pat_len;
+ /* clear the pattern by moving next chars to the left */
+ memmove(p, p + pat_len, p_end);
+ p[p_end] = '\0';
+ /* here we moved chars */
+ p--;
+ }
+ }
+
+ return;
+}
+
+/* this procedure replaces the given char to another */
+static void tr_string(char **text, char from, char to)
+{
+ char *p = *text;
+
+ for (; *p != '\0'; p++) {
+ if (*p == from)
+ *p = to;
+ }
+
+ return;
+}
+
+
+
+/* ----------------------------------------------------------------- */
+static int copy_file(char *from_file, char *to_file)
+{
+ FILE *in, *out;
+ int len = 0;
+ char buffer[1024];
+ int mask = 0;
+
+ /* there must be absolute paths which are hardly less than 2 chars long */
+ if (!from_file || !to_file || (strlen(from_file) <= 2)
+ || (strlen(to_file) <= 2))
+ return -1;
+
+ if ((in = fopen(from_file, "r")) == NULL)
+ return -1;
+
+ if ((out = fopen(to_file, "w")) == NULL)
+ return -1;
+ while ((len = fread(buffer, 1, sizeof(buffer), in)) > 0) {
+ fwrite(buffer, 1, len, out);
+ }
+
+ fclose(in);
+ fclose(out);
+
+ /* change file permission */
+ mask = umask(0);
+ umask(mask);
+ chmod(to_file, 0660 & ~mask);
+
+
+ return 0;
+}
+
+
--------------------------------->Cut Here<-------------------------------
С наилучшими пожеланиями
Николай Варинов.
тел.+7 4912 243873
mailto:nic@sotcom.ru
Получено Mon Nov 12 07:46:39 2007