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) Thu Jul 10 19:41:37 EEST 2008 (edwin)
------------------------------------- -------------------------------------
* unit_tests/: add unit tests for binaries * unit_tests/: add unit tests for binaries

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

110
configure vendored

@ -1514,6 +1514,7 @@ Optional Features:
--disable-bzip2 disable bzip2 support --disable-bzip2 disable bzip2 support
--disable-rpath do not hardcode runtime library paths --disable-rpath do not hardcode runtime library paths
--disable-unrar don't build libclamunrar and libclamunrar_iface --disable-unrar don't build libclamunrar and libclamunrar_iface
--disable-ipv6 disable IPv6 support
--disable-dns disable support for database verification through --disable-dns disable support for database verification through
DNS DNS
--disable-clamuko disable clamuko support (Linux, DragonFly and FreeBSD only) --disable-clamuko disable clamuko support (Linux, DragonFly and FreeBSD only)
@ -4777,7 +4778,7 @@ ia64-*-hpux*)
;; ;;
*-*-irix6*) *-*-irix6*)
# Find out which ABI we are using. # 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 if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5 (eval $ac_compile) 2>&5
ac_status=$? ac_status=$?
@ -6867,11 +6868,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -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) (eval "$lt_compile" 2>conftest.err)
ac_status=$? ac_status=$?
cat conftest.err >&5 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 if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized # The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output. # 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:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -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) (eval "$lt_compile" 2>conftest.err)
ac_status=$? ac_status=$?
cat conftest.err >&5 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 if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized # The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output. # 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:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'` -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) (eval "$lt_compile" 2>out/conftest.err)
ac_status=$? ac_status=$?
cat out/conftest.err >&5 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 if (exit $ac_status) && test -s out/conftest2.$ac_objext
then then
# The compiler can only warn and ignore the option if not recognized # 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_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 9641 "configure" #line 9642 "configure"
#include "confdefs.h" #include "confdefs.h"
#if HAVE_DLFCN_H #if HAVE_DLFCN_H
@ -9738,7 +9739,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line 9741 "configure" #line 9742 "configure"
#include "confdefs.h" #include "confdefs.h"
#if HAVE_DLFCN_H #if HAVE_DLFCN_H
@ -15025,6 +15026,97 @@ else
fi 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. # Check whether --enable-dns was given.
if test "${enable_dns+set}" = set; then if test "${enable_dns+set}" = set; then
enableval=$enable_dns; want_dns=$enableval enableval=$enable_dns; want_dns=$enableval

@ -469,6 +469,37 @@ AC_ARG_ENABLE([unrar],
[ --disable-unrar don't build libclamunrar and libclamunrar_iface ], [ --disable-unrar don't build libclamunrar and libclamunrar_iface ],
want_unrar=$enableval, want_unrar="yes") 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_ARG_ENABLE([dns],
AC_HELP_STRING([--disable-dns], [disable support for database verification through DNS]), AC_HELP_STRING([--disable-dns], [disable support for database verification through DNS]),
[want_dns=$enableval], [want_dns=yes] [want_dns=$enableval], [want_dns=yes]

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

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

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

@ -55,8 +55,15 @@ int notify(const char *cfgfile)
#ifndef C_WINDOWS #ifndef C_WINDOWS
struct sockaddr_un server; struct sockaddr_un server;
#endif #endif
#ifdef SUPPORT_IPv6
struct addrinfo hints, *res;
char port[6];
const char *addr;
int ret;
#else
struct sockaddr_in server2; struct sockaddr_in server2;
struct hostent *he; struct hostent *he;
#endif
struct cfgstruct *copt; struct cfgstruct *copt;
const struct cfgstruct *cpt; const struct cfgstruct *cpt;
int sockd, bread; int sockd, bread;
@ -93,8 +100,49 @@ int notify(const char *cfgfile)
} else } else
#endif #endif
if((cpt = cfgopt(copt, "TCPSocket"))->enabled) { if((cpt = cfgopt(copt, "TCPSocket"))->enabled) {
socktype = "TCP"; 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 #ifdef PF_INET
if((sockd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { if((sockd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
#else #else
@ -110,10 +158,11 @@ int notify(const char *cfgfile)
server2.sin_port = htons(cpt->numarg); server2.sin_port = htons(cpt->numarg);
if((cpt = cfgopt(copt, "TCPAddr"))->enabled) { if((cpt = cfgopt(copt, "TCPAddr"))->enabled) {
if ((he = gethostbyname(cpt->strarg)) == 0) { if((he = gethostbyname(cpt->strarg)) == 0) {
perror("gethostbyname()"); perror("gethostbyname()");
logg("^Clamd was NOT notified: Can't resolve hostname '%s'\n", cpt->strarg); logg("^Clamd was NOT notified: Can't resolve hostname '%s'\n", cpt->strarg);
freecfg(copt); freecfg(copt);
closesocket(sockd);
return 1; return 1;
} }
server2.sin_addr = *(struct in_addr *) he->h_addr_list[0]; server2.sin_addr = *(struct in_addr *) he->h_addr_list[0];
@ -130,6 +179,8 @@ int notify(const char *cfgfile)
return 1; return 1;
} }
#endif
} else { } else {
logg("^Clamd was NOT notified: No socket specified in %s\n", cfgfile); logg("^Clamd was NOT notified: No socket specified in %s\n", cfgfile);
freecfg(copt); freecfg(copt);

Loading…
Cancel
Save