changeset 2546:06457f0bd444 draft

Add the ability to dump DHCPv6 leases. Control DHCPv4 vs DHCPv6 dumping via the family option.
author Roy Marples <roy@marples.name>
date Sun, 22 Jun 2014 13:05:05 +0000
parents 7cb89ed1d31e
children b3c982abad99
files dhcp.c dhcp.h dhcp6.c dhcp6.h dhcpcd-hooks/02-dump dhcpcd.c
diffstat 6 files changed, 84 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/dhcp.c	Sun Jun 22 10:06:53 2014 +0000
+++ b/dhcp.c	Sun Jun 22 13:05:05 2014 +0000
@@ -2733,40 +2733,23 @@
 }
 
 int
-dhcp_dump(struct dhcpcd_ctx *ctx, const char *ifname)
+dhcp_dump(struct interface *ifp)
 {
-	struct interface *ifp;
 	struct dhcp_state *state;
 
-	if (ctx->ifaces == NULL) {
-		ctx->ifaces = malloc(sizeof(*ctx->ifaces));
-		if (ctx->ifaces == NULL)
-			return -1;
-		TAILQ_INIT(ctx->ifaces);
-	}
-	state = NULL;
-	ifp = calloc(1, sizeof(*ifp));
-	if (ifp == NULL)
-		goto eexit;
-	ifp->ctx = ctx;
-	TAILQ_INSERT_HEAD(ctx->ifaces, ifp, next);
 	ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
 	if (state == NULL)
 		goto eexit;
-	ifp->options = calloc(1, sizeof(*ifp->options));
-	if (ifp->options == NULL)
-		goto eexit;
-	strlcpy(ifp->name, ifname, sizeof(ifp->name));
 	snprintf(state->leasefile, sizeof(state->leasefile),
 	    LEASEFILE, ifp->name);
 	state->new = read_lease(ifp);
 	if (state->new == NULL && errno == ENOENT) {
-		strlcpy(state->leasefile, ifname, sizeof(state->leasefile));
+		strlcpy(state->leasefile, ifp->name, sizeof(state->leasefile));
 		state->new = read_lease(ifp);
 	}
 	if (state->new == NULL) {
 		if (errno == ENOENT)
-			syslog(LOG_ERR, "%s: no lease to dump", ifname);
+			syslog(LOG_ERR, "%s: no lease to dump", ifp->name);
 		return -1;
 	}
 	state->reason = "DUMP";
--- a/dhcp.h	Sun Jun 22 10:06:53 2014 +0000
+++ b/dhcp.h	Sun Jun 22 13:05:05 2014 +0000
@@ -285,7 +285,7 @@
 void dhcp_reboot_newopts(struct interface *, unsigned long long);
 void dhcp_close(struct interface *);
 void dhcp_free(struct interface *);
-int dhcp_dump(struct dhcpcd_ctx *, const char *);
+int dhcp_dump(struct interface *);
 #else
 #define dhcp_printoptions
 #define dhcp_drop(a, b)
@@ -294,7 +294,7 @@
 #define dhcp_reboot_newopts(a, b)
 #define dhcp_close(a)
 #define dhcp_free(a)
-#define dhcp_dump(a, b) -1
+#define dhcp_dump(a) -1
 #endif
 
 #endif
--- a/dhcp6.c	Sun Jun 22 10:06:53 2014 +0000
+++ b/dhcp6.c	Sun Jun 22 13:05:05 2014 +0000
@@ -1665,6 +1665,7 @@
 	if (stat(state->leasefile, &st) == -1) {
 		if (errno == ENOENT)
 			return 0;
+		syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
 		return -1;
 	}
 	syslog(LOG_DEBUG, "%s: reading lease `%s'",
@@ -1674,12 +1675,17 @@
 		return -1;
 	}
 	state->new = malloc((size_t)st.st_size);
-	if (state->new == NULL)
+	if (state->new == NULL) {
+		syslog(LOG_ERR, "%s: %m", __func__);
 		return -1;
+	}
 	state->new_len = (size_t)st.st_size;
 	fd = open(state->leasefile, O_RDONLY);
-	if (fd == -1)
+	if (fd == -1) {
+		syslog(LOG_ERR, "%s: %s: %s: %m", ifp->name, __func__,
+		    state->leasefile);
 		return -1;
+	}
 	bytes = read(fd, state->new, state->new_len);
 	close(fd);
 	if (bytes < (ssize_t)state->new_len) {
@@ -2978,3 +2984,35 @@
 
 	return (ssize_t)n;
 }
+
+int
+dhcp6_dump(struct interface *ifp)
+{
+	struct dhcp6_state *state;
+	int r;
+
+	ifp->if_data[IF_DATA_DHCP6] = state = calloc(1, sizeof(*state));
+	if (state == NULL)
+		goto eexit;
+	TAILQ_INIT(&state->addrs);
+	snprintf(state->leasefile, sizeof(state->leasefile),
+	    LEASEFILE6, ifp->name);
+	r = dhcp6_readlease(ifp);
+	if (r == -1 && errno == ENOENT) {
+		strlcpy(state->leasefile, ifp->name, sizeof(state->leasefile));
+		r = dhcp6_readlease(ifp);
+	}
+	if (r == -1) {
+		if (errno == ENOENT)
+			syslog(LOG_ERR, "%s: no lease to dump", ifp->name);
+		else
+			syslog(LOG_ERR, "%s: dhcp6_readlease: %m", ifp->name);
+		return -1;
+	}
+	state->reason = "DUMP6";
+	return script_runreason(ifp, state->reason);
+
+eexit:
+	syslog(LOG_ERR, "%s: %m", __func__);
+	return -1;
+}
--- a/dhcp6.h	Sun Jun 22 10:06:53 2014 +0000
+++ b/dhcp6.h	Sun Jun 22 13:05:05 2014 +0000
@@ -236,6 +236,7 @@
 void dhcp6_handleifa(struct dhcpcd_ctx *, int, const char *,
     const struct in6_addr *addr, int);
 void dhcp6_drop(struct interface *, const char *);
+int dhcp6_dump(struct interface *);
 #else
 #define dhcp6_printoptions()
 #define dhcp6_addrexists(a, b) (0)
@@ -245,6 +246,7 @@
 #define dhcp6_env(a, b, c, d, e)
 #define dhcp6_free(a)
 #define dhcp6_drop(a, b)
+#define dhcp6_dump(a) -1
 #endif
 
 #endif
--- a/dhcpcd-hooks/02-dump	Sun Jun 22 10:06:53 2014 +0000
+++ b/dhcpcd-hooks/02-dump	Sun Jun 22 13:05:05 2014 +0000
@@ -1,6 +1,8 @@
 # Just echo our DHCP options we have
 
-if [ "$reason" = "DUMP" ]; then
+case "$reason" in
+DUMP|DUMP6)
 	set | sed -ne 's/^new_//p' | sort
 	exit 0
-fi
+	;;
+esac
--- a/dhcpcd.c	Sun Jun 22 10:06:53 2014 +0000
+++ b/dhcpcd.c	Sun Jun 22 13:05:05 2014 +0000
@@ -1351,12 +1351,44 @@
 	if (chdir("/") == -1)
 		syslog(LOG_ERR, "chdir `/': %m");
 
+	/* Freeing allocated addresses from dumping leases can trigger
+	 * eloop removals as well, so init here. */
+	ctx.eloop = eloop_init();
+	if (ctx.eloop == NULL) {
+		syslog(LOG_ERR, "%s: %m", __func__);
+		goto exit_failure;
+	}
+
 	if (ctx.options & DHCPCD_DUMPLEASE) {
 		if (optind != argc - 1) {
 			syslog(LOG_ERR, "dumplease requires an interface");
 			goto exit_failure;
 		}
-		if (dhcp_dump(&ctx, argv[optind]) == -1)
+		i = 0;
+		if (ctx.ifaces == NULL) {
+			ctx.ifaces = malloc(sizeof(*ctx.ifaces));
+			if (ctx.ifaces == NULL) {
+				syslog(LOG_ERR, "%s: %m", __func__);
+				goto exit_failure;
+			}
+			TAILQ_INIT(ctx.ifaces);
+		}
+		ifp = calloc(1, sizeof(*ifp));
+		if (ifp == NULL)
+			goto exit_failure;
+		strlcpy(ifp->name, argv[optind], sizeof(ifp->name));
+		ifp->ctx = &ctx;
+		TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
+		configure_interface(ifp, 0, NULL);
+		if (family == 0 || family == AF_INET) {
+			if (dhcp_dump(ifp) == -1)
+				i = 1;
+		}
+		if (family == 0 || family == AF_INET6) {
+			if (dhcp6_dump(ifp) == -1)
+				i = 1;
+		}
+		if (i == -1)
 			goto exit_failure;
 		goto exit_success;
 	}
@@ -1396,12 +1428,6 @@
 		syslog(LOG_WARNING,
 		    PACKAGE " will not work correctly unless run as root");
 
-	ctx.eloop = eloop_init();
-	if (ctx.eloop == NULL) {
-		syslog(LOG_ERR, "%s: %m", __func__);
-		goto exit_failure;
-	}
-
 #ifdef USE_SIGNALS
 	if (sig != 0) {
 		pid = read_pid(pidfile);