]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
BSD: don't listen to own route messages
authorRoy Marples <roy@marples.name>
Fri, 30 Nov 2018 03:27:57 +0000 (03:27 +0000)
committerRoy Marples <roy@marples.name>
Fri, 30 Nov 2018 03:27:57 +0000 (03:27 +0000)
This makes the code a lot simpler and reduces the changes
of overflowing the route socket.

src/dhcpcd.c
src/dhcpcd.h
src/if-bsd.c
src/if-linux.c
src/if-options.h
src/if-sun.c
src/ipv4.c

index 55558c3c23affc9fa925702ae86fa3c45d865b4e..a007923daf5fbf1b9aa58c1743bd15f0ac1379ec 100644 (file)
@@ -314,13 +314,6 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
                return 0;
        }
 
-       /* Store the pid and routing message seq number so we can identify
-        * the last message successfully sent to the kernel.
-        * This allows us to ignore all messages we sent after forking
-        * and detaching. */
-       ctx->ppid = getpid();
-       ctx->pseq = ctx->sseq;
-
        switch (pid = fork()) {
        case -1:
                logerr("%s: fork", __func__);
index 4f1c2101d5a186782f68d67ecfc2b24c2f755774..9743ae629a6c58065049f924c5937ca16a6c5051 100644 (file)
@@ -166,13 +166,6 @@ struct dhcpcd_ctx {
 
        char *randomstate; /* original state */
 
-       /* Used to track the last routing message,
-        * so we can ignore messages the parent process sent
-        * but the child receives when forking.
-        * getppid(2) is unreliable because we detach. */
-       pid_t ppid;     /* parent pid */
-       int pseq;       /* last seq in parent */
-
 #ifdef INET
        struct dhcp_opt *dhcp_opts;
        size_t dhcp_opts_len;
index e9ebfdcef01e659d526109ccaebe23edbe25e561..68914b87a50deebad76958a3f89a2038fa4d0433 100644 (file)
@@ -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__);
index b5f7983d6b6bae4edfce88a17dde954974244ab7..88e879cc148aef7fd1d7231f44f66fc6da8c66f0 100644 (file)
@@ -854,7 +854,6 @@ send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
                struct priv *priv;
 
                priv = (struct priv *)ctx->priv;
-               ctx->sseq = ctx->seq;
                r = get_netlink(ctx, priv->sndrcv_iov, ifp, s, 0, callback);
        } else
                r = -1;
index 8dfe3486e94689f50d334390c2a13f638985ac4b..8a3c4479de54d7eb00688568e9b43b62ad7a7dde 100644 (file)
 #define DHCPCD_DHCP6                   (1ULL << 50)
 #define DHCPCD_IF_UP                   (1ULL << 51)
 #define DHCPCD_INFORM6                 (1ULL << 52)
-#define DHCPCD_RTM_PPID                        (1ULL << 53)
+// unused                              (1ULL << 53)
 #define DHCPCD_IPV6RA_AUTOCONF         (1ULL << 54)
 #define DHCPCD_ROUTER_HOST_ROUTE_WARNED        (1ULL << 55)
 #define DHCPCD_LASTLEASE_EXTEND                (1ULL << 56)
index dfe7734a83ec760971fbdf8a8e2c622741e570dd..4f902ba3f8104e95db445349890a4e0a32e6f35f 100644 (file)
@@ -114,6 +114,7 @@ int
 if_opensockets_os(struct dhcpcd_ctx *ctx)
 {
        struct priv             *priv;
+       int                     n;
 
        if ((priv = malloc(sizeof(*priv))) == NULL)
                return -1;
@@ -128,11 +129,21 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
 
        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
@@ -537,27 +548,6 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
        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
@@ -989,10 +979,6 @@ if_route(unsigned char cmd, const struct rt *rt)
         * 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)));                                  \
@@ -1069,7 +1055,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;
 }
 
index 8008f9e658df38de4791bcc36f291cf8cb79f356..3720f153f8bd36c06bbf9de20843c592f324c3b3 100644 (file)
@@ -880,6 +880,9 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
        case RTM_DELADDR:
                if (ia == NULL)
                        return;
+               if (mask->s_addr != INADDR_ANY &&
+                   mask->s_addr != ia->mask.s_addr)
+                       return;
                TAILQ_REMOVE(&state->addrs, ia, next);
                break;
        default: