376307a0 |
/*
* Copyright (C) 2007 Tomasz Kojm <tkojm@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
|
4cd80898 |
#ifndef _WIN32 |
b54eb319 |
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> |
44eb77a1 |
#endif |
b54eb319 |
|
376307a0 |
#include "mirman.h"
#include "libclamav/clamav.h"
#include "shared/output.h"
|
3027857c |
#ifndef HAVE_GETADDRINFO |
9424a482 |
#ifndef AF_INET6 |
6df88f29 |
#define AF_INET6 0xbeef /* foo */ |
9424a482 |
#endif
#endif
|
dd8a6b10 |
#define IGNORE_SHORT (3600) /* 1 hour */
#define IGNORE_LONG (6 * IGNORE_SHORT) /* 6 hours */ |
376307a0 |
|
6df88f29 |
void |
dd8a6b10 |
mirman_free(struct mirdat *mdat) |
376307a0 |
{ |
6df88f29 |
if (mdat && mdat->num)
{
free (mdat->mirtab);
mdat->num = 0; |
376307a0 |
}
}
|
dd8a6b10 |
fc_error_t mirman_read(const char *file, struct mirdat *mdat, uint8_t active) |
376307a0 |
{ |
6df88f29 |
struct mirdat_ip mip;
int fd, bread;
|
dd8a6b10 |
memset (mdat, 0, sizeof(struct mirdat)); |
6df88f29 |
if (!(mdat->active = active)) |
dd8a6b10 |
return FC_SUCCESS; |
6df88f29 |
if ((fd = open (file, O_RDONLY | O_BINARY)) == -1) |
dd8a6b10 |
return FCE_OPEN; |
6df88f29 |
|
dd8a6b10 |
while ((bread = read (fd, &mip, sizeof(mip))) == sizeof(mip)) |
6df88f29 |
{
mdat->mirtab =
(struct mirdat_ip *) realloc (mdat->mirtab, |
dd8a6b10 |
(mdat->num + 1) * sizeof(mip)); |
6df88f29 |
if (!mdat->mirtab)
{ |
dd8a6b10 |
logg("!Can't allocate memory for mdat->mirtab\n"); |
6df88f29 |
mirman_free (mdat);
close (fd); |
dd8a6b10 |
return FCE_MEM; |
6df88f29 |
} |
dd8a6b10 |
memcpy (&mdat->mirtab[mdat->num], &mip, sizeof(mip)); |
6df88f29 |
mdat->num++; |
376307a0 |
}
|
6df88f29 |
close (fd); |
376307a0 |
|
6df88f29 |
if (bread)
{ |
dd8a6b10 |
logg("^Removing broken %s file.\n", file); |
6df88f29 |
unlink (file);
mirman_free (mdat); |
dd8a6b10 |
return FCE_FILE; |
376307a0 |
}
|
dd8a6b10 |
return FC_SUCCESS; |
376307a0 |
}
|
dd8a6b10 |
fc_error_t mirman_check(uint32_t * ip, int af, struct mirdat *mdat,
struct mirdat_ip **md, mir_status_t *mirror_status) |
376307a0 |
{ |
dd8a6b10 |
fc_error_t status = FC_SUCCESS;
unsigned int i;
unsigned int flevel = cl_retflevel (); |
6df88f29 |
|
dd8a6b10 |
if (NULL == md || NULL == mdat || NULL == ip) {
logg("!mirman_check: Invalid arguments.\n");
status = FCE_ARG;
goto done;
} |
6df88f29 |
|
dd8a6b10 |
*md = NULL; |
6df88f29 |
if (!mdat->active) |
dd8a6b10 |
{
*mirror_status = MIRROR_OK;
goto done;
} |
6df88f29 |
for (i = 0; i < mdat->num; i++)
{ |
dd8a6b10 |
if ((af == AF_INET && mdat->mirtab[i].ip4 == *ip) ||
((af == AF_INET6) && (!memcmp (mdat->mirtab[i].ip6, ip, 4 * sizeof(uint32_t))))) |
6df88f29 |
{ |
dd8a6b10 |
/*
* Mirror found in mirror table.
*/ |
6df88f29 |
|
dd8a6b10 |
if (mdat->dbflevel && (mdat->dbflevel > flevel) && (mdat->dbflevel - flevel > 3)) |
6df88f29 |
{ |
dd8a6b10 |
/* Functionality level of database is lower than
* level of the database we already have */
if (difftime(time(NULL), mdat->mirtab[i].atime) < (mdat->dbflevel - flevel) * 3600)
{
*mirror_status = MIRROR_IGNORE__OUTDATED_VERSION;
goto done;
} |
6df88f29 |
}
|
dd8a6b10 |
if ((mdat->mirtab[i].atime > 0) &&
(IGNORE_NO != mdat->mirtab[i].ignore)) |
6df88f29 |
{ |
dd8a6b10 |
/*
* Found, but the ignore flag is set.
*/
if (difftime(time(NULL), mdat->mirtab[i].atime) > IGNORE_LONG) |
6df88f29 |
{ |
dd8a6b10 |
/* Long-Ignore timeout expired,
* the mirror can be attempted again */
mdat->mirtab[i].ignore = IGNORE_NO;
}
else if ((mdat->mirtab[i].ignore == IGNORE_SHORTTERM) &&
(difftime(time(NULL), mdat->mirtab[i].atime) > IGNORE_SHORT))
{
/* Mirror was only set to Short-Term ignore...
* the Short-Ignore timeout expired,
* the mirror can be attempted again */
mdat->mirtab[i].ignore = IGNORE_NO; |
6df88f29 |
}
else
{ |
dd8a6b10 |
*mirror_status = MIRROR_IGNORE__PREV_ERRS;
goto done; |
6df88f29 |
}
}
|
dd8a6b10 |
/* Mirror found, and is ok to try. */
*md = &mdat->mirtab[i];
*mirror_status = MIRROR_OK;
goto done; |
6df88f29 |
} |
376307a0 |
}
|
dd8a6b10 |
/* Mirror wasn't in mirror table. */
*mirror_status = MIRROR_OK;
done:
return status; |
376307a0 |
}
|
dd8a6b10 |
fc_error_t mirman_update(uint32_t * ip, int af, struct mirdat *mdat, fc_error_t error) |
376307a0 |
{ |
dd8a6b10 |
fc_error_t status = FCE_ARG;
unsigned int i = 0;
struct mirdat_ip *mirror = NULL; |
376307a0 |
|
dd8a6b10 |
if (!mdat->active) {
/* Disable mirrors.dat management when using a proxy. */
return FC_SUCCESS;
} |
a7db63d1 |
|
dd8a6b10 |
/*
* Attempt to find the ip in the mirror table.
*/ |
6df88f29 |
for (i = 0; i < mdat->num; i++)
{ |
dd8a6b10 |
if (((af == AF_INET) && (mdat->mirtab[i].ip4 == *ip)) ||
((af == AF_INET6) && (!memcmp(mdat->mirtab[i].ip6, ip, 4 * sizeof(uint32_t))))) |
6df88f29 |
{ |
dd8a6b10 |
mirror = &mdat->mirtab[i]; |
6df88f29 |
break;
} |
376307a0 |
}
|
dd8a6b10 |
if (NULL == mirror) |
6df88f29 |
{ |
dd8a6b10 |
/*
* Allocate space in the mirror table for the new mirror IP
*/ |
6df88f29 |
mdat->mirtab = |
dd8a6b10 |
(struct mirdat_ip *) realloc(mdat->mirtab,
(mdat->num + 1) * sizeof(struct mirdat_ip)); |
6df88f29 |
if (!mdat->mirtab)
{ |
dd8a6b10 |
logg("!Can't allocate memory for new element in mdat->mirtab\n");
return FCE_MEM; |
6df88f29 |
} |
dd8a6b10 |
memset (&mdat->mirtab[mdat->num], 0, sizeof(struct mirdat_ip)); |
6df88f29 |
if (af == AF_INET)
{
mdat->mirtab[mdat->num].ip4 = *ip;
}
else
{
mdat->mirtab[mdat->num].ip4 = 0; |
dd8a6b10 |
memcpy (mdat->mirtab[mdat->num].ip6, ip, 4 * sizeof(uint32_t)); |
6df88f29 |
}
mdat->mirtab[mdat->num].atime = 0; |
dd8a6b10 |
mdat->mirtab[mdat->num].succ = 0;
mdat->mirtab[mdat->num].fail = 0;
mdat->mirtab[mdat->num].ignore = 0;
mirror = &mdat->mirtab[mdat->num]; |
6df88f29 |
mdat->num++; |
376307a0 |
}
|
dd8a6b10 |
mirror->atime = 0; /* will be updated in mirman_write() */ |
376307a0 |
|
dd8a6b10 |
if (FC_SUCCESS == error) {
mirror->succ++;
mirror->fail = 0;
}
else
{
mirror->succ = 0;
mirror->fail++;
} |
09005700 |
|
dd8a6b10 |
if (mirror->fail >= 6)
{
mirror->ignore = IGNORE_LONGTERM;
}
else if (mirror->fail >= 3)
{
mirror->ignore = IGNORE_SHORTTERM;
}
else
{
mirror->ignore = IGNORE_NO;
}
return FC_SUCCESS; |
09005700 |
}
|
dd8a6b10 |
void mirman_list(const struct mirdat *mdat) |
376307a0 |
{ |
6df88f29 |
unsigned int i;
time_t tm;
char ip[46]; |
7c647273 |
|
6df88f29 |
for (i = 0; i < mdat->num; i++)
{ |
dd8a6b10 |
printf("Mirror #%u\n", i + 1); |
3027857c |
#ifdef HAVE_GETADDRINFO |
6df88f29 |
if (mdat->mirtab[i].ip4) |
dd8a6b10 |
printf("IP: %s\n",
inet_ntop(AF_INET, &mdat->mirtab[i].ip4, ip, sizeof(ip))); |
6df88f29 |
else |
dd8a6b10 |
printf("IP: %s\n",
inet_ntop(AF_INET6, mdat->mirtab[i].ip6, ip, sizeof(ip))); |
9424a482 |
#else |
6df88f29 |
if (mdat->mirtab[i].ip4) |
dd8a6b10 |
printf("IP: %s\n",
inet_ntoa(*(struct in_addr *)&mdat->mirtab[i].ip4)); |
9424a482 |
#endif |
dd8a6b10 |
printf("Successes: %u\n", mdat->mirtab[i].succ);
printf("Failures: %u\n", mdat->mirtab[i].fail); |
6df88f29 |
tm = mdat->mirtab[i].atime; |
dd8a6b10 |
printf("Last access: %s", ctime((const time_t *) &tm));
if (mdat->mirtab[i].ignore) {
time_t ignore_expires = tm + ((mdat->mirtab[i].ignore == IGNORE_LONGTERM) ? IGNORE_LONG
: IGNORE_SHORT);
double difference = difftime(ignore_expires, time(NULL));
if (difference > 0) {
uint32_t remaining = difference;
uint32_t seconds, minutes, hours;
seconds = remaining % 60;
remaining = remaining / 60;
minutes = remaining % 60;
remaining = remaining / 60;
hours = remaining % 60;
printf("Ignore: Yes, %d hours %d minutes %d seconds remaining.\n",
hours, minutes, seconds);
} else {
printf("Ignore: No\n");
}
} else {
printf("Ignore: No\n");
} |
6df88f29 |
if (i != mdat->num - 1) |
dd8a6b10 |
printf("-------------------------------------\n"); |
376307a0 |
}
}
|
dd8a6b10 |
void mirman_whitelist(struct mirdat *mdat, unsigned int mode) |
a68aa31f |
{ |
6df88f29 |
unsigned int i; |
a68aa31f |
|
dd8a6b10 |
if (NULL == mdat) {
logg("!mirman_whitelist: Invalid arguments!\n");
return;
}
switch (mode)
{
case 1:
logg("*Whitelisting all blacklisted mirrors\n");
break;
case 2:
logg("*Whitelisting short-term blacklisted mirrors\n");
break;
default:
logg("!mirman_whitelist: Unexpected mode argument: %u\n", mode);
return;
}
|
6df88f29 |
for (i = 0; i < mdat->num; i++) |
dd8a6b10 |
{
if (mode == 1)
{
mdat->mirtab[i].ignore = IGNORE_NO;
}
else if ((mode == 2) && (IGNORE_SHORTTERM == mdat->mirtab[i].ignore))
{
mdat->mirtab[i].ignore = IGNORE_NO;
}
}
return; |
a68aa31f |
}
|
dd8a6b10 |
fc_error_t mirman_write(const char *file, const char *dir, struct mirdat *mdat) |
376307a0 |
{ |
6df88f29 |
int fd;
unsigned int i;
char path[512]; |
376307a0 |
|
dd8a6b10 |
snprintf(path, sizeof(path), "%s/%s", dir, file);
path[sizeof(path) - 1] = 0; |
376307a0 |
|
6df88f29 |
if (!mdat->num) |
dd8a6b10 |
return FC_SUCCESS; |
376307a0 |
|
6df88f29 |
if ((fd = |
dd8a6b10 |
open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600)) == -1) |
6df88f29 |
{ |
dd8a6b10 |
logg("!Can't open %s for writing\n", path);
return FCE_OPEN; |
376307a0 |
}
|
6df88f29 |
for (i = 0; i < mdat->num; i++)
if (!mdat->mirtab[i].atime) |
dd8a6b10 |
mdat->mirtab[i].atime = (uint32_t) time(NULL); |
04a1171f |
|
dd8a6b10 |
if (write(fd, mdat->mirtab, mdat->num * sizeof(struct mirdat_ip)) == -1) |
6df88f29 |
{ |
dd8a6b10 |
logg("!Can't write to %s\n", path);
close(fd);
return FCE_FILE; |
376307a0 |
}
|
dd8a6b10 |
close(fd);
return FC_SUCCESS; |
376307a0 |
} |