Browse code

Add IPv6 support to clamd.

Shawn Webb authored on 2014/01/26 11:50:33
Showing 7 changed files
... ...
@@ -117,7 +117,8 @@ int main(int argc, char **argv)
117 117
     char *pua_cats = NULL, *pt;
118 118
     int ret, tcpsock = 0, localsock = 0, i, min_port, max_port;
119 119
     unsigned int sigs = 0;
120
-    int lsockets[2], nlsockets = 0;
120
+    int *lsockets=NULL;
121
+    unsigned int nlsockets = 0;
121 122
     unsigned int dboptions = 0;
122 123
 #ifdef C_LINUX
123 124
     STATBUF sb;
... ...
@@ -537,15 +538,48 @@ int main(int argc, char **argv)
537 537
         }
538 538
 
539 539
         if(tcpsock) {
540
-            if ((lsockets[nlsockets] = tcpserver(opts)) == -1) {
541
-                ret = 1;
542
-                break;
540
+            int *t;
541
+
542
+            opt = optget(opts, "TCPAddr");
543
+            if (opt->enabled) {
544
+                int breakout = 0;
545
+
546
+                while (opt && opt->strarg) {
547
+                    char *ipaddr = (!strcmp(opt->strarg, "all") ? NULL : opt->strarg);
548
+
549
+                    if (tcpserver(&lsockets, &nlsockets, ipaddr, opts) == -1) {
550
+                        ret = 1;
551
+                        breakout = 1;
552
+                        break;
553
+                    }
554
+
555
+                    opt = opt->nextarg;
556
+                }
557
+
558
+                if (breakout)
559
+                    break;
560
+            } else {
561
+                if (tcpserver(&lsockets, &nlsockets, NULL, opts) == -1) {
562
+                    ret = 1;
563
+                    break;
564
+                }
543 565
             }
544
-            nlsockets++;
545 566
         }
546 567
 #ifndef _WIN32
547 568
         if(localsock) {
569
+            int *t;
548 570
             mode_t sock_mode, umsk = umask(0777); /* socket is created with 000 to avoid races */
571
+
572
+            t = realloc(lsockets, sizeof(int) * (nlsockets + 1));
573
+            if (!(t)) {
574
+                if ((lsockets))
575
+                    free(lsockets);
576
+
577
+                ret = 1;
578
+                break;
579
+            }
580
+            lsockets = t;
581
+
549 582
             if ((lsockets[nlsockets] = localserver(opts)) == -1) {
550 583
                 ret = 1;
551 584
                 umask(umsk);
... ...
@@ -46,50 +46,77 @@
46 46
 #include "server.h"
47 47
 #include "tcpserver.h"
48 48
 
49
-int tcpserver(const struct optstruct *opts)
49
+int tcpserver(int **lsockets, unsigned int *nlsockets, char *ipaddr, const struct optstruct *opts)
50 50
 {
51
-    struct sockaddr_in server;
51
+    struct addrinfo hints, *info, *p;
52
+    int *sockets;
52 53
     int sockfd, backlog;
53
-    char *estr;
54
-    int true = 1;
54
+    int *t;
55
+    char *estr, port[10];
56
+    int yes = 1;
57
+    int res;
55 58
 
56
-    if (cfg_tcpsock(opts, &server, INADDR_ANY) == -1) {
57
-	logg("!TCP: Couldn't configure socket, check your configuration\n");
58
-	return -1;
59
-    }
59
+    sockets = *lsockets;
60 60
 
61
-    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
62
-	estr = strerror(errno);
63
-	logg("!TCP: socket() error: %s\n", estr);
64
-	return -1;
65
-    }
61
+    snprintf(port, sizeof(port), "%lld", optget(opts, "TCPSocket")->numarg);
66 62
 
67
-    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *) &true, sizeof(true)) == -1) {
68
-	logg("!TCP: setsocktopt(SO_REUSEADDR) error: %s\n", strerror(errno));
69
-    }
63
+    memset(&hints, 0x00, sizeof(struct addrinfo));
64
+    hints.ai_family = AF_UNSPEC;
65
+    hints.ai_socktype = SOCK_STREAM;
66
+    hints.ai_flags = AI_PASSIVE;
70 67
 
71
-    if(bind(sockfd, (struct sockaddr *) &server, (socklen_t)sizeof(struct sockaddr_in)) == -1) {
72
-	estr = strerror(errno);
73
-	logg("!TCP: bind() error: %s\n", estr);
74
-	closesocket(sockfd);
75
-	return -1;
76
-    } else {
77
-	const struct optstruct *taddr = optget(opts, "TCPAddr");
78
-	if(taddr->enabled)
79
-	    logg("#TCP: Bound to address %s on port %u\n", taddr->strarg, (unsigned int) optget(opts, "TCPSocket")->numarg);
80
-	else
81
-	    logg("#TCP: Bound to port %u\n", (unsigned int) optget(opts, "TCPSocket")->numarg);
68
+    if ((res = getaddrinfo(ipaddr, port, &hints, &info))) {
69
+        logg("!TCP: getaddrinfo: %s\n", gai_strerror(res));
70
+        return -1;
82 71
     }
83 72
 
84
-    backlog = optget(opts, "MaxConnectionQueueLength")->numarg;
85
-    logg("#TCP: Setting connection queue length to %d\n", backlog);
73
+    for (p = info; p != NULL; p = p->ai_next) {
74
+        t = realloc(sockets, sizeof(int) * (*nlsockets + 1));
75
+        if (!(t)) {
76
+            return -1;
77
+        }
78
+        sockets = t;
79
+
80
+        if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
81
+            estr = strerror(errno);
82
+            logg("!TCP: socket() error: %s\n", estr);
83
+            continue;
84
+        }
85
+
86
+        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof(yes)) == -1) {
87
+            logg("!TCP: setsocktopt(SO_REUSEADDR) error: %s\n", strerror(errno));
88
+        }
89
+
90
+        if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
91
+            estr = strerror(errno);
92
+            logg("!TCP: bind() error when trying to listen on [%s]:%s: %s\n", ipaddr, port, estr);
93
+            closesocket(sockfd);
86 94
 
87
-    if(listen(sockfd, backlog) == -1) {
88
-	estr = strerror(errno);
89
-	logg("!TCP: listen() error: %s\n", estr);
90
-	closesocket(sockfd);
91
-	return -1;
95
+            continue;
96
+        } else {
97
+            if((ipaddr))
98
+                logg("#TCP: Bound to address %s on port %u\n", ipaddr, (unsigned int) optget(opts, "TCPSocket")->numarg);
99
+            else
100
+                logg("#TCP: Bound to port %u\n", (unsigned int) optget(opts, "TCPSocket")->numarg);
101
+        }
102
+
103
+        backlog = optget(opts, "MaxConnectionQueueLength")->numarg;
104
+        logg("#TCP: Setting connection queue length to %d\n", backlog);
105
+
106
+        if(listen(sockfd, backlog) == -1) {
107
+            estr = strerror(errno);
108
+            logg("!TCP: listen() error: %s\n", estr);
109
+            closesocket(sockfd);
110
+
111
+            continue;
112
+        }
113
+
114
+        sockets[*nlsockets] = sockfd;
115
+        (*nlsockets)++;
92 116
     }
93 117
 
94
-    return sockfd;
118
+    freeaddrinfo(info);
119
+    *lsockets = sockets;
120
+
121
+    return 0;
95 122
 }
... ...
@@ -23,6 +23,6 @@
23 23
 
24 24
 #include "shared/optparser.h"
25 25
 
26
-int tcpserver(const struct optstruct *opts);
26
+int tcpserver(int **lsockets, unsigned int *nlsockets, char *ipaddr, const struct optstruct *opts);
27 27
 
28 28
 #endif
... ...
@@ -83,38 +83,50 @@ static int isremote(const struct optstruct *opts) {
83 83
     int s, ret;
84 84
     const struct optstruct *opt;
85 85
     static struct sockaddr_in testsock;
86
+    char *ipaddr;
86 87
 
87 88
 #ifndef _WIN32
88 89
     if((opt = optget(clamdopts, "LocalSocket"))->enabled) {
89
-	memset((void *)&nixsock, 0, sizeof(nixsock));
90
-	nixsock.sun_family = AF_UNIX;
91
-	strncpy(nixsock.sun_path, opt->strarg, sizeof(nixsock.sun_path));
92
-	nixsock.sun_path[sizeof(nixsock.sun_path)-1]='\0';
93
-	mainsa = (struct sockaddr *)&nixsock;
94
-	mainsasz = sizeof(nixsock);
95
-	return 0;
90
+        memset((void *)&nixsock, 0, sizeof(nixsock));
91
+        nixsock.sun_family = AF_UNIX;
92
+        strncpy(nixsock.sun_path, opt->strarg, sizeof(nixsock.sun_path));
93
+        nixsock.sun_path[sizeof(nixsock.sun_path)-1]='\0';
94
+        mainsa = (struct sockaddr *)&nixsock;
95
+        mainsasz = sizeof(nixsock);
96
+        return 0;
96 97
     }
97 98
 #endif
98 99
     if(!(opt = optget(clamdopts, "TCPSocket"))->enabled)
99
-	return 0;
100
+        return 0;
100 101
 
101 102
     mainsa = (struct sockaddr *)&tcpsock;
102 103
     mainsasz = sizeof(tcpsock);
103 104
 
104
-    if (cfg_tcpsock(clamdopts, &tcpsock, INADDR_LOOPBACK) == -1) {
105
-	logg("!Can't lookup clamd hostname: %s.\n", strerror(errno));
106
-	mainsa = NULL;
107
-	return 0;
108
-    }
109
-    memcpy((void *)&testsock, (void *)&tcpsock, sizeof(testsock));
110
-    testsock.sin_port = htons(INADDR_ANY);
111
-    if((s = socket(testsock.sin_family, SOCK_STREAM, 0)) < 0) {
112
-      logg("isremote: socket() returning: %s.\n", strerror(errno));
113
-      mainsa = NULL;
114
-      return 0;
105
+    opt = optget(clamdopts, "TCPAddr");
106
+    while (opt) {
107
+        ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg);
108
+
109
+        if (cfg_tcpsock(ipaddr, clamdopts, &tcpsock, INADDR_LOOPBACK) == -1) {
110
+            logg("!Can't lookup clamd hostname: %s.\n", strerror(errno));
111
+            mainsa = NULL;
112
+            return 0;
113
+        }
114
+
115
+        memcpy((void *)&testsock, (void *)&tcpsock, sizeof(testsock));
116
+        testsock.sin_port = htons(INADDR_ANY);
117
+        if((s = socket(testsock.sin_family, SOCK_STREAM, 0)) < 0) {
118
+            logg("isremote: socket() returning: %s.\n", strerror(errno));
119
+            mainsa = NULL;
120
+            return 0;
121
+        }
122
+
123
+        ret = (bind(s, (struct sockaddr *)&testsock, (socklen_t)sizeof(testsock)) != 0);
124
+        closesocket(s);
125
+        if (ret)
126
+            return ret;
127
+
128
+        opt = opt->nextarg;
115 129
     }
116
-    ret = (bind(s, (struct sockaddr *)&testsock, (socklen_t)sizeof(testsock)) != 0);
117
-    closesocket(s);
118 130
     return ret;
119 131
 }
120 132
 
... ...
@@ -319,25 +319,28 @@ int match_regex(const char *filename, const char *pattern)
319 319
 	return match;
320 320
 }
321 321
 
322
-int cfg_tcpsock(const struct optstruct *opts, struct sockaddr_in *tcpsock, in_addr_t defaultbind)
322
+int cfg_tcpsock(char *ipaddr, const struct optstruct *opts, struct sockaddr_in *tcpsock, in_addr_t defaultbind)
323 323
 {
324 324
     struct hostent *he;
325 325
     const struct optstruct *opt = optget(opts, "TCPSocket");
326 326
 
327 327
     if(opt->numarg > 65535)
328
-	return -1;
328
+        return -1;
329 329
 
330 330
     memset(tcpsock, 0, sizeof(*tcpsock));
331 331
     tcpsock->sin_family = AF_INET;
332 332
     tcpsock->sin_port = htons(opt->numarg);
333 333
 
334
-    if(!(opt = optget(opts, "TCPAddr"))->enabled) {
335
-	tcpsock->sin_addr.s_addr = htonl(defaultbind);
336
-	return 0;
334
+    if(!(ipaddr)) {
335
+        tcpsock->sin_addr.s_addr = htonl(defaultbind);
336
+        return 0;
337
+    }
338
+
339
+    he = gethostbyname(ipaddr);
340
+    if(!he) {
341
+        cli_errmsg("gethostbyname: %s\n", strerror(errno));
342
+        return -1;
337 343
     }
338
-    he = gethostbyname(opt->strarg);
339
-    if(!he)
340
-	return -1;
341 344
 
342 345
     tcpsock->sin_addr = *(struct in_addr *) he->h_addr_list[0];
343 346
     return 0;
... ...
@@ -51,7 +51,7 @@ int filecopy(const char *src, const char *dest);
51 51
 int daemonize(void);
52 52
 const char *get_version(void);
53 53
 int match_regex(const char *filename, const char *pattern);
54
-int cfg_tcpsock(const struct optstruct *opts, struct sockaddr_in *server, in_addr_t defaultbind);
54
+int cfg_tcpsock(char *ipaddr, const struct optstruct *opts, struct sockaddr_in *server, in_addr_t defaultbind);
55 55
 int cli_is_abspath(const char *path);
56 56
 unsigned int countlines(const char *filename);
57 57
 
... ...
@@ -217,7 +217,7 @@ const struct clam_option __clam_options[] = {
217 217
     { "TCPSocket", NULL, 0, TYPE_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_CLAMD, "A TCP port number the daemon will listen on.", "3310" },
218 218
 
219 219
     /* FIXME: add a regex for IP addr */
220
-    { "TCPAddr", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "By default clamd binds to INADDR_ANY.\nThis option allows you to restrict the TCP address and provide\nsome degree of protection from the outside world.", "127.0.0.1" },
220
+    { "TCPAddr", NULL, 0, TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "By default clamd binds to INADDR_ANY.\nThis option allows you to restrict the TCP address and provide\nsome degree of protection from the outside world.", "127.0.0.1" },
221 221
 
222 222
     { "MaxConnectionQueueLength", NULL, 0, TYPE_NUMBER, MATCH_NUMBER, 200, NULL, 0, OPT_CLAMD, "Maximum length the queue of pending connections may grow to.", "30" },
223 223