Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Oct 1995 00:13:27 -0700 (PDT)
From:      Lyndon Nerenberg <lyndon@orthanc.com>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/768: rwhod does not support multicast (+FIX)
Message-ID:  <199510060713.AAA00451@multivac.orthanc.com>
Resent-Message-ID: <199510060720.AAA14877@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         768
>Category:       bin
>Synopsis:       rwhod does not support multicast (+FIX)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Oct  6 00:20:03 PDT 1995
>Last-Modified:
>Originator:     Lyndon Nerenberg
>Organization:
Orthanc Systems: Internet and UNIX consulting
___________________________________________________________
lyndon@orthanc.com || canada!lyndon || Fax: +1 604 561 2067
                 http://www.orthanc.com/
>Release:        FreeBSD 2.0.5-RELEASE i386
>Environment:

	

>Description:

	rwhod has been extended to support multicast broascasts (sic).
	This is highly useful when monitoring machines on disparate
	networks. FreeBSD doesn't support this (yet).

>How-To-Repeat:

	

>Fix:
	
	The appended diff patches /usr/src/usr.sbin/rwhod/rwhod.[c8]
	to include support for multicast. It also adds a definition
	for _PATH_KERNEL to /usr/src/include/paths.h. I'm not sure
	about the latter wrt POSIX (nee _PATH_UNIX), however I feel the
	inclusion of _PATH_KERNEL would be useful in other contexts
	(and the new rwhod.c requires it).

	This code was lifted verbatim from BSD/OS 1.1 (one line
	had to be changed). It's an older CSRG version with Stanford U
	patches. No BSDi copyrights were found anywhere in the code.


===================================================================
RCS file: include/paths.h,v
retrieving revision 1.1
diff -c -r1.1 include/paths.h
*** 1.1	1995/10/06 06:45:24
--- include/paths.h	1995/10/06 06:46:03
***************
*** 60,65 ****
--- 60,66 ----
  #define	_PATH_SHELLS	"/etc/shells"
  #define	_PATH_TTY	"/dev/tty"
  #define	_PATH_UNIX	"don't use _PATH_UNIX"
+ #define _PATH_KERNEL	"/kernel"
  #define	_PATH_VI	"/usr/bin/vi"
  
  /* Provide trailing slash, since mostly used for building pathnames. */
===================================================================
RCS file: usr.sbin/rwhod/rwhod.c,v
retrieving revision 1.1
diff -c -r1.1 usr.sbin/rwhod/rwhod.c
*** 1.1	1995/10/06 06:41:36
--- usr.sbin/rwhod/rwhod.c	1995/10/06 06:44:59
***************
*** 1,6 ****
  /*
!  * Copyright (c) 1983, 1993
!  *	The Regents of the University of California.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
--- 1,6 ----
  /*
!  * Copyright (c) 1983 The Regents of the University of California.
!  * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
***************
*** 32,44 ****
   */
  
  #ifndef lint
! static char copyright[] =
! "@(#) Copyright (c) 1983, 1993\n\
! 	The Regents of the University of California.  All rights reserved.\n";
  #endif /* not lint */
  
  #ifndef lint
! static char sccsid[] = "@(#)rwhod.c	8.1 (Berkeley) 6/6/93";
  #endif /* not lint */
  
  #include <sys/param.h>
--- 32,44 ----
   */
  
  #ifndef lint
! char copyright[] =
! "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
!  All rights reserved.\n";
  #endif /* not lint */
  
  #ifndef lint
! static char sccsid[] = "@(#)rwhod.c	5.20 (Berkeley) 3/2/91 plus MULTICAST 1.2";
  #endif /* not lint */
  
  #include <sys/param.h>
***************
*** 46,70 ****
  #include <sys/stat.h>
  #include <sys/signal.h>
  #include <sys/ioctl.h>
! #include <sys/sysctl.h>
  
  #include <net/if.h>
- #include <net/if_dl.h>
- #include <net/route.h>
  #include <netinet/in.h>
  #include <protocols/rwhod.h>
  
  #include <ctype.h>
  #include <errno.h>
- #include <fcntl.h>
  #include <netdb.h>
! #include <paths.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <syslog.h>
- #include <unistd.h>
  #include <utmp.h>
  
  /*
   * Alarm interval. Don't forget to change the down time check in ruptime
--- 46,117 ----
  #include <sys/stat.h>
  #include <sys/signal.h>
  #include <sys/ioctl.h>
! #include <sys/file.h>
  
  #include <net/if.h>
  #include <netinet/in.h>
+ 
+ #include <arpa/inet.h>
  #include <protocols/rwhod.h>
  
  #include <ctype.h>
  #include <errno.h>
  #include <netdb.h>
! #include <nlist.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <syslog.h>
  #include <utmp.h>
+ #include <unistd.h>
+ #include <paths.h>
+ 
+ int	getloadavg __P((double *, int));
+ 
+ /*
+  * This version of Berkeley's rwhod has been modified to use IP multicast
+  * datagrams, under control of new command-line options:
+  *
+  *	rwhod -m	causes rwhod to use IP multicast (instead of
+  *			broadcast or unicast) on all interfaces that have
+  *			the IFF_MULTICAST flag set in their "ifnet" structs
+  *			(excluding the loopback interface).  The multicast
+  *			reports are sent with a time-to-live of 1, to prevent
+  *			forwarding beyond the directly-connected subnet(s).
+  *
+  *	rwhod -M <ttl>	causes rwhod to send IP multicast datagrams with a
+  *			time-to-live of <ttl>, via a SINGLE interface rather
+  *			than all interfaces.  <ttl> must be between 0 and
+  *			MAX_MULTICAST_SCOPE, defined below.  Note that "-M 1"
+  *			is different than "-m", in that "-M 1" specifies
+  *			transmission on one interface only; the two modes
+  *			are exclusive.
+  *
+  *
+  * When "-m" is used, the program accepts multicast rwhod reports from all
+  * multicast-capable interfaces.  If a <ttl> argument is given, it accepts
+  * multicast reports from only one interface, the one on which reports are
+  * sent (which may be controlled via the host's routing table).  Regardless
+  * of options, the program accepts broadcast or unicast reports from
+  * all interfaces.  Thus, this program will hear the reports of old,
+  * non-multicasting rwhods, but, if multicasting is used, those old rwhods
+  * won't hear the reports generated by this program.
+  *
+  *                  -- Steve Deering, Stanford University, February 1989
+  */
+ 
+ #define NO_MULTICAST		0	  /* multicast modes */
+ #define PER_INTERFACE_MULTICAST	1
+ #define SCOPED_MULTICAST	2
+ 
+ #define MAX_MULTICAST_SCOPE	32	  /* "site-wide", by convention */
+ 
+ #define INADDR_WHOD_GROUP (u_long)0xe0000103      /* 224.0.1.3 */
+ 					  /* (belongs in protocols/rwhod.h) */
+ 
+ int			multicast_mode  = NO_MULTICAST;
+ int			multicast_scope;
+ struct sockaddr_in	multicast_addr;
  
  /*
   * Alarm interval. Don't forget to change the down time check in ruptime
***************
*** 75,88 ****
  char	myname[MAXHOSTNAMELEN];
  
  /*
!  * We communicate with each neighbor in a list constructed at the time we're
!  * started up.  Neighbors are currently directly connected via a hardware
!  * interface.
   */
  struct	neighbor {
  	struct	neighbor *n_next;
  	char	*n_name;		/* interface name */
! 	struct	sockaddr *n_addr;		/* who to send to */
  	int	n_addrlen;		/* size of address */
  	int	n_flags;		/* should forward?, interface flags */
  };
--- 122,136 ----
  char	myname[MAXHOSTNAMELEN];
  
  /*
!  * We communicate with each neighbor in
!  * a list constructed at the time we're
!  * started up.  Neighbors are currently
!  * directly connected via a hardware interface.
   */
  struct	neighbor {
  	struct	neighbor *n_next;
  	char	*n_name;		/* interface name */
! 	char	*n_addr;		/* who to send to */
  	int	n_addrlen;		/* size of address */
  	int	n_flags;		/* should forward?, interface flags */
  };
***************
*** 92,170 ****
  struct	servent *sp;
  int	s, utmpf;
  
! #define	WHDRSIZE	(sizeof(mywd) - sizeof(mywd.wd_we))
  
- int	 configure __P((int));
- void	 getboottime __P((int));
- void	 onalrm __P((int));
- void	 quit __P((char *));
- void	 rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
- int	 verify __P((char *));
  #ifdef DEBUG
! char	*interval __P((int, char *));
! void	 Sendto __P((int, char *, int, int, char *, int));
! #define	 sendto Sendto
  #endif
  
  int
  main(argc, argv)
  	int argc;
! 	char argv[];
  {
! 	struct sockaddr_in from;
  	struct stat st;
  	char path[64];
- 	int on = 1;
- 	char *cp;
- 	struct sockaddr_in sin;
  
  	if (getuid()) {
  		fprintf(stderr, "rwhod: not super user\n");
  		exit(1);
  	}
  	sp = getservbyname("who", "udp");
  	if (sp == NULL) {
  		fprintf(stderr, "rwhod: udp/who: unknown service\n");
  		exit(1);
  	}
! #ifndef DEBUG
! 	daemon(1, 0);
! #endif
  	if (chdir(_PATH_RWHODIR) < 0) {
! 		(void)fprintf(stderr, "rwhod: %s: %s\n",
! 		    _PATH_RWHODIR, strerror(errno));
  		exit(1);
  	}
! 	(void) signal(SIGHUP, getboottime);
! 	openlog("rwhod", LOG_PID, LOG_DAEMON);
  	/*
  	 * Establish host name as returned by system.
  	 */
! 	if (gethostname(myname, sizeof(myname) - 1) < 0) {
  		syslog(LOG_ERR, "gethostname: %m");
  		exit(1);
  	}
! 	if ((cp = index(myname, '.')) != NULL)
  		*cp = '\0';
! 	strncpy(mywd.wd_hostname, myname, sizeof(myname) - 1);
  	utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
  	if (utmpf < 0) {
  		syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
  		exit(1);
  	}
! 	getboottime(0);
  	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  		syslog(LOG_ERR, "socket: %m");
  		exit(1);
  	}
! 	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
  		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
  		exit(1);
  	}
! 	memset(&sin, 0, sizeof(sin));
  	sin.sin_family = AF_INET;
  	sin.sin_port = sp->s_port;
! 	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  		syslog(LOG_ERR, "bind: %m");
  		exit(1);
  	}
--- 140,251 ----
  struct	servent *sp;
  int	s, utmpf;
  
! #define	WHDRSIZE	(sizeof (mywd) - sizeof (mywd.wd_we))
! 
! int	configure __P((int));
! void	getkmem __P((int));
! void	onalrm __P((int));
! int	verify __P((char *));
  
  #ifdef DEBUG
! int	prsend __P((int, const void *, int, int, const struct sockaddr *, int));
! #define	sendto prsend
  #endif
  
  int
  main(argc, argv)
  	int argc;
! 	char *argv[];
  {
! 	int ch, on, debug;
! 	char *cp;
  	struct stat st;
+ 	struct sockaddr_in from, sin;
  	char path[64];
  
  	if (getuid()) {
  		fprintf(stderr, "rwhod: not super user\n");
  		exit(1);
  	}
+ 	debug = 0;
+ 	while ((ch = getopt(argc, argv, "dmM:")) != EOF) {
+ 		switch (ch) {
+ 
+ 		case 'd':
+ 			debug = 1;
+ 			break;
+ 
+ 		case 'm':
+ 			multicast_mode = PER_INTERFACE_MULTICAST;
+ 			break;
+ 
+ 		case 'M':
+ 			multicast_mode  = SCOPED_MULTICAST;
+ 			multicast_scope = strtol(optarg, &cp, 10);
+ 			if (cp == optarg || *cp ||
+ 			    (u_int)multicast_scope > MAX_MULTICAST_SCOPE) {
+ 				fprintf(stderr,
+ 				    "rwhod: ttl must not exceed %u\n",
+ 				    MAX_MULTICAST_SCOPE);
+ 				exit(1);
+ 			}
+ 			break;
+ 
+ 		default:
+ 			goto usage;
+ 		}
+ 	}
+ 	if (optind < argc) {
+ usage:
+ 		fprintf(stderr, "usage: rwhod [ -d ] [ -m | -M ttl ]\n");
+ 		exit(1);
+ 	}
+ 
+ 	/* from now on, all errors go via syslog only */
+ 	openlog("rwhod", LOG_PID, debug ? LOG_DAEMON|LOG_PERROR : LOG_DAEMON);
  	sp = getservbyname("who", "udp");
  	if (sp == NULL) {
  		fprintf(stderr, "rwhod: udp/who: unknown service\n");
+ 		syslog(LOG_ERR, "udp/who: unknown service");
  		exit(1);
  	}
! 	if (!debug)
! 		daemon(1, 0);
  	if (chdir(_PATH_RWHODIR) < 0) {
! 		syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR);
  		exit(1);
  	}
! 	(void) signal(SIGHUP, getkmem);
  	/*
  	 * Establish host name as returned by system.
  	 */
! 	if (gethostname(myname, sizeof (myname) - 1) < 0) {
  		syslog(LOG_ERR, "gethostname: %m");
  		exit(1);
  	}
! 	if ((cp = strchr(myname, '.')) != NULL)
  		*cp = '\0';
! 	strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
  	utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644);
  	if (utmpf < 0) {
  		syslog(LOG_ERR, "%s: %m", _PATH_UTMP);
  		exit(1);
  	}
! 	getkmem(0);
  	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  		syslog(LOG_ERR, "socket: %m");
  		exit(1);
  	}
! 	on = 1;
! 	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
  		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
  		exit(1);
  	}
! 	bzero(&sin, sizeof(sin));
  	sin.sin_family = AF_INET;
+ 	multicast_addr.sin_family = AF_INET;
  	sin.sin_port = sp->s_port;
! 	if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  		syslog(LOG_ERR, "bind: %m");
  		exit(1);
  	}
***************
*** 174,182 ****
  	onalrm(0);
  	for (;;) {
  		struct whod wd;
! 		int cc, whod, len = sizeof(from);
  
! 		cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0,
  			(struct sockaddr *)&from, &len);
  		if (cc <= 0) {
  			if (cc < 0 && errno != EINTR)
--- 255,263 ----
  	onalrm(0);
  	for (;;) {
  		struct whod wd;
! 		int cc, whod, len = sizeof (from);
  
! 		cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
  			(struct sockaddr *)&from, &len);
  		if (cc <= 0) {
  			if (cc < 0 && errno != EINTR)
***************
*** 207,213 ****
  			syslog(LOG_WARNING, "%s: %m", path);
  			continue;
  		}
! #if ENDIAN != BIG_ENDIAN
  		{
  			int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
  			struct whoent *we;
--- 288,294 ----
  			syslog(LOG_WARNING, "%s: %m", path);
  			continue;
  		}
! #if BYTE_ORDER != BIG_ENDIAN
  		{
  			int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
  			struct whoent *we;
***************
*** 259,279 ****
  struct	utmp *utmp;
  int	alarmcount;
  
  void
! onalrm(signo)
! 	int signo;
  {
  	register struct neighbor *np;
  	register struct whoent *we = mywd.wd_we, *wlast;
  	register int i;
  	struct stat stb;
- 	double avenrun[3];
- 	time_t now;
  	int cc;
  
- 	now = time(NULL);
  	if (alarmcount % 10 == 0)
! 		getboottime(0);
  	alarmcount++;
  	(void) fstat(utmpf, &stb);
  	if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) {
--- 340,361 ----
  struct	utmp *utmp;
  int	alarmcount;
  
+ /* ARGSUSED */
  void
! onalrm(sig)
! 	int sig;
  {
  	register struct neighbor *np;
  	register struct whoent *we = mywd.wd_we, *wlast;
  	register int i;
  	struct stat stb;
  	int cc;
+ 	double avenrun[3];
+ 	time_t now = time((time_t *)NULL);
+ 	char *strerror();
  
  	if (alarmcount % 10 == 0)
! 		getkmem(0);
  	alarmcount++;
  	(void) fstat(utmpf, &stb);
  	if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) {
***************
*** 284,310 ****
  				utmp = (struct utmp *)realloc(utmp, utmpsize);
  			else
  				utmp = (struct utmp *)malloc(utmpsize);
! 			if (! utmp) {
  				fprintf(stderr, "rwhod: malloc failed\n");
  				utmpsize = 0;
  				goto done;
  			}
  		}
! 		(void) lseek(utmpf, (off_t)0, L_SET);
  		cc = read(utmpf, (char *)utmp, stb.st_size);
  		if (cc < 0) {
  			fprintf(stderr, "rwhod: %s: %s\n",
  			    _PATH_UTMP, strerror(errno));
  			goto done;
  		}
! 		wlast = &mywd.wd_we[1024 / sizeof(struct whoent) - 1];
! 		utmpent = cc / sizeof(struct utmp);
  		for (i = 0; i < utmpent; i++)
  			if (utmp[i].ut_name[0]) {
! 				memcpy(we->we_utmp.out_line, utmp[i].ut_line,
! 				   sizeof(utmp[i].ut_line));
! 				memcpy(we->we_utmp.out_name, utmp[i].ut_name,
! 				   sizeof(utmp[i].ut_name));
  				we->we_utmp.out_time = htonl(utmp[i].ut_time);
  				if (we >= wlast)
  					break;
--- 366,392 ----
  				utmp = (struct utmp *)realloc(utmp, utmpsize);
  			else
  				utmp = (struct utmp *)malloc(utmpsize);
! 			if (utmp == NULL) {
  				fprintf(stderr, "rwhod: malloc failed\n");
  				utmpsize = 0;
  				goto done;
  			}
  		}
! 		(void) lseek(utmpf, (long)0, L_SET);
  		cc = read(utmpf, (char *)utmp, stb.st_size);
  		if (cc < 0) {
  			fprintf(stderr, "rwhod: %s: %s\n",
  			    _PATH_UTMP, strerror(errno));
  			goto done;
  		}
! 		wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
! 		utmpent = cc / sizeof (struct utmp);
  		for (i = 0; i < utmpent; i++)
  			if (utmp[i].ut_name[0]) {
! 				bcopy(utmp[i].ut_line, we->we_utmp.out_line,
! 				   sizeof (utmp[i].ut_line));
! 				bcopy(utmp[i].ut_name, we->we_utmp.out_name,
! 				   sizeof (utmp[i].ut_name));
  				we->we_utmp.out_time = htonl(utmp[i].ut_time);
  				if (we >= wlast)
  					break;
***************
*** 328,343 ****
  			we->we_idle = htonl(now - stb.st_atime);
  		we++;
  	}
! 	(void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0]));
  	for (i = 0; i < 3; i++)
  		mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
  	cc = (char *)we - (char *)&mywd;
  	mywd.wd_sendtime = htonl(time(0));
  	mywd.wd_vers = WHODVERSION;
  	mywd.wd_type = WHODTYPE_STATUS;
! 	for (np = neighbors; np != NULL; np = np->n_next)
! 		(void)sendto(s, (char *)&mywd, cc, 0,
! 				np->n_addr, np->n_addrlen);
  	if (utmpent && chdir(_PATH_RWHODIR)) {
  		syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR);
  		exit(1);
--- 410,446 ----
  			we->we_idle = htonl(now - stb.st_atime);
  		we++;
  	}
! 	(void) getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0]));
  	for (i = 0; i < 3; i++)
  		mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
  	cc = (char *)we - (char *)&mywd;
  	mywd.wd_sendtime = htonl(time(0));
  	mywd.wd_vers = WHODVERSION;
  	mywd.wd_type = WHODTYPE_STATUS;
! 	if (multicast_mode == SCOPED_MULTICAST) {
! 		(void) sendto(s, (char *)&mywd, cc, 0,
! 		    (struct sockaddr *)&multicast_addr, sizeof(multicast_addr));
! 	}
! 	else for (np = neighbors; np != NULL; np = np->n_next) {
! 		if (multicast_mode == PER_INTERFACE_MULTICAST &&
! 		    np->n_flags & IFF_MULTICAST) {
! 			/*
! 			 * Select the outgoing interface for the multicast.
! 			 */
! 			if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
! 			    &(((struct sockaddr_in *)np->n_addr)->sin_addr),
! 			    sizeof(struct in_addr)) < 0) {
! 				syslog(LOG_ERR,
! 					"setsockopt IP_MULTICAST_IF: %m");
! 				exit(1);
! 			}
! 			(void) sendto(s, (char *)&mywd, cc, 0,
! 				(struct sockaddr *)&multicast_addr,
! 				sizeof(multicast_addr));
! 		} else
! 			(void) sendto(s, (char *)&mywd, cc, 0,
! 				(struct sockaddr *)np->n_addr, np->n_addrlen);
! 	}
  	if (utmpent && chdir(_PATH_RWHODIR)) {
  		syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR);
  		exit(1);
***************
*** 346,396 ****
  	(void) alarm(AL_INTERVAL);
  }
  
  void
! getboottime(signo)
! 	int signo;
! {
! 	int mib[2];
! 	size_t size;
! 	struct timeval tm;
! 
! 	mib[0] = CTL_KERN;
! 	mib[1] = KERN_BOOTTIME;
! 	size = sizeof(tm);
! 	if (sysctl(mib, 2, &tm, &size, NULL, 0) == -1) {
! 		syslog(LOG_ERR, "cannot get boottime: %m");
! 		exit(1);
! 	}
! 	mywd.wd_boottime = htonl(tm.tv_sec);
! }
! 
! void
! quit(msg)
! 	char *msg;
  {
! 	syslog(LOG_ERR, msg);
! 	exit(1);
! }
! 
! #define ROUNDUP(a) \
! 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
! #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
! 
! void
! rt_xaddrs(cp, cplim, rtinfo)
! 	register caddr_t cp, cplim;
! 	register struct rt_addrinfo *rtinfo;
! {
! 	register struct sockaddr *sa;
! 	register int i;
! 
! 	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
! 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
! 		if ((rtinfo->rti_addrs & (1 << i)) == 0)
! 			continue;
! 		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
! 		ADVANCE(cp, sa);
! 	}
  }
  
  /*
--- 449,492 ----
  	(void) alarm(AL_INTERVAL);
  }
  
+ /* ARGSUSED */
  void
! getkmem(sig)
! 	int sig;
  {
! 	static ino_t kernel_ino;
! 	static time_t kernel_ctime;
! 	int kmemf;
! 	struct stat sb;
! 	static struct nlist nl[] = {
! #define	NL_BOOTTIME	0
! 		{ "_boottime" },
! 		0
! 	};
! 
! 	if (stat(_PATH_KERNEL, &sb) < 0) {
! 		if (kernel_ctime)
! 			return;
! 	} else {
! 		if (sb.st_ctime == kernel_ctime && sb.st_ino == kernel_ino)
! 			return;
! 		kernel_ctime = sb.st_ctime;
! 		kernel_ino = sb.st_ino;
! 	}
! 	while (nlist(_PATH_KERNEL, nl)) {
! 		syslog(LOG_WARNING, "%s: namelist botch", _PATH_KERNEL);
! 		sleep(300);
! 	}
! 	kmemf = open(_PATH_KMEM, O_RDONLY, 0);
! 	if (kmemf < 0) {
! 		syslog(LOG_ERR, "%s: %m", _PATH_KMEM);
! 		exit(1);
! 	}
! 	(void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, L_SET);
! 	(void) read(kmemf, (char *)&mywd.wd_boottime,
! 	    sizeof (mywd.wd_boottime));
! 	(void) close(kmemf);
! 	mywd.wd_boottime = htonl(mywd.wd_boottime);
  }
  
  /*
***************
*** 401,499 ****
  configure(s)
  	int s;
  {
  	register struct neighbor *np;
! 	register struct if_msghdr *ifm;
! 	register struct ifa_msghdr *ifam;
! 	struct sockaddr_dl *sdl;
! 	size_t needed;
! 	int mib[6], flags = 0, len;
! 	char *buf, *lim, *next;
! 	struct rt_addrinfo info;
! 
! 	mib[0] = CTL_NET;
! 	mib[1] = PF_ROUTE;
! 	mib[2] = 0;
! 	mib[3] = AF_INET;
! 	mib[4] = NET_RT_IFLIST;
! 	mib[5] = 0;
! 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
! 		quit("route-sysctl-estimate");
! 	if ((buf = malloc(needed)) == NULL)
! 		quit("malloc");
! 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
! 		quit("actual retrieval of interface table");
! 	lim = buf + needed;
! 
! 	sdl = NULL;		/* XXX just to keep gcc -Wall happy */
! 	for (next = buf; next < lim; next += ifm->ifm_msglen) {
! 		ifm = (struct if_msghdr *)next;
! 		if (ifm->ifm_type == RTM_IFINFO) {
! 			sdl = (struct sockaddr_dl *)(ifm + 1);
! 			flags = ifm->ifm_flags;
! 			continue;
! 		}
! 		if ((flags & IFF_UP) == 0 ||
! 		    (flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
! 			continue;
! 		if (ifm->ifm_type != RTM_NEWADDR)
! 			quit("out of sync parsing NET_RT_IFLIST");
! 		ifam = (struct ifa_msghdr *)ifm;
! 		info.rti_addrs = ifam->ifam_addrs;
! 		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
! 			&info);
! 		/* gag, wish we could get rid of Internet dependencies */
! #define dstaddr	info.rti_info[RTAX_BRD]
! #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr
! #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port
! 		if (dstaddr == 0 || dstaddr->sa_family != AF_INET)
  			continue;
- 		PORT_SA(dstaddr) = sp->s_port;
  		for (np = neighbors; np != NULL; np = np->n_next)
! 			if (memcmp(sdl->sdl_data, np->n_name,
! 				   sdl->sdl_nlen) == 0 &&
! 			    IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr))
  				break;
  		if (np != NULL)
  			continue;
! 		len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1;
! 		np = (struct neighbor *)malloc(len);
  		if (np == NULL)
! 			quit("malloc of neighbor structure");
! 		memset(np, 0, len);
! 		np->n_flags = flags;
! 		np->n_addr = (struct sockaddr *)(np + 1);
! 		np->n_addrlen = dstaddr->sa_len;
! 		np->n_name = np->n_addrlen + (char *)np->n_addr;
  		np->n_next = neighbors;
  		neighbors = np;
- 		memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen);
- 		memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen);
  	}
- 	free(buf);
  	return (1);
  }
  
  #ifdef DEBUG
! void
! Sendto(s, buf, cc, flags, to, tolen)
  	int s;
! 	char *buf;
! 	int cc, flags;
! 	char *to;
  	int tolen;
  {
  	register struct whod *w = (struct whod *)buf;
  	register struct whoent *we;
  	struct sockaddr_in *sin = (struct sockaddr_in *)to;
  
! 	printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
  	printf("hostname %s %s\n", w->wd_hostname,
  	   interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), "  up"));
  	printf("load %4.2f, %4.2f, %4.2f\n",
  	    ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
  	    ntohl(w->wd_loadav[2]) / 100.0);
  	cc -= WHDRSIZE;
! 	for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) {
  		time_t t = ntohl(we->we_utmp.out_time);
  		printf("%-8.8s %s:%s %.12s",
  			we->we_utmp.out_name,
--- 497,666 ----
  configure(s)
  	int s;
  {
+ 	char buf[BUFSIZ], *cp, *cplim;
+ 	struct ifconf ifc;
+ 	struct ifreq ifreq, *ifr;
+ 	struct sockaddr_in *sin;
  	register struct neighbor *np;
! 
! 	if (multicast_mode == SCOPED_MULTICAST) {
! 		struct ip_mreq mreq;
! 		unsigned char ttl;
! 
! 		mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
! 		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
! 		if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
! 					&mreq, sizeof(mreq)) < 0) {
! 			syslog(LOG_ERR,
! 				"setsockopt IP_ADD_MEMBERSHIP: %m");
! 			return (0);
! 		}
! 		ttl = multicast_scope;
! 		if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
! 					&ttl, sizeof(ttl)) < 0) {
! 			syslog(LOG_ERR,
! 				"setsockopt IP_MULTICAST_TTL: %m");
! 			return (0);
! 		}
! 		multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP);
! 		multicast_addr.sin_port = sp->s_port;
! 		return (1);
! 	}
! 
! 	ifc.ifc_len = sizeof (buf);
! 	ifc.ifc_buf = buf;
! 	if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
! 		syslog(LOG_ERR, "ioctl (get interface configuration)");
! 		return (0);
! 	}
! 	ifr = ifc.ifc_req;
! #ifdef AF_LINK
! #define max(a, b) (a > b ? a : b)
! #define size(p)	max((p).sa_len, sizeof(p))
! #else
! #define size(p) (sizeof (p))
! #endif
! 	cplim = buf + ifc.ifc_len; /* skip over if's with big ifr_addr's */
! 	for (cp = buf; cp < cplim;
! 			cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
! 		ifr = (struct ifreq *)cp;
! 		if (ifr->ifr_addr.sa_family != AF_INET)
  			continue;
  		for (np = neighbors; np != NULL; np = np->n_next)
! 			if (np->n_name &&
! 			    strcmp(ifr->ifr_name, np->n_name) == 0)
  				break;
  		if (np != NULL)
  			continue;
! 		ifreq = *ifr;
! 		np = (struct neighbor *)malloc(sizeof (*np));
  		if (np == NULL)
! 			continue;
! 		np->n_name = malloc(strlen(ifr->ifr_name) + 1);
! 		if (np->n_name == NULL) {
! 			free((char *)np);
! 			continue;
! 		}
! 		strcpy(np->n_name, ifr->ifr_name);
! 		np->n_addrlen = sizeof (ifr->ifr_addr);
! 		np->n_addr = malloc(np->n_addrlen);
! 		if (np->n_addr == NULL) {
! 			free(np->n_name);
! 			free((char *)np);
! 			continue;
! 		}
! 		bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
! 		if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
! 			syslog(LOG_ERR, "ioctl (get interface flags)");
! 			free((char *)np);
! 			continue;
! 		}
! 		if (multicast_mode == PER_INTERFACE_MULTICAST &&
! 		    (ifreq.ifr_flags & IFF_UP) &&
! 		    (ifreq.ifr_flags & IFF_MULTICAST) &&
! 		   !(ifreq.ifr_flags & IFF_LOOPBACK)) {
! 			struct ip_mreq mreq;
! 
! 			mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
! 			mreq.imr_interface.s_addr =
! 			  ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr;
! 			if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
! 						&mreq, sizeof(mreq)) < 0) {
! 				syslog(LOG_ERR,
! 					"setsockopt IP_ADD_MEMBERSHIP: %m");
! 				free(np->n_addr);
! 				free(np->n_name);
! 				free((char *)np);
! 				continue;
! 			}
! 			multicast_addr.sin_addr.s_addr
! 						= htonl(INADDR_WHOD_GROUP);
! 			multicast_addr.sin_port = sp->s_port;
! 			np->n_flags = ifreq.ifr_flags;
! 			np->n_next = neighbors;
! 			neighbors = np;
! 			continue;
! 		}
! 		if ((ifreq.ifr_flags & IFF_UP) == 0 ||
! 		    (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
! 			free((char *)np);
! 			continue;
! 		}
! 		np->n_flags = ifreq.ifr_flags;
! 		if (np->n_flags & IFF_POINTOPOINT) {
! 			if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
! 				syslog(LOG_ERR, "ioctl (get dstaddr)");
! 				free((char *)np);
! 				continue;
! 			}
! 			/* we assume addresses are all the same size */
! 			bcopy((char *)&ifreq.ifr_dstaddr,
! 			  np->n_addr, np->n_addrlen);
! 		}
! 		if (np->n_flags & IFF_BROADCAST) {
! 			if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
! 				syslog(LOG_ERR, "ioctl (get broadaddr)");
! 				free((char *)np);
! 				continue;
! 			}
! 			/* we assume addresses are all the same size */
! 			bcopy((char *)&ifreq.ifr_broadaddr,
! 			  np->n_addr, np->n_addrlen);
! 		}
! 		/* gag, wish we could get rid of Internet dependencies */
! 		sin = (struct sockaddr_in *)np->n_addr;
! 		sin->sin_port = sp->s_port;
  		np->n_next = neighbors;
  		neighbors = np;
  	}
  	return (1);
  }
  
  #ifdef DEBUG
! /* ARGSUSED */
! int
! prsend(s, buf, cc0, flags, to, tolen)
  	int s;
! 	const void *buf;
! 	int cc0, flags;
! 	const struct sockaddr *to;
  	int tolen;
  {
  	register struct whod *w = (struct whod *)buf;
  	register struct whoent *we;
+ 	register int cc = cc0;
  	struct sockaddr_in *sin = (struct sockaddr_in *)to;
+ 	char *interval __P((int, const char *));
  
! 	printf("sendto %lx.%d\n", ntohl(sin->sin_addr.s_addr),
! 	    ntohs(sin->sin_port));
  	printf("hostname %s %s\n", w->wd_hostname,
  	   interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), "  up"));
  	printf("load %4.2f, %4.2f, %4.2f\n",
  	    ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
  	    ntohl(w->wd_loadav[2]) / 100.0);
  	cc -= WHDRSIZE;
! 	for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) {
  		time_t t = ntohl(we->we_utmp.out_time);
  		printf("%-8.8s %s:%s %.12s",
  			we->we_utmp.out_name,
***************
*** 511,516 ****
--- 678,684 ----
  		}
  		printf("\n");
  	}
+ 	return (cc0);
  }
  
  char *
===================================================================
RCS file: usr.sbin/rwhod/rwhod.8,v
retrieving revision 1.1
diff -c -r1.1 usr.sbin/rwhod/rwhod.8
*** 1.1	1995/10/06 06:42:57
--- usr.sbin/rwhod/rwhod.8	1995/10/06 06:52:34
***************
*** 1,5 ****
! .\" Copyright (c) 1983, 1991, 1993
! .\"	The Regents of the University of California.  All rights reserved.
  .\"
  .\" Redistribution and use in source and binary forms, with or without
  .\" modification, are permitted provided that the following conditions
--- 1,5 ----
! .\" Copyright (c) 1983, 1991 The Regents of the University of California.
! .\" All rights reserved.
  .\"
  .\" Redistribution and use in source and binary forms, with or without
  .\" modification, are permitted provided that the following conditions
***************
*** 29,69 ****
  .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  .\" SUCH DAMAGE.
  .\"
! .\"     @(#)rwhod.8	8.2 (Berkeley) 12/11/93
  .\"
! .Dd December 11, 1993
  .Dt RWHOD 8
  .Os BSD 4.2
  .Sh NAME
  .Nm rwhod
  .Nd system status server
  .Sh SYNOPSIS
! .Nm rwhod
  .Sh DESCRIPTION
! .Nm Rwhod
! is the server which maintains the database used by the
  .Xr rwho 1
  and
  .Xr ruptime 1
  programs.  Its operation is predicated on the ability to
  .Em broadcast
  messages on a network.
  .Pp
! .Nm Rwhod
! operates as both a producer and consumer of status information.
  As a producer of information it periodically
  queries the state of the system and constructs
! status messages which are broadcast on a network.
  As a consumer of information, it listens for other
! .Nm rwhod
  servers' status messages, validating them, then recording
  them in a collection of files located in the directory
  .Pa /var/rwho .
  .Pp
  The server transmits and receives messages at the port indicated
  in the ``rwho'' service specification; see 
  .Xr services 5 .
! The messages sent and received, are of the form:
  .Bd -literal -offset indent
  struct	outmp {
  	char	out_line[8];		/* tty name */
--- 29,119 ----
  .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  .\" SUCH DAMAGE.
  .\"
! .\"     @(#)rwhod.8	6.5 (Berkeley) 3/16/91
  .\"
! .Dd March 16, 1991
  .Dt RWHOD 8
  .Os BSD 4.2
  .Sh NAME
  .Nm rwhod
  .Nd system status server
  .Sh SYNOPSIS
! .Nm
! .br
! .Nm
! .Fl m
! .br
! .Nm
! .Fl M Ar ttl
  .Sh DESCRIPTION
! The
! .Nm
! server maintains the database used by the
  .Xr rwho 1
  and
  .Xr ruptime 1
  programs.  Its operation is predicated on the ability to
  .Em broadcast
+ or
+ .Em multicast
  messages on a network.
  .Pp
! The
! .Nm
! program operates as both a producer and consumer of status information.
  As a producer of information it periodically
  queries the state of the system and constructs
! status messages which are broadcast or multicast on a network.
  As a consumer of information, it listens for other
! .Nm
  servers' status messages, validating them, then recording
  them in a collection of files located in the directory
  .Pa /var/rwho .
  .Pp
+ The
+ .Fl m
+ and
+ .Fl M
+ flags configure
+ .Nm
+ to use multicast rather than broadcast.
+ Under
+ .Fl m ,
+ .Nm
+ sends its multicast message to all multicast-capable interfaces
+ (those with
+ .Dv IFF_MULTICAST
+ set in their flags; see
+ .Xr ifconfig 8 ).
+ In this case the time-to-live is fixed at 1,
+ preventing the multicast from being forwarded beyond
+ any directly-connected subnets.
+ With
+ .Fl M ,
+ .Nm
+ sends its multicast message with the given
+ .Ar ttl
+ as its time to live, but to the
+ .Dq whod
+ group
+ .Pq Dv 224.0.1.3
+ rather than individually to each interface.
+ This is intended to be used with a multicast router
+ which will distribute the message to members of the multicast group.
+ .Pp
+ In any mode, broadcast or multicast,
+ .Nm
+ will accept all forms of reports.
+ This means that if broadcast and multicast
+ .Nm
+ servers are combined on one network,
+ the multicast-capable systems will see everyone,
+ while the broadcast-only machines will see only each other.
+ .Pp
  The server transmits and receives messages at the port indicated
  in the ``rwho'' service specification; see 
  .Xr services 5 .
! The messages sent and received are of the form:
  .Bd -literal -offset indent
  struct	outmp {
  	char	out_line[8];		/* tty name */
***************
*** 126,146 ****
  performs an
  .Xr nlist 3
  on
! .Pa /kernel
  every 30 minutes to guard against
  the possibility that this file is not the system
  image currently operating.
  .Sh SEE ALSO
  .Xr rwho 1 ,
  .Xr ruptime 1
  .Sh BUGS
- There should be a way to relay status information between networks. 
  Status information should be sent only upon request rather than continuously.
  People often interpret the server dying
! or network communication failures
  as a machine going down.
  .Sh HISTORY
  The
  .Nm
  command appeared in
  .Bx 4.2 .
--- 176,197 ----
  performs an
  .Xr nlist 3
  on
! .Pa /bsd
  every 30 minutes to guard against
  the possibility that this file is not the system
  image currently operating.
  .Sh SEE ALSO
+ .Xr mrouted 8 ,
  .Xr rwho 1 ,
  .Xr ruptime 1
  .Sh BUGS
  Status information should be sent only upon request rather than continuously.
  People often interpret the server dying
! or network communtication failures
  as a machine going down.
  .Sh HISTORY
  The
  .Nm
  command appeared in
  .Bx 4.2 .
+ The multicast additions are from Stanford University.
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199510060713.AAA00451>