aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Tan <samueltan@google.com>2015-08-13 18:09:30 -0700
committerSamuel Tan <samueltan@google.com>2015-08-18 13:47:00 -0700
commit5158c9dfe576a285663b4ba16828fd6e9b35779c (patch)
treea6acaa54045d7cedcdbd4a6a451aab09aa10b00d
parentb2d21e6cab5a0167e9e4d0698795b38f6c790ab3 (diff)
downloaddhcpcd-6.8.2-5158c9dfe576a285663b4ba16828fd6e9b35779c.tar.gz
[PATCH] Track and validate disputed addresses
Cherry-picked from https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/ master/net-misc/dhcpcd/files/patches/dhcpcd-6.8.2-Track-and-validate- disputed-addresses.patch. Keep track of whether we have received a NAK response. If we accept an ACK shortly after a NAK, although we accept this address, it must be more carefully evaluated by using the "ARP for self" method. If this method succeeds, the system should proceed as normal (either doing a gateway ARP or sending the success notification via D-Bus). Moreover, if the "ARP self" method fails, it will DECLINE the lease and restart the DHCP process. When examining any messages from the DHCP server in this restarted session, ignore the first OFFER if it is for the previously declined IP address. In scenarios where there may be more than one conflicting DHCP server on the network, this allows the possibility to accept a more viable offer. BUG: 22956197 Change-Id: I3f2e6cfbaf9c14ce09218e817e2dd35517d78f85 Reviewed-on: https://chromium-review.googlesource.com/208273
-rw-r--r--arp.c1
-rw-r--r--dhcp.c31
-rw-r--r--dhcp.h3
3 files changed, 29 insertions, 6 deletions
diff --git a/arp.c b/arp.c
index 5fb23a3..96cf40c 100644
--- a/arp.c
+++ b/arp.c
@@ -133,6 +133,7 @@ arp_packet(void *arg)
int flags;
state = D_STATE(ifp);
+ state->failed.s_addr = 0;
flags = 0;
while (!(flags & RAW_EOF)) {
bytes = if_readrawpacket(ifp, ETHERTYPE_ARP,
diff --git a/dhcp.c b/dhcp.c
index e57f6e0..c788013 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -1818,6 +1818,8 @@ dhcp_discover(void *arg)
state->state = DHS_DISCOVER;
state->xid = dhcp_xid(ifp);
+ state->nak_receive_count = 0;
+ state->failed_address_offer_count = 0;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
if (ifo->fallback)
eloop_timeout_add_sec(ifp->ctx->eloop,
@@ -1844,6 +1846,7 @@ dhcp_request(void *arg)
struct dhcp_state *state = D_STATE(ifp);
state->state = DHS_REQUEST;
+ state->nak_receive_count = 0;
send_request(ifp);
}
@@ -1883,6 +1886,7 @@ dhcp_renew(void *arg)
lease->leasetime - lease->renewaltime);
state->state = DHS_RENEW;
state->xid = dhcp_xid(ifp);
+ state->nak_receive_count = 0;
send_renew(ifp);
}
@@ -1909,6 +1913,7 @@ dhcp_rebind(void *arg)
state->state = DHS_REBIND;
eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp);
state->lease.server.s_addr = 0;
+ state->nak_receive_count = 0;
ifp->options->options &= ~(DHCPCD_CSR_WARNED |
DHCPCD_ROUTER_HOST_ROUTE_WARNED);
send_rebind(ifp);
@@ -2610,10 +2615,14 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
struct ipv4_addr *ia;
#endif
- if (amsg)
+ if (amsg) {
astate->failed.s_addr = state->offer->yiaddr;
- else
+ state->failed.s_addr = state->offer->yiaddr;
+ } else {
astate->failed = astate->addr;
+ state->failed = astate->addr;
+ }
+
arp_report_conflicted(astate, amsg);
unlink(state->leasefile);
if (!state->lease.frominfo)
@@ -2781,9 +2790,10 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
return;
log_dhcp(LOG_WARNING, "NAK (deferred):", ifp, dhcp, from);
- eloop_timeout_add_sec(ifp->ctx->eloop,
- DHCP_BASE, handle_nak, ifp);
-
+ if (state->nak_receive_count == 0)
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ DHCP_BASE, handle_nak, ifp);
+ state->nak_receive_count++;
return;
}
@@ -2878,6 +2888,14 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
if ((type == 0 || type == DHCP_OFFER) &&
(state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND))
{
+ if (dhcp->yiaddr == state->failed.s_addr &&
+ state->failed_address_offer_count == 0) {
+ log_dhcp(LOG_WARNING,
+ "reject previously declined address",
+ ifp, dhcp, from);
+ state->failed_address_offer_count++;
+ return;
+ }
lease->frominfo = 0;
lease->addr.s_addr = dhcp->yiaddr;
lease->cookie = dhcp->cookie;
@@ -2953,7 +2971,8 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
astate = NULL;
#ifndef IN_IFF_TENTATIVE
- if (ifo->options & DHCPCD_ARP
+ if ((ifo->options & DHCPCD_ARP || state->nak_receive_count > 0 ||
+ dhcp->yiaddr == state->failed.s_addr)
&& state->addr.s_addr != state->offer->yiaddr)
#endif
{
diff --git a/dhcp.h b/dhcp.h
index ed94395..e136a9c 100644
--- a/dhcp.h
+++ b/dhcp.h
@@ -240,6 +240,9 @@ struct dhcp_state {
struct arp_state *arp_ipv4ll;
unsigned int conflicts;
+ int nak_receive_count;
+ int failed_address_offer_count;
+ struct in_addr failed;
time_t defend;
char randomstate[128];
struct dhcp_server_info server_info;