190173d7dSPawel Jakub Dawidek /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 490173d7dSPawel Jakub Dawidek * Copyright (c) 1983, 1993 The Regents of the University of California. 5223eee08SPawel Jakub Dawidek * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org> 690173d7dSPawel Jakub Dawidek * All rights reserved. 7dea673e9SRodney W. Grimes * 8dea673e9SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9dea673e9SRodney W. Grimes * modification, are permitted provided that the following conditions 10dea673e9SRodney W. Grimes * are met: 11dea673e9SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13dea673e9SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15dea673e9SRodney W. Grimes * documentation and/or other materials provided with the distribution. 16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 17dea673e9SRodney W. Grimes * may be used to endorse or promote products derived from this software 18dea673e9SRodney W. Grimes * without specific prior written permission. 19dea673e9SRodney W. Grimes * 20dea673e9SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21dea673e9SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22dea673e9SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23dea673e9SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24dea673e9SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25dea673e9SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26dea673e9SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27dea673e9SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28dea673e9SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29dea673e9SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30dea673e9SRodney W. Grimes * SUCH DAMAGE. 31dea673e9SRodney W. Grimes */ 32dea673e9SRodney W. Grimes 33dea673e9SRodney W. Grimes #include <sys/param.h> 34cc94da1bSEnji Cooper #include <sys/capsicum.h> 35cc94da1bSEnji Cooper #include <sys/ioctl.h> 36cc94da1bSEnji Cooper #include <sys/procdesc.h> 37dea673e9SRodney W. Grimes #include <sys/socket.h> 38dea673e9SRodney W. Grimes #include <sys/stat.h> 39dea673e9SRodney W. Grimes #include <sys/signal.h> 40dea673e9SRodney W. Grimes #include <sys/sysctl.h> 41223eee08SPawel Jakub Dawidek #include <sys/wait.h> 42dea673e9SRodney W. Grimes 43dea673e9SRodney W. Grimes #include <net/if.h> 44dea673e9SRodney W. Grimes #include <net/if_dl.h> 45dea673e9SRodney W. Grimes #include <net/route.h> 46dea673e9SRodney W. Grimes #include <netinet/in.h> 474de93204SIan Dowse #include <arpa/inet.h> 48dea673e9SRodney W. Grimes #include <protocols/rwhod.h> 49dea673e9SRodney W. Grimes 50dea673e9SRodney W. Grimes #include <ctype.h> 517672a014SMariusz Zaborski #include <capsicum_helpers.h> 5211588fbdSPhilippe Charnier #include <err.h> 53dea673e9SRodney W. Grimes #include <errno.h> 54dea673e9SRodney W. Grimes #include <fcntl.h> 5590173d7dSPawel Jakub Dawidek #include <grp.h> 56dea673e9SRodney W. Grimes #include <netdb.h> 57dea673e9SRodney W. Grimes #include <paths.h> 5890173d7dSPawel Jakub Dawidek #include <pwd.h> 59dea673e9SRodney W. Grimes #include <stdio.h> 60dea673e9SRodney W. Grimes #include <stdlib.h> 61dea673e9SRodney W. Grimes #include <string.h> 62dea673e9SRodney W. Grimes #include <syslog.h> 6326175573SAlfred Perlstein #include <timeconv.h> 64b5810e94SEd Schouten #include <utmpx.h> 6590173d7dSPawel Jakub Dawidek #include <unistd.h> 6690173d7dSPawel Jakub Dawidek 6790173d7dSPawel Jakub Dawidek #define UNPRIV_USER "daemon" 6890173d7dSPawel Jakub Dawidek #define UNPRIV_GROUP "daemon" 6990173d7dSPawel Jakub Dawidek 7090173d7dSPawel Jakub Dawidek #define NO_MULTICAST 0 /* multicast modes */ 7190173d7dSPawel Jakub Dawidek #define PER_INTERFACE_MULTICAST 1 7290173d7dSPawel Jakub Dawidek #define SCOPED_MULTICAST 2 7390173d7dSPawel Jakub Dawidek 7490173d7dSPawel Jakub Dawidek #define MAX_MULTICAST_SCOPE 32 /* "site-wide", by convention */ 7590173d7dSPawel Jakub Dawidek 7690173d7dSPawel Jakub Dawidek #define INADDR_WHOD_GROUP (u_long)0xe0000103 /* 224.0.1.3 */ 7790173d7dSPawel Jakub Dawidek /* (belongs in protocols/rwhod.h) */ 7890173d7dSPawel Jakub Dawidek 7990173d7dSPawel Jakub Dawidek int insecure_mode; 8090173d7dSPawel Jakub Dawidek int quiet_mode; 8190173d7dSPawel Jakub Dawidek int iff_flag = IFF_POINTOPOINT; 8290173d7dSPawel Jakub Dawidek int multicast_mode = NO_MULTICAST; 8390173d7dSPawel Jakub Dawidek int multicast_scope; 8490173d7dSPawel Jakub Dawidek struct sockaddr_in multicast_addr = 8590173d7dSPawel Jakub Dawidek { sizeof(multicast_addr), AF_INET, 0, { 0 }, { 0 } }; 8690173d7dSPawel Jakub Dawidek 8790173d7dSPawel Jakub Dawidek /* 88223eee08SPawel Jakub Dawidek * Sleep interval. Don't forget to change the down time check in ruptime 8990173d7dSPawel Jakub Dawidek * if this is changed. 9090173d7dSPawel Jakub Dawidek */ 91223eee08SPawel Jakub Dawidek #define SL_INTERVAL (3 * 60) 9290173d7dSPawel Jakub Dawidek 9390173d7dSPawel Jakub Dawidek char myname[MAXHOSTNAMELEN]; 9490173d7dSPawel Jakub Dawidek 9590173d7dSPawel Jakub Dawidek /* 9690173d7dSPawel Jakub Dawidek * We communicate with each neighbor in a list constructed at the time we're 9790173d7dSPawel Jakub Dawidek * started up. Neighbors are currently directly connected via a hardware 9890173d7dSPawel Jakub Dawidek * interface. 9990173d7dSPawel Jakub Dawidek */ 10090173d7dSPawel Jakub Dawidek struct neighbor { 10190173d7dSPawel Jakub Dawidek struct neighbor *n_next; 10290173d7dSPawel Jakub Dawidek char *n_name; /* interface name */ 10390173d7dSPawel Jakub Dawidek struct sockaddr *n_addr; /* who to send to */ 10490173d7dSPawel Jakub Dawidek int n_addrlen; /* size of address */ 10590173d7dSPawel Jakub Dawidek int n_flags; /* should forward?, interface flags */ 10690173d7dSPawel Jakub Dawidek }; 10790173d7dSPawel Jakub Dawidek 10890173d7dSPawel Jakub Dawidek struct neighbor *neighbors; 10990173d7dSPawel Jakub Dawidek struct whod mywd; 11090173d7dSPawel Jakub Dawidek struct servent *sp; 11190173d7dSPawel Jakub Dawidek int s; 112223eee08SPawel Jakub Dawidek int fdp; 113223eee08SPawel Jakub Dawidek pid_t pid_child_receiver; 11490173d7dSPawel Jakub Dawidek 11590173d7dSPawel Jakub Dawidek #define WHDRSIZE (int)(sizeof(mywd) - sizeof(mywd.wd_we)) 11690173d7dSPawel Jakub Dawidek 11790173d7dSPawel Jakub Dawidek int configure(int so); 11890173d7dSPawel Jakub Dawidek void getboottime(int signo __unused); 119223eee08SPawel Jakub Dawidek void receiver_process(void); 12090173d7dSPawel Jakub Dawidek void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo); 12190173d7dSPawel Jakub Dawidek void run_as(uid_t *uid, gid_t *gid); 12290173d7dSPawel Jakub Dawidek void quit(const char *msg); 123223eee08SPawel Jakub Dawidek void sender_process(void); 12490173d7dSPawel Jakub Dawidek int verify(char *name, int maxlen); 125a2cc93ecSAlfonso Gregory static void usage(void) __dead2; 12690173d7dSPawel Jakub Dawidek 12790173d7dSPawel Jakub Dawidek #ifdef DEBUG 12890173d7dSPawel Jakub Dawidek char *interval(int time, char *updown); 12990173d7dSPawel Jakub Dawidek void Sendto(int s, const void *buf, size_t cc, int flags, 13090173d7dSPawel Jakub Dawidek const struct sockaddr *to, int tolen); 13190173d7dSPawel Jakub Dawidek #define sendto Sendto 13290173d7dSPawel Jakub Dawidek #endif 133dea673e9SRodney W. Grimes 134dea673e9SRodney W. Grimes /* 13584f8341eSJordan K. Hubbard * This version of Berkeley's rwhod has been modified to use IP multicast 13684f8341eSJordan K. Hubbard * datagrams, under control of a new command-line option: 13784f8341eSJordan K. Hubbard * 13884f8341eSJordan K. Hubbard * rwhod -m causes rwhod to use IP multicast (instead of 13984f8341eSJordan K. Hubbard * broadcast or unicast) on all interfaces that have 14084f8341eSJordan K. Hubbard * the IFF_MULTICAST flag set in their "ifnet" structs 14184f8341eSJordan K. Hubbard * (excluding the loopback interface). The multicast 14284f8341eSJordan K. Hubbard * reports are sent with a time-to-live of 1, to prevent 14384f8341eSJordan K. Hubbard * forwarding beyond the directly-connected subnet(s). 14484f8341eSJordan K. Hubbard * 14584f8341eSJordan K. Hubbard * rwhod -m <ttl> causes rwhod to send IP multicast datagrams with a 14684f8341eSJordan K. Hubbard * time-to-live of <ttl>, via a SINGLE interface rather 14784f8341eSJordan K. Hubbard * than all interfaces. <ttl> must be between 0 and 14884f8341eSJordan K. Hubbard * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" 14984f8341eSJordan K. Hubbard * is different than "-m", in that "-m 1" specifies 15084f8341eSJordan K. Hubbard * transmission on one interface only. 15184f8341eSJordan K. Hubbard * 15284f8341eSJordan K. Hubbard * When "-m" is used without a <ttl> argument, the program accepts multicast 15384f8341eSJordan K. Hubbard * rwhod reports from all multicast-capable interfaces. If a <ttl> argument 15484f8341eSJordan K. Hubbard * is given, it accepts multicast reports from only one interface, the one 15584f8341eSJordan K. Hubbard * on which reports are sent (which may be controlled via the host's routing 15684f8341eSJordan K. Hubbard * table). Regardless of the "-m" option, the program accepts broadcast or 15784f8341eSJordan K. Hubbard * unicast reports from all interfaces. Thus, this program will hear the 15884f8341eSJordan K. Hubbard * reports of old, non-multicasting rwhods, but, if multicasting is used, 15984f8341eSJordan K. Hubbard * those old rwhods won't hear the reports generated by this program. 16084f8341eSJordan K. Hubbard * 16184f8341eSJordan K. Hubbard * -- Steve Deering, Stanford University, February 1989 16284f8341eSJordan K. Hubbard */ 163dea673e9SRodney W. Grimes int 16426175573SAlfred Perlstein main(int argc, char *argv[]) 165dea673e9SRodney W. Grimes { 16690173d7dSPawel Jakub Dawidek int on; 167dea673e9SRodney W. Grimes char *cp; 16826175573SAlfred Perlstein struct sockaddr_in soin; 16928f0ced1SPaul Traina uid_t unpriv_uid; 17028f0ced1SPaul Traina gid_t unpriv_gid; 171dea673e9SRodney W. Grimes 17290173d7dSPawel Jakub Dawidek on = 1; 17311588fbdSPhilippe Charnier if (getuid()) 17411588fbdSPhilippe Charnier errx(1, "not super user"); 17528f0ced1SPaul Traina 17628f0ced1SPaul Traina run_as(&unpriv_uid, &unpriv_gid); 17728f0ced1SPaul Traina 17890173d7dSPawel Jakub Dawidek argv++; 17990173d7dSPawel Jakub Dawidek argc--; 18084f8341eSJordan K. Hubbard while (argc > 0 && *argv[0] == '-') { 18184f8341eSJordan K. Hubbard if (strcmp(*argv, "-m") == 0) { 18284f8341eSJordan K. Hubbard if (argc > 1 && isdigit(*(argv + 1)[0])) { 18390173d7dSPawel Jakub Dawidek argv++; 18490173d7dSPawel Jakub Dawidek argc--; 18584f8341eSJordan K. Hubbard multicast_mode = SCOPED_MULTICAST; 18684f8341eSJordan K. Hubbard multicast_scope = atoi(*argv); 18790173d7dSPawel Jakub Dawidek if (multicast_scope > MAX_MULTICAST_SCOPE) { 18811588fbdSPhilippe Charnier errx(1, "ttl must not exceed %u", 18984f8341eSJordan K. Hubbard MAX_MULTICAST_SCOPE); 19084f8341eSJordan K. Hubbard } 19190173d7dSPawel Jakub Dawidek } else { 19290173d7dSPawel Jakub Dawidek multicast_mode = PER_INTERFACE_MULTICAST; 19384f8341eSJordan K. Hubbard } 19490173d7dSPawel Jakub Dawidek } else if (strcmp(*argv, "-i") == 0) { 195ae94be3fSDag-Erling Smørgrav insecure_mode = 1; 19690173d7dSPawel Jakub Dawidek } else if (strcmp(*argv, "-l") == 0) { 19721358153SSteve Price quiet_mode = 1; 19890173d7dSPawel Jakub Dawidek } else if (strcmp(*argv, "-p") == 0) { 1992a7bd795SBrian Somers iff_flag = 0; 20090173d7dSPawel Jakub Dawidek } else { 20111588fbdSPhilippe Charnier usage(); 20290173d7dSPawel Jakub Dawidek } 20390173d7dSPawel Jakub Dawidek argv++; 20490173d7dSPawel Jakub Dawidek argc--; 20584f8341eSJordan K. Hubbard } 20611588fbdSPhilippe Charnier if (argc > 0) 20711588fbdSPhilippe Charnier usage(); 208dea673e9SRodney W. Grimes #ifndef DEBUG 209dea673e9SRodney W. Grimes daemon(1, 0); 210dea673e9SRodney W. Grimes #endif 211dea673e9SRodney W. Grimes (void) signal(SIGHUP, getboottime); 2126f691f7eSPawel Jakub Dawidek openlog("rwhod", LOG_PID | LOG_NDELAY, LOG_DAEMON); 21384f8341eSJordan K. Hubbard sp = getservbyname("who", "udp"); 21484f8341eSJordan K. Hubbard if (sp == NULL) { 21551f5c480SPhilippe Charnier syslog(LOG_ERR, "who/udp: unknown service"); 21684f8341eSJordan K. Hubbard exit(1); 21784f8341eSJordan K. Hubbard } 21884f8341eSJordan K. Hubbard if (chdir(_PATH_RWHODIR) < 0) { 21948060c09SPhilippe Charnier syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR); 22084f8341eSJordan K. Hubbard exit(1); 22184f8341eSJordan K. Hubbard } 222dea673e9SRodney W. Grimes /* 223dea673e9SRodney W. Grimes * Establish host name as returned by system. 224dea673e9SRodney W. Grimes */ 225dea673e9SRodney W. Grimes if (gethostname(myname, sizeof(myname) - 1) < 0) { 226dea673e9SRodney W. Grimes syslog(LOG_ERR, "gethostname: %m"); 227dea673e9SRodney W. Grimes exit(1); 228dea673e9SRodney W. Grimes } 229b3608ae1SEd Schouten if ((cp = strchr(myname, '.')) != NULL) 230dea673e9SRodney W. Grimes *cp = '\0'; 23190173d7dSPawel Jakub Dawidek strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname)); 232dea673e9SRodney W. Grimes getboottime(0); 233dea673e9SRodney W. Grimes if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 234dea673e9SRodney W. Grimes syslog(LOG_ERR, "socket: %m"); 235dea673e9SRodney W. Grimes exit(1); 236dea673e9SRodney W. Grimes } 237dea673e9SRodney W. Grimes if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { 238dea673e9SRodney W. Grimes syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); 239dea673e9SRodney W. Grimes exit(1); 240dea673e9SRodney W. Grimes } 24126175573SAlfred Perlstein memset(&soin, 0, sizeof(soin)); 24226175573SAlfred Perlstein soin.sin_len = sizeof(soin); 24326175573SAlfred Perlstein soin.sin_family = AF_INET; 24426175573SAlfred Perlstein soin.sin_port = sp->s_port; 24526175573SAlfred Perlstein if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) { 246dea673e9SRodney W. Grimes syslog(LOG_ERR, "bind: %m"); 247dea673e9SRodney W. Grimes exit(1); 248dea673e9SRodney W. Grimes } 24911522ca5SSimon L. B. Nielsen if (setgid(unpriv_gid) != 0) { 25011522ca5SSimon L. B. Nielsen syslog(LOG_ERR, "setgid: %m"); 25111522ca5SSimon L. B. Nielsen exit(1); 25211522ca5SSimon L. B. Nielsen } 25311522ca5SSimon L. B. Nielsen if (setgroups(1, &unpriv_gid) != 0) { /* XXX BOGUS groups[0] = egid */ 25411522ca5SSimon L. B. Nielsen syslog(LOG_ERR, "setgroups: %m"); 25511522ca5SSimon L. B. Nielsen exit(1); 25611522ca5SSimon L. B. Nielsen } 25711522ca5SSimon L. B. Nielsen if (setuid(unpriv_uid) != 0) { 25811522ca5SSimon L. B. Nielsen syslog(LOG_ERR, "setuid: %m"); 25911522ca5SSimon L. B. Nielsen exit(1); 26011522ca5SSimon L. B. Nielsen } 261dea673e9SRodney W. Grimes if (!configure(s)) 262dea673e9SRodney W. Grimes exit(1); 26321358153SSteve Price if (!quiet_mode) { 264223eee08SPawel Jakub Dawidek pid_child_receiver = pdfork(&fdp, 0); 265223eee08SPawel Jakub Dawidek if (pid_child_receiver == 0) { 266223eee08SPawel Jakub Dawidek receiver_process(); 267223eee08SPawel Jakub Dawidek } else if (pid_child_receiver > 0) { 268223eee08SPawel Jakub Dawidek sender_process(); 269223eee08SPawel Jakub Dawidek } else if (pid_child_receiver == -1) { 2702057b58bSPawel Jakub Dawidek if (errno == ENOSYS) { 2712057b58bSPawel Jakub Dawidek syslog(LOG_ERR, 272f2b525e6SPawel Jakub Dawidek "The pdfork(2) system call is not available - kernel too old."); 2732057b58bSPawel Jakub Dawidek } else { 274223eee08SPawel Jakub Dawidek syslog(LOG_ERR, "pdfork: %m"); 2752057b58bSPawel Jakub Dawidek } 276223eee08SPawel Jakub Dawidek exit(1); 27721358153SSteve Price } 278223eee08SPawel Jakub Dawidek } else { 279223eee08SPawel Jakub Dawidek receiver_process(); 280223eee08SPawel Jakub Dawidek } 281223eee08SPawel Jakub Dawidek } 282223eee08SPawel Jakub Dawidek 283223eee08SPawel Jakub Dawidek static void 284223eee08SPawel Jakub Dawidek usage(void) 285223eee08SPawel Jakub Dawidek { 286223eee08SPawel Jakub Dawidek 287223eee08SPawel Jakub Dawidek fprintf(stderr, "usage: rwhod [-i] [-p] [-l] [-m [ttl]]\n"); 288223eee08SPawel Jakub Dawidek exit(1); 289223eee08SPawel Jakub Dawidek } 290223eee08SPawel Jakub Dawidek 291223eee08SPawel Jakub Dawidek void 292223eee08SPawel Jakub Dawidek run_as(uid_t *uid, gid_t *gid) 293223eee08SPawel Jakub Dawidek { 294223eee08SPawel Jakub Dawidek struct passwd *pw; 295223eee08SPawel Jakub Dawidek struct group *gr; 296223eee08SPawel Jakub Dawidek 297223eee08SPawel Jakub Dawidek pw = getpwnam(UNPRIV_USER); 298223eee08SPawel Jakub Dawidek if (pw == NULL) { 299223eee08SPawel Jakub Dawidek syslog(LOG_ERR, "getpwnam(%s): %m", UNPRIV_USER); 300223eee08SPawel Jakub Dawidek exit(1); 301223eee08SPawel Jakub Dawidek } 302223eee08SPawel Jakub Dawidek *uid = pw->pw_uid; 303223eee08SPawel Jakub Dawidek 304223eee08SPawel Jakub Dawidek gr = getgrnam(UNPRIV_GROUP); 305223eee08SPawel Jakub Dawidek if (gr == NULL) { 306223eee08SPawel Jakub Dawidek syslog(LOG_ERR, "getgrnam(%s): %m", UNPRIV_GROUP); 307223eee08SPawel Jakub Dawidek exit(1); 308223eee08SPawel Jakub Dawidek } 309223eee08SPawel Jakub Dawidek *gid = gr->gr_gid; 310223eee08SPawel Jakub Dawidek } 311223eee08SPawel Jakub Dawidek 312223eee08SPawel Jakub Dawidek /* 313223eee08SPawel Jakub Dawidek * Check out host name for unprintables 314223eee08SPawel Jakub Dawidek * and other funnies before allowing a file 315223eee08SPawel Jakub Dawidek * to be created. Sorry, but blanks aren't allowed. 316223eee08SPawel Jakub Dawidek */ 317223eee08SPawel Jakub Dawidek int 318223eee08SPawel Jakub Dawidek verify(char *name, int maxlen) 319223eee08SPawel Jakub Dawidek { 320223eee08SPawel Jakub Dawidek int size; 321223eee08SPawel Jakub Dawidek 322223eee08SPawel Jakub Dawidek size = 0; 323223eee08SPawel Jakub Dawidek while (*name != '\0' && size < maxlen - 1) { 324d9216799SPawel Jakub Dawidek if (!isascii((unsigned char)*name) || 325d9216799SPawel Jakub Dawidek !(isalnum((unsigned char)*name) || 326d9216799SPawel Jakub Dawidek ispunct((unsigned char)*name))) { 327223eee08SPawel Jakub Dawidek return (0); 328d9216799SPawel Jakub Dawidek } 329223eee08SPawel Jakub Dawidek name++; 330223eee08SPawel Jakub Dawidek size++; 331223eee08SPawel Jakub Dawidek } 332223eee08SPawel Jakub Dawidek *name = '\0'; 333223eee08SPawel Jakub Dawidek return (size > 0); 334223eee08SPawel Jakub Dawidek } 335223eee08SPawel Jakub Dawidek 336223eee08SPawel Jakub Dawidek void 337223eee08SPawel Jakub Dawidek receiver_process(void) 338223eee08SPawel Jakub Dawidek { 339223eee08SPawel Jakub Dawidek struct sockaddr_in from; 340223eee08SPawel Jakub Dawidek struct stat st; 3417008be5bSPawel Jakub Dawidek cap_rights_t rights; 342223eee08SPawel Jakub Dawidek char path[64]; 3436f691f7eSPawel Jakub Dawidek int dirfd; 344dea673e9SRodney W. Grimes struct whod wd; 34590173d7dSPawel Jakub Dawidek socklen_t len; 34678e3eed0SStefan Farfeleder int cc, whod; 347d4474241SMatthew Dillon time_t t; 348dea673e9SRodney W. Grimes 34990173d7dSPawel Jakub Dawidek len = sizeof(from); 3506f691f7eSPawel Jakub Dawidek dirfd = open(".", O_RDONLY | O_DIRECTORY); 3516f691f7eSPawel Jakub Dawidek if (dirfd < 0) { 3526f691f7eSPawel Jakub Dawidek syslog(LOG_WARNING, "%s: %m", _PATH_RWHODIR); 3536f691f7eSPawel Jakub Dawidek exit(1); 3546f691f7eSPawel Jakub Dawidek } 3557008be5bSPawel Jakub Dawidek cap_rights_init(&rights, CAP_CREATE, CAP_FSTAT, CAP_FTRUNCATE, 3567008be5bSPawel Jakub Dawidek CAP_LOOKUP, CAP_SEEK, CAP_WRITE); 357377421dfSMariusz Zaborski if (caph_rights_limit(dirfd, &rights) < 0) { 3586f691f7eSPawel Jakub Dawidek syslog(LOG_WARNING, "cap_rights_limit: %m"); 3596f691f7eSPawel Jakub Dawidek exit(1); 3606f691f7eSPawel Jakub Dawidek } 3617672a014SMariusz Zaborski if (caph_enter() < 0) { 3626f691f7eSPawel Jakub Dawidek syslog(LOG_ERR, "cap_enter: %m"); 3636f691f7eSPawel Jakub Dawidek exit(1); 3646f691f7eSPawel Jakub Dawidek } 365223eee08SPawel Jakub Dawidek for (;;) { 36690173d7dSPawel Jakub Dawidek cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from, 36790173d7dSPawel Jakub Dawidek &len); 368dea673e9SRodney W. Grimes if (cc <= 0) { 369dea673e9SRodney W. Grimes if (cc < 0 && errno != EINTR) 370dea673e9SRodney W. Grimes syslog(LOG_WARNING, "recv: %m"); 371dea673e9SRodney W. Grimes continue; 372dea673e9SRodney W. Grimes } 373ae94be3fSDag-Erling Smørgrav if (from.sin_port != sp->s_port && !insecure_mode) { 3744de93204SIan Dowse syslog(LOG_WARNING, "%d: bad source port from %s", 3754de93204SIan Dowse ntohs(from.sin_port), inet_ntoa(from.sin_addr)); 3764de93204SIan Dowse continue; 3774de93204SIan Dowse } 3784de93204SIan Dowse if (cc < WHDRSIZE) { 3794de93204SIan Dowse syslog(LOG_WARNING, "short packet from %s", 3804de93204SIan Dowse inet_ntoa(from.sin_addr)); 381dea673e9SRodney W. Grimes continue; 382dea673e9SRodney W. Grimes } 383dea673e9SRodney W. Grimes if (wd.wd_vers != WHODVERSION) 384dea673e9SRodney W. Grimes continue; 385dea673e9SRodney W. Grimes if (wd.wd_type != WHODTYPE_STATUS) 386dea673e9SRodney W. Grimes continue; 38790173d7dSPawel Jakub Dawidek if (!verify(wd.wd_hostname, sizeof(wd.wd_hostname))) { 3884de93204SIan Dowse syslog(LOG_WARNING, "malformed host name from %s", 3894de93204SIan Dowse inet_ntoa(from.sin_addr)); 390dea673e9SRodney W. Grimes continue; 391dea673e9SRodney W. Grimes } 39290173d7dSPawel Jakub Dawidek (void) snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname); 393dea673e9SRodney W. Grimes /* 394dea673e9SRodney W. Grimes * Rather than truncating and growing the file each time, 395dea673e9SRodney W. Grimes * use ftruncate if size is less than previous size. 396dea673e9SRodney W. Grimes */ 3976f691f7eSPawel Jakub Dawidek whod = openat(dirfd, path, O_WRONLY | O_CREAT, 0644); 398dea673e9SRodney W. Grimes if (whod < 0) { 399dea673e9SRodney W. Grimes syslog(LOG_WARNING, "%s: %m", path); 400dea673e9SRodney W. Grimes continue; 401dea673e9SRodney W. Grimes } 4027008be5bSPawel Jakub Dawidek cap_rights_init(&rights, CAP_FSTAT, CAP_FTRUNCATE, CAP_WRITE); 403377421dfSMariusz Zaborski if (caph_rights_limit(whod, &rights) < 0) { 4046f691f7eSPawel Jakub Dawidek syslog(LOG_WARNING, "cap_rights_limit: %m"); 4056f691f7eSPawel Jakub Dawidek exit(1); 4066f691f7eSPawel Jakub Dawidek } 407dea673e9SRodney W. Grimes #if ENDIAN != BIG_ENDIAN 408dea673e9SRodney W. Grimes { 409dea673e9SRodney W. Grimes struct whoent *we; 41090173d7dSPawel Jakub Dawidek int i, n; 411dea673e9SRodney W. Grimes 41290173d7dSPawel Jakub Dawidek n = (cc - WHDRSIZE) / sizeof(struct whoent); 413dea673e9SRodney W. Grimes /* undo header byte swapping before writing to file */ 414dea673e9SRodney W. Grimes wd.wd_sendtime = ntohl(wd.wd_sendtime); 415dea673e9SRodney W. Grimes for (i = 0; i < 3; i++) 416dea673e9SRodney W. Grimes wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); 417dea673e9SRodney W. Grimes wd.wd_boottime = ntohl(wd.wd_boottime); 418dea673e9SRodney W. Grimes we = wd.wd_we; 419dea673e9SRodney W. Grimes for (i = 0; i < n; i++) { 420dea673e9SRodney W. Grimes we->we_idle = ntohl(we->we_idle); 421dea673e9SRodney W. Grimes we->we_utmp.out_time = 422dea673e9SRodney W. Grimes ntohl(we->we_utmp.out_time); 423dea673e9SRodney W. Grimes we++; 424dea673e9SRodney W. Grimes } 425dea673e9SRodney W. Grimes } 426dea673e9SRodney W. Grimes #endif 427d4474241SMatthew Dillon (void) time(&t); 428170ac683SMatthew Dillon wd.wd_recvtime = _time_to_int(t); 429dea673e9SRodney W. Grimes (void) write(whod, (char *)&wd, cc); 430dea673e9SRodney W. Grimes if (fstat(whod, &st) < 0 || st.st_size > cc) 431dea673e9SRodney W. Grimes ftruncate(whod, cc); 432dea673e9SRodney W. Grimes (void) close(whod); 433dea673e9SRodney W. Grimes } 4346f691f7eSPawel Jakub Dawidek (void) close(dirfd); 435dea673e9SRodney W. Grimes } 436dea673e9SRodney W. Grimes 43728f0ced1SPaul Traina void 438223eee08SPawel Jakub Dawidek sender_process(void) 43928f0ced1SPaul Traina { 440223eee08SPawel Jakub Dawidek int sendcount; 441dea673e9SRodney W. Grimes double avenrun[3]; 442dea673e9SRodney W. Grimes time_t now; 443223eee08SPawel Jakub Dawidek int i, cc, status; 44490173d7dSPawel Jakub Dawidek struct utmpx *ut; 44590173d7dSPawel Jakub Dawidek struct stat stb; 44690173d7dSPawel Jakub Dawidek struct neighbor *np; 44790173d7dSPawel Jakub Dawidek struct whoent *we, *wend; 448dea673e9SRodney W. Grimes 449223eee08SPawel Jakub Dawidek sendcount = 0; 450223eee08SPawel Jakub Dawidek for (;;) { 45190173d7dSPawel Jakub Dawidek we = mywd.wd_we; 452dea673e9SRodney W. Grimes now = time(NULL); 453223eee08SPawel Jakub Dawidek if (sendcount % 10 == 0) 454dea673e9SRodney W. Grimes getboottime(0); 455223eee08SPawel Jakub Dawidek sendcount++; 45641477e05SEd Schouten wend = &mywd.wd_we[1024 / sizeof(struct whoent)]; 45741477e05SEd Schouten setutxent(); 45841477e05SEd Schouten while ((ut = getutxent()) != NULL && we < wend) { 45941477e05SEd Schouten if (ut->ut_type != USER_PROCESS) 46041477e05SEd Schouten continue; 46141477e05SEd Schouten strncpy(we->we_utmp.out_line, ut->ut_line, 46241477e05SEd Schouten sizeof(we->we_utmp.out_line)); 46341477e05SEd Schouten strncpy(we->we_utmp.out_name, ut->ut_user, 46441477e05SEd Schouten sizeof(we->we_utmp.out_name)); 46541477e05SEd Schouten we->we_utmp.out_time = 46641477e05SEd Schouten htonl(_time_to_time32(ut->ut_tv.tv_sec)); 467dea673e9SRodney W. Grimes we++; 468dea673e9SRodney W. Grimes } 46941477e05SEd Schouten endutxent(); 470dea673e9SRodney W. Grimes 47190173d7dSPawel Jakub Dawidek if (chdir(_PATH_DEV) < 0) { 472dea673e9SRodney W. Grimes syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); 473dea673e9SRodney W. Grimes exit(1); 474dea673e9SRodney W. Grimes } 47541477e05SEd Schouten wend = we; 47641477e05SEd Schouten for (we = mywd.wd_we; we < wend; we++) { 477dea673e9SRodney W. Grimes if (stat(we->we_utmp.out_line, &stb) >= 0) 478dea673e9SRodney W. Grimes we->we_idle = htonl(now - stb.st_atime); 479dea673e9SRodney W. Grimes } 480223eee08SPawel Jakub Dawidek (void) getloadavg(avenrun, 481*4c6e656eSElyes Haouas nitems(avenrun)); 482dea673e9SRodney W. Grimes for (i = 0; i < 3; i++) 483dea673e9SRodney W. Grimes mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); 48441477e05SEd Schouten cc = (char *)wend - (char *)&mywd; 485170ac683SMatthew Dillon mywd.wd_sendtime = htonl(_time_to_time32(time(NULL))); 486dea673e9SRodney W. Grimes mywd.wd_vers = WHODVERSION; 487dea673e9SRodney W. Grimes mywd.wd_type = WHODTYPE_STATUS; 48884f8341eSJordan K. Hubbard if (multicast_mode == SCOPED_MULTICAST) { 489dea673e9SRodney W. Grimes (void) sendto(s, (char *)&mywd, cc, 0, 49084f8341eSJordan K. Hubbard (struct sockaddr *)&multicast_addr, 49184f8341eSJordan K. Hubbard sizeof(multicast_addr)); 49290173d7dSPawel Jakub Dawidek } else { 49390173d7dSPawel Jakub Dawidek for (np = neighbors; np != NULL; np = np->n_next) { 49484f8341eSJordan K. Hubbard if (multicast_mode == PER_INTERFACE_MULTICAST && 49590173d7dSPawel Jakub Dawidek (np->n_flags & IFF_MULTICAST) != 0) { 49684f8341eSJordan K. Hubbard /* 49790173d7dSPawel Jakub Dawidek * Select the outgoing interface for the 49890173d7dSPawel Jakub Dawidek * multicast. 49984f8341eSJordan K. Hubbard */ 50090173d7dSPawel Jakub Dawidek if (setsockopt(s, IPPROTO_IP, 50190173d7dSPawel Jakub Dawidek IP_MULTICAST_IF, 50284f8341eSJordan K. Hubbard &(((struct sockaddr_in *)np->n_addr)->sin_addr), 50384f8341eSJordan K. Hubbard sizeof(struct in_addr)) < 0) { 50484f8341eSJordan K. Hubbard syslog(LOG_ERR, 50584f8341eSJordan K. Hubbard "setsockopt IP_MULTICAST_IF: %m"); 50684f8341eSJordan K. Hubbard exit(1); 50784f8341eSJordan K. Hubbard } 50884f8341eSJordan K. Hubbard (void) sendto(s, (char *)&mywd, cc, 0, 50984f8341eSJordan K. Hubbard (struct sockaddr *)&multicast_addr, 51084f8341eSJordan K. Hubbard sizeof(multicast_addr)); 51190173d7dSPawel Jakub Dawidek } else { 51290173d7dSPawel Jakub Dawidek (void) sendto(s, (char *)&mywd, cc, 0, 513dea673e9SRodney W. Grimes np->n_addr, np->n_addrlen); 51484f8341eSJordan K. Hubbard } 51590173d7dSPawel Jakub Dawidek } 51690173d7dSPawel Jakub Dawidek } 51790173d7dSPawel Jakub Dawidek if (chdir(_PATH_RWHODIR) < 0) { 518dea673e9SRodney W. Grimes syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); 519dea673e9SRodney W. Grimes exit(1); 520dea673e9SRodney W. Grimes } 521223eee08SPawel Jakub Dawidek if (waitpid(pid_child_receiver, &status, WNOHANG) == 522223eee08SPawel Jakub Dawidek pid_child_receiver) { 523223eee08SPawel Jakub Dawidek break; 524223eee08SPawel Jakub Dawidek } 525223eee08SPawel Jakub Dawidek sleep(SL_INTERVAL); 526223eee08SPawel Jakub Dawidek } 527dea673e9SRodney W. Grimes } 528dea673e9SRodney W. Grimes 529dea673e9SRodney W. Grimes void 53090173d7dSPawel Jakub Dawidek getboottime(int signo __unused) 531dea673e9SRodney W. Grimes { 532dea673e9SRodney W. Grimes int mib[2]; 533dea673e9SRodney W. Grimes size_t size; 534dea673e9SRodney W. Grimes struct timeval tm; 535dea673e9SRodney W. Grimes 536dea673e9SRodney W. Grimes mib[0] = CTL_KERN; 537dea673e9SRodney W. Grimes mib[1] = KERN_BOOTTIME; 538dea673e9SRodney W. Grimes size = sizeof(tm); 539cc94da1bSEnji Cooper if (sysctl(mib, nitems(mib), &tm, &size, NULL, 0) == -1) { 540dea673e9SRodney W. Grimes syslog(LOG_ERR, "cannot get boottime: %m"); 541dea673e9SRodney W. Grimes exit(1); 542dea673e9SRodney W. Grimes } 543170ac683SMatthew Dillon mywd.wd_boottime = htonl(_time_to_time32(tm.tv_sec)); 544dea673e9SRodney W. Grimes } 545dea673e9SRodney W. Grimes 546dea673e9SRodney W. Grimes void 54790173d7dSPawel Jakub Dawidek quit(const char *msg) 548dea673e9SRodney W. Grimes { 54990173d7dSPawel Jakub Dawidek 550ed9ee320SKris Kennaway syslog(LOG_ERR, "%s", msg); 551dea673e9SRodney W. Grimes exit(1); 552dea673e9SRodney W. Grimes } 553dea673e9SRodney W. Grimes 554dea673e9SRodney W. Grimes void 55590173d7dSPawel Jakub Dawidek rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 556dea673e9SRodney W. Grimes { 55790173d7dSPawel Jakub Dawidek struct sockaddr *sa; 55890173d7dSPawel Jakub Dawidek int i; 559dea673e9SRodney W. Grimes 560dea673e9SRodney W. Grimes memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); 56190173d7dSPawel Jakub Dawidek for (i = 0; i < RTAX_MAX && cp < cplim; i++) { 562dea673e9SRodney W. Grimes if ((rtinfo->rti_addrs & (1 << i)) == 0) 563dea673e9SRodney W. Grimes continue; 56490173d7dSPawel Jakub Dawidek sa = (struct sockaddr *)cp; 56590173d7dSPawel Jakub Dawidek rtinfo->rti_info[i] = sa; 5660b46c085SLuigi Rizzo cp += SA_SIZE(sa); 567dea673e9SRodney W. Grimes } 568dea673e9SRodney W. Grimes } 569dea673e9SRodney W. Grimes 570dea673e9SRodney W. Grimes /* 571dea673e9SRodney W. Grimes * Figure out device configuration and select 572dea673e9SRodney W. Grimes * networks which deserve status information. 573dea673e9SRodney W. Grimes */ 574dea673e9SRodney W. Grimes int 57590173d7dSPawel Jakub Dawidek configure(int so) 576dea673e9SRodney W. Grimes { 57790173d7dSPawel Jakub Dawidek struct neighbor *np; 57890173d7dSPawel Jakub Dawidek struct if_msghdr *ifm; 57990173d7dSPawel Jakub Dawidek struct ifa_msghdr *ifam; 580dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 581dea673e9SRodney W. Grimes size_t needed; 58290173d7dSPawel Jakub Dawidek int mib[6], flags, lflags, len; 583dea673e9SRodney W. Grimes char *buf, *lim, *next; 584dea673e9SRodney W. Grimes struct rt_addrinfo info; 585dea673e9SRodney W. Grimes 58690173d7dSPawel Jakub Dawidek flags = 0; 58784f8341eSJordan K. Hubbard if (multicast_mode != NO_MULTICAST) { 58884f8341eSJordan K. Hubbard multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP); 58984f8341eSJordan K. Hubbard multicast_addr.sin_port = sp->s_port; 59084f8341eSJordan K. Hubbard } 59184f8341eSJordan K. Hubbard 59284f8341eSJordan K. Hubbard if (multicast_mode == SCOPED_MULTICAST) { 59384f8341eSJordan K. Hubbard struct ip_mreq mreq; 59484f8341eSJordan K. Hubbard unsigned char ttl; 59584f8341eSJordan K. Hubbard 59684f8341eSJordan K. Hubbard mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); 59784f8341eSJordan K. Hubbard mreq.imr_interface.s_addr = htonl(INADDR_ANY); 59826175573SAlfred Perlstein if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, 59984f8341eSJordan K. Hubbard &mreq, sizeof(mreq)) < 0) { 60084f8341eSJordan K. Hubbard syslog(LOG_ERR, 60184f8341eSJordan K. Hubbard "setsockopt IP_ADD_MEMBERSHIP: %m"); 60284f8341eSJordan K. Hubbard return (0); 60384f8341eSJordan K. Hubbard } 60484f8341eSJordan K. Hubbard ttl = multicast_scope; 60590173d7dSPawel Jakub Dawidek if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 60690173d7dSPawel Jakub Dawidek sizeof(ttl)) < 0) { 60784f8341eSJordan K. Hubbard syslog(LOG_ERR, 60884f8341eSJordan K. Hubbard "setsockopt IP_MULTICAST_TTL: %m"); 60984f8341eSJordan K. Hubbard return (0); 61084f8341eSJordan K. Hubbard } 61184f8341eSJordan K. Hubbard return (1); 61284f8341eSJordan K. Hubbard } 61384f8341eSJordan K. Hubbard 614dea673e9SRodney W. Grimes mib[0] = CTL_NET; 615dea673e9SRodney W. Grimes mib[1] = PF_ROUTE; 616dea673e9SRodney W. Grimes mib[2] = 0; 617dea673e9SRodney W. Grimes mib[3] = AF_INET; 618dea673e9SRodney W. Grimes mib[4] = NET_RT_IFLIST; 619dea673e9SRodney W. Grimes mib[5] = 0; 620cc94da1bSEnji Cooper if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 621dea673e9SRodney W. Grimes quit("route-sysctl-estimate"); 622dea673e9SRodney W. Grimes if ((buf = malloc(needed)) == NULL) 623dea673e9SRodney W. Grimes quit("malloc"); 624cc94da1bSEnji Cooper if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) 625dea673e9SRodney W. Grimes quit("actual retrieval of interface table"); 626dea673e9SRodney W. Grimes lim = buf + needed; 627dea673e9SRodney W. Grimes 628dea673e9SRodney W. Grimes sdl = NULL; /* XXX just to keep gcc -Wall happy */ 629dea673e9SRodney W. Grimes for (next = buf; next < lim; next += ifm->ifm_msglen) { 630dea673e9SRodney W. Grimes ifm = (struct if_msghdr *)next; 631dea673e9SRodney W. Grimes if (ifm->ifm_type == RTM_IFINFO) { 632dea673e9SRodney W. Grimes sdl = (struct sockaddr_dl *)(ifm + 1); 633dea673e9SRodney W. Grimes flags = ifm->ifm_flags; 634dea673e9SRodney W. Grimes continue; 635dea673e9SRodney W. Grimes } 63690173d7dSPawel Jakub Dawidek if ((flags & IFF_UP) == 0) 63790173d7dSPawel Jakub Dawidek continue; 63890173d7dSPawel Jakub Dawidek lflags = IFF_BROADCAST | iff_flag; 63990173d7dSPawel Jakub Dawidek if (multicast_mode == PER_INTERFACE_MULTICAST) 64090173d7dSPawel Jakub Dawidek lflags |= IFF_MULTICAST; 64190173d7dSPawel Jakub Dawidek if ((flags & lflags) == 0) 642dea673e9SRodney W. Grimes continue; 643dea673e9SRodney W. Grimes if (ifm->ifm_type != RTM_NEWADDR) 644dea673e9SRodney W. Grimes quit("out of sync parsing NET_RT_IFLIST"); 645dea673e9SRodney W. Grimes ifam = (struct ifa_msghdr *)ifm; 646dea673e9SRodney W. Grimes info.rti_addrs = ifam->ifam_addrs; 647dea673e9SRodney W. Grimes rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, 648dea673e9SRodney W. Grimes &info); 649dea673e9SRodney W. Grimes /* gag, wish we could get rid of Internet dependencies */ 650dea673e9SRodney W. Grimes #define dstaddr info.rti_info[RTAX_BRD] 65184f8341eSJordan K. Hubbard #define ifaddr info.rti_info[RTAX_IFA] 652dea673e9SRodney W. Grimes #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr 653dea673e9SRodney W. Grimes #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port 654dea673e9SRodney W. Grimes if (dstaddr == 0 || dstaddr->sa_family != AF_INET) 655dea673e9SRodney W. Grimes continue; 656dea673e9SRodney W. Grimes PORT_SA(dstaddr) = sp->s_port; 65790173d7dSPawel Jakub Dawidek for (np = neighbors; np != NULL; np = np->n_next) { 658dea673e9SRodney W. Grimes if (memcmp(sdl->sdl_data, np->n_name, 659dea673e9SRodney W. Grimes sdl->sdl_nlen) == 0 && 66090173d7dSPawel Jakub Dawidek IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) { 661dea673e9SRodney W. Grimes break; 66290173d7dSPawel Jakub Dawidek } 66390173d7dSPawel Jakub Dawidek } 664dea673e9SRodney W. Grimes if (np != NULL) 665dea673e9SRodney W. Grimes continue; 666dea673e9SRodney W. Grimes len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1; 66790173d7dSPawel Jakub Dawidek np = malloc(len); 668dea673e9SRodney W. Grimes if (np == NULL) 669dea673e9SRodney W. Grimes quit("malloc of neighbor structure"); 670dea673e9SRodney W. Grimes memset(np, 0, len); 671dea673e9SRodney W. Grimes np->n_flags = flags; 672dea673e9SRodney W. Grimes np->n_addr = (struct sockaddr *)(np + 1); 673dea673e9SRodney W. Grimes np->n_addrlen = dstaddr->sa_len; 674dea673e9SRodney W. Grimes np->n_name = np->n_addrlen + (char *)np->n_addr; 675dea673e9SRodney W. Grimes memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen); 676dea673e9SRodney W. Grimes memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); 67784f8341eSJordan K. Hubbard if (multicast_mode == PER_INTERFACE_MULTICAST && 67890173d7dSPawel Jakub Dawidek (flags & IFF_MULTICAST) != 0 && 67990173d7dSPawel Jakub Dawidek (flags & IFF_LOOPBACK) == 0) { 68084f8341eSJordan K. Hubbard struct ip_mreq mreq; 68184f8341eSJordan K. Hubbard 68284f8341eSJordan K. Hubbard memcpy((char *)np->n_addr, (char *)ifaddr, 68384f8341eSJordan K. Hubbard np->n_addrlen); 68484f8341eSJordan K. Hubbard mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); 68584f8341eSJordan K. Hubbard mreq.imr_interface.s_addr = 68684f8341eSJordan K. Hubbard ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; 68784f8341eSJordan K. Hubbard if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, 68884f8341eSJordan K. Hubbard &mreq, sizeof(mreq)) < 0) { 68984f8341eSJordan K. Hubbard syslog(LOG_ERR, 69084f8341eSJordan K. Hubbard "setsockopt IP_ADD_MEMBERSHIP: %m"); 69184f8341eSJordan K. Hubbard #if 0 69284f8341eSJordan K. Hubbard /* Fall back to broadcast on this if. */ 69384f8341eSJordan K. Hubbard np->n_flags &= ~IFF_MULTICAST; 69484f8341eSJordan K. Hubbard #else 69590173d7dSPawel Jakub Dawidek free(np); 69684f8341eSJordan K. Hubbard continue; 69784f8341eSJordan K. Hubbard #endif 69884f8341eSJordan K. Hubbard } 69984f8341eSJordan K. Hubbard } 70084f8341eSJordan K. Hubbard np->n_next = neighbors; 70184f8341eSJordan K. Hubbard neighbors = np; 702dea673e9SRodney W. Grimes } 703dea673e9SRodney W. Grimes free(buf); 704dea673e9SRodney W. Grimes return (1); 705dea673e9SRodney W. Grimes } 706dea673e9SRodney W. Grimes 707dea673e9SRodney W. Grimes #ifdef DEBUG 708dea673e9SRodney W. Grimes void 70990173d7dSPawel Jakub Dawidek Sendto(int s, const void *buf, size_t cc, int flags, const struct sockaddr *to, 71090173d7dSPawel Jakub Dawidek int tolen) 711dea673e9SRodney W. Grimes { 71290173d7dSPawel Jakub Dawidek struct whod *w; 71390173d7dSPawel Jakub Dawidek struct whoent *we; 71490173d7dSPawel Jakub Dawidek struct sockaddr_in *sin; 715dea673e9SRodney W. Grimes 71690173d7dSPawel Jakub Dawidek w = (struct whod *)buf; 71790173d7dSPawel Jakub Dawidek sin = (struct sockaddr_in *)to; 71828f0ced1SPaul Traina printf("sendto %x.%d\n", ntohl(sin->sin_addr.s_addr), 71928f0ced1SPaul Traina ntohs(sin->sin_port)); 720dea673e9SRodney W. Grimes printf("hostname %s %s\n", w->wd_hostname, 721dea673e9SRodney W. Grimes interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); 722dea673e9SRodney W. Grimes printf("load %4.2f, %4.2f, %4.2f\n", 723dea673e9SRodney W. Grimes ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0, 724dea673e9SRodney W. Grimes ntohl(w->wd_loadav[2]) / 100.0); 725dea673e9SRodney W. Grimes cc -= WHDRSIZE; 726dea673e9SRodney W. Grimes for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) { 727170ac683SMatthew Dillon time_t t = _time32_to_time(ntohl(we->we_utmp.out_time)); 72890173d7dSPawel Jakub Dawidek 72990173d7dSPawel Jakub Dawidek printf("%-8.8s %s:%s %.12s", we->we_utmp.out_name, 73090173d7dSPawel Jakub Dawidek w->wd_hostname, we->we_utmp.out_line, ctime(&t) + 4); 731dea673e9SRodney W. Grimes we->we_idle = ntohl(we->we_idle) / 60; 73290173d7dSPawel Jakub Dawidek if (we->we_idle != 0) { 733dea673e9SRodney W. Grimes if (we->we_idle >= 100 * 60) 734dea673e9SRodney W. Grimes we->we_idle = 100 * 60 - 1; 735dea673e9SRodney W. Grimes if (we->we_idle >= 60) 736dea673e9SRodney W. Grimes printf(" %2d", we->we_idle / 60); 737dea673e9SRodney W. Grimes else 738dea673e9SRodney W. Grimes printf(" "); 739dea673e9SRodney W. Grimes printf(":%02d", we->we_idle % 60); 740dea673e9SRodney W. Grimes } 741dea673e9SRodney W. Grimes printf("\n"); 742dea673e9SRodney W. Grimes } 743dea673e9SRodney W. Grimes } 744dea673e9SRodney W. Grimes 745dea673e9SRodney W. Grimes char * 74690173d7dSPawel Jakub Dawidek interval(int time, char *updown) 747dea673e9SRodney W. Grimes { 748dea673e9SRodney W. Grimes static char resbuf[32]; 749dea673e9SRodney W. Grimes int days, hours, minutes; 750dea673e9SRodney W. Grimes 751dea673e9SRodney W. Grimes if (time < 0 || time > 3 * 30 * 24 * 60 * 60) { 752dea673e9SRodney W. Grimes (void) sprintf(resbuf, " %s ??:??", updown); 753dea673e9SRodney W. Grimes return (resbuf); 754dea673e9SRodney W. Grimes } 755dea673e9SRodney W. Grimes minutes = (time + 59) / 60; /* round to minutes */ 75690173d7dSPawel Jakub Dawidek hours = minutes / 60; 75790173d7dSPawel Jakub Dawidek minutes %= 60; 75890173d7dSPawel Jakub Dawidek days = hours / 24; 75990173d7dSPawel Jakub Dawidek hours %= 24; 76090173d7dSPawel Jakub Dawidek if (days > 0) { 761dea673e9SRodney W. Grimes (void) sprintf(resbuf, "%s %2d+%02d:%02d", 762dea673e9SRodney W. Grimes updown, days, hours, minutes); 76390173d7dSPawel Jakub Dawidek } else { 764dea673e9SRodney W. Grimes (void) sprintf(resbuf, "%s %2d:%02d", 765dea673e9SRodney W. Grimes updown, hours, minutes); 76690173d7dSPawel Jakub Dawidek } 767dea673e9SRodney W. Grimes return (resbuf); 768dea673e9SRodney W. Grimes } 769dea673e9SRodney W. Grimes #endif 770