@@ -954,7 +954,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
954954 char duidbuf [DUID_HEXSTRLEN ], hostname [256 ];
955955
956956 dhcpv6_for_each_option (start , end , otype , olen , odata ) {
957- if (otype == DHCPV6_OPT_CLIENTID ) {
957+ switch (otype ) {
958+ case DHCPV6_OPT_CLIENTID :
958959 duid = odata ;
959960 duid_len = olen ;
960961
@@ -965,17 +966,33 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
965966
966967 if (olen <= DUID_MAX_LEN )
967968 odhcpd_hexlify (duidbuf , odata , olen );
968- } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255 ) {
969+ break ;
970+
971+ case DHCPV6_OPT_FQDN :
972+ if (olen < 2 || olen > 255 )
973+ break ;
974+
969975 uint8_t fqdn_buf [256 ];
970976 memcpy (fqdn_buf , odata , olen );
971977 fqdn_buf [olen ++ ] = 0 ;
972978
973979 if (dn_expand (& fqdn_buf [1 ], & fqdn_buf [olen ], & fqdn_buf [1 ], hostname , sizeof (hostname )) > 0 )
974980 hostname_len = strcspn (hostname , "." );
975- } else if (otype == DHCPV6_OPT_RECONF_ACCEPT )
981+
982+ break ;
983+
984+ case DHCPV6_OPT_RECONF_ACCEPT :
976985 accept_reconf = true;
977- else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr -> msg_type == DHCPV6_MSG_SOLICIT )
978- rapid_commit = true;
986+ break ;
987+
988+ case DHCPV6_OPT_RAPID_COMMIT :
989+ if (hdr -> msg_type == DHCPV6_MSG_SOLICIT )
990+ rapid_commit = true;
991+ break ;
992+
993+ default :
994+ break ;
995+ }
979996 }
980997
981998 if (!duid || duid_len < DUID_MIN_LEN || duid_len > DUID_MAX_LEN )
@@ -1091,8 +1108,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
10911108 * If there's a DUID configured for this static lease, but without
10921109 * an IAID, we will proceed under the assumption that a request
10931110 * with the right DUID but with *any* IAID should be able to take
1094- * over the assignment. E.g. when switching from WiFi to ethernet
1095- * on the same client. This is similar to how multiple MAC adresses
1111+ * over the assignment. E.g. when switching from WiFi to Ethernet
1112+ * on the same client. This is similar to how multiple MAC addresses
10961113 * are handled for DHCPv4.
10971114 */
10981115 for (size_t i = 0 ; i < lease_cfg -> duid_count ; i ++ ) {
@@ -1135,15 +1152,21 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11351152proceed :
11361153 /* Generic message handling */
11371154 uint16_t status = DHCPV6_STATUS_OK ;
1155+ bool assigned = false;
11381156
1139- if (hdr -> msg_type == DHCPV6_MSG_SOLICIT ||
1140- hdr -> msg_type == DHCPV6_MSG_REQUEST ||
1141- (hdr -> msg_type == DHCPV6_MSG_REBIND && !a )) {
1142- bool assigned = !!a ;
1157+ switch (hdr -> msg_type ) {
1158+ case DHCPV6_MSG_SOLICIT :
1159+ case DHCPV6_MSG_REQUEST :
1160+ case DHCPV6_MSG_REBIND : {
1161+ if (hdr -> msg_type == DHCPV6_MSG_REBIND && a )
1162+ break ;
1163+
1164+ assigned = (a != NULL );
11431165
11441166 if (!a ) {
11451167 if ((!iface -> no_dynamic_dhcp || (lease_cfg && is_na )) &&
11461168 (iface -> dhcpv6_pd || iface -> dhcpv6_na )) {
1169+
11471170 /* Create new binding */
11481171 a = dhcpv6_alloc_lease (duid_len );
11491172
@@ -1153,25 +1176,27 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11531176 a -> iaid = ia -> iaid ;
11541177 a -> length = reqlen ;
11551178 a -> peer = * addr ;
1179+ a -> iface = iface ;
1180+ a -> flags = is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA ;
1181+ a -> valid_until = now ;
1182+ a -> preferred_until = now ;
1183+
11561184 if (is_na )
11571185 a -> assigned_host_id = lease_cfg ? lease_cfg -> hostid : 0 ;
11581186 else
11591187 a -> assigned_subnet_id = reqhint ;
1160- a -> valid_until = now ;
1161- a -> preferred_until = now ;
1162- a -> iface = iface ;
1163- a -> flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA );
11641188
11651189 if (first )
11661190 memcpy (a -> key , first -> key , sizeof (a -> key ));
11671191 else
11681192 odhcpd_urandom (a -> key , sizeof (a -> key ));
11691193
1170- if (is_pd && iface -> dhcpv6_pd )
1194+ if (is_pd && iface -> dhcpv6_pd ) {
11711195 while (!(assigned = assign_pd (iface , a )) &&
11721196 ++ a -> length <= 64 );
1173- else if (is_na && iface -> dhcpv6_na )
1197+ } else if (is_na && iface -> dhcpv6_na ) {
11741198 assigned = assign_na (iface , a );
1199+ }
11751200
11761201 if (lease_cfg && assigned ) {
11771202 if (lease_cfg -> hostname ) {
@@ -1189,15 +1214,20 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11891214 }
11901215 }
11911216
1192- if (!assigned || iface -> addr6_len == 0 )
1217+ /* Status evaluation */
1218+ if (!assigned || iface -> addr6_len == 0 ) {
11931219 /* Set error status */
1194- status = ( is_pd ) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL ;
1195- else if (hdr -> msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link (ia , a , iface )) {
1220+ status = is_pd ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL ;
1221+ } else if (hdr -> msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link (ia , a , iface )) {
11961222 /* Send NOTONLINK status for the IA */
11971223 status = DHCPV6_STATUS_NOTONLINK ;
11981224 assigned = false;
1199- } else if (accept_reconf && assigned && !first &&
1200- hdr -> msg_type != DHCPV6_MSG_REBIND ) {
1225+ }
1226+
1227+ /* Reconfigure Accept */
1228+ if (accept_reconf && assigned && !first &&
1229+ hdr -> msg_type != DHCPV6_MSG_REBIND ) {
1230+
12011231 size_t handshake_len = 4 ;
12021232 buf [0 ] = 0 ;
12031233 buf [1 ] = DHCPV6_OPT_RECONF_ACCEPT ;
@@ -1213,6 +1243,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12131243 1 ,
12141244 {0 }
12151245 };
1246+
12161247 memcpy (auth .key , a -> key , sizeof (a -> key ));
12171248 memcpy (buf + handshake_len , & auth , sizeof (auth ));
12181249 handshake_len += sizeof (auth );
@@ -1226,19 +1257,24 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12261257 first = a ;
12271258 }
12281259
1229- ia_response_len = build_ia (buf , buflen , status , ia , a , iface ,
1230- hdr -> msg_type == DHCPV6_MSG_REBIND ? false : true);
1260+ ia_response_len = build_ia (
1261+ buf , buflen , status , ia , a , iface ,
1262+ hdr -> msg_type != DHCPV6_MSG_REBIND );
1263+
12311264
12321265 /* Was only a solicitation: mark binding for removal in 60 seconds */
12331266 if (assigned && hdr -> msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit ) {
1267+
12341268 a -> bound = false;
12351269 a -> valid_until = now + 60 ;
12361270
12371271 } else if (assigned &&
12381272 ((hdr -> msg_type == DHCPV6_MSG_SOLICIT && rapid_commit ) ||
12391273 hdr -> msg_type == DHCPV6_MSG_REQUEST ||
12401274 hdr -> msg_type == DHCPV6_MSG_REBIND )) {
1275+
12411276 if (hostname_len > 0 && (!a -> lease_cfg || !a -> lease_cfg -> hostname )) {
1277+
12421278 char * tmp = realloc (a -> hostname , hostname_len + 1 );
12431279 if (tmp ) {
12441280 a -> hostname = tmp ;
@@ -1247,40 +1283,66 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12471283 a -> hostname_valid = odhcpd_hostname_valid (a -> hostname );
12481284 }
12491285 }
1286+
12501287 a -> accept_fr_nonce = accept_reconf ;
12511288 a -> bound = true;
12521289 apply_lease (a , true);
1290+
12531291 } else if (!assigned ) {
1254- /* Cleanup failed assignment */
1292+ /* Clean up failed assignment */
12551293 dhcpv6_free_lease (a );
12561294 a = NULL ;
12571295 }
1258- } else if (hdr -> msg_type == DHCPV6_MSG_RENEW ||
1259- hdr -> msg_type == DHCPV6_MSG_RELEASE ||
1260- hdr -> msg_type == DHCPV6_MSG_REBIND ||
1261- hdr -> msg_type == DHCPV6_MSG_DECLINE ) {
1262- if (!a && hdr -> msg_type != DHCPV6_MSG_REBIND ) {
1296+
1297+ break ;
1298+ }
1299+
1300+ case DHCPV6_MSG_RENEW :
1301+ case DHCPV6_MSG_RELEASE :
1302+ case DHCPV6_MSG_DECLINE : {
1303+ /* RENEW / RELEASE / DECLINE require an existing binding */
1304+ if (!a ) {
12631305 status = DHCPV6_STATUS_NOBINDING ;
12641306 ia_response_len = build_ia (buf , buflen , status , ia , a , iface , false);
1265- } else if (hdr -> msg_type == DHCPV6_MSG_RENEW ||
1266- hdr -> msg_type == DHCPV6_MSG_REBIND ) {
1307+ break ;
1308+ }
1309+
1310+ switch (hdr -> msg_type ) {
1311+ case DHCPV6_MSG_RENEW :
12671312 ia_response_len = build_ia (buf , buflen , status , ia , a , iface , false);
1268- if (a ) {
1269- a -> bound = true;
1270- apply_lease (a , true);
1271- }
1272- } else if (hdr -> msg_type == DHCPV6_MSG_RELEASE ) {
1313+
1314+ a -> bound = true;
1315+ apply_lease (a , true);
1316+ break ;
1317+
1318+ case DHCPV6_MSG_RELEASE :
1319+ /* Immediately expire the lease */
12731320 a -> valid_until = now - 1 ;
1274- } else if ((a -> flags & OAF_DHCPV6_NA ) && hdr -> msg_type == DHCPV6_MSG_DECLINE ) {
1321+ break ;
1322+
1323+ case DHCPV6_MSG_DECLINE :
1324+ /* DECLINE only applies to non-temporary addresses */
1325+ if (!(a -> flags & OAF_DHCPV6_NA ))
1326+ break ;
1327+
12751328 a -> bound = false;
12761329
1277- if (!a -> lease_cfg || a -> lease_cfg -> hostid != a -> assigned_host_id ) {
1278- memset (a -> duid , 0 , a -> duid_len );
1279- a -> valid_until = now + 3600 ; /* Block address for 1h */
1280- } else
1330+ if (a -> lease_cfg &&
1331+ a -> lease_cfg -> hostid == a -> assigned_host_id ) {
1332+ /* Static lease: release immediately */
12811333 a -> valid_until = now - 1 ;
1334+ } else {
1335+ /* Dynamic lease: block address for 1 hour */
1336+ memset (a -> duid , 0 , a -> duid_len );
1337+ a -> valid_until = now + 3600 ;
1338+ }
1339+ break ;
12821340 }
1283- } else if (hdr -> msg_type == DHCPV6_MSG_CONFIRM ) {
1341+
1342+ break ;
1343+ }
1344+
1345+ case DHCPV6_MSG_CONFIRM :
12841346 if (ia_addr_present && !dhcpv6_ia_on_link (ia , a , iface )) {
12851347 notonlink = true;
12861348 break ;
@@ -1290,13 +1352,25 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12901352 response_len = 0 ;
12911353 goto out ;
12921354 }
1355+ break ;
1356+
1357+ default :
1358+ break ;
1359+
1360+ }
1361+
1362+ if (hdr -> msg_type == DHCPV6_MSG_REBIND && a ) {
1363+ ia_response_len = build_ia (buf , buflen , status , ia , a , iface , false);
1364+ a -> bound = true;
1365+ apply_lease (a , true);
12931366 }
12941367
12951368 buf += ia_response_len ;
12961369 buflen -= ia_response_len ;
12971370 response_len += ia_response_len ;
12981371 dhcpv6_log (hdr -> msg_type , iface , now , duidbuf , is_pd , a , status );
1299- }
1372+
1373+ } /* end dhcpv6_for_each_option */
13001374
13011375 switch (hdr -> msg_type ) {
13021376 case DHCPV6_MSG_RELEASE :
0 commit comments