From: Roy Marples Date: Fri, 27 Mar 2020 16:14:48 +0000 (+0000) Subject: dhcpcd: dumping lease uses control socket to get the lease X-Git-Tag: v9.0.0~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4453ac7ac41f08970802477a091f365e52ff15e2;p=thirdparty%2Fdhcpcd.git dhcpcd: dumping lease uses control socket to get the lease Thanks to privsep it's hard to know where the lease is now stored. As such, the only true location is from the running dhcpcd process. The ability to read a raw lease from stdin has been dropped. --- diff --git a/src/dhcp.c b/src/dhcp.c index e7193379..758ad779 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -3690,31 +3690,6 @@ dhcp_openbpf(struct interface *ifp) return 0; } -int -dhcp_dump(struct interface *ifp) -{ - struct dhcp_state *state; - - ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state)); - if (state == NULL) - goto eexit; - state->bpf_fd = -1; - dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), - AF_INET, ifp); - state->new_len = read_lease(ifp, &state->new); - if (state->new == NULL) { - logerr("%s: %s", - *ifp->name ? ifp->name : state->leasefile, __func__); - return -1; - } - state->reason = "DUMP"; - return script_runreason(ifp, state->reason); - -eexit: - logerr(__func__); - return -1; -} - void dhcp_free(struct interface *ifp) { diff --git a/src/dhcp.h b/src/dhcp.h index 8f513454..5b01a52c 100644 --- a/src/dhcp.h +++ b/src/dhcp.h @@ -276,7 +276,6 @@ void dhcp_bind(struct interface *); void dhcp_reboot_newopts(struct interface *, unsigned long long); void dhcp_close(struct interface *); void dhcp_free(struct interface *); -int dhcp_dump(struct interface *); #endif /* INET */ #endif /* DHCP_H */ diff --git a/src/dhcp6.c b/src/dhcp6.c index 4e44edcb..129d5f0e 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -4182,26 +4182,4 @@ delegated: return 1; } - -int -dhcp6_dump(struct interface *ifp) -{ - struct dhcp6_state *state; - - ifp->if_data[IF_DATA_DHCP6] = state = calloc(1, sizeof(*state)); - if (state == NULL) { - logerr(__func__); - return -1; - } - TAILQ_INIT(&state->addrs); - dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), - AF_INET6, ifp); - if (dhcp6_readlease(ifp, 0) == -1) { - logerr("%s: %s", __func__, - *ifp->name ? ifp->name : state->leasefile); - return -1; - } - state->reason = "DUMP6"; - return script_runreason(ifp, state->reason); -} #endif diff --git a/src/dhcp6.h b/src/dhcp6.h index ac2c47a0..c7d11889 100644 --- a/src/dhcp6.h +++ b/src/dhcp6.h @@ -241,7 +241,6 @@ void dhcp6_handleifa(int, struct ipv6_addr *, pid_t); int dhcp6_dadcompleted(const struct interface *); void dhcp6_abort(struct interface *); void dhcp6_drop(struct interface *, const char *); -int dhcp6_dump(struct interface *); #endif /* DHCP6 */ #endif /* DHCP6_H */ diff --git a/src/dhcpcd.8.in b/src/dhcpcd.8.in index d41bf40a..4bd32f78 100644 --- a/src/dhcpcd.8.in +++ b/src/dhcpcd.8.in @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 22, 2020 +.Dd March 27, 2020 .Dt DHCPCD 8 .Os .Sh NAME @@ -684,10 +684,9 @@ To test INFORM the interface needs to be configured with the desired address before starting .Nm . .It Fl U , Fl Fl dumplease Ar interface -Dumps the last lease for the +Dumps the current lease for the .Ar interface to stdout. -If omitted, standard input is used to read a DHCP wire formatted message. Use the .Fl 4 or diff --git a/src/dhcpcd.c b/src/dhcpcd.c index bd2556ea..d70ff37b 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -1458,7 +1458,7 @@ dhcpcd_getinterfaces(void *arg) TAILQ_FOREACH(ifp, fd->ctx->ifaces, next) { if (!ifp->active) continue; - if (send_interface(fd, ifp) == -1) + if (send_interface(fd, ifp, AF_UNSPEC) == -1) logerr(__func__); } } @@ -1469,7 +1469,7 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, { struct interface *ifp; unsigned long long opts; - int opt, oi, do_reboot, do_renew; + int opt, oi, do_reboot, do_renew, af = AF_UNSPEC; size_t len, l; char *tmp, *p; @@ -1492,12 +1492,6 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, return 0; } - /* Only privileged users can control dhcpcd via the socket. */ - if (fd->flags & FD_UNPRIV) { - errno = EPERM; - return -1; - } - /* Log the command */ len = 1; for (opt = 0; opt < argc; opt++) @@ -1542,9 +1536,50 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, case 'N': do_renew = 1; break; + case 'U': + opts |= DHCPCD_DUMPLEASE; + break; + case '4': + af = AF_INET; + break; + case '6': + af = AF_INET6; + break; } } + if (opts & DHCPCD_DUMPLEASE) { + ctx->options |= DHCPCD_DUMPLEASE; + size_t nifaces = 0; + + for (oi = optind; oi < argc; oi++) { + if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) + continue; + if (!ifp->active) + continue; + opt = send_interface(NULL, ifp, af); + if (opt != -1) + nifaces += (size_t)opt; + } + if (write(fd->fd, &nifaces, sizeof(nifaces)) != sizeof(nifaces)) + return -1; + for (oi = optind; oi < argc; oi++) { + if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) + continue; + if (!ifp->active) + continue; + send_interface(fd, ifp, af); + } + ctx->options &= ~DHCPCD_DUMPLEASE; + return 0; + } + + /* Only privileged users can control dhcpcd via the socket. */ + if (fd->flags & FD_UNPRIV) { + errno = EPERM; + return -1; + } + if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) { if (optind == argc) { stop_all_interfaces(ctx, opts); @@ -1583,6 +1618,86 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, return 0; } +static int +dhcpcd_readdump(struct dhcpcd_ctx *ctx) +{ + int error = 0; + size_t nifaces, buflen = 0, dlen; + ssize_t len; + char *buf = NULL, *dp, *de; + bool print; + +again1: + len = read(ctx->control_fd, &nifaces, sizeof(nifaces)); + if (len == -1) { + if (errno == EAGAIN) + goto again1; + return -1; + } + if (len != sizeof(nifaces)) { + errno = EINVAL; + return -1; + } + for (; nifaces > 0; nifaces--) { +again2: + len = read(ctx->control_fd, &dlen, sizeof(dlen)); + if (len == -1) { + if (errno == EAGAIN) + goto again2; + error = -1; + goto out; + } + if (len != sizeof(dlen)) { + errno = EINVAL; + goto out; + } + if (dlen > buflen) { + char *nbuf = realloc(buf, dlen); + if (nbuf == NULL) { + error = -1; + goto out; + } + buf = nbuf; + buflen = dlen; + } +again3: + if (read(ctx->control_fd, buf, dlen) != (ssize_t)dlen) { + if (errno == EAGAIN) + goto again3; + error = -1; + goto out; + } + dp = buf; + de = dp + dlen; + while (dp < de) { + if (dp + 6 >= de) /* _new and = something */ + break; + if (dp[0] == 'n' && dp[3] == '_') { + if (dp[1] == 'e' && dp[2] == 'w') { + print = true; + dp += 4; + } else if (dp[1] == 'd' && + isdigit((unsigned char)dp[2])) + print = true; + } else + print = false; + while (dp < de && *dp != '\0') { + if (print) + putchar(*dp); + dp++; + } + if (print) + putchar('\n'); + dp++; + } + fflush(stdout); + } + +out: + free(buf); + return error; +} + static void dhcpcd_fork_cb(void *arg) { @@ -1891,74 +2006,7 @@ printpidfile: logerr("%s: eloop_signal_mask", __func__); goto exit_failure; } -#endif - if (ctx.options & DHCPCD_DUMPLEASE) { - /* Open sockets so we can dump something about - * valid interfaces. */ - if (if_opensockets(&ctx) == -1) { - logerr("%s: if_opensockets", __func__); - goto exit_failure; - } - if (optind != argc) { - /* We need to try and find the interface so we can load - * the hardware address to compare automated IAID */ - ctx.ifaces = if_discover(&ctx, &ifaddrs, - argc - optind, argv + optind); - } else { - if ((ctx.ifaces = malloc(sizeof(*ctx.ifaces))) != NULL) - TAILQ_INIT(ctx.ifaces); - } - if (ctx.ifaces == NULL) { - logerr("%s: if_discover", __func__); - goto exit_failure; - } - ifp = if_find(ctx.ifaces, argv[optind]); - if (ifp == NULL) { - ifp = calloc(1, sizeof(*ifp)); - if (ifp == NULL) { - logerr(__func__); - goto exit_failure; - } - if (optind != argc) - strlcpy(ctx.pidfile, argv[optind], - sizeof(ctx.pidfile)); - ifp->ctx = &ctx; - TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next); - if (family == 0) { - if (ctx.pidfile[0] != '\0' && - ctx.pidfile[strlen(ctx.pidfile) - 1] == '6') - family = AF_INET6; - else - family = AF_INET; - } - } - configure_interface(ifp, ctx.argc, ctx.argv, 0); - i = 0; - if (family == 0 || family == AF_INET) { -#ifdef INET - if (dhcp_dump(ifp) == -1) - i = -1; -#else - if (family == AF_INET) - logerrx("No INET support"); -#endif - } - if (family == 0 || family == AF_INET6) { -#ifdef DHCP6 - if (dhcp6_dump(ifp) == -1) - i = -1; -#else - if (family == AF_INET6) - logerrx("No DHCP6 support"); -#endif - } - if (i == -1) - goto exit_failure; - goto exit_success; - } - -#ifdef USE_SIGNALS /* Test against siga instead of sig to avoid gcc * warning about a bogus potential signed overflow. * The end result will be the same. */ @@ -1972,18 +2020,30 @@ printpidfile: if (ctx.control_fd == -1) ctx.control_fd = control_open(NULL); if (ctx.control_fd != -1) { - loginfox("sending commands to master dhcpcd process"); + if (!(ctx.options & DHCPCD_DUMPLEASE)) + loginfox("sending commands to dhcpcd process"); len = control_send(&ctx, argc, argv); - if (len > 0) { + if (len > 0) logdebugx("send OK"); - goto exit_success; - } else { + else { logerr("%s: control_send", __func__); goto exit_failure; } + if (ctx.options & DHCPCD_DUMPLEASE) { + if (dhcpcd_readdump(&ctx) == -1) { + logerr("%s: dhcpcd_readdump", __func__); + goto exit_failure; + } + } + goto exit_success; } else { if (errno != ENOENT) logerr("%s: control_open", __func__); + if (ctx.options & DHCPCD_DUMPLEASE) { + if (errno == ENOENT) + logerrx("dhcpcd is not running"); + goto exit_failure; + } } ctx.options &= ~DHCPCD_FORKED; #ifdef USE_SIGNALS @@ -2312,7 +2372,6 @@ exit1: eloop_free(ctx.ps_eloop); #endif eloop_free(ctx.eloop); - if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) loginfox(PACKAGE " exited"); logclose(); diff --git a/src/script.c b/src/script.c index 68aadff7..04620ce1 100644 --- a/src/script.c +++ b/src/script.c @@ -535,7 +535,7 @@ make: if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL) goto eexit; - return buf_pos - 1; + return buf_pos; eexit: logerr(__func__); @@ -556,13 +556,12 @@ send_interface1(struct fd_list *fd, const struct interface *ifp, len = make_env(ifp->ctx, ifp, reason); if (len == -1) return -1; - return control_queue(fd, ctx->script_buf, (size_t)len, 1); + return control_queue(fd, ctx->script_buf, (size_t)len, 1); } int -send_interface(struct fd_list *fd, const struct interface *ifp) +send_interface(struct fd_list *fd, const struct interface *ifp, int af) { - const char *reason; int retval = 0; #ifdef INET const struct dhcp_state *d; @@ -571,50 +570,78 @@ send_interface(struct fd_list *fd, const struct interface *ifp) const struct dhcp6_state *d6; #endif - switch (ifp->carrier) { - case LINK_UP: - reason = "CARRIER"; - break; - case LINK_DOWN: - case LINK_DOWN_IFFUP: - reason = "NOCARRIER"; - break; - default: - reason = "UNKNOWN"; - break; - } - if (send_interface1(fd, ifp, reason) == -1) - retval = -1; -#ifdef INET - if (D_STATE_RUNNING(ifp)) { - d = D_CSTATE(ifp); - if (send_interface1(fd, ifp, d->reason) == -1) - retval = -1; + if (af == AF_UNSPEC || af == AF_LINK) { + const char *reason; + + switch (ifp->carrier) { + case LINK_UP: + reason = "CARRIER"; + break; + case LINK_DOWN: + case LINK_DOWN_IFFUP: + reason = "NOCARRIER"; + break; + default: + reason = "UNKNOWN"; + break; + } + if (fd != NULL) { + if (send_interface1(fd, ifp, reason) == -1) + retval = -1; + } else + retval++; } + +#ifdef INET + if (af == AF_UNSPEC || af == AF_INET) { + if (D_STATE_RUNNING(ifp)) { + d = D_CSTATE(ifp); + if (fd != NULL) { + if (send_interface1(fd, ifp, d->reason) == -1) + retval = -1; + } else + retval++; + } #ifdef IPV4LL - if (IPV4LL_STATE_RUNNING(ifp)) { - if (send_interface1(fd, ifp, "IPV4LL") == -1) - retval = -1; - } + if (IPV4LL_STATE_RUNNING(ifp)) { + if (fd != NULL) { + if (send_interface1(fd, ifp, "IPV4LL") == -1) + retval = -1; + } else + retval++; + } #endif + } #endif #ifdef INET6 - if (IPV6_STATE_RUNNING(ifp)) { - if (send_interface1(fd, ifp, "STATIC6") == -1) - retval = -1; - } - if (RS_STATE_RUNNING(ifp)) { - if (send_interface1(fd, ifp, "ROUTERADVERT") == -1) - retval = -1; - } + if (af == AF_UNSPEC || af == AF_INET6) { + if (IPV6_STATE_RUNNING(ifp)) { + if (fd != NULL) { + if (send_interface1(fd, ifp, "STATIC6") == -1) + retval = -1; + } else + retval++; + } + if (RS_STATE_RUNNING(ifp)) { + if (fd != NULL) { + if (send_interface1(fd, ifp, + "ROUTERADVERT") == -1) + retval = -1; + } else + retval++; + } #ifdef DHCP6 - if (D6_STATE_RUNNING(ifp)) { - d6 = D6_CSTATE(ifp); - if (send_interface1(fd, ifp, d6->reason) == -1) - retval = -1; - } + if (D6_STATE_RUNNING(ifp)) { + d6 = D6_CSTATE(ifp); + if (fd != NULL) { + if (send_interface1(fd, ifp, d6->reason) == -1) + retval = -1; + } else + retval++; + } #endif + } #endif return retval; diff --git a/src/script.h b/src/script.h index e35ca86d..0f20f988 100644 --- a/src/script.h +++ b/src/script.h @@ -35,7 +35,7 @@ __printflike(2, 3) int efprintf(FILE *, const char *, ...); void if_printoptions(void); char ** script_buftoenv(struct dhcpcd_ctx *, char *, size_t); pid_t script_exec(const struct dhcpcd_ctx *, char *const *, char *const *); -int send_interface(struct fd_list *, const struct interface *); +int send_interface(struct fd_list *, const struct interface *, int); int script_runreason(const struct interface *, const char *); int script_runchroot(struct dhcpcd_ctx *, char *); #endif