From: Roy Marples Date: Mon, 6 Nov 2017 12:10:02 +0000 (+0000) Subject: Ensure that xid is unique across all interfaces. X-Git-Tag: v7.0.0-rc4~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=03d56964fe00eabed95289f1897a5a0ae54fbf38;p=thirdparty%2Fdhcpcd.git Ensure that xid is unique across all interfaces. --- diff --git a/src/dhcp.c b/src/dhcp.c index 55a6d69d..2e0341d5 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -1518,6 +1518,8 @@ static void 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 @@ dhcp_new_xid(struct interface *ifp) 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 diff --git a/src/dhcp6.c b/src/dhcp6.c index 206d2fa3..b4805771 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -392,6 +392,8 @@ dhcp6_updateelapsed(struct interface *ifp, struct dhcp6_message *m, size_t len) 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 @@ dhcp6_newxid(const struct interface *ifp, struct dhcp6_message *m) /* 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