summaryrefslogtreecommitdiffstats
path: root/usr.sbin/rwhod
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/rwhod')
-rw-r--r--usr.sbin/rwhod/rwhod.844
-rw-r--r--usr.sbin/rwhod/rwhod.c168
2 files changed, 196 insertions, 16 deletions
diff --git a/usr.sbin/rwhod/rwhod.8 b/usr.sbin/rwhod/rwhod.8
index 2922bcc..fc4b628 100644
--- a/usr.sbin/rwhod/rwhod.8
+++ b/usr.sbin/rwhod/rwhod.8
@@ -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
diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c
index 75c02ff..66ead27 100644
--- a/usr.sbin/rwhod/rwhod.c
+++ b/usr.sbin/rwhod/rwhod.c
@@ -67,6 +67,49 @@ static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93";
#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
+ (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) {
- (void)fprintf(stderr, "rwhod: %s: %s\n",
- _PATH_RWHODIR, strerror(errno));
+ syslog(LOG_ERR, "rwhod: %s: %m\n", _PATH_RWHODIR);
exit(1);
}
- (void) signal(SIGHUP, getboottime);
- openlog("rwhod", LOG_PID, LOG_DAEMON);
/*
* 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);
OpenPOWER on IntegriCloud