Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157543266
D45123.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D45123.id.diff
View Options
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
@@ -39,6 +39,7 @@
#include <sys/signal.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
+#include <sys/_sockaddr_storage.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -73,16 +74,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 *sa;
/*
* Sleep interval. Don't forget to change the down time check in ruptime
@@ -107,7 +113,6 @@
struct neighbor *neighbors;
struct whod mywd;
-struct servent *sp;
int s;
int fdp;
pid_t pid_child_receiver;
@@ -163,9 +168,9 @@
int
main(int argc, char *argv[])
{
- int on;
+ int on, error, success = 0;
char *cp;
- struct sockaddr_in soin;
+ struct addrinfo hints, *servinfo, *p;
uid_t unpriv_uid;
gid_t unpriv_gid;
@@ -210,9 +215,14 @@
#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");
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(NULL, "who", &hints, &servinfo);
+ if (error) {
+ const char *error_message = gai_strerror(error);
+ syslog(LOG_ERR, "getaddrinfo: %s", error_message);
exit(1);
}
if (chdir(_PATH_RWHODIR) < 0) {
@@ -230,22 +240,51 @@
*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 = servinfo; 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, SOL_SOCKET, 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
+ };
+ if (bind(s, p->ai_addr, p->ai_addrlen) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ close(s);
+ continue;
+ }
+
+ sa = p->ai_addr; // Save as global variable
+ 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");
- exit(1);
+ if (!success) {
+ syslog(LOG_ERR, "No suitable address found for creating a socket");
+ exit(1); // Exit with an error status
}
+
if (setgid(unpriv_gid) != 0) {
syslog(LOG_ERR, "setgid: %m");
exit(1);
@@ -278,6 +317,7 @@
} else {
receiver_process();
}
+ freeaddrinfo(servinfo);
}
static void
@@ -336,14 +376,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,6 +402,12 @@
syslog(LOG_ERR, "cap_enter: %m");
exit(1);
}
+ error = getnameinfo(sa, sizeof(*sa), host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); // Get address and port of us
+ if (error) {
+ const char *error_message = gai_strerror(error);
+ syslog(LOG_ERR, "getnameinfo: %s", error_message);
+ exit(1);
+ }
for (;;) {
cc = recvfrom(s, &wd, sizeof(wd), 0, (struct sockaddr *)&from,
&len);
@@ -370,14 +416,20 @@
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) {
+ const char *error_message = gai_strerror(error);
+ syslog(LOG_ERR, "getnameinfo: %s", error_message);
+ exit(1);
+ }
+ if (strcmp(service, service_from) && !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 +438,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);
@@ -497,13 +549,31 @@
* 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:
+ if (setsockopt(s, IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ &(((struct sockaddr_in6*)np->n_addr)->sin6_addr),
+ sizeof(struct in6_addr)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IPV6_MULTICAST_IF: %m");
+ exit(1);
+ }
+ break;
+#endif
}
(void) sendto(s, (char *)&mywd, cc, 0,
(struct sockaddr *)&multicast_addr,
@@ -579,42 +649,82 @@
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;
-
- 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);
- }
- 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);
+ switch (sa->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if (multicast_mode != NO_MULTICAST) {
+ struct sockaddr_in tmp;
+ tmp.sin_family = AF_INET;
+ tmp.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP);
+ tmp.sin_port = ((struct sockaddr_in *)(sa))->sin_port;
+ struct sockaddr *tmp2 = (struct sockaddr *)&tmp;
+ memcpy(&multicast_addr, tmp2, sizeof(multicast_addr));
+ }
+ 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(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IP_ADD_MEMBERSHIP: %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);
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (multicast_mode != NO_MULTICAST) {
+ struct sockaddr_in6 tmp;
+ tmp.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, IN6ADDR_WHOD_GROUP, &(tmp.sin6_addr));
+ tmp.sin6_port = ((struct sockaddr_in6 *)(sa))->sin6_port;
+ struct sockaddr *tmp2 = (struct sockaddr *)&tmp;
+ memcpy(&multicast_addr, tmp2, sizeof(multicast_addr));
+ }
+ if (multicast_mode == SCOPED_MULTICAST) {
+ struct ipv6_mreq mreq;
+ unsigned char ttl;
+ inet_pton(AF_INET6, IN6ADDR_WHOD_GROUP, &mreq.ipv6mr_multiaddr);
+ mreq.ipv6mr_interface = 0;
+ if (setsockopt(so, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
+ sizeof(mreq)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IPV6_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] = sa->sa_family;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
@@ -649,15 +759,38 @@
/* 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 != sa->sa_family)
continue;
- PORT_SA(dstaddr) = sp->s_port;
+ switch (dstaddr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ PORT_SA(dstaddr) = PORT_SA(sa);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ PORT_SA6(dstaddr) = PORT_SA6(sa);
+ break;
+#endif
+ }
+ error = getnameinfo(dstaddr, sizeof(*dstaddr), host_dst, NI_MAXHOST, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error) {
+ const char *error_message = gai_strerror(error);
+ syslog(LOG_ERR, "getnameinfo: %s", error_message);
+ exit(1);
+ }
for (np = neighbors; np != NULL; np = np->n_next) {
+ error = getnameinfo(np->n_addr, sizeof(*np->n_addr), host_np, NI_MAXHOST, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error) {
+ const char *error_message = gai_strerror(error);
+ syslog(LOG_ERR, "getnameinfo: %s", error_message);
+ 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)) {
break;
}
}
@@ -677,23 +810,57 @@
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 (sa->sa_family) {
+#ifdef INET
+ case AF_INET: {
+ 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(np);
- continue;
+ free(np);
+ continue;
+#endif
+ }
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct ipv6_mreq mreq6;
+ memcpy((char *)np->n_addr, (char *)ifaddr,
+ np->n_addrlen);
+
+ inet_pton(AF_INET6, IN6ADDR_WHOD_GROUP,
+ &mreq6.ipv6mr_multiaddr);
+ mreq6.ipv6mr_interface = 0;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ (const char *)&mreq6,
+ sizeof(mreq6)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt IPV6_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
Details
Attached
Mime Type
text/plain
Expires
Sat, May 23, 3:39 PM (9 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33448997
Default Alt Text
D45123.id.diff (13 KB)
Attached To
Mode
D45123: rwhod: IPv6 clean
Attached
Detach File
Event Timeline
Log In to Comment