diff --git a/ChangeLog b/ChangeLog index 6ee1bfb03..2e35524d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/clamav-config.h.in b/clamav-config.h.in index 0692a0eaf..92d56d347 100644 --- a/clamav-config.h.in +++ b/clamav-config.h.in @@ -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 diff --git a/configure b/configure index 88d86c593..5842bec23 100755 --- a/configure +++ b/configure @@ -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 < conftest.$ac_ext <&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 + #include + #include + 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 diff --git a/configure.in b/configure.in index 5cf29e199..855d32ffe 100644 --- a/configure.in +++ b/configure.in @@ -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 + #include + #include + 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] diff --git a/freshclam/manager.c b/freshclam/manager.c index 7dbde09a6..d16d5fa29 100644 --- a/freshclam/manager.c +++ b/freshclam/manager.c @@ -40,6 +40,7 @@ #ifndef C_WINDOWS #include #include +#include #endif #include #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"); diff --git a/freshclam/mirman.c b/freshclam/mirman.c index 1c2daad77..b3318102f 100644 --- a/freshclam/mirman.c +++ b/freshclam/mirman.c @@ -35,6 +35,10 @@ #include #include +#include +#include +#include + #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; diff --git a/freshclam/mirman.h b/freshclam/mirman.h index 9d6980160..3499f88e5 100644 --- a/freshclam/mirman.h +++ b/freshclam/mirman.h @@ -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); diff --git a/freshclam/notify.c b/freshclam/notify.c index ed6cd5b2e..ed4af7a2b 100644 --- a/freshclam/notify.c +++ b/freshclam/notify.c @@ -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);