From: Evgeniy Manachkin <sfstudio@mail.ru>
Date: Mon, 30 Mar 2015 20:05:52 +0600
Subject: dhcpv6: ignore advertise messages with none of requested data and
missed status codes.
with RENEW fix. Thanks TheMiron.
[ Roger Shimizu's comment ]
The patch was originally from:
- https://sourceforge.net/p/wide-dhcpv6/bugs/34/
- https://gitorious.org/wive-ng-mt/wive-ng-mt/commit/844e8a1a0d9026ba6fef8b224583e97890ca522e
- https://gitorious.org/wive-ng-mt/wive-ng-mt/commit/3f93dfec7a13c086f891b2ab9a974de2331d9b7d
This resolved upstream issue #34:
- https://sourceforge.net/p/wide-dhcpv6/bugs/34
Closes: #765453
---
dhcp6c.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 55 insertions(+), 12 deletions(-)
diff --git a/dhcp6c.c b/dhcp6c.c
index 4e1356b..849835e 100644
--- a/dhcp6c.c
+++ b/dhcp6c.c
@@ -1484,10 +1484,10 @@ client6_recv()
switch(dh6->dh6_msgtype) {
case DH6_ADVERTISE:
- (void)client6_recvadvert(ifp, dh6, len, &optinfo);
+ client6_recvadvert(ifp, dh6, len, &optinfo);
break;
case DH6_REPLY:
- (void)client6_recvreply(ifp, dh6, len, &optinfo);
+ client6_recvreply(ifp, dh6, len, &optinfo);
break;
default:
debug_printf(LOG_INFO, FNAME, "received an unexpected message (%s) "
@@ -1511,6 +1511,7 @@ client6_recvadvert(ifp, dh6, len, optinfo)
struct dhcp6_event *ev;
struct dhcp6_eventdata *evd;
struct authparam *authparam = NULL, authparam0;
+ int have_ia = -1;
/* find the corresponding event based on the received xid */
ev = find_event_withid(ifp, ntohl(dh6->dh6_xid) & DH6_XIDMASK);
@@ -1549,38 +1550,80 @@ client6_recvadvert(ifp, dh6, len, optinfo)
* includes a Status Code option containing the value NoPrefixAvail
* [RFC3633 Section 11.1].
* Likewise, the client MUST ignore any Advertise message that includes
- * a Status Code option containing the value NoAddrsAvail.
+ * a Status Code option containing the value NoAddrsAvail.
* [RFC3315 Section 17.1.3].
* We only apply this when we are going to request an address or
* a prefix.
*/
- for (evd = TAILQ_FIRST(&ev->data_list); evd;
- evd = TAILQ_NEXT(evd, link)) {
+ for (evd = TAILQ_FIRST(&ev->data_list); evd; evd = TAILQ_NEXT(evd, link)) {
+ struct dhcp6_listval *lv, *slv;
u_int16_t stcode;
char *stcodestr;
switch (evd->type) {
- case DHCP6_EVDATA_IAPD:
+ case DHCP6_EVDATA_IAPD:
stcode = DH6OPT_STCODE_NOPREFIXAVAIL;
stcodestr = "NoPrefixAvail";
break;
- case DHCP6_EVDATA_IANA:
+ case DHCP6_EVDATA_IANA:
stcode = DH6OPT_STCODE_NOADDRSAVAIL;
stcodestr = "NoAddrsAvail";
break;
- default:
+ default:
continue;
}
+
if (dhcp6_find_listval(&optinfo->stcode_list,
DHCP6_LISTVAL_STCODE, &stcode, 0)) {
- debug_printf(LOG_INFO, FNAME,
- "advertise contains %s status", stcodestr);
+ debug_printf(LOG_INFO, FNAME, "advertise contains %s status", stcodestr);
return (-1);
}
+
+ if (have_ia > 0 || TAILQ_EMPTY((struct dhcp6_list *)evd->data))
+ continue;
+
+ have_ia = 0;
+ /* parse list of IA_PD */
+ if (evd->type == DHCP6_EVDATA_IAPD) {
+ TAILQ_FOREACH(lv, (struct dhcp6_list *)evd->data, link) {
+ slv = dhcp6_find_listval(&optinfo->iapd_list, DHCP6_LISTVAL_IAPD, &lv->val_ia, 0);
+ if (slv == NULL)
+ continue;
+ TAILQ_FOREACH(slv, &slv->sublist, link) {
+ if (slv->type == DHCP6_LISTVAL_PREFIX6) {
+ have_ia = 1;
+ break;
+ }
+ }
+ }
+ }
+ /* parse list of IA_NA */
+ if (evd->type == DHCP6_EVDATA_IANA) {
+ TAILQ_FOREACH(lv, (struct dhcp6_list *)evd->data, link) {
+ slv = dhcp6_find_listval(&optinfo->iana_list, DHCP6_LISTVAL_IANA, &lv->val_ia, 0);
+ if (slv == NULL)
+ continue;
+ TAILQ_FOREACH(slv, &slv->sublist, link) {
+ if (slv->type == DHCP6_LISTVAL_STATEFULADDR6) {
+ have_ia = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Ignore message with none of requested addresses and/or
+ * a prefixes as if NoAddrsAvail/NoPrefixAvail Status Code
+ * was included.
+ */
+ if (have_ia == 0) {
+ debug_printf(LOG_INFO, FNAME, "advertise contains no address/prefix");
+ return (-1);
}
- if (ev->state != DHCP6S_SOLICIT ||
- (ifp->send_flags & DHCIFF_RAPID_COMMIT) || infreq_mode) {
+ if (ev->state != DHCP6S_SOLICIT || (ifp->send_flags & DHCIFF_RAPID_COMMIT) || infreq_mode) {
/*
* We expected a reply message, but do actually receive an
* Advertise message. The server should be configured not to