diff options
| author | Roy Marples <roy@marples.name> | 2018-11-30 03:27:57 +0000 |
|---|---|---|
| committer | Roy Marples <roy@marples.name> | 2018-11-30 03:27:57 +0000 |
| commit | 642351e6355a614c1a362a9e739f05a680d17703 (patch) | |
| tree | 4841069833fab775d61bfdc89a3f8a7ca031a0f4 /src/if-bsd.c | |
| parent | 8b3fe788e6549825121872d4aad2fcf67abb88b7 (diff) | |
| download | dhcpcd-642351e6355a614c1a362a9e739f05a680d17703.tar.xz | |
BSD: don't listen to own route messages
This makes the code a lot simpler and reduces the changes
of overflowing the route socket.
Diffstat (limited to 'src/if-bsd.c')
| -rw-r--r-- | src/if-bsd.c | 165 |
1 files changed, 69 insertions, 96 deletions
diff --git a/src/if-bsd.c b/src/if-bsd.c index e9ebfdce..68914b87 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -125,9 +125,7 @@ int 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, @@ -164,12 +162,21 @@ if_opensockets_os(struct dhcpcd_ctx *ctx) 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 @@ -477,11 +484,6 @@ if_route(unsigned char cmd, const struct rt *rt) 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); \ @@ -596,7 +598,6 @@ if_route(unsigned char cmd, const struct rt *rt) 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; } @@ -873,7 +874,6 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia) 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) @@ -894,7 +894,6 @@ if_addrflags6(const struct interface *ifp, const struct in6_addr *addr, flags = -1; return flags; } -#endif int if_getlifetime6(struct ipv6_addr *ia) @@ -975,43 +974,11 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) (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; @@ -1058,26 +1025,6 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) 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; @@ -1115,12 +1062,27 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) 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)); @@ -1132,38 +1094,38 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) 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) @@ -1185,15 +1147,26 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) { 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__); |
