changeset 4177:bce060648873 draft

Ensure that xid is unique across all interfaces.
author Roy Marples <roy@marples.name>
date Mon, 06 Nov 2017 12:10:02 +0000
parents 612d80156afd
children ffc26bed14d2
files src/dhcp.c src/dhcp6.c
diffstat 2 files changed, 54 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/dhcp.c	Fri Nov 03 16:38:18 2017 +0000
+++ b/src/dhcp.c	Mon Nov 06 12:10:02 2017 +0000
@@ -1518,6 +1518,8 @@
 dhcp_new_xid(struct interface *ifp)
 {
 	struct dhcp_state *state;
+	const struct interface *ifp1;
+	const struct dhcp_state *state1;
 
 	state = D_STATE(ifp);
 	if (ifp->options->options & DHCPCD_XID_HWADDR &&
@@ -1526,8 +1528,30 @@
 		memcpy(&state->xid,
 		    (ifp->hwaddr + ifp->hwlen) - sizeof(state->xid),
 		    sizeof(state->xid));
-	else
+	else {
+again:
 		state->xid = arc4random();
+	}
+
+	/* Ensure it's unique */
+	TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) {
+		if (ifp == ifp1)
+			continue;
+		if ((state1 = D_CSTATE(ifp1)) == NULL)
+			continue;
+		if (state1->xid == state->xid)
+			break;
+	}
+	if (ifp1 != NULL) {
+		if (ifp->options->options & DHCPCD_XID_HWADDR &&
+		    ifp->hwlen >= sizeof(state->xid))
+		{
+			logerrx("%s: duplicate xid on %s",
+			    ifp->name, ifp1->name);
+			    return;
+		}
+		goto again;
+	}
 
 	/* We can't do this when sharing leases across interfaes */
 #if 0
--- a/src/dhcp6.c	Fri Nov 03 16:38:18 2017 +0000
+++ b/src/dhcp6.c	Mon Nov 06 12:10:02 2017 +0000
@@ -392,6 +392,8 @@
 static void
 dhcp6_newxid(const struct interface *ifp, struct dhcp6_message *m)
 {
+	const struct interface *ifp1;
+	const struct dhcp6_state *state1;
 	uint32_t xid;
 
 	if (ifp->options->options & DHCPCD_XID_HWADDR &&
@@ -399,12 +401,38 @@
 		/* The lower bits are probably more unique on the network */
 		memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid),
 		    sizeof(xid));
-	else
+	else {
+again:
 		xid = arc4random();
+	}
 
 	m->xid[0] = (xid >> 16) & 0xff;
 	m->xid[1] = (xid >> 8) & 0xff;
 	m->xid[2] = xid & 0xff;
+
+	/* Ensure it's unique */
+	TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) {
+		if (ifp == ifp1)
+			continue;
+		if ((state1 = D6_CSTATE(ifp1)) == NULL)
+			continue;
+		if (state1->send != NULL &&
+		    state1->send->xid[0] == m->xid[0] &&
+		    state1->send->xid[1] == m->xid[1] &&
+		    state1->send->xid[2] == m->xid[2])
+			break;
+	}
+
+	if (ifp1 != NULL) {
+		if (ifp->options->options & DHCPCD_XID_HWADDR &&
+		    ifp->hwlen >= sizeof(xid))
+		{
+			logerrx("%s: duplicate xid on %s",
+			    ifp->name, ifp1->name);
+			    return;
+		}
+		goto again;
+	}
 }
 
 #ifndef SMALL