From: Roy Marples Date: Fri, 31 Jan 2014 11:47:27 +0000 (+0000) Subject: Implement support for RFC 3203, FORCERENEW message. X-Git-Tag: v6.3.0~75 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c6eb161be2dad3e269865126c03d72a959a79707;p=thirdparty%2Fdhcpcd.git Implement support for RFC 3203, FORCERENEW message. --- diff --git a/arp.c b/arp.c index 13779a48..a2310180 100644 --- a/arp.c +++ b/arp.c @@ -106,7 +106,6 @@ arp_failure(struct interface *ifp) unlink(state->leasefile); if (!state->lease.frominfo) dhcp_decline(ifp); - dhcp_close(ifp); eloop_timeout_delete(NULL, ifp); if (state->lease.frominfo) start_interface(ifp); @@ -336,3 +335,19 @@ arp_start(struct interface *ifp) state->arping_index = 0; arp_probe(ifp); } + +void +arp_close(struct interface *ifp) +{ + struct dhcp_state *state = D_STATE(ifp); + + if (state == NULL) + return; + + if (state->arp_fd != -1) { + eloop_event_delete(state->arp_fd); + close(state->arp_fd); + state->arp_fd = -1; + } +} + diff --git a/arp.h b/arp.h index c2d4fe51..2dac1bb7 100644 --- a/arp.h +++ b/arp.h @@ -45,4 +45,5 @@ void arp_announce(void *); void arp_probe(void *); void arp_start(struct interface *); +void arp_close(struct interface *); #endif diff --git a/dhcp.c b/dhcp.c index 3e9d2f80..21b152a3 100644 --- a/dhcp.c +++ b/dhcp.c @@ -1718,9 +1718,8 @@ dhcp_bind(void *arg) struct if_options *ifo = iface->options; struct dhcp_lease *lease = &state->lease; struct timeval tv; + uint8_t ipv4ll = 0; - /* We're binding an address now - ensure that sockets are closed */ - dhcp_close(iface); state->reason = NULL; if (clock_monotonic) get_monotonic(&lease->boundtime); @@ -1741,6 +1740,7 @@ dhcp_bind(void *arg) iface->name, inet_ntoa(lease->addr)); lease->leasetime = ~0U; state->reason = "IPV4LL"; + ipv4ll = 1; } else if (ifo->options & DHCPCD_INFORM) { if (ifo->req_addr.s_addr != 0) lease->addr.s_addr = ifo->req_addr.s_addr; @@ -1822,6 +1822,8 @@ dhcp_bind(void *arg) } ipv4_applyaddr(iface); daemonise(); + if (!ipv4ll) + arp_close(iface); state->state = DHS_BOUND; if (ifo->options & DHCPCD_ARP) { state->claims = 0; @@ -2011,6 +2013,8 @@ dhcp_drop(struct interface *ifp, const char *reason) state = D_STATE(ifp); if (state == NULL) return; + dhcp_close(ifp); + arp_close(ifp); eloop_timeouts_delete(ifp, dhcp_expire, NULL); if (ifp->options->options & DHCPCD_RELEASE) { unlink(state->leasefile); @@ -2164,6 +2168,49 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp, log_dhcp1(LOG_WARNING, "no authentication", iface, dhcp, from, 0); + /* RFC 3203 */ + if (type == DHCP_FORCERENEW) { + if (from->s_addr == INADDR_ANY || + from->s_addr == INADDR_BROADCAST) + { + log_dhcp(LOG_ERR, "discarding Force Renew", + iface, dhcp, from); + return; + } + if (auth == NULL) { + log_dhcp(LOG_ERR, "unauthenticated Force Renew", + iface, dhcp, from); + return; + } + if (state->state != DHS_BOUND) { + log_dhcp(LOG_DEBUG, "not bound, ignoring Force Renew", + iface, dhcp, from); + return; + } + log_dhcp(LOG_ERR, "Force Renew from", iface, dhcp, from); + /* The rebind and expire timings are still the same, we just + * enter the renew state early */ + eloop_timeout_delete(dhcp_renew, iface); + dhcp_renew(iface); + return; + } + + if (state->state == DHS_BOUND) { + /* Before we supported FORCERENEW we closed off the raw + * port so we effectively ignored all messages. + * As such we'll not log by default here. */ + //log_dhcp(LOG_DEBUG, "bound, ignoring", iface, dhcp, from); + return; + } + + /* Ensure it's the right transaction */ + if (state->xid != ntohl(dhcp->xid)) { + syslog(LOG_DEBUG, + "%s: wrong xid 0x%x (expecting 0x%x) from %s", + iface->name, ntohl(dhcp->xid), state->xid, + inet_ntoa(*from)); + return; + } /* reset the message counter */ state->interval = 0; @@ -2175,13 +2222,14 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp, log_dhcp(LOG_WARNING, "reject NAK", iface, dhcp, from); return; } + /* We should restart on a NAK */ log_dhcp(LOG_WARNING, "NAK:", iface, dhcp, from); if (!(options & DHCPCD_TEST)) { dhcp_drop(iface, "NAK"); unlink(state->leasefile); } - dhcp_close(iface); + /* If we constantly get NAKS then we should slowly back off */ eloop_timeout_add_sec(state->nakoff, dhcp_discover, iface); if (state->nakoff == 0) @@ -2291,11 +2339,6 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp, lease->frominfo = 0; eloop_timeout_delete(NULL, iface); - /* We now have an offer, so close the DHCP sockets. - * This allows us to safely ARP when broken DHCP servers send an ACK - * follows by an invalid NAK. */ - dhcp_close(iface); - if (ifo->options & DHCPCD_ARP && state->addr.s_addr != state->offer->yiaddr) { @@ -2441,14 +2484,6 @@ dhcp_handlepacket(void *arg) iface->name, inet_ntoa(from)); continue; } - /* Ensure it's the right transaction */ - if (state->xid != ntohl(dhcp->xid)) { - syslog(LOG_DEBUG, - "%s: wrong xid 0x%x (expecting 0x%x) from %s", - iface->name, ntohl(dhcp->xid), state->xid, - inet_ntoa(from)); - continue; - } /* Ensure packet is for us */ if (iface->hwlen <= sizeof(dhcp->chaddr) && memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen)) @@ -2465,6 +2500,21 @@ dhcp_handlepacket(void *arg) free(dhcp); } +static void +dhcp_handleudp(void *arg) +{ + const struct interface *ifp; + const struct dhcp_state *state; + ssize_t bytes; + uint8_t buffer[sizeof(struct dhcp_message)]; + + ifp = arg; + state = D_CSTATE(ifp); + bytes = read(state->udp_fd, buffer, sizeof(buffer)); + /* Just read what's in the UDP fd and discard it as we always read + * from the raw fd */ +} + static int dhcp_open(struct interface *ifp) { @@ -2491,15 +2541,13 @@ dhcp_open(struct interface *ifp) eloop_event_add(state->raw_fd, dhcp_handlepacket, ifp); } if (state->udp_fd == -1 && - state->addr.s_addr != 0 && - state->new != NULL && - (state->new->cookie == htonl(MAGIC_COOKIE) || - ifp->options->options & DHCPCD_INFORM)) + ifp->options->options & DHCPCD_DHCP) { if (dhcp_openudp(ifp) == -1 && errno != EADDRINUSE) { syslog(LOG_ERR, "%s: dhcp_openudp: %m", ifp->name); return -1; } + eloop_event_add(state->udp_fd, dhcp_handleudp, ifp); } return 0; } @@ -2686,7 +2734,6 @@ dhcp_start(struct interface *ifp) syslog(LOG_WARNING, "%s: needs a clientid to configure", ifp->name); dhcp_drop(ifp, "FAIL"); - dhcp_close(ifp); eloop_timeout_delete(NULL, ifp); return; } diff --git a/dhcp.h b/dhcp.h index b1777f85..92e8bd2c 100644 --- a/dhcp.h +++ b/dhcp.h @@ -57,6 +57,7 @@ #define DHCP_NAK 6 #define DHCP_RELEASE 7 #define DHCP_INFORM 8 +#define DHCP_FORCERENEW 9 /* Constants taken from RFC 2131. */ #define T1 0.5 diff --git a/dhcpcd.8.in b/dhcpcd.8.in index df49ab8b..770d23a0 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 30, 2014 +.Dd January 31, 2014 .Dt DHCPCD 8 .Os .Sh NAME @@ -98,7 +98,8 @@ sets the hostname to the one supplied by the DHCP server. .Nm then daemonises and waits for the lease renewal time to lapse. It will then attempt to renew its lease and reconfigure if the new lease -changes. +changes when the lease beings to expire or the DHCP server sends message +to renew early. .Pp .Nm is also an implementation of the BOOTP client specified in @@ -652,10 +653,10 @@ running on the .Xr resolvconf 8 .Sh STANDARDS RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2855, RFC\ 3004, -RFC\ 3118, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, RFC\ 3442, -RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 4242, RFC\ 4361, -RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 5227, RFC\ 5942, -RFC\ 5969, RFC\ 6106. +RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, RFC\ 3397, +RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, RFC\ 4242, +RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, RFC\ 5227, +RFC\ 5942, RFC\ 5969, RFC\ 6106. .Sh AUTHORS .An Roy Marples Aq Mt roy@marples.name .Sh BUGS diff --git a/dhcpcd.c b/dhcpcd.c index 70210f11..16b8e8af 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -328,7 +328,6 @@ stop_interface(struct interface *ifp) dhcp6_drop(ifp, NULL); ipv6nd_drop(ifp); dhcp_drop(ifp, "STOP"); - dhcp_close(ifp); eloop_timeout_delete(NULL, ifp); if (ifp->options->options & DHCPCD_DEPARTED) script_runreason(ifp, "DEPARTED"); @@ -526,7 +525,6 @@ handle_carrier(int carrier, int flags, const char *ifname) if (ifp->carrier == LINK_UP) syslog(LOG_INFO, "%s: carrier lost", ifp->name); ifp->carrier = LINK_DOWN; - dhcp_close(ifp); dhcp6_drop(ifp, "EXPIRE6"); ipv6nd_drop(ifp); /* Don't blindly delete our knowledge of LL addresses. diff --git a/ipv4ll.c b/ipv4ll.c index 731a6f4b..b32b9f69 100644 --- a/ipv4ll.c +++ b/ipv4ll.c @@ -151,7 +151,6 @@ ipv4ll_handle_failure(void *arg) } } - dhcp_close(ifp); free(state->offer); state->offer = NULL; eloop_timeout_delete(NULL, ifp);