Page MenuHomeFreeBSD

D45124.diff
No OneTemporary

D45124.diff

diff --git a/usr.sbin/rwhod/Makefile b/usr.sbin/rwhod/Makefile
--- a/usr.sbin/rwhod/Makefile
+++ b/usr.sbin/rwhod/Makefile
@@ -1,3 +1,4 @@
+.include <src.opts.mk>
PROG= rwhod
MAN= rwhod.8
@@ -6,4 +7,11 @@
WARNS?= 3
+.if ${MK_INET_SUPPORT} != "no"
+CFLAGS+= -DINET
+.endif
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DINET6
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c
--- a/usr.sbin/rwhod/rwhod.c
+++ b/usr.sbin/rwhod/rwhod.c
@@ -73,16 +73,21 @@
#define MAX_MULTICAST_SCOPE 32 /* "site-wide", by convention */
+#ifdef INET
#define INADDR_WHOD_GROUP (u_long)0xe0000103 /* 224.0.1.3 */
/* (belongs in protocols/rwhod.h) */
+#endif
+#ifdef INET6
+#define IN6ADDR_WHOD_GROUP "ff02::103" /* link local address */
+#endif
int insecure_mode;
int quiet_mode;
int iff_flag = IFF_POINTOPOINT;
int multicast_mode = NO_MULTICAST;
int multicast_scope;
-struct sockaddr_in multicast_addr =
- { sizeof(multicast_addr), AF_INET, 0, { 0 }, { 0 } };
+struct sockaddr_storage multicast_addr;
+struct sockaddr *my_sa;
/*
* Sleep interval. Don't forget to change the down time check in ruptime
@@ -107,7 +112,6 @@
struct neighbor *neighbors;
struct whod mywd;
-struct servent *sp;
int s;
int fdp;
pid_t pid_child_receiver;
@@ -163,9 +167,9 @@
int
main(int argc, char *argv[])
{
- int on;
+ int on, error, success = 0;
char *cp;
- struct sockaddr_in soin;
+ struct addrinfo *res, *p;
uid_t unpriv_uid;
gid_t unpriv_gid;
@@ -210,11 +214,19 @@
#endif
(void) signal(SIGHUP, getboottime);
openlog("rwhod", LOG_PID | LOG_NDELAY, LOG_DAEMON);
- sp = getservbyname("who", "udp");
- if (sp == NULL) {
- syslog(LOG_ERR, "who/udp: unknown service");
+ error = getaddrinfo(NULL, "who", &(struct addrinfo){
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_flags = AI_PASSIVE
+ }, &res);
+ if (error != 0) {
+ syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
exit(1);
}
+ if (res->ai_next != NULL) {
+ syslog(LOG_INFO, "Multiple addresses were returned."
+ "Only the first address will be used.");
+ }
if (chdir(_PATH_RWHODIR) < 0) {
syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR);
exit(1);
@@ -230,20 +242,49 @@
*cp = '\0';
strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname));
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);
+ for (p = res; p != NULL; p = p->ai_next) {
+ if ((s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ continue;
+ }
+ switch (p->ai_family) {
+#ifdef INET
+ case AF_INET:
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ close(s);
+ continue;
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &on, sizeof(on)) < 0) {
+ syslog(LOG_ERR, "setsockopt IPV6_MULTICAST_IF: %m");
+ close(s);
+ continue;
+ }
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+ syslog(LOG_ERR, "setsockopt IPV6_V6ONLY: %m");
+ close(s);
+ continue;
+ }
+ break;
+#endif
+ default:
+ continue;
+ };
+ if (bind(s, p->ai_addr, p->ai_addrlen) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ close(s);
+ exit(1);
+ }
+ my_sa = p->ai_addr;
+ success = 1;
+ break;
}
- memset(&soin, 0, sizeof(soin));
- soin.sin_len = sizeof(soin);
- soin.sin_family = AF_INET;
- soin.sin_port = sp->s_port;
- if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) {
- syslog(LOG_ERR, "bind: %m");
+ if (success == 0) {
+ syslog(LOG_ERR, "No suitable address found for creating a socket");
exit(1);
}
if (setgid(unpriv_gid) != 0) {
@@ -278,6 +319,7 @@
} else {
receiver_process();
}
+ freeaddrinfo(res);
}
static void
@@ -336,14 +378,14 @@
void
receiver_process(void)
{
- struct sockaddr_in from;
+ struct sockaddr from;
struct stat st;
cap_rights_t rights;
- char path[64];
+ char path[64], host[NI_MAXHOST], host_from[NI_MAXHOST], service[NI_MAXSERV], service_from[NI_MAXSERV];
int dirfd;
struct whod wd;
socklen_t len;
- int cc, whod;
+ int cc, whod, error;
time_t t;
len = sizeof(from);
@@ -362,22 +404,33 @@
syslog(LOG_ERR, "cap_enter: %m");
exit(1);
}
+ error = getnameinfo(my_sa, my_sa->sa_len, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ syslog(LOG_ERR, "getnameinfo: %s", gai_strerror(error));
+ exit(1);
+ }
for (;;) {
- cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from,
+ cc = recvfrom(s, &wd, sizeof(wd), 0, &from,
&len);
if (cc <= 0) {
if (cc < 0 && errno != EINTR)
syslog(LOG_WARNING, "recv: %m");
continue;
}
- if (from.sin_port != sp->s_port && !insecure_mode) {
- syslog(LOG_WARNING, "%d: bad source port from %s",
- ntohs(from.sin_port), inet_ntoa(from.sin_addr));
+ error = getnameinfo(&from, len, host_from, NI_MAXHOST, service_from,
+ NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ syslog(LOG_ERR, "getnameinfo: %s", gai_strerror(error));
+ exit(1);
+ }
+ if (strcmp(service, service_from) != 0 && !insecure_mode) {
+ syslog(LOG_WARNING, "%s: bad source port from %s",
+ service_from, host_from);
continue;
}
if (cc < WHDRSIZE) {
syslog(LOG_WARNING, "short packet from %s",
- inet_ntoa(from.sin_addr));
+ host_from);
continue;
}
if (wd.wd_vers != WHODVERSION)
@@ -386,7 +439,7 @@
continue;
if (!verify(wd.wd_hostname, sizeof(wd.wd_hostname))) {
syslog(LOG_WARNING, "malformed host name from %s",
- inet_ntoa(from.sin_addr));
+ host_from);
continue;
}
(void) snprintf(path, sizeof(path), "whod.%s", wd.wd_hostname);
@@ -441,6 +494,7 @@
double avenrun[3];
time_t now;
int i, cc, status;
+ unsigned int ifindex;
struct utmpx *ut;
struct stat stb;
struct neighbor *np;
@@ -497,13 +551,32 @@
* 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);
+ switch (np->n_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ 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);
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ifindex = if_nametoindex(np->n_name);
+ if (setsockopt(s, IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ &ifindex,
+ sizeof(ifindex)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IPV6_MULTICAST_IF: %m");
+ exit(1);
+ }
+ break;
+#endif
}
(void) sendto(s, (char *)&mywd, cc, 0,
(struct sockaddr *)&multicast_addr,
@@ -574,47 +647,88 @@
int
configure(int so)
{
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct group_req greq;
struct neighbor *np;
struct if_msghdr *ifm;
struct ifa_msghdr *ifam;
struct sockaddr_dl *sdl;
size_t needed;
- int mib[6], flags, lflags, len;
- char *buf, *lim, *next;
+ int mib[6], flags, lflags, len, error;
+ char *buf, *lim, *next, host_dst[NI_MAXHOST], host_np[NI_MAXHOST];
struct rt_addrinfo info;
flags = 0;
- 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;
+ switch (my_sa->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (multicast_mode != NO_MULTICAST) {
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP);
+ sin.sin_port = ((struct sockaddr_in *)(my_sa))->sin_port;
+ memcpy(&multicast_addr, (struct sockaddr *)&sin, sizeof(multicast_addr));
+ }
+ if (multicast_mode == SCOPED_MULTICAST) {
+ unsigned char ttl;
- mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP);
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- if (setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- syslog(LOG_ERR,
- "setsockopt IP_ADD_MEMBERSHIP: %m");
- return (0);
+ greq.gr_group = multicast_addr;
+ greq.gr_interface = 0;
+ if (setsockopt(so, IPPROTO_IP, MCAST_JOIN_GROUP, &greq,
+ sizeof(greq)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt MCAST_JOIN_GROUP: %m");
+ return (0);
+ }
+ ttl = multicast_scope;
+ if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
+ sizeof(ttl)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IP_MULTICAST_TTL: %m");
+ return (0);
+ }
+ return (1);
}
- ttl = multicast_scope;
- if (setsockopt(so, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
- sizeof(ttl)) < 0) {
- syslog(LOG_ERR,
- "setsockopt IP_MULTICAST_TTL: %m");
- return (0);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (multicast_mode != NO_MULTICAST) {
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, IN6ADDR_WHOD_GROUP, &(sin6.sin6_addr));
+ sin6.sin6_port = ((struct sockaddr_in6 *)(my_sa))->sin6_port;
+ memcpy(&multicast_addr, (struct sockaddr *)&sin6, sizeof(multicast_addr));
}
- return (1);
+ if (multicast_mode == SCOPED_MULTICAST) {
+ int ttl;
+
+ greq.gr_group = multicast_addr;
+ greq.gr_interface = 0;
+ if (setsockopt(so, IPPROTO_IPV6, MCAST_JOIN_GROUP, &greq,
+ sizeof(greq)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt MCAST_JOIN_GROUP: %m");
+ return (0);
+ }
+ ttl = multicast_scope;
+ if (setsockopt(so, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &ttl, sizeof(ttl)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IPV6_MULTICAST_HOPS: %m");
+ return (0);
+ }
+ return (1);
+ }
+ break;
+#endif
}
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
- mib[3] = AF_INET;
+ mib[3] = my_sa->sa_family;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
@@ -649,15 +763,37 @@
/* 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)
+#define PORT_SA6(x) ((struct sockaddr_in6 *)(x))->sin6_port
+ if (dstaddr == 0 || dstaddr->sa_family != my_sa->sa_family)
continue;
- PORT_SA(dstaddr) = sp->s_port;
+ switch (dstaddr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ PORT_SA(dstaddr) = PORT_SA(my_sa);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ PORT_SA6(dstaddr) = PORT_SA6(my_sa);
+ break;
+#endif
+ }
+ error = getnameinfo(dstaddr, dstaddr->sa_len, host_dst, NI_MAXHOST, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ syslog(LOG_ERR, "getnameinfo: %s", gai_strerror(error));
+ exit(1);
+ }
for (np = neighbors; np != NULL; np = np->n_next) {
+ error = getnameinfo(np->n_addr, np->n_addr->sa_len, host_np, NI_MAXHOST,
+ NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error != 0) {
+ syslog(LOG_ERR, "getnameinfo: %s", gai_strerror(error));
+ exit(1);
+ }
if (memcmp(sdl->sdl_data, np->n_name,
sdl->sdl_nlen) == 0 &&
- IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) {
+ strcmp(host_np, host_dst) == 0) {
break;
}
}
@@ -677,23 +813,48 @@
if (multicast_mode == PER_INTERFACE_MULTICAST &&
(flags & IFF_MULTICAST) != 0 &&
(flags & IFF_LOOPBACK) == 0) {
- 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");
+ switch (my_sa->sa_family) {
+#ifdef INET
+ case AF_INET: {
+ memcpy((char *)np->n_addr, (char *)ifaddr,
+ np->n_addrlen);
+ greq.gr_group = multicast_addr;
+ greq.gr_interface= if_nametoindex(np->n_name);
+ if (setsockopt(s, IPPROTO_IP, MCAST_JOIN_GROUP,
+ &greq, sizeof(greq)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt MCAST_JOIN_GROUP: %m");
#if 0
/* Fall back to broadcast on this if. */
np->n_flags &= ~IFF_MULTICAST;
#else
- free(np);
- continue;
+ free(np);
+ continue;
+#endif
+ }
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ memcpy((char *)np->n_addr, (char *)ifaddr,
+ np->n_addrlen);
+ greq.gr_group = multicast_addr;
+ greq.gr_interface= if_nametoindex(np->n_name);
+ if (setsockopt(s, IPPROTO_IPV6, MCAST_JOIN_GROUP,
+ &greq, sizeof(greq)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt MCAST_JOIN_GROUP: %m");
+#if 0
+ /* Fall back to broadcast on this if. */
+ np->n_flags &= ~IFF_MULTICAST;
+#else
+ free(np);
+ continue;
+#endif
+ }
+ break;
+ }
#endif
}
}

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 18, 11:36 PM (21 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15905023
Default Alt Text
D45124.diff (13 KB)

Event Timeline