]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
If we are to add/delete/change a route but have not yet daemonised,
authorRoy Marples <roy@marples.name>
Wed, 6 Jan 2016 10:54:36 +0000 (10:54 +0000)
committerRoy Marples <roy@marples.name>
Wed, 6 Jan 2016 10:54:36 +0000 (10:54 +0000)
flag that we are to track the parent pid.
On successful route message, remember the sequence number.
Once daemonised, ignore messages from the parent pid until we find
the saved sequence number - at this point remove the flag to track parent pid.

This fixes an issue where we didn't correctly ignore messages we generated
before forking but catching them in the child process.

dhcpcd.c
dhcpcd.h
if-bsd.c
if-linux.c
if-options.h

index aee3219ab03fe16dad7d67fc38d9e8136eff6cc9..9ac56c6ba2f1de44a7938a7aaf2691cca0fc1512 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -322,29 +322,38 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
        if (ctx->options & DHCPCD_DAEMONISED ||
            !(ctx->options & DHCPCD_DAEMONISE))
                return 0;
+       logger(ctx, LOG_DEBUG, "forking to background");
+
        /* Setup a signal pipe so parent knows when to exit. */
        if (pipe(sidpipe) == -1) {
                logger(ctx, LOG_ERR, "pipe: %m");
                return 0;
        }
-       logger(ctx, LOG_DEBUG, "forking to background");
+
+       /* 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:
                logger(ctx, LOG_ERR, "fork: %m");
                return 0;
        case 0:
                setsid();
+               /* Notify parent it's safe to exit as we've detached. */
+               close(sidpipe[0]);
+               if (write(sidpipe[1], &buf, 1) == -1)
+                       logger(ctx, LOG_ERR, "failed to notify parent: %m");
+               close(sidpipe[1]);
                /* Some polling methods don't survive after forking,
                 * so ensure we can requeue all our events. */
                if (eloop_requeue(ctx->eloop) == -1) {
                        logger(ctx, LOG_ERR, "eloop_requeue: %m");
                        eloop_exit(ctx->eloop, EXIT_FAILURE);
                }
-               /* Notify parent it's safe to exit as we've detached. */
-               close(sidpipe[0]);
-               if (write(sidpipe[1], &buf, 1) == -1)
-                       logger(ctx, LOG_ERR, "failed to notify parent: %m");
-               close(sidpipe[1]);
                if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
                        dup2(fd, STDIN_FILENO);
                        dup2(fd, STDOUT_FILENO);
index 947afe13d9c2fc4a23f5b3ed8f5aa6e808ebf062..ea1a7df5e92188240aceda8120701a57f15ae0b5 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -122,6 +122,7 @@ struct dhcpcd_ctx {
 #endif
        int link_fd;
        int seq;        /* route message sequence no */
+       int sseq;       /* successful seq no sent */
 
 #ifdef USE_SIGNALS
        sigset_t sigset;
@@ -140,6 +141,13 @@ 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 db1738054a28454fd6fd44c1ee71db4b8dd19940..9d263249ab83d0b7da7dcf54c6af2c5f1a67fa18 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -541,6 +541,11 @@ if_route(unsigned char cmd, const struct rt *rt)
        size_t l;
        struct in_addr src_addr;
 
+       if ((cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE) &&
+           rt->iface->ctx->options & DHCPCD_DAEMONISE &&
+           !(rt->iface->ctx->options & DHCPCD_DAEMONISED))
+               rt->iface->ctx->options |= DHCPCD_RTM_PPID;
+
 #define ADDSU {                                                                      \
                l = RT_ROUNDUP(su.sa.sa_len);                                 \
                memcpy(bp, &su, l);                                           \
@@ -658,8 +663,10 @@ if_route(unsigned char cmd, const struct rt *rt)
 #undef ADDSU
 
        rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
-       return write(rt->iface->ctx->link_fd,
-           &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
+       if (write(rt->iface->ctx->link_fd, &rtm, rtm.hdr.rtm_msglen) == -1)
+               return -1;
+       rt->iface->ctx->sseq = rt->iface->ctx->seq;
+       return 0;
 }
 
 int
@@ -926,6 +933,11 @@ if_route6(unsigned char cmd, const struct rt6 *rt)
        char *bp = rtm.buffer;
        size_t l;
 
+       if ((cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE) &&
+           rt->iface->ctx->options & DHCPCD_DAEMONISE &&
+           !(rt->iface->ctx->options & DHCPCD_DAEMONISED))
+               rt->iface->ctx->options |= DHCPCD_RTM_PPID;
+
 #define ADDSU {                                                                      \
                l = RT_ROUNDUP(su.sa.sa_len);                                 \
                memcpy(bp, &su, l);                                           \
@@ -1010,8 +1022,10 @@ if_route6(unsigned char cmd, const struct rt6 *rt)
 #undef ADDSU
 
        rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
-       return write(rt->iface->ctx->link_fd,
-           &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
+       if (write(rt->iface->ctx->link_fd, &rtm, rtm.hdr.rtm_msglen) == -1)
+               return -1;
+       rt->iface->ctx->sseq = rt->iface->ctx->seq;
+       return 0;
 }
 
 int
@@ -1136,9 +1150,26 @@ if_managelink(struct dhcpcd_ctx *ctx)
        e = msg + bytes;
        for (p = msg; p < e; p += rtm->rtm_msglen) {
                rtm = (struct rt_msghdr *)(void *)p;
-               // Ignore messages generated by us
-               if (rtm->rtm_pid == getpid())
-                       break;
+               if (rtm->rtm_type == RTM_MISS)
+                       continue;
+               /* Ignore messages generated by us */
+               if (rtm->rtm_pid == getpid()) {
+                       ctx->options &= ~DHCPCD_RTM_PPID;
+                       continue;
+               }
+               /* Ignore messages sent by the parent process 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 the kernel
+                        * routing table. */
+                       if (rtm->rtm_seq == ctx->pseq)
+                               ctx->options &= ~DHCPCD_RTM_PPID;
+                       continue;
+               }
                switch(rtm->rtm_type) {
 #ifdef RTM_IFANNOUNCE
                case RTM_IFANNOUNCE:
index b78f180030f4dd6ecf5081551a045f6341b3a679..051449085a8f7bb8ba81b665327d606d1b26fb1c 100644 (file)
@@ -886,9 +886,10 @@ send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
        hdr->nlmsg_flags |= NLM_F_ACK;
        hdr->nlmsg_seq = ++ctx->seq;
 
-       if (sendmsg(s, &msg, 0) != -1)
+       if (sendmsg(s, &msg, 0) != -1) {
+               ctx->sseq = ctx-seq;
                r = get_netlink(ctx, ifp, s, 0, callback);
-       else
+       else
                r = -1;
        close(s);
        return r;
index 429e8b5e2684d2e4894b5a7d47b44bc0a1520e0c..df33784d22617f315b1643d3553b66a0a3ed5f50 100644 (file)
 #define DHCPCD_DHCP6                   (1ULL << 50)
 #define DHCPCD_IF_UP                   (1ULL << 51)
 #define DHCPCD_INFORM6                 (1ULL << 52)
-// unassinged                          (1ULL << 53)
+#define DHCPCD_RTM_PPID                        (1ULL << 53)
 #define DHCPCD_IPV6RA_AUTOCONF         (1ULL << 54)
 #define DHCPCD_ROUTER_HOST_ROUTE_WARNED        (1ULL << 55)
 #define DHCPCD_IPV6RA_ACCEPT_NOPUBLIC  (1ULL << 56)