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>