1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
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
|