Browse code

Added --broadcast

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@931 77e5149b-7576-45b1-b177-96237e5ba77b

Nigel Horne authored on 2004/09/27 21:45:47
Showing 4 changed files
... ...
@@ -1,3 +1,9 @@
1
+Mon Sep 27 13:44:45 BST 2004 (njh)
2
+----------------------------------
3
+  * clamav-milter:	SESSIONS: try to gracefully close when shutting down
4
+		honour HAVE_IN_ADDR_T
5
+		Added --broadcast option
6
+
1 7
 Mon Sep 27 04:00:14 CEST 2004 (tk)
2 8
 ----------------------------------
3 9
   * libclamav: ignore ndb signatures in cl_scanbuff()
... ...
@@ -501,6 +501,9 @@ Changes
501 501
 		Honour LogFacility
502 502
 		When sanitising the quarantine's filename, don't sanitise
503 503
 		the directory name as well
504
+0.80b	27/9/04	Added quit() routine to tidy when shutting down
505
+		honour HAVE_IN_ADDR_T
506
+		Added --broadcast option
504 507
 
505 508
 INTERNATIONALISATION
506 509
 
... ...
@@ -26,6 +26,9 @@
26 26
  *
27 27
  * Change History:
28 28
  * $Log: clamav-milter.c,v $
29
+ * Revision 1.133  2004/09/27 12:43:23  nigelhorne
30
+ * Added --broadcast
31
+ *
29 32
  * Revision 1.132  2004/09/25 15:47:19  nigelhorne
30 33
  * Honour LogFacility
31 34
  *
... ...
@@ -407,9 +410,9 @@
407 407
  * Revision 1.6  2003/09/28 16:37:23  nigelhorne
408 408
  * Added -f flag use MaxThreads if --max-children not set
409 409
  */
410
-static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.132 2004/09/25 15:47:19 nigelhorne Exp $";
410
+static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.133 2004/09/27 12:43:23 nigelhorne Exp $";
411 411
 
412
-#define	CM_VERSION	"0.80a"
412
+#define	CM_VERSION	"0.80b"
413 413
 
414 414
 /*#define	CONFDIR	"/usr/local/etc"*/
415 415
 
... ...
@@ -493,6 +496,10 @@ int	deny_severity = LOG_NOTICE;
493 493
 typedef	unsigned short	in_port_t;
494 494
 #endif
495 495
 
496
+#ifndef	HAVE_IN_ADDR_T
497
+typedef	unsigned int	in_addr_t;
498
+#endif
499
+
496 500
 /*
497 501
  * Do not define SESSION in a production environment - it has been known to put
498 502
  * clamd into a loop when clamav-milter is restarted and sending STREAM often
... ...
@@ -622,6 +629,8 @@ static	void	clamdIsDown(void);
622 622
 static	void	*watchdog(void *a);
623 623
 #endif
624 624
 static	int	logg_facility(const char *name);
625
+static	void	quit(void);
626
+static	void	broadcast(const char *mess);
625 627
 
626 628
 static	char	clamav_version[128];
627 629
 static	int	fflag = 0;	/* force a scan, whatever */
... ...
@@ -632,6 +641,10 @@ static	int	bflag = 0;	/*
632 632
 				 * sender. This probably isn't a good idea
633 633
 				 * since most reply addresses will be fake
634 634
 				 */
635
+static	int	Bflag = 0;	/*
636
+				 * Broadcast a message when a virus is found,
637
+				 * this allows remote network management
638
+				 */
635 639
 static	int	pflag = 0;	/*
636 640
 				 * Send a warning to the postmaster only,
637 641
 				 * this means user's won't be told when someone
... ...
@@ -739,6 +752,7 @@ static	pthread_cond_t	watchdog_cond = PTHREAD_COND_INITIALIZER;
739 739
 
740 740
 static	const	char	*postmaster = "postmaster";
741 741
 static	const	char	*from = "MAILER-DAEMON";
742
+static	int	quitting;
742 743
 
743 744
 /*
744 745
  * NULL terminated whitelist of target ("to") addresses that we do NOT scan
... ...
@@ -760,6 +774,7 @@ help(void)
760 760
 
761 761
 	puts(_("\t--advisory\t\t-A\tFlag viruses rather than deleting them."));
762 762
 	puts(_("\t--bounce\t\t-b\tSend a failure message to the sender."));
763
+	puts(_("\t--broadcast\t\t-B\tBroadcast to a network manager when a virus is found."));
763 764
 	puts(_("\t--config-file=FILE\t-c FILE\tRead configuration from FILE."));
764 765
 	puts(_("\t--debug\t\t\t-D\tPrint debug messages."));
765 766
 	puts(_("\t--dont-log-clean\t-C\tDon't add an entry to syslog that a mail is clean."));
... ...
@@ -845,9 +860,9 @@ main(int argc, char **argv)
845 845
 	for(;;) {
846 846
 		int opt_index = 0;
847 847
 #ifdef	CL_DEBUG
848
-		const char *args = "a:Abc:CDfF:lm:nNop:PqQ:dhHs:St:T:U:Vx:";
848
+		const char *args = "a:AbBc:CDfF:lm:nNop:PqQ:dhHs:St:T:U:Vx:";
849 849
 #else
850
-		const char *args = "a:Abc:CDfF:lm:nNop:PqQ:dhHs:St:T:U:V";
850
+		const char *args = "a:AbBc:CDfF:lm:nNop:PqQ:dhHs:St:T:U:V";
851 851
 #endif
852 852
 
853 853
 		static struct option long_options[] = {
... ...
@@ -861,6 +876,9 @@ main(int argc, char **argv)
861 861
 				"bounce", 0, NULL, 'b'
862 862
 			},
863 863
 			{
864
+				"broadcast", 0, NULL, 'B'
865
+			},
866
+			{
864 867
 				"config-file", 1, NULL, 'c'
865 868
 			},
866 869
 			{
... ...
@@ -963,6 +981,9 @@ main(int argc, char **argv)
963 963
 			case 'b':	/* bounce worms/viruses */
964 964
 				bflag++;
965 965
 				break;
966
+			case 'B':	/* broadcast */
967
+				Bflag++;
968
+				break;
966 969
 			case 'c':	/* where is clamd.conf? */
967 970
 				cfgfile = optarg;
968 971
 				break;
... ...
@@ -1372,6 +1393,8 @@ main(int argc, char **argv)
1372 1372
 #endif
1373 1373
 	}
1374 1374
 
1375
+	atexit(quit);
1376
+
1375 1377
 #ifdef	SESSION
1376 1378
 	pthread_create(&tid, NULL, watchdog, NULL);
1377 1379
 #endif
... ...
@@ -1570,6 +1593,7 @@ pingServer(int serverNumber)
1570 1570
 	 * Also version command is verbose: says "clamd / ClamAV version"
1571 1571
 	 * instead of "clamAV version"
1572 1572
 	 */
1573
+	cli_dbgmsg("pingServer%d: sending VERSION\n", serverNumber);
1573 1574
 	if(send(sock, "VERSION\n", 8, 0) < 8) {
1574 1575
 		perror("send");
1575 1576
 		close(sock);
... ...
@@ -1799,6 +1823,9 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
1799 1799
 #endif
1800 1800
 	const char *remoteIP;
1801 1801
 
1802
+	if(quitting)
1803
+		return cl_error;
1804
+
1802 1805
 	if(ctx == NULL) {
1803 1806
 		if(use_syslog)
1804 1807
 			syslog(LOG_ERR, _("clamfi_connect: ctx is null"));
... ...
@@ -2680,6 +2707,8 @@ clamfi_eom(SMFICTX *ctx)
2680 2680
 
2681 2681
 		snprintf(reject, sizeof(reject) - 1, _("%s detected by ClamAV - http://www.clamav.net"), virusname);
2682 2682
 		smfi_setreply(ctx, (char *)privdata->rejectCode, "5.7.1", reject);
2683
+		if(Bflag)
2684
+			broadcast(mess);
2683 2685
 	}
2684 2686
 	clamfi_cleanup(ctx);
2685 2687
 
... ...
@@ -3759,7 +3788,7 @@ watchdog(void *a)
3759 3759
 
3760 3760
 	assert(cmdSockets != NULL);
3761 3761
 
3762
-	for(;;) {
3762
+	while(!quitting) {
3763 3763
 		int i;
3764 3764
 		struct timespec ts;
3765 3765
 		struct timeval tp;
... ...
@@ -3936,3 +3965,80 @@ logg_facility(const char *name)
3936 3936
 
3937 3937
 	return -1;
3938 3938
 }
3939
+
3940
+static void
3941
+quit(void)
3942
+{
3943
+#ifdef	SESSION
3944
+	int i;
3945
+
3946
+	quitting++;
3947
+
3948
+	if(use_syslog)
3949
+		syslog(LOG_INFO, _("Stopping: %s"), clamav_version);
3950
+
3951
+	pthread_mutex_lock(&sstatus_mutex);
3952
+	for(i = 0; i < max_children; i++) {
3953
+		const int sock = cmdSockets[i];
3954
+
3955
+		/*
3956
+		 * Check all free sessions are still usable
3957
+		 * This could take some time with many free
3958
+		 * sessions to slow remote servers, so only do this
3959
+		 * when the system is quiet (not 100% accurate when
3960
+		 * determining this since n_children isn't locked but
3961
+		 * that doesn't really matter)
3962
+		 */
3963
+		cli_dbgmsg("quit: close server %d\n", i);
3964
+		if(cmdSocketsStatus[i] == CMDSOCKET_FREE) {
3965
+			send(sock, "END\n", 4, 0);
3966
+			shutdown(sock, SHUT_WR);
3967
+			cmdSocketsStatus[i] = CMDSOCKET_DOWN;
3968
+			pthread_mutex_unlock(&sstatus_mutex);
3969
+			close(sock);
3970
+			pthread_mutex_lock(&sstatus_mutex);
3971
+		}
3972
+	}
3973
+	pthread_mutex_unlock(&sstatus_mutex);
3974
+#else
3975
+	quitting++;
3976
+
3977
+	if(use_syslog)
3978
+		syslog(LOG_INFO, _("Stopping: %s"), clamav_version);
3979
+#endif
3980
+}
3981
+
3982
+static void
3983
+broadcast(const char *mess)
3984
+{
3985
+	int on;
3986
+	struct sockaddr_in s;
3987
+	const sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
3988
+
3989
+	if(sock < 0) {
3990
+		perror("socket");
3991
+		return;
3992
+	}
3993
+
3994
+	/*
3995
+	 * SO_BROADCAST doesn't sent to all NICs on Linux, it only broadcasts
3996
+	 * on eth0. You can use SO_BINDTODEVICE to get around that, but you
3997
+	 * need to have uid == 0 for that
3998
+	 */
3999
+	on = 1;
4000
+	if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (int *)&on, sizeof(on)) < 0) {
4001
+		perror("setsockopt");
4002
+		close(sock);
4003
+		return;
4004
+	}
4005
+
4006
+	memset(&s, '\0', sizeof(struct sockaddr_in));
4007
+	s.sin_family = AF_INET;
4008
+	s.sin_port = (in_port_t)htons(tcpSocket);
4009
+	s.sin_addr.s_addr = htonl(INADDR_BROADCAST);
4010
+
4011
+	if(sendto(sock, mess, strlen(mess), 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0)
4012
+		perror("sendto");
4013
+
4014
+	close(sock);
4015
+}
... ...
@@ -63,6 +63,12 @@ Send a failure message to the sender, and to the postmaster.
63 63
 fake their source address, so this option is not recommended ].
64 64
 See also \-\-noreject.
65 65
 .TP
66
+\fB\-B, \-\-broadcast\fR
67
+When a virus is intercepted, broadcast a UDP message to the TCPSocket port set
68
+in \fBclamd.conf\fR.
69
+A future network management program (yet to be written) will intercept these
70
+broadcasts to raise a warning on the operator's desk.
71
+.TP
66 72
 \fB-C, \-\-dont-log-clean\fR
67 73
 Messages without viruses are usually logged if SysLog is set in
68 74
 \fBclamd.conf\fR since it gives a feel-good factor.
... ...
@@ -185,7 +191,7 @@ There is no support for IPv6.
185 185
 clamav\-milter \-ol local:/var/run/clamav/clmilter.sock
186 186
 .SH "AUTHOR"
187 187
 .LP
188
-Nigel Horne <njh@clamav.net>
188
+Nigel Horne <njh@bandsman.co.uk>
189 189
 .SH "SEE ALSO"
190 190
 .LP
191 191
 clamd(8), clamscan(1), freshclam(1), sigtool(1), clamd.conf(5), hosts_access(5)