if_opensockets_os(struct dhcpcd_ctx *ctx)
{
struct priv *priv;
-#ifdef SO_RERROR
- int on = 1;
-#endif
+ int n;
#if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER)
unsigned char msgfilter[] = {
RTM_IFINFO,
if (ctx->link_fd == -1)
return -1;
+ /* Ignore our own route(4) messages.
+ * Sadly there is no way of doing this for route(4) messages
+ * generated from addresses we add/delete. */
+ n = 0;
+ if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_USELOOPBACK,
+ &n, sizeof(n)) == -1)
+ logerr("%s: SO_USELOOPBACK", __func__);
+
#ifdef SO_RERROR
/* Tell recvmsg(2) to return ENOBUFS if the receiving socket overflows
* from too many route(4) messages so we can re-sync our state
* with reality. */
+ n = 1;
if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RERROR,
- &on, sizeof(on)) == -1)
+ &n, sizeof(n)) == -1)
logerr("%s: SO_RERROR", __func__);
#endif
assert(rt != NULL);
ctx = rt->rt_ifp->ctx;
- if ((cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE) &&
- ctx->options & DHCPCD_DAEMONISE &&
- !(ctx->options & DHCPCD_DAEMONISED))
- ctx->options |= DHCPCD_RTM_PPID;
-
#define ADDSA(sa) do { \
memcpy(bp, (sa), (sa)->sa_len); \
bp += RT_ROUNDUP((sa)->sa_len); \
rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1)
return -1;
- ctx->sseq = ctx->seq;
return 0;
}
cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa);
}
-#if !(defined(HAVE_IFADDRS_ADDRFLAGS) && defined(HAVE_IFAM_ADDRFLAGS))
int
if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
__unused const char *alias)
flags = -1;
return flags;
}
-#endif
int
if_getlifetime6(struct ipv6_addr *ia)
(unsigned int)ifm->ifm_flags, ifp->name);
}
-static int
-if_ownmsgpid(struct dhcpcd_ctx *ctx, pid_t pid, int seq)
-{
-
- /* Ignore messages generated by us */
- if (getpid() == pid) {
- ctx->options &= ~DHCPCD_RTM_PPID;
- return 1;
- }
-
- /* Ignore messages sent by the parent after forking */
- if ((ctx->options &
- (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED)) ==
- (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED) &&
- ctx->ppid == pid)
- {
- /* If this is the last successful message sent,
- * clear the check flag as it's possible another
- * process could re-use the same pid and also
- * manipulate the routing table. */
- if (ctx->pseq == seq)
- ctx->options &= ~DHCPCD_RTM_PPID;
- return 1;
- }
-
- /* Not a message we made. */
- return 0;
-}
-
static void
if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
{
struct rt rt;
- if (if_ownmsgpid(ctx, rtm->rtm_pid, rtm->rtm_seq))
- return;
-
/* Ignore errors. */
if (rtm->rtm_errno != 0)
return;
return;
#ifdef HAVE_IFAM_PID
- if (if_ownmsgpid(ctx, ifam->ifam_pid, 0)) {
-#ifdef HAVE_IFAM_ADDRFLAGS
- /* If the kernel isn't doing DAD for the newly added
- * address we need to let it through. */
- if (ifam->ifam_type != RTM_NEWADDR)
- return;
- switch (rti_info[RTAX_IFA]->sa_family) {
- case AF_INET:
- if (ifam->ifam_addrflags & IN_IFF_TENTATIVE)
- return;
- break;
- case AF_INET6:
- if (ifam->ifam_addrflags & IN6_IFF_TENTATIVE)
- return;
- break;
- default:
- return;
- }
-#endif
- }
pid = ifam->ifam_pid;
#else
pid = 0;
sin = (const void *)rti_info[RTAX_NETMASK];
mask.s_addr = sin != NULL && sin->sin_family == AF_INET ?
sin->sin_addr.s_addr : INADDR_ANY;
+ sin = (const void *)rti_info[RTAX_BRD];
+ bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ?
+ sin->sin_addr.s_addr : INADDR_ANY;
#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
- /* NetBSD-7 and older send an invalid broadcast address.
+ /*
+ * NetBSD-7 and older send an invalid broadcast address.
* So we need to query the actual address to get
- * the right one. */
+ * the right one.
+ */
{
+#else
+ /*
+ * If the address was deleted, lets check if it's
+ * a late message and it still exists (maybe modified).
+ * If so, ignore it as deleting an address causes
+ * dhcpcd to drop any lease to which it belongs.
+ */
+ if (ifam->ifam_type == RTM_DELADDR) {
+#endif
+#ifdef SIOCGIFALIAS
struct in_aliasreq ifra;
memset(&ifra, 0, sizeof(ifra));
if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) {
if (errno != EADDRNOTAVAIL)
logerr("%s: SIOCGIFALIAS", __func__);
- break;
+ if (ifam->ifam_type != RTM_DELADDR)
+ break;
}
- bcast = ifra.ifra_broadaddr.sin_addr;
- }
-#else
- sin = (const void *)rti_info[RTAX_BRD];
- bcast.s_addr = sin != NULL && sin->sin_family == AF_INET ?
- sin->sin_addr.s_addr : INADDR_ANY;
+#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000
+ else
+ bcast = ifra.ifra_broadaddr.sin_addr;
#endif
-
-#if defined(__FreeBSD__) || defined(__DragonFly__)
- /* FreeBSD sends RTM_DELADDR for each assigned address
- * to an interface just brought down.
- * This is wrong, because the address still exists.
- * So we need to ignore it.
- * Oddly enough this only happens for INET addresses. */
- if (ifam->ifam_type == RTM_DELADDR) {
- struct ifreq ifr;
- struct sockaddr_in *ifr_sin;
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
- ifr_sin = (void *)&ifr.ifr_addr;
- ifr_sin->sin_family = AF_INET;
- ifr_sin->sin_addr = addr;
- if (ioctl(ctx->pf_inet_fd, SIOCGIFADDR, &ifr) == 0) {
- logwarnx("%s: ignored false RTM_DELADDR for %s",
- ifp->name, inet_ntoa(addr));
- break;
+#else
+#warning No SIOCGIFALIAS support
+ /*
+ * No SIOCGIFALIAS? That sucks!
+ * This makes this call very heavy weight, but we
+ * really need to know if the message is late or not.
+ */
+ struct ifaddrs *ifaddrs = NULL, *ifa;
+ struct in_addr *a;
+
+ getifaddrs(&ifa);
+ for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ a = (void *)ifa->ifa_addr;
+ if (a->s_addr == addr.s_addr &&
+ strcmp(ifa->ifa_name, ifp->name) == 0)
+ break;
}
- }
+ freeifaddrs(ifa);
+ if (ifa != NULL)
+ break;
#endif
+ }
#ifndef HAVE_IFAM_ADDRFLAGS
if (ifam->ifam_type == RTM_DELADDR)
{
struct in6_addr addr6, mask6;
const struct sockaddr_in6 *sin6;
+ int flags;
sin6 = (const void *)rti_info[RTAX_IFA];
addr6 = sin6->sin6_addr;
sin6 = (const void *)rti_info[RTAX_NETMASK];
mask6 = sin6->sin6_addr;
+ /*
+ * If the address was deleted, lets check if it's
+ * a late message and it still exists (maybe modified).
+ * If so, ignore it as deleting an address causes
+ * dhcpcd to drop any lease to which it belongs.
+ */
+ if (ifam->ifam_type == RTM_DELADDR) {
+ flags = if_addrflags6(ifp, &addr6, NULL);
+ if (flags != -1)
+ break;
+ addrflags = 0;
+ }
#ifndef HAVE_IFAM_ADDRFLAGS
- if (ifam->ifam_type == RTM_DELADDR)
- addrflags = 0;
else if ((addrflags = if_addrflags6(ifp, &addr6, NULL)) == -1) {
if (errno != EADDRNOTAVAIL)
logerr("%s: if_addrflags6", __func__);
if_opensockets_os(struct dhcpcd_ctx *ctx)
{
struct priv *priv;
+ int n;
if ((priv = malloc(sizeof(*priv))) == NULL)
return -1;
ctx->link_fd = socket(PF_ROUTE,
SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-#ifdef INET
- if (ctx->link_fd == -1)
+
+ if (ctx->link_fd == -1) {
free(ctx->priv);
-#endif
- return ctx->link_fd == -1 ? -1 : 0;
+ return -1;
+ }
+
+ /* Ignore our own route(4) messages.
+ * Sadly there is no way of doing this for route(4) messages
+ * generated from addresses we add/delete. */
+ n = 0;
+ if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_USELOOPBACK,
+ &n, sizeof(n)) == -1)
+ logerr("%s: SO_USELOOPBACK", __func__);
+
+ return 0;
}
void
const struct sockaddr *sa;
struct rt rt;
- /* Ignore messages generated by us */
- if (rtm->rtm_pid == getpid()) {
- ctx->options &= ~DHCPCD_RTM_PPID;
- return;
- }
-
- /* Ignore messages sent by the parent after forking */
- if ((ctx->options &
- (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED)) ==
- (DHCPCD_RTM_PPID | DHCPCD_DAEMONISED) &&
- rtm->rtm_pid == ctx->ppid)
- {
- /* If this is the last successful message sent,
- * clear the check flag as it's possible another
- * process could re-use the same pid and also
- * manipulate therouting table. */
- if (rtm->rtm_seq == ctx->pseq)
- ctx->options &= ~DHCPCD_RTM_PPID;
- return;
- }
-
sa = (const void *)(rtm + 1);
switch (sa->sa_family) {
#ifdef INET6
* This includes subnet/prefix routes. */
ctx = rt->rt_ifp->ctx;
- if ((cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE) &&
- ctx->options & DHCPCD_DAEMONISE &&
- !(ctx->options & DHCPCD_DAEMONISED))
- ctx->options |= DHCPCD_RTM_PPID;
#define ADDSA(sa) do { \
l = RT_ROUNDUP(salen((sa))); \
rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1)
return -1;
- ctx->sseq = ctx->seq;
return 0;
}