freshclam: IPv6 support (bb#715)

git-svn: trunk@3940
0.95
Tomasz Kojm 18 years ago
parent 82ff41a969
commit b54eb319c6
  1. 5
      ChangeLog
  2. 3
      clamav-config.h.in
  3. 110
      configure
  4. 31
      configure.in
  5. 235
      freshclam/manager.c
  6. 28
      freshclam/mirman.c
  7. 12
      freshclam/mirman.h
  8. 55
      freshclam/notify.c

@ -1,3 +1,8 @@
Fri Jul 11 20:14:14 CEST 2008 (tk)
----------------------------------
* freshclam: IPv6 support (bb#715)
* configure: --disable-ipv6
Thu Jul 10 19:41:37 EEST 2008 (edwin)
-------------------------------------
* unit_tests/: add unit tests for binaries

@ -369,6 +369,9 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Use IPv6 aware code */
#undef SUPPORT_IPv6
/* use syslog */
#undef USE_SYSLOG

110
configure vendored

@ -1514,6 +1514,7 @@ Optional Features:
--disable-bzip2 disable bzip2 support
--disable-rpath do not hardcode runtime library paths
--disable-unrar don't build libclamunrar and libclamunrar_iface
--disable-ipv6 disable IPv6 support
--disable-dns disable support for database verification through
DNS
--disable-clamuko disable clamuko support (Linux, DragonFly and FreeBSD only)
@ -4777,7 +4778,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 4780 "configure"' > conftest.$ac_ext
echo '#line 4781 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@ -6867,11 +6868,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6870: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6871: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6874: \$? = $ac_status" >&5
echo "$as_me:6875: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -7157,11 +7158,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7160: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7161: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7164: \$? = $ac_status" >&5
echo "$as_me:7165: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -7261,11 +7262,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7264: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7265: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7268: \$? = $ac_status" >&5
echo "$as_me:7269: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -9638,7 +9639,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 9641 "configure"
#line 9642 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -9738,7 +9739,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
#line 9741 "configure"
#line 9742 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -15025,6 +15026,97 @@ else
fi
# Check whether --enable-ipv6 was given.
if test "${enable_ipv6+set}" = set; then
enableval=$enable_ipv6; want_ipv6=$enableval
else
want_ipv6="yes"
fi
if test "$want_ipv6" = "yes"
then
{ echo "$as_me:$LINENO: checking for getaddrinfo" >&5
echo $ECHO_N "checking for getaddrinfo... $ECHO_C" >&6; }
if test "${have_gai+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
{ { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
See \`config.log' for more details." >&5
echo "$as_me: error: cannot run test program while cross compiling
See \`config.log' for more details." >&2;}
{ (exit 1); exit 1; }; }
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char **argv)
{
struct addrinfo *res;
if(getaddrinfo("127.0.0.1", NULL, NULL, &res) < 0)
return 1;
freeaddrinfo(res);
return 0;
}
_ACEOF
rm -f conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_try") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
have_gai=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
have_gai=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
fi
{ echo "$as_me:$LINENO: result: $have_gai" >&5
echo "${ECHO_T}$have_gai" >&6; }
if test "$have_gai" = yes; then
cat >>confdefs.h <<\_ACEOF
#define SUPPORT_IPv6 1
_ACEOF
fi
fi
# Check whether --enable-dns was given.
if test "${enable_dns+set}" = set; then
enableval=$enable_dns; want_dns=$enableval

@ -469,6 +469,37 @@ AC_ARG_ENABLE([unrar],
[ --disable-unrar don't build libclamunrar and libclamunrar_iface ],
want_unrar=$enableval, want_unrar="yes")
AC_ARG_ENABLE([ipv6],
[ --disable-ipv6 disable IPv6 support],
want_ipv6=$enableval, want_ipv6="yes")
if test "$want_ipv6" = "yes"
then
AC_MSG_CHECKING([for getaddrinfo])
AC_CACHE_VAL([have_gai],[
AC_TRY_RUN([
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char **argv)
{
struct addrinfo *res;
if(getaddrinfo("127.0.0.1", NULL, NULL, &res) < 0)
return 1;
freeaddrinfo(res);
return 0;
}
],
[have_gai=yes],
[have_gai=no])
])
AC_MSG_RESULT([$have_gai])
if test "$have_gai" = yes; then
AC_DEFINE(SUPPORT_IPv6, 1, [Use IPv6 aware code])
fi
fi
AC_ARG_ENABLE([dns],
AC_HELP_STRING([--disable-dns], [disable support for database verification through DNS]),
[want_dns=$enableval], [want_dns=yes]

@ -40,6 +40,7 @@
#ifndef C_WINDOWS
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include <sys/types.h>
#ifndef C_WINDOWS
@ -82,14 +83,39 @@
#define closesocket(s) close(s)
#endif
static int getclientsock(const char *localip)
#ifndef SUPPORT_IPv6
static const char *ghbn_err(int err) /* hstrerror() */
{
switch(err) {
case HOST_NOT_FOUND:
return "Host not found";
case NO_DATA:
return "No IP address";
case NO_RECOVERY:
return "Unrecoverable DNS error";
case TRY_AGAIN:
return "Temporary DNS error";
default:
return "Unknown error";
}
}
#endif
static int getclientsock(const char *localip, int prot)
{
int socketfd = -1;
#ifdef PF_INET
socketfd = socket(PF_INET, SOCK_STREAM, 0);
#ifdef SUPPORT_IPv6
if(prot == PF_INET6)
socketfd = socket(PF_INET6, SOCK_STREAM, 0);
else
socketfd = socket(PF_INET, SOCK_STREAM, 0);
#else
socketfd = socket(AF_INET, SOCK_STREAM, 0);
socketfd = socket(PF_INET, SOCK_STREAM, 0);
#endif
if(socketfd < 0) {
@ -98,42 +124,49 @@ static int getclientsock(const char *localip)
}
if(localip) {
struct hostent *he;
#ifdef SUPPORT_IPv6
struct addrinfo *res;
int ret;
if((he = gethostbyname(localip)) == NULL) {
const char *herr;
switch(h_errno) {
case HOST_NOT_FOUND:
herr = "Host not found";
break;
case NO_DATA:
herr = "No IP address";
break;
ret = getaddrinfo(localip, NULL, NULL, &res);
if(ret) {
logg("!Could not resolve local ip address '%s': %s\n", localip, gai_strerror(ret));
logg("^Using standard local ip address and port for fetching.\n");
} else {
char ipaddr[46];
case NO_RECOVERY:
herr = "Unrecoverable DNS error";
break;
if(bind(socketfd, res->ai_addr, res->ai_addrlen) != 0) {
logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
logg("^Using default client ip.\n");
} else {
void *addr;
case TRY_AGAIN:
herr = "Temporary DNS error";
break;
if(res->ai_family == AF_INET6)
addr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
else
addr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
default:
herr = "Unknown error";
break;
if(inet_ntop(res->ai_family, addr, ipaddr, sizeof(ipaddr)))
logg("*Using ip '%s' for fetching.\n", ipaddr);
}
logg("!Could not resolve local ip address '%s': %s\n", localip, herr);
freeaddrinfo(res);
}
#else /* IPv4 */
struct hostent *he;
if(!(he = gethostbyname(localip))) {
logg("!Could not resolve local ip address '%s': %s\n", localip, ghbn_err(h_errno));
logg("^Using standard local ip address and port for fetching.\n");
} else {
struct sockaddr_in client;
unsigned char *ia;
char ipaddr[16];
struct sockaddr_in client;
unsigned char *ia;
char ipaddr[16];
memset ((char *) &client, 0, sizeof(struct sockaddr_in));
memset((char *) &client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_addr = *(struct in_addr *) he->h_addr_list[0];
if (bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
if(bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
logg("^Using default client ip.\n");
} else {
@ -142,6 +175,7 @@ static int getclientsock(const char *localip)
logg("*Using ip '%s' for fetching.\n", ipaddr);
}
}
#endif
}
return socketfd;
@ -149,22 +183,21 @@ static int getclientsock(const char *localip)
static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat, int logerr)
{
int socketfd = -1, port, i, ret;
int socketfd, port, ret;
#ifdef SUPPORT_IPv6
struct addrinfo hints, *res = NULL, *rp;
#else
struct sockaddr_in name;
struct hostent *host;
char ipaddr[16];
unsigned char *ia;
int i;
#endif
char ipaddr[46];
const char *hostpt;
if(ip)
strcpy(ip, "???");
socketfd = getclientsock(localip);
if(socketfd < 0)
return -1;
name.sin_family = AF_INET;
if(proxy) {
hostpt = proxy;
@ -190,31 +223,74 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
port = 80;
}
if((host = gethostbyname(hostpt)) == NULL) {
const char *herr;
switch(h_errno) {
case HOST_NOT_FOUND:
herr = "Host not found";
break;
#ifdef SUPPORT_IPv6
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
ret = getaddrinfo(hostpt, "80", &hints, &res);
if(ret) {
logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, gai_strerror(ret));
return -1;
}
case NO_DATA:
herr = "No IP address";
break;
for(rp = res; rp; rp = rp->ai_next) {
void *addr;
case NO_RECOVERY:
herr = "Unrecoverable DNS error";
break;
if(rp->ai_family == AF_INET6)
addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
else
addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
case TRY_AGAIN:
herr = "Temporary DNS error";
break;
if(!inet_ntop(rp->ai_family, addr, ipaddr, sizeof(ipaddr))) {
logg("%cinet_ntop() failed\n", logerr ? '!' : '^');
freeaddrinfo(res);
return -1;
}
default:
herr = "Unknown error";
break;
if((ret = mirman_check(addr, rp->ai_family, mdat))) {
if(ret == 1)
logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
else
logg("Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
continue;
}
logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, herr);
closesocket(socketfd);
if(ip)
strcpy(ip, ipaddr);
if(rp != res)
logg("Trying host %s (%s)...\n", hostpt, ipaddr);
socketfd = getclientsock(localip, rp->ai_family);
if(socketfd < 0) {
freeaddrinfo(res);
return -1;
}
#ifdef SO_ERROR
if(wait_connect(socketfd, rp->ai_addr, rp->ai_addrlen, ctimeout) == -1) {
#else
if(connect(socketfd, rp->ai_addr, rp->ai_addrlen) == -1) {
#endif
logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
closesocket(socketfd);
continue;
} else {
if(rp->ai_family == AF_INET)
mdat->currip[0] = *((uint32_t *) addr);
else
memcpy(mdat->currip, addr, 4);
mdat->af = rp->ai_family;
freeaddrinfo(res);
return socketfd;
}
}
freeaddrinfo(res);
#else /* IPv4 */
if((host = gethostbyname(hostpt)) == NULL) {
logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, ghbn_err(h_errno));
return -1;
}
@ -223,7 +299,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
ia = (unsigned char *) host->h_addr_list[i];
sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
if((ret = mirman_check(((struct in_addr *) ia)->s_addr, mdat))) {
if((ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat))) {
if(ret == 1)
logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
else
@ -237,9 +313,15 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
if(i > 0)
logg("Trying host %s (%s)...\n", hostpt, ipaddr);
memset ((char *) &name, 0, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr = *((struct in_addr *) host->h_addr_list[i]);
name.sin_port = htons(port);
socketfd = getclientsock(localip, AF_INET);
if(socketfd < 0)
return -1;
#ifdef SO_ERROR
if(wait_connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in), ctimeout) == -1) {
#else
@ -247,17 +329,15 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
#endif
logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
closesocket(socketfd);
if((socketfd = getclientsock(localip)) == -1)
return -1;
continue;
} else {
mdat->currip = ((struct in_addr *) ia)->s_addr;
mdat->currip[0] = ((struct in_addr *) ia)->s_addr;
mdat->af = AF_INET;
return socketfd;
}
}
#endif
closesocket(socketfd);
return -2;
}
@ -339,7 +419,7 @@ static char *proxyauth(const char *user, const char *pass)
static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, char *ip, const char *localip, const char *proxy, int port, const char *user, const char *pass, const char *uas, int *ims, int ctimeout, int rtimeout, struct mirdat *mdat, int logerr)
{
char cmd[512], head[513], buffer[FILEBUFF], ipaddr[16], *ch, *tmp;
char cmd[512], head[513], buffer[FILEBUFF], ipaddr[46], *ch, *tmp;
int bread, cnt, sd;
unsigned int i, j;
char *remotename = NULL, *authorization = NULL;
@ -437,7 +517,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
if(bread == -1) {
logg("%cremote_cvdhead: Error while reading CVD header from %s\n", logerr ? '!' : '^', hostname);
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
return NULL;
}
@ -451,7 +531,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) {
*ims = 0;
logg("OK (IMS)\n");
mirman_update(mdat->currip, mdat, 0);
mirman_update(mdat->currip, mdat->af, mdat, 0);
return NULL;
} else {
*ims = 1;
@ -460,7 +540,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
!strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
logg("%cUnknown response from remote server\n", logerr ? '!' : '^');
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
return NULL;
}
@ -478,7 +558,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
if(sizeof(buffer) - i < 512) {
logg("%cremote_cvdhead: Malformed CVD header (too short)\n", logerr ? '!' : '^');
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
return NULL;
}
@ -487,7 +567,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
for(j = 0; j < 512; j++) {
if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
logg("%cremote_cvdhead: Malformed CVD header (bad chars)\n", logerr ? '!' : '^');
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
return NULL;
}
head[j] = ch[j];
@ -495,10 +575,10 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
if(!(cvd = cl_cvdparse(head))) {
logg("%cremote_cvdhead: Malformed CVD header (can't parse)\n", logerr ? '!' : '^');
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
} else {
logg("OK\n");
mirman_update(mdat->currip, mdat, 0);
mirman_update(mdat->currip, mdat->af, mdat, 0);
}
return cvd;
@ -587,7 +667,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
#endif
logg("%cgetfile: Error while reading database from %s (IP: %s)\n", logerr ? '!' : '^', hostname, ipaddr);
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
closesocket(sd);
return 52;
}
@ -613,7 +693,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
!strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr);
mirman_update(mdat->currip, mdat, 1);
mirman_update(mdat->currip, mdat->af, mdat, 1);
closesocket(sd);
return 58;
}
@ -678,7 +758,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
else
logg("Downloading %s [*]\n", srcfile);
mirman_update(mdat->currip, mdat, 0);
mirman_update(mdat->currip, mdat->af, mdat, 0);
return 0;
}
@ -1203,7 +1283,7 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
time_t currtime;
int ret, updated = 0, outdated = 0, signo = 0;
unsigned int ttl;
char ipaddr[16], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
char ipaddr[46], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
const char *arg = NULL;
const struct cfgstruct *cpt;
struct mirdat mdat;
@ -1213,6 +1293,9 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
time(&currtime);
logg("ClamAV update process started at %s", ctime(&currtime));
#ifdef SUPPORT_IPv6
logg("*Using IPv6 aware code\n");
#endif
#ifndef HAVE_LIBGMP
logg("SECURITY WARNING: NO SUPPORT FOR DIGITAL SIGNATURES\n");

@ -35,6 +35,10 @@
#include <fcntl.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "mirman.h"
#include "libclamav/cltypes.h"
@ -94,7 +98,7 @@ int mirman_read(const char *file, struct mirdat *mdat, uint8_t active)
return 0;
}
int mirman_check(uint32_t ip, struct mirdat *mdat)
int mirman_check(uint32_t *ip, int af, struct mirdat *mdat)
{
unsigned int i, flevel = cl_retflevel();
@ -103,7 +107,8 @@ int mirman_check(uint32_t ip, struct mirdat *mdat)
return 0;
for(i = 0; i < mdat->num; i++) {
if(mdat->mirtab[i].atime && mdat->mirtab[i].ip == ip) {
if(mdat->mirtab[i].atime && ((af == AF_INET && mdat->mirtab[i].ip4 == *ip) || (af == AF_INET6 && !memcmp(mdat->mirtab[i].ip6, ip, 4)))) {
if(mdat->dbflevel && (mdat->dbflevel > flevel) && (mdat->dbflevel - flevel > 3))
if(time(NULL) - mdat->mirtab[i].atime < 4 * 3600)
@ -123,7 +128,7 @@ int mirman_check(uint32_t ip, struct mirdat *mdat)
return 0;
}
int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
int mirman_update(uint32_t *ip, int af, struct mirdat *mdat, uint8_t broken)
{
unsigned int i, found = 0;
@ -132,7 +137,7 @@ int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
return 0;
for(i = 0; i < mdat->num; i++) {
if(mdat->mirtab[i].ip == ip) {
if((af == AF_INET && mdat->mirtab[i].ip4 == *ip) || (af == AF_INET6 && !memcmp(mdat->mirtab[i].ip6, ip, 4))) {
found = 1;
break;
}
@ -160,7 +165,12 @@ int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
logg("!Can't allocate memory for new element in mdat->mirtab\n");
return -1;
}
mdat->mirtab[mdat->num].ip = ip;
if(af == AF_INET) {
mdat->mirtab[mdat->num].ip4 = *ip;
} else {
mdat->mirtab[mdat->num].ip4 = 0;
memcpy(mdat->mirtab[mdat->num].ip6, ip, 4);
}
mdat->mirtab[mdat->num].atime = 0;
mdat->mirtab[mdat->num].succ = 0;
mdat->mirtab[mdat->num].fail = 0;
@ -179,14 +189,16 @@ int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
void mirman_list(const struct mirdat *mdat)
{
unsigned int i;
unsigned char *ip;
time_t tm;
char ip[46];
for(i = 0; i < mdat->num; i++) {
printf("Mirror #%u\n", i + 1);
ip = (unsigned char *) &mdat->mirtab[i].ip;
printf("IP: %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
if(mdat->mirtab[i].ip4)
printf("IP: %s\n", inet_ntop(AF_INET, &mdat->mirtab[i].ip4, ip, sizeof(ip)));
else
printf("IP: %s\n", inet_ntop(AF_INET6, mdat->mirtab[i].ip6, ip, sizeof(ip)));
printf("Successes: %u\n", mdat->mirtab[i].succ);
printf("Failures: %u\n", mdat->mirtab[i].fail);
tm = mdat->mirtab[i].atime;

@ -22,25 +22,27 @@
#include "libclamav/cltypes.h"
struct mirdat_ip {
uint32_t ip; /* IP address */
uint32_t ip4; /* IPv4 address */
uint32_t atime; /* last access time */
uint32_t succ; /* number of successful downloads from this ip */
uint32_t fail; /* number of failures */
uint8_t ignore; /* ignore flag */
char res[32]; /* reserved */
uint32_t ip6[4]; /* IPv6 address */
char res[16]; /* reserved */
};
struct mirdat {
uint8_t active;
unsigned int num;
uint32_t currip;
uint32_t currip[4];
uint32_t af;
uint32_t dbflevel;
struct mirdat_ip *mirtab;
};
int mirman_read(const char *file, struct mirdat *mdat, uint8_t active);
int mirman_check(uint32_t ip, struct mirdat *mdat);
int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken);
int mirman_check(uint32_t *ip, int af, struct mirdat *mdat);
int mirman_update(uint32_t *ip, int af, struct mirdat *mdat, uint8_t broken);
void mirman_list(const struct mirdat *mdat);
int mirman_write(const char *file, struct mirdat *mdat);
void mirman_free(struct mirdat *mdat);

@ -55,8 +55,15 @@ int notify(const char *cfgfile)
#ifndef C_WINDOWS
struct sockaddr_un server;
#endif
#ifdef SUPPORT_IPv6
struct addrinfo hints, *res;
char port[6];
const char *addr;
int ret;
#else
struct sockaddr_in server2;
struct hostent *he;
#endif
struct cfgstruct *copt;
const struct cfgstruct *cpt;
int sockd, bread;
@ -93,8 +100,49 @@ int notify(const char *cfgfile)
} else
#endif
if((cpt = cfgopt(copt, "TCPSocket"))->enabled) {
socktype = "TCP";
#if SUPPORT_IPv6
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(port, 5, "%d", cpt->numarg);
port[5] = 0;
if((cpt = cfgopt(copt, "TCPAddr"))->enabled)
addr = cpt->strarg;
else
addr = NULL;
ret = getaddrinfo(addr, port, &hints, &res);
if(ret) {
perror("getaddrinfo()");
logg("^Clamd was NOT notified: Can't resolve hostname %s\n", addr ? addr : "");
freecfg(copt);
return 1;
}
if((sockd = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
perror("socket()");
logg("^Clamd was NOT notified: Can't create TCP socket\n");
freecfg(copt);
freeaddrinfo(res);
return 1;
}
if(connect(sockd, res->ai_addr, res->ai_addrlen) == -1) {
perror("connect()");
closesocket(sockd);
logg("^Clamd was NOT notified: Can't connect to clamd on %s:%s\n", addr, port);
freecfg(copt);
freeaddrinfo(res);
return 1;
}
freeaddrinfo(res);
#else /* IPv4 */
#ifdef PF_INET
if((sockd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
#else
@ -110,10 +158,11 @@ int notify(const char *cfgfile)
server2.sin_port = htons(cpt->numarg);
if((cpt = cfgopt(copt, "TCPAddr"))->enabled) {
if ((he = gethostbyname(cpt->strarg)) == 0) {
if((he = gethostbyname(cpt->strarg)) == 0) {
perror("gethostbyname()");
logg("^Clamd was NOT notified: Can't resolve hostname '%s'\n", cpt->strarg);
freecfg(copt);
closesocket(sockd);
return 1;
}
server2.sin_addr = *(struct in_addr *) he->h_addr_list[0];
@ -130,6 +179,8 @@ int notify(const char *cfgfile)
return 1;
}
#endif
} else {
logg("^Clamd was NOT notified: No socket specified in %s\n", cfgfile);
freecfg(copt);

Loading…
Cancel
Save