mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-28 13:22:48 +00:00
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:
parent
80effc40da
commit
84f8341ef7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=10087
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user