Browse code

freshclam: IPv6 support (bb#715)

git-svn: trunk@3940

Tomasz Kojm authored on 2008/07/12 03:39:40
Showing 8 changed files
... ...
@@ -1,3 +1,8 @@
1
+Fri Jul 11 20:14:14 CEST 2008 (tk)
2
+----------------------------------
3
+  * freshclam: IPv6 support (bb#715)
4
+  * configure: --disable-ipv6
5
+
1 6
 Thu Jul 10 19:41:37 EEST 2008 (edwin)
2 7
 -------------------------------------
3 8
  * unit_tests/: add unit tests for binaries
... ...
@@ -369,6 +369,9 @@
369 369
 /* Define to 1 if you have the ANSI C header files. */
370 370
 #undef STDC_HEADERS
371 371
 
372
+/* Use IPv6 aware code */
373
+#undef SUPPORT_IPv6
374
+
372 375
 /* use syslog */
373 376
 #undef USE_SYSLOG
374 377
 
... ...
@@ -1514,6 +1514,7 @@ Optional Features:
1514 1514
   --disable-bzip2	  disable bzip2 support
1515 1515
   --disable-rpath         do not hardcode runtime library paths
1516 1516
   --disable-unrar	  don't build libclamunrar and libclamunrar_iface
1517
+  --disable-ipv6          disable IPv6 support
1517 1518
   --disable-dns           disable support for database verification through
1518 1519
                           DNS
1519 1520
   --disable-clamuko	  disable clamuko support (Linux, DragonFly and FreeBSD only)
... ...
@@ -4777,7 +4778,7 @@ ia64-*-hpux*)
4777 4777
   ;;
4778 4778
 *-*-irix6*)
4779 4779
   # Find out which ABI we are using.
4780
-  echo '#line 4780 "configure"' > conftest.$ac_ext
4780
+  echo '#line 4781 "configure"' > conftest.$ac_ext
4781 4781
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
4782 4782
   (eval $ac_compile) 2>&5
4783 4783
   ac_status=$?
... ...
@@ -6867,11 +6868,11 @@ else
6867 6867
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
6868 6868
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
6869 6869
    -e 's:$: $lt_compiler_flag:'`
6870
-   (eval echo "\"\$as_me:6870: $lt_compile\"" >&5)
6870
+   (eval echo "\"\$as_me:6871: $lt_compile\"" >&5)
6871 6871
    (eval "$lt_compile" 2>conftest.err)
6872 6872
    ac_status=$?
6873 6873
    cat conftest.err >&5
6874
-   echo "$as_me:6874: \$? = $ac_status" >&5
6874
+   echo "$as_me:6875: \$? = $ac_status" >&5
6875 6875
    if (exit $ac_status) && test -s "$ac_outfile"; then
6876 6876
      # The compiler can only warn and ignore the option if not recognized
6877 6877
      # So say no if there are warnings other than the usual output.
... ...
@@ -7157,11 +7158,11 @@ else
7157 7157
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
7158 7158
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
7159 7159
    -e 's:$: $lt_compiler_flag:'`
7160
-   (eval echo "\"\$as_me:7160: $lt_compile\"" >&5)
7160
+   (eval echo "\"\$as_me:7161: $lt_compile\"" >&5)
7161 7161
    (eval "$lt_compile" 2>conftest.err)
7162 7162
    ac_status=$?
7163 7163
    cat conftest.err >&5
7164
-   echo "$as_me:7164: \$? = $ac_status" >&5
7164
+   echo "$as_me:7165: \$? = $ac_status" >&5
7165 7165
    if (exit $ac_status) && test -s "$ac_outfile"; then
7166 7166
      # The compiler can only warn and ignore the option if not recognized
7167 7167
      # So say no if there are warnings other than the usual output.
... ...
@@ -7261,11 +7262,11 @@ else
7261 7261
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
7262 7262
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
7263 7263
    -e 's:$: $lt_compiler_flag:'`
7264
-   (eval echo "\"\$as_me:7264: $lt_compile\"" >&5)
7264
+   (eval echo "\"\$as_me:7265: $lt_compile\"" >&5)
7265 7265
    (eval "$lt_compile" 2>out/conftest.err)
7266 7266
    ac_status=$?
7267 7267
    cat out/conftest.err >&5
7268
-   echo "$as_me:7268: \$? = $ac_status" >&5
7268
+   echo "$as_me:7269: \$? = $ac_status" >&5
7269 7269
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
7270 7270
    then
7271 7271
      # The compiler can only warn and ignore the option if not recognized
... ...
@@ -9638,7 +9639,7 @@ else
9638 9638
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
9639 9639
   lt_status=$lt_dlunknown
9640 9640
   cat > conftest.$ac_ext <<EOF
9641
-#line 9641 "configure"
9641
+#line 9642 "configure"
9642 9642
 #include "confdefs.h"
9643 9643
 
9644 9644
 #if HAVE_DLFCN_H
... ...
@@ -9738,7 +9739,7 @@ else
9738 9738
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
9739 9739
   lt_status=$lt_dlunknown
9740 9740
   cat > conftest.$ac_ext <<EOF
9741
-#line 9741 "configure"
9741
+#line 9742 "configure"
9742 9742
 #include "confdefs.h"
9743 9743
 
9744 9744
 #if HAVE_DLFCN_H
... ...
@@ -15025,6 +15026,97 @@ else
15025 15025
 fi
15026 15026
 
15027 15027
 
15028
+# Check whether --enable-ipv6 was given.
15029
+if test "${enable_ipv6+set}" = set; then
15030
+  enableval=$enable_ipv6; want_ipv6=$enableval
15031
+else
15032
+  want_ipv6="yes"
15033
+fi
15034
+
15035
+
15036
+if test "$want_ipv6" = "yes"
15037
+then
15038
+    { echo "$as_me:$LINENO: checking for getaddrinfo" >&5
15039
+echo $ECHO_N "checking for getaddrinfo... $ECHO_C" >&6; }
15040
+    if test "${have_gai+set}" = set; then
15041
+  echo $ECHO_N "(cached) $ECHO_C" >&6
15042
+else
15043
+
15044
+		if test "$cross_compiling" = yes; then
15045
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
15046
+See \`config.log' for more details." >&5
15047
+echo "$as_me: error: cannot run test program while cross compiling
15048
+See \`config.log' for more details." >&2;}
15049
+   { (exit 1); exit 1; }; }
15050
+else
15051
+  cat >conftest.$ac_ext <<_ACEOF
15052
+/* confdefs.h.  */
15053
+_ACEOF
15054
+cat confdefs.h >>conftest.$ac_ext
15055
+cat >>conftest.$ac_ext <<_ACEOF
15056
+/* end confdefs.h.  */
15057
+
15058
+		    #include <sys/types.h>
15059
+		    #include <sys/socket.h>
15060
+		    #include <netdb.h>
15061
+		    int main(int argc, char **argv)
15062
+		    {
15063
+			    struct addrinfo *res;
15064
+
15065
+			if(getaddrinfo("127.0.0.1", NULL, NULL, &res) < 0)
15066
+			    return 1;
15067
+			freeaddrinfo(res);
15068
+			return 0;
15069
+		    }
15070
+
15071
+_ACEOF
15072
+rm -f conftest$ac_exeext
15073
+if { (ac_try="$ac_link"
15074
+case "(($ac_try" in
15075
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
15076
+  *) ac_try_echo=$ac_try;;
15077
+esac
15078
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
15079
+  (eval "$ac_link") 2>&5
15080
+  ac_status=$?
15081
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
15082
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
15083
+  { (case "(($ac_try" in
15084
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
15085
+  *) ac_try_echo=$ac_try;;
15086
+esac
15087
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
15088
+  (eval "$ac_try") 2>&5
15089
+  ac_status=$?
15090
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
15091
+  (exit $ac_status); }; }; then
15092
+  have_gai=yes
15093
+else
15094
+  echo "$as_me: program exited with status $ac_status" >&5
15095
+echo "$as_me: failed program was:" >&5
15096
+sed 's/^/| /' conftest.$ac_ext >&5
15097
+
15098
+( exit $ac_status )
15099
+have_gai=no
15100
+fi
15101
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
15102
+fi
15103
+
15104
+
15105
+
15106
+fi
15107
+
15108
+    { echo "$as_me:$LINENO: result: $have_gai" >&5
15109
+echo "${ECHO_T}$have_gai" >&6; }
15110
+    if test "$have_gai" = yes; then
15111
+
15112
+cat >>confdefs.h <<\_ACEOF
15113
+#define SUPPORT_IPv6 1
15114
+_ACEOF
15115
+
15116
+    fi
15117
+fi
15118
+
15028 15119
 # Check whether --enable-dns was given.
15029 15120
 if test "${enable_dns+set}" = set; then
15030 15121
   enableval=$enable_dns; want_dns=$enableval
... ...
@@ -469,6 +469,37 @@ AC_ARG_ENABLE([unrar],
469 469
 [  --disable-unrar	  don't build libclamunrar and libclamunrar_iface ],
470 470
 want_unrar=$enableval, want_unrar="yes")
471 471
 
472
+AC_ARG_ENABLE([ipv6],
473
+[  --disable-ipv6          disable IPv6 support],
474
+want_ipv6=$enableval, want_ipv6="yes")
475
+
476
+if test "$want_ipv6" = "yes"
477
+then
478
+    AC_MSG_CHECKING([for getaddrinfo])
479
+    AC_CACHE_VAL([have_gai],[
480
+		AC_TRY_RUN([
481
+		    #include <sys/types.h>
482
+		    #include <sys/socket.h>
483
+		    #include <netdb.h>
484
+		    int main(int argc, char **argv)
485
+		    {
486
+			    struct addrinfo *res;
487
+
488
+			if(getaddrinfo("127.0.0.1", NULL, NULL, &res) < 0)
489
+			    return 1;
490
+			freeaddrinfo(res);
491
+			return 0;
492
+		    }
493
+		],
494
+		[have_gai=yes],
495
+		[have_gai=no])
496
+		])
497
+    AC_MSG_RESULT([$have_gai])
498
+    if test "$have_gai" = yes; then
499
+	AC_DEFINE(SUPPORT_IPv6, 1, [Use IPv6 aware code])
500
+    fi
501
+fi
502
+
472 503
 AC_ARG_ENABLE([dns],
473 504
     AC_HELP_STRING([--disable-dns], [disable support for database verification through DNS]),
474 505
     [want_dns=$enableval], [want_dns=yes]
... ...
@@ -40,6 +40,7 @@
40 40
 #ifndef C_WINDOWS
41 41
 #include <netinet/in.h>
42 42
 #include <netdb.h>
43
+#include <arpa/inet.h>
43 44
 #endif
44 45
 #include <sys/types.h>
45 46
 #ifndef C_WINDOWS
... ...
@@ -82,14 +83,39 @@
82 82
 #define	closesocket(s)	close(s)
83 83
 #endif
84 84
 
85
-static int getclientsock(const char *localip)
85
+#ifndef SUPPORT_IPv6
86
+static const char *ghbn_err(int err) /* hstrerror() */
87
+{
88
+    switch(err) {
89
+	case HOST_NOT_FOUND:
90
+	    return "Host not found";
91
+
92
+	case NO_DATA:
93
+	    return "No IP address";
94
+
95
+	case NO_RECOVERY:
96
+	    return "Unrecoverable DNS error";
97
+
98
+	case TRY_AGAIN:
99
+	    return "Temporary DNS error";
100
+
101
+	default:
102
+	    return "Unknown error";
103
+    }
104
+}
105
+#endif
106
+
107
+static int getclientsock(const char *localip, int prot)
86 108
 {
87 109
 	int socketfd = -1;
88 110
 
89
-#ifdef PF_INET
90
-    socketfd = socket(PF_INET, SOCK_STREAM, 0);
111
+#ifdef SUPPORT_IPv6
112
+    if(prot == PF_INET6)
113
+	socketfd = socket(PF_INET6, SOCK_STREAM, 0);
114
+    else
115
+	socketfd = socket(PF_INET, SOCK_STREAM, 0);
91 116
 #else
92
-    socketfd = socket(AF_INET, SOCK_STREAM, 0);
117
+    socketfd = socket(PF_INET, SOCK_STREAM, 0);
93 118
 #endif
94 119
 
95 120
     if(socketfd < 0) {
... ...
@@ -98,42 +124,49 @@ static int getclientsock(const char *localip)
98 98
     }
99 99
 
100 100
     if(localip) {
101
-	struct hostent *he;
101
+#ifdef SUPPORT_IPv6
102
+	    struct addrinfo *res;
103
+	    int ret;
102 104
 
103
-	if((he = gethostbyname(localip)) == NULL) {
104
-	    const char *herr;
105
-	    switch(h_errno) {
106
-	        case HOST_NOT_FOUND:
107
-		    herr = "Host not found";
108
-		    break;
109
-
110
-		case NO_DATA:
111
-		    herr = "No IP address";
112
-		    break;
105
+	ret = getaddrinfo(localip, NULL, NULL, &res);
106
+	if(ret) {
107
+	    logg("!Could not resolve local ip address '%s': %s\n", localip, gai_strerror(ret));
108
+	    logg("^Using standard local ip address and port for fetching.\n");
109
+	} else {
110
+		char ipaddr[46];
113 111
 
114
-		case NO_RECOVERY:
115
-		    herr = "Unrecoverable DNS error";
116
-		    break;
112
+	    if(bind(socketfd, res->ai_addr, res->ai_addrlen) != 0) {
113
+		logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
114
+		logg("^Using default client ip.\n");
115
+	    } else {
116
+		    void *addr;
117 117
 
118
-		case TRY_AGAIN:
119
-		    herr = "Temporary DNS error";
120
-		    break;
118
+		if(res->ai_family == AF_INET6)
119
+		    addr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
120
+		else
121
+		    addr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
121 122
 
122
-		default:
123
-		    herr = "Unknown error";
124
-		    break;
123
+		if(inet_ntop(res->ai_family, addr, ipaddr, sizeof(ipaddr)))
124
+		    logg("*Using ip '%s' for fetching.\n", ipaddr);
125 125
 	    }
126
-	    logg("!Could not resolve local ip address '%s': %s\n", localip, herr);
126
+	    freeaddrinfo(res);
127
+	}
128
+
129
+#else /* IPv4 */
130
+	    struct hostent *he;
131
+
132
+	if(!(he = gethostbyname(localip))) {
133
+	    logg("!Could not resolve local ip address '%s': %s\n", localip, ghbn_err(h_errno));
127 134
 	    logg("^Using standard local ip address and port for fetching.\n");
128 135
 	} else {
129
-	    struct sockaddr_in client;
130
-	    unsigned char *ia;
131
-	    char ipaddr[16];
136
+		struct sockaddr_in client;
137
+		unsigned char *ia;
138
+		char ipaddr[16];
132 139
 
133
-	    memset ((char *) &client, 0, sizeof(struct sockaddr_in));
140
+	    memset((char *) &client, 0, sizeof(client));
134 141
 	    client.sin_family = AF_INET;
135 142
 	    client.sin_addr = *(struct in_addr *) he->h_addr_list[0];
136
-	    if (bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
143
+	    if(bind(socketfd, (struct sockaddr *) &client, sizeof(struct sockaddr_in)) != 0) {
137 144
 		logg("!Could not bind to local ip address '%s': %s\n", localip, strerror(errno));
138 145
 		logg("^Using default client ip.\n");
139 146
 	    } else {
... ...
@@ -142,6 +175,7 @@ static int getclientsock(const char *localip)
142 142
 		logg("*Using ip '%s' for fetching.\n", ipaddr);
143 143
 	    }
144 144
 	}
145
+#endif
145 146
     }
146 147
 
147 148
     return socketfd;
... ...
@@ -149,22 +183,21 @@ static int getclientsock(const char *localip)
149 149
 
150 150
 static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat, int logerr)
151 151
 {
152
-	int socketfd = -1, port, i, ret;
152
+	int socketfd, port, ret;
153
+#ifdef SUPPORT_IPv6
154
+	struct addrinfo hints, *res = NULL, *rp;
155
+#else
153 156
 	struct sockaddr_in name;
154 157
 	struct hostent *host;
155
-	char ipaddr[16];
156 158
 	unsigned char *ia;
159
+	int i;
160
+#endif
161
+	char ipaddr[46];
157 162
 	const char *hostpt;
158 163
 
159 164
     if(ip)
160 165
 	strcpy(ip, "???");
161 166
 
162
-    socketfd = getclientsock(localip);
163
-    if(socketfd < 0)
164
-	return -1;
165
-
166
-    name.sin_family = AF_INET;
167
-
168 167
     if(proxy) {
169 168
 	hostpt = proxy;
170 169
 
... ...
@@ -190,31 +223,74 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
190 190
 	port = 80;
191 191
     }
192 192
 
193
-    if((host = gethostbyname(hostpt)) == NULL) {
194
-	const char *herr;
195
-	switch(h_errno) {
196
-	    case HOST_NOT_FOUND:
197
-		herr = "Host not found";
198
-		break;
193
+#ifdef SUPPORT_IPv6
194
+    memset(&hints, 0, sizeof(hints));
195
+    hints.ai_family = AF_UNSPEC;
196
+    hints.ai_socktype = SOCK_STREAM;
197
+    ret = getaddrinfo(hostpt, "80", &hints, &res);
198
+    if(ret) {
199
+	logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, gai_strerror(ret));
200
+	return -1;
201
+    }
199 202
 
200
-	    case NO_DATA:
201
-		herr = "No IP address";
202
-		break;
203
+    for(rp = res; rp; rp = rp->ai_next) {
204
+	    void *addr;
203 205
 
204
-	    case NO_RECOVERY:
205
-		herr = "Unrecoverable DNS error";
206
-		break;
206
+	if(rp->ai_family == AF_INET6)
207
+	    addr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr;
208
+	else
209
+	    addr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr;
207 210
 
208
-	    case TRY_AGAIN:
209
-		herr = "Temporary DNS error";
210
-		break;
211
+	if(!inet_ntop(rp->ai_family, addr, ipaddr, sizeof(ipaddr))) {
212
+	    logg("%cinet_ntop() failed\n", logerr ? '!' : '^');
213
+	    freeaddrinfo(res);
214
+	    return -1;
215
+	}
211 216
 
212
-	    default:
213
-		herr = "Unknown error";
214
-		break;
217
+	if((ret = mirman_check(addr, rp->ai_family, mdat))) {
218
+	    if(ret == 1)
219
+		logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
220
+	    else
221
+		logg("Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
222
+	    continue;
215 223
 	}
216
-        logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, herr);
217
-	closesocket(socketfd);
224
+
225
+	if(ip)
226
+	    strcpy(ip, ipaddr);
227
+
228
+	if(rp != res)
229
+	    logg("Trying host %s (%s)...\n", hostpt, ipaddr);
230
+
231
+	socketfd = getclientsock(localip, rp->ai_family);
232
+	if(socketfd < 0) {
233
+	    freeaddrinfo(res);
234
+	    return -1;
235
+	}
236
+
237
+#ifdef SO_ERROR
238
+	if(wait_connect(socketfd, rp->ai_addr, rp->ai_addrlen, ctimeout) == -1) {
239
+#else
240
+	if(connect(socketfd, rp->ai_addr, rp->ai_addrlen) == -1) {
241
+#endif
242
+	    logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
243
+	    closesocket(socketfd);
244
+	    continue;
245
+	} else {
246
+	    if(rp->ai_family == AF_INET)
247
+		mdat->currip[0] = *((uint32_t *) addr);
248
+	    else
249
+		memcpy(mdat->currip, addr, 4);
250
+	    mdat->af = rp->ai_family;
251
+	    freeaddrinfo(res);
252
+	    return socketfd;
253
+	}
254
+    }
255
+    freeaddrinfo(res);
256
+
257
+#else /* IPv4 */
258
+
259
+    if((host = gethostbyname(hostpt)) == NULL) {
260
+        logg("%cCan't get information about %s: %s\n", logerr ? '!' : '^', hostpt, ghbn_err(h_errno));
218 261
 	return -1;
219 262
     }
220 263
 
... ...
@@ -223,7 +299,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
223 223
 	ia = (unsigned char *) host->h_addr_list[i];
224 224
 	sprintf(ipaddr, "%u.%u.%u.%u", ia[0], ia[1], ia[2], ia[3]);
225 225
 
226
-	if((ret = mirman_check(((struct in_addr *) ia)->s_addr, mdat))) {
226
+	if((ret = mirman_check(&((struct in_addr *) ia)->s_addr, AF_INET, mdat))) {
227 227
 	    if(ret == 1)
228 228
 		logg("Ignoring mirror %s (due to previous errors)\n", ipaddr);
229 229
 	    else
... ...
@@ -237,9 +313,15 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
237 237
 	if(i > 0)
238 238
 	    logg("Trying host %s (%s)...\n", hostpt, ipaddr);
239 239
 
240
+	memset ((char *) &name, 0, sizeof(name));
241
+	name.sin_family = AF_INET;
240 242
 	name.sin_addr = *((struct in_addr *) host->h_addr_list[i]);
241 243
 	name.sin_port = htons(port);
242 244
 
245
+	socketfd = getclientsock(localip, AF_INET);
246
+	if(socketfd < 0)
247
+	    return -1;
248
+
243 249
 #ifdef SO_ERROR
244 250
 	if(wait_connect(socketfd, (struct sockaddr *) &name, sizeof(struct sockaddr_in), ctimeout) == -1) {
245 251
 #else
... ...
@@ -247,17 +329,15 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
247 247
 #endif
248 248
 	    logg("Can't connect to port %d of host %s (IP: %s)\n", port, hostpt, ipaddr);
249 249
 	    closesocket(socketfd);
250
-	    if((socketfd = getclientsock(localip)) == -1)
251
-		return -1;
252
-
253 250
 	    continue;
254 251
 	} else {
255
-	    mdat->currip = ((struct in_addr *) ia)->s_addr;
252
+	    mdat->currip[0] = ((struct in_addr *) ia)->s_addr;
253
+	    mdat->af = AF_INET;
256 254
 	    return socketfd;
257 255
 	}
258 256
     }
257
+#endif
259 258
 
260
-    closesocket(socketfd);
261 259
     return -2;
262 260
 }
263 261
 
... ...
@@ -339,7 +419,7 @@ static char *proxyauth(const char *user, const char *pass)
339 339
 
340 340
 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)
341 341
 {
342
-	char cmd[512], head[513], buffer[FILEBUFF], ipaddr[16], *ch, *tmp;
342
+	char cmd[512], head[513], buffer[FILEBUFF], ipaddr[46], *ch, *tmp;
343 343
 	int bread, cnt, sd;
344 344
 	unsigned int i, j;
345 345
 	char *remotename = NULL, *authorization = NULL;
... ...
@@ -437,7 +517,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
437 437
 
438 438
     if(bread == -1) {
439 439
 	logg("%cremote_cvdhead: Error while reading CVD header from %s\n", logerr ? '!' : '^', hostname);
440
-	mirman_update(mdat->currip, mdat, 1);
440
+	mirman_update(mdat->currip, mdat->af, mdat, 1);
441 441
 	return NULL;
442 442
     }
443 443
 
... ...
@@ -451,7 +531,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
451 451
     if((strstr(buffer, "HTTP/1.1 304")) != NULL || (strstr(buffer, "HTTP/1.0 304")) != NULL) { 
452 452
 	*ims = 0;
453 453
 	logg("OK (IMS)\n");
454
-	mirman_update(mdat->currip, mdat, 0);
454
+	mirman_update(mdat->currip, mdat->af, mdat, 0);
455 455
 	return NULL;
456 456
     } else {
457 457
 	*ims = 1;
... ...
@@ -460,7 +540,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
460 460
     if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
461 461
        !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
462 462
 	logg("%cUnknown response from remote server\n", logerr ? '!' : '^');
463
-	mirman_update(mdat->currip, mdat, 1);
463
+	mirman_update(mdat->currip, mdat->af, mdat, 1);
464 464
 	return NULL;
465 465
     }
466 466
 
... ...
@@ -478,7 +558,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
478 478
 
479 479
     if(sizeof(buffer) - i < 512) {
480 480
 	logg("%cremote_cvdhead: Malformed CVD header (too short)\n", logerr ? '!' : '^');
481
-	mirman_update(mdat->currip, mdat, 1);
481
+	mirman_update(mdat->currip, mdat->af, mdat, 1);
482 482
 	return NULL;
483 483
     }
484 484
 
... ...
@@ -487,7 +567,7 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
487 487
     for(j = 0; j < 512; j++) {
488 488
 	if(!ch || (ch && !*ch) || (ch && !isprint(ch[j]))) {
489 489
 	    logg("%cremote_cvdhead: Malformed CVD header (bad chars)\n", logerr ? '!' : '^');
490
-	    mirman_update(mdat->currip, mdat, 1);
490
+	    mirman_update(mdat->currip, mdat->af, mdat, 1);
491 491
 	    return NULL;
492 492
 	}
493 493
 	head[j] = ch[j];
... ...
@@ -495,10 +575,10 @@ static struct cl_cvd *remote_cvdhead(const char *file, const char *hostname, cha
495 495
 
496 496
     if(!(cvd = cl_cvdparse(head))) {
497 497
 	logg("%cremote_cvdhead: Malformed CVD header (can't parse)\n", logerr ? '!' : '^');
498
-	mirman_update(mdat->currip, mdat, 1);
498
+	mirman_update(mdat->currip, mdat->af, mdat, 1);
499 499
     } else {
500 500
 	logg("OK\n");
501
-	mirman_update(mdat->currip, mdat, 0);
501
+	mirman_update(mdat->currip, mdat->af, mdat, 0);
502 502
     }
503 503
 
504 504
     return cvd;
... ...
@@ -587,7 +667,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
587 587
 	if((i >= sizeof(buffer) - 1) || recv(sd, buffer + i, 1, 0) == -1) {
588 588
 #endif
589 589
 	    logg("%cgetfile: Error while reading database from %s (IP: %s)\n", logerr ? '!' : '^', hostname, ipaddr);
590
-	    mirman_update(mdat->currip, mdat, 1);
590
+	    mirman_update(mdat->currip, mdat->af, mdat, 1);
591 591
 	    closesocket(sd);
592 592
 	    return 52;
593 593
 	}
... ...
@@ -613,7 +693,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
613 613
     if(!strstr(buffer, "HTTP/1.1 200") && !strstr(buffer, "HTTP/1.0 200") &&
614 614
        !strstr(buffer, "HTTP/1.1 206") && !strstr(buffer, "HTTP/1.0 206")) {
615 615
 	logg("%cgetfile: Unknown response from remote server (IP: %s)\n", logerr ? '!' : '^', ipaddr);
616
-	mirman_update(mdat->currip, mdat, 1);
616
+	mirman_update(mdat->currip, mdat->af, mdat, 1);
617 617
 	closesocket(sd);
618 618
 	return 58;
619 619
     }
... ...
@@ -678,7 +758,7 @@ static int getfile(const char *srcfile, const char *destfile, const char *hostna
678 678
     else
679 679
         logg("Downloading %s [*]\n", srcfile);
680 680
 
681
-    mirman_update(mdat->currip, mdat, 0);
681
+    mirman_update(mdat->currip, mdat->af, mdat, 0);
682 682
     return 0;
683 683
 }
684 684
 
... ...
@@ -1203,7 +1283,7 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
1203 1203
 	time_t currtime;
1204 1204
 	int ret, updated = 0, outdated = 0, signo = 0;
1205 1205
 	unsigned int ttl;
1206
-	char ipaddr[16], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
1206
+	char ipaddr[46], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
1207 1207
 	const char *arg = NULL;
1208 1208
 	const struct cfgstruct *cpt;
1209 1209
 	struct mirdat mdat;
... ...
@@ -1213,6 +1293,9 @@ int downloadmanager(const struct cfgstruct *copt, const struct optstruct *opt, c
1213 1213
 
1214 1214
     time(&currtime);
1215 1215
     logg("ClamAV update process started at %s", ctime(&currtime));
1216
+#ifdef SUPPORT_IPv6
1217
+    logg("*Using IPv6 aware code\n");
1218
+#endif
1216 1219
 
1217 1220
 #ifndef HAVE_LIBGMP
1218 1221
     logg("SECURITY WARNING: NO SUPPORT FOR DIGITAL SIGNATURES\n");
... ...
@@ -35,6 +35,10 @@
35 35
 #include <fcntl.h>
36 36
 #include <time.h>
37 37
 
38
+#include <sys/socket.h>
39
+#include <netinet/in.h>
40
+#include <arpa/inet.h>
41
+
38 42
 #include "mirman.h"
39 43
 
40 44
 #include "libclamav/cltypes.h"
... ...
@@ -94,7 +98,7 @@ int mirman_read(const char *file, struct mirdat *mdat, uint8_t active)
94 94
     return 0;
95 95
 }
96 96
 
97
-int mirman_check(uint32_t ip, struct mirdat *mdat)
97
+int mirman_check(uint32_t *ip, int af, struct mirdat *mdat)
98 98
 {
99 99
 	unsigned int i, flevel = cl_retflevel();
100 100
 
... ...
@@ -103,7 +107,8 @@ int mirman_check(uint32_t ip, struct mirdat *mdat)
103 103
 	return 0;
104 104
 
105 105
     for(i = 0; i < mdat->num; i++) {
106
-	if(mdat->mirtab[i].atime && mdat->mirtab[i].ip == ip) {
106
+
107
+	if(mdat->mirtab[i].atime && ((af == AF_INET && mdat->mirtab[i].ip4 == *ip) || (af == AF_INET6 && !memcmp(mdat->mirtab[i].ip6, ip, 4)))) {
107 108
 
108 109
 	    if(mdat->dbflevel && (mdat->dbflevel > flevel) && (mdat->dbflevel - flevel > 3))
109 110
 		if(time(NULL) - mdat->mirtab[i].atime < 4 * 3600)
... ...
@@ -123,7 +128,7 @@ int mirman_check(uint32_t ip, struct mirdat *mdat)
123 123
     return 0;
124 124
 }
125 125
 
126
-int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
126
+int mirman_update(uint32_t *ip, int af, struct mirdat *mdat, uint8_t broken)
127 127
 {
128 128
 	unsigned int i, found = 0;
129 129
 
... ...
@@ -132,7 +137,7 @@ int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
132 132
 	return 0;
133 133
 
134 134
     for(i = 0; i < mdat->num; i++) {
135
-	if(mdat->mirtab[i].ip == ip) {
135
+	if((af == AF_INET && mdat->mirtab[i].ip4 == *ip) || (af == AF_INET6 && !memcmp(mdat->mirtab[i].ip6, ip, 4))) {
136 136
 	    found = 1;
137 137
 	    break;
138 138
 	}
... ...
@@ -160,7 +165,12 @@ int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
160 160
 	    logg("!Can't allocate memory for new element in mdat->mirtab\n");
161 161
 	    return -1;
162 162
 	}
163
-	mdat->mirtab[mdat->num].ip = ip;
163
+	if(af == AF_INET) {
164
+	    mdat->mirtab[mdat->num].ip4 = *ip;
165
+	} else {
166
+	    mdat->mirtab[mdat->num].ip4 = 0;
167
+	    memcpy(mdat->mirtab[mdat->num].ip6, ip, 4);
168
+	}
164 169
 	mdat->mirtab[mdat->num].atime = 0;
165 170
 	mdat->mirtab[mdat->num].succ = 0;
166 171
 	mdat->mirtab[mdat->num].fail = 0;
... ...
@@ -179,14 +189,16 @@ int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken)
179 179
 void mirman_list(const struct mirdat *mdat)
180 180
 {
181 181
 	unsigned int i;
182
-	unsigned char *ip;
183 182
 	time_t tm;
183
+	char ip[46];
184 184
 
185 185
 
186 186
     for(i = 0; i < mdat->num; i++) {
187 187
 	printf("Mirror #%u\n", i + 1);
188
-	ip = (unsigned char *) &mdat->mirtab[i].ip;
189
-	printf("IP: %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
188
+	if(mdat->mirtab[i].ip4)
189
+	    printf("IP: %s\n", inet_ntop(AF_INET, &mdat->mirtab[i].ip4, ip, sizeof(ip)));
190
+	else
191
+	    printf("IP: %s\n", inet_ntop(AF_INET6, mdat->mirtab[i].ip6, ip, sizeof(ip)));
190 192
 	printf("Successes: %u\n", mdat->mirtab[i].succ);
191 193
 	printf("Failures: %u\n", mdat->mirtab[i].fail);
192 194
 	tm = mdat->mirtab[i].atime;
... ...
@@ -22,25 +22,27 @@
22 22
 #include "libclamav/cltypes.h"
23 23
 
24 24
 struct mirdat_ip {
25
-    uint32_t ip;	    /* IP address */
25
+    uint32_t ip4;	    /* IPv4 address */
26 26
     uint32_t atime;	    /* last access time */
27 27
     uint32_t succ;	    /* number of successful downloads from this ip */
28 28
     uint32_t fail;	    /* number of failures */
29 29
     uint8_t ignore;	    /* ignore flag */
30
-    char res[32];	    /* reserved */
30
+    uint32_t ip6[4];	    /* IPv6 address */
31
+    char res[16];	    /* reserved */
31 32
 };
32 33
 
33 34
 struct mirdat {
34 35
     uint8_t active;
35 36
     unsigned int num;
36
-    uint32_t currip;
37
+    uint32_t currip[4];
38
+    uint32_t af;
37 39
     uint32_t dbflevel;
38 40
     struct mirdat_ip *mirtab;
39 41
 };
40 42
 
41 43
 int mirman_read(const char *file, struct mirdat *mdat, uint8_t active);
42
-int mirman_check(uint32_t ip, struct mirdat *mdat);
43
-int mirman_update(uint32_t ip, struct mirdat *mdat, uint8_t broken);
44
+int mirman_check(uint32_t *ip, int af, struct mirdat *mdat);
45
+int mirman_update(uint32_t *ip, int af, struct mirdat *mdat, uint8_t broken);
44 46
 void mirman_list(const struct mirdat *mdat);
45 47
 int mirman_write(const char *file, struct mirdat *mdat);
46 48
 void mirman_free(struct mirdat *mdat);
... ...
@@ -55,8 +55,15 @@ int notify(const char *cfgfile)
55 55
 #ifndef	C_WINDOWS
56 56
 	struct sockaddr_un server;
57 57
 #endif
58
+#ifdef SUPPORT_IPv6
59
+	struct addrinfo hints, *res;
60
+	char port[6];
61
+	const char *addr;
62
+	int ret;
63
+#else
58 64
         struct sockaddr_in server2;
59 65
 	struct hostent *he;
66
+#endif
60 67
 	struct cfgstruct *copt;
61 68
 	const struct cfgstruct *cpt;
62 69
 	int sockd, bread;
... ...
@@ -93,8 +100,49 @@ int notify(const char *cfgfile)
93 93
     } else
94 94
 #endif
95 95
     if((cpt = cfgopt(copt, "TCPSocket"))->enabled) {
96
-
97 96
 	socktype = "TCP";
97
+
98
+#if SUPPORT_IPv6
99
+	memset(&hints, 0, sizeof(hints));
100
+	hints.ai_family = AF_UNSPEC;
101
+	hints.ai_socktype = SOCK_STREAM;
102
+	snprintf(port, 5, "%d", cpt->numarg);
103
+	port[5] = 0;
104
+
105
+	if((cpt = cfgopt(copt, "TCPAddr"))->enabled)
106
+	    addr = cpt->strarg;
107
+	else
108
+	    addr = NULL;
109
+
110
+	ret = getaddrinfo(addr, port, &hints, &res);
111
+
112
+	if(ret) {
113
+	    perror("getaddrinfo()");
114
+	    logg("^Clamd was NOT notified: Can't resolve hostname %s\n", addr ? addr : "");
115
+	    freecfg(copt);
116
+	    return 1;
117
+	}
118
+
119
+	if((sockd = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
120
+	    perror("socket()");
121
+	    logg("^Clamd was NOT notified: Can't create TCP socket\n");
122
+	    freecfg(copt);
123
+	    freeaddrinfo(res);
124
+	    return 1;
125
+	}
126
+
127
+	if(connect(sockd, res->ai_addr, res->ai_addrlen) == -1) {
128
+	    perror("connect()");
129
+	    closesocket(sockd);
130
+	    logg("^Clamd was NOT notified: Can't connect to clamd on %s:%s\n", addr, port);
131
+	    freecfg(copt);
132
+	    freeaddrinfo(res);
133
+	    return 1;
134
+	}
135
+	freeaddrinfo(res);
136
+
137
+#else /* IPv4 */
138
+
98 139
 #ifdef PF_INET
99 140
 	if((sockd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
100 141
 #else
... ...
@@ -110,10 +158,11 @@ int notify(const char *cfgfile)
110 110
 	server2.sin_port = htons(cpt->numarg);
111 111
 
112 112
 	if((cpt = cfgopt(copt, "TCPAddr"))->enabled) {
113
-	    if ((he = gethostbyname(cpt->strarg)) == 0) {
113
+	    if((he = gethostbyname(cpt->strarg)) == 0) {
114 114
 		perror("gethostbyname()");
115 115
 		logg("^Clamd was NOT notified: Can't resolve hostname '%s'\n", cpt->strarg);
116 116
 		freecfg(copt);
117
+		closesocket(sockd);
117 118
 		return 1;
118 119
 	    }
119 120
 	    server2.sin_addr = *(struct in_addr *) he->h_addr_list[0];
... ...
@@ -130,6 +179,8 @@ int notify(const char *cfgfile)
130 130
 	    return 1;
131 131
 	}
132 132
 
133
+#endif
134
+
133 135
     } else {
134 136
 	logg("^Clamd was NOT notified: No socket specified in %s\n", cfgfile);
135 137
 	freecfg(copt);