Here are patches to add full multicast support to rwhod, and an updated man

page.  I tried all three modes (rwhod, rwhod -m, rwhod -m 32) on a machine
with 2 ethernet interfaces and they all worked.
Submitted by:	Bill Fenner <fenner@parc.xerox.com>
This commit is contained in:
Jordan K. Hubbard 1995-08-17 00:51:40 +00:00
parent 80effc40da
commit 84f8341ef7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=10087
2 changed files with 197 additions and 17 deletions

View File

@ -39,6 +39,7 @@
.Nd system status server
.Sh SYNOPSIS
.Nm rwhod
.Op Fl m Op Ar ttl
.Sh DESCRIPTION
.Nm Rwhod
is the server which maintains the database used by the
@ -47,19 +48,59 @@ and
.Xr ruptime 1
programs. Its operation is predicated on the ability to
.Em broadcast
or
.Em multicast
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.
status messages which are broadcasted or multicasted 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
.Fl m
option causes rwhod to use IP multicast (instead of
broadcast) 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).
.Pp
If the optional
.Ar ttl
argument is supplied with the
.Fl m
flag, rwhod will 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
32 (or MAX_MULTICAST_SCOPE). Note that
.Fl m Ar 1
is different than
.Fl m ,
in that
.Fl m Ar 1
specifies transmission on one interface only.
.Pp
When
.Fl m
is used without a
.Ar ttl
argument, the program accepts multicast
rwhod reports from all multicast-capable interfaces. If a
.Ar 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 the "-m" option, 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.
.Pp
The server transmits and receives messages at the port indicated
in the ``rwho'' service specification; see
.Xr services 5 .
@ -134,7 +175,6 @@ image currently operating.
.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

View File

@ -66,6 +66,49 @@ static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";
#include <unistd.h>
#include <utmp.h>
/*
* This version of Berkeley's rwhod has been modified to use IP multicast
* datagrams, under control of a new command-line option:
*
* 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.
*
* When "-m" is used without a <ttl> argument, 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 the "-m" option, 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 = { sizeof multicast_addr, AF_INET };
/*
* Alarm interval. Don't forget to change the down time check in ruptime
* if this is changed.
@ -109,7 +152,7 @@ void Sendto __P((int, char *, int, int, char *, int));
int
main(argc, argv)
int argc;
char argv[];
char *argv[];
{
struct sockaddr_in from;
struct stat st;
@ -122,21 +165,43 @@ main(argc, argv)
fprintf(stderr, "rwhod: not super user\n");
exit(1);
}
sp = getservbyname("who", "udp");
if (sp == NULL) {
fprintf(stderr, "rwhod: udp/who: unknown service\n");
argv++; argc--;
while (argc > 0 && *argv[0] == '-') {
if (strcmp(*argv, "-m") == 0) {
if (argc > 1 && isdigit(*(argv + 1)[0])) {
argv++, argc--;
multicast_mode = SCOPED_MULTICAST;
multicast_scope = atoi(*argv);
if (multicast_scope > MAX_MULTICAST_SCOPE) {
fprintf(stderr,
"rwhod: ttl must not exceed %u\n",
MAX_MULTICAST_SCOPE);
exit(1);
}
}
else multicast_mode = PER_INTERFACE_MULTICAST;
}
else goto usage;
argv++, argc--;
}
if (argc > 0) {
usage: fprintf(stderr, "usage: rwhod [ -m [ ttl ] ]\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);
sp = getservbyname("who", "udp");
if (sp == NULL) {
syslog(LOG_ERR, "rwhod: udp/who: unknown service\n");
exit(1);
}
if (chdir(_PATH_RWHODIR) < 0) {
syslog(LOG_ERR, "rwhod: %s: %m\n", _PATH_RWHODIR);
exit(1);
}
/*
* Establish host name as returned by system.
*/
@ -162,6 +227,7 @@ main(argc, argv)
exit(1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = sp->s_port;
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
@ -335,9 +401,30 @@ onalrm(signo)
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 (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,
np->n_addr, np->n_addrlen);
}
if (utmpent && chdir(_PATH_RWHODIR)) {
syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR);
exit(1);
@ -410,6 +497,33 @@ configure(s)
char *buf, *lim, *next;
struct rt_addrinfo info;
if (multicast_mode != NO_MULTICAST) {
multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP);
multicast_addr.sin_port = sp->s_port;
}
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);
}
return(1);
}
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
@ -433,7 +547,9 @@ configure(s)
continue;
}
if ((flags & IFF_UP) == 0 ||
(flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
(flags & (((multicast_mode == PER_INTERFACE_MULTICAST) ?
IFF_MULTICAST : 0) |
IFF_BROADCAST|IFF_POINTOPOINT)) == 0)
continue;
if (ifm->ifm_type != RTM_NEWADDR)
quit("out of sync parsing NET_RT_IFLIST");
@ -443,6 +559,7 @@ configure(s)
&info);
/* gag, wish we could get rid of Internet dependencies */
#define dstaddr info.rti_info[RTAX_BRD]
#define ifaddr info.rti_info[RTAX_IFA]
#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)
@ -464,10 +581,33 @@ configure(s)
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);
if (multicast_mode == PER_INTERFACE_MULTICAST &&
(flags & IFF_MULTICAST) &&
!(flags & IFF_LOOPBACK)) {
struct ip_mreq mreq;
memcpy((char *)np->n_addr, (char *)ifaddr,
np->n_addrlen);
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");
#if 0
/* Fall back to broadcast on this if. */
np->n_flags &= ~IFF_MULTICAST;
#else
free((char *)np);
continue;
#endif
}
}
np->n_next = neighbors;
neighbors = np;
}
free(buf);
return (1);