@@ -958,7 +958,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
958958 char duidbuf [DUID_HEXSTRLEN ], hostname [256 ];
959959
960960 dhcpv6_for_each_option (start , end , otype , olen , odata ) {
961- if (otype == DHCPV6_OPT_CLIENTID ) {
961+ switch (otype ) {
962+ case DHCPV6_OPT_CLIENTID :
962963 duid = odata ;
963964 duid_len = olen ;
964965
@@ -969,17 +970,33 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
969970
970971 if (olen <= DUID_MAX_LEN )
971972 odhcpd_hexlify (duidbuf , odata , olen );
972- } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255 ) {
973+ break ;
974+
975+ case DHCPV6_OPT_FQDN :
976+ if (olen < 2 || olen > 255 )
977+ break ;
978+
973979 uint8_t fqdn_buf [256 ];
974980 memcpy (fqdn_buf , odata , olen );
975981 fqdn_buf [olen ++ ] = 0 ;
976982
977983 if (dn_expand (& fqdn_buf [1 ], & fqdn_buf [olen ], & fqdn_buf [1 ], hostname , sizeof (hostname )) > 0 )
978984 hostname_len = strcspn (hostname , "." );
979- } else if (otype == DHCPV6_OPT_RECONF_ACCEPT )
985+
986+ break ;
987+
988+ case DHCPV6_OPT_RECONF_ACCEPT :
980989 accept_reconf = true;
981- else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr -> msg_type == DHCPV6_MSG_SOLICIT )
982- rapid_commit = true;
990+ break ;
991+
992+ case DHCPV6_OPT_RAPID_COMMIT :
993+ if (hdr -> msg_type == DHCPV6_MSG_SOLICIT )
994+ rapid_commit = true;
995+ break ;
996+
997+ default :
998+ break ;
999+ }
9831000 }
9841001
9851002 if (!duid || duid_len < DUID_MIN_LEN || duid_len > DUID_MAX_LEN )
@@ -1095,8 +1112,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
10951112 * If there's a DUID configured for this static lease, but without
10961113 * an IAID, we will proceed under the assumption that a request
10971114 * with the right DUID but with *any* IAID should be able to take
1098- * over the assignment. E.g. when switching from WiFi to ethernet
1099- * on the same client. This is similar to how multiple MAC adresses
1115+ * over the assignment. E.g. when switching from WiFi to Ethernet
1116+ * on the same client. This is similar to how multiple MAC addresses
11001117 * are handled for DHCPv4.
11011118 */
11021119 for (size_t i = 0 ; i < lease_cfg -> duid_count ; i ++ ) {
@@ -1139,11 +1156,16 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11391156proceed :
11401157 /* Generic message handling */
11411158 uint16_t status = DHCPV6_STATUS_OK ;
1159+ bool assigned = false;
11421160
1143- if (hdr -> msg_type == DHCPV6_MSG_SOLICIT ||
1144- hdr -> msg_type == DHCPV6_MSG_REQUEST ||
1145- (hdr -> msg_type == DHCPV6_MSG_REBIND && !a )) {
1146- bool assigned = !!a ;
1161+ switch (hdr -> msg_type ) {
1162+ case DHCPV6_MSG_SOLICIT :
1163+ case DHCPV6_MSG_REQUEST :
1164+ case DHCPV6_MSG_REBIND : {
1165+ if (hdr -> msg_type == DHCPV6_MSG_REBIND && a )
1166+ break ;
1167+
1168+ assigned = (a != NULL );
11471169
11481170 if (!a ) {
11491171 if ((!iface -> no_dynamic_dhcp || (lease_cfg && is_na )) &&
@@ -1157,25 +1179,27 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11571179 a -> iaid = ia -> iaid ;
11581180 a -> length = reqlen ;
11591181 a -> peer = * addr ;
1182+ a -> iface = iface ;
1183+ a -> flags = is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA ;
1184+ a -> valid_until = now ;
1185+ a -> preferred_until = now ;
1186+
11601187 if (is_na )
11611188 a -> assigned_host_id = lease_cfg ? lease_cfg -> hostid : 0 ;
11621189 else
11631190 a -> assigned_subnet_id = reqhint ;
1164- a -> valid_until = now ;
1165- a -> preferred_until = now ;
1166- a -> iface = iface ;
1167- a -> flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA );
11681191
11691192 if (first )
11701193 memcpy (a -> key , first -> key , sizeof (a -> key ));
11711194 else
11721195 odhcpd_urandom (a -> key , sizeof (a -> key ));
11731196
1174- if (is_pd && iface -> dhcpv6_pd )
1197+ if (is_pd && iface -> dhcpv6_pd ) {
11751198 while (!(assigned = assign_pd (iface , a )) &&
11761199 ++ a -> length <= 64 );
1177- else if (is_na && iface -> dhcpv6_na )
1200+ } else if (is_na && iface -> dhcpv6_na ) {
11781201 assigned = assign_na (iface , a );
1202+ }
11791203
11801204 if (lease_cfg && assigned ) {
11811205 if (lease_cfg -> hostname ) {
@@ -1193,15 +1217,20 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11931217 }
11941218 }
11951219
1196- if (!assigned || iface -> addr6_len == 0 )
1220+ /* Status evaluation */
1221+ if (!assigned || iface -> addr6_len == 0 ) {
11971222 /* Set error status */
1198- status = ( is_pd ) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL ;
1199- else if (hdr -> msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link (ia , a , iface )) {
1223+ status = is_pd ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL ;
1224+ } else if (hdr -> msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link (ia , a , iface )) {
12001225 /* Send NOTONLINK status for the IA */
12011226 status = DHCPV6_STATUS_NOTONLINK ;
12021227 assigned = false;
1203- } else if (accept_reconf && assigned && !first &&
1204- hdr -> msg_type != DHCPV6_MSG_REBIND ) {
1228+ }
1229+
1230+ /* Reconfigure Accept */
1231+ if (accept_reconf && assigned && !first &&
1232+ hdr -> msg_type != DHCPV6_MSG_REBIND ) {
1233+
12051234 size_t handshake_len = 4 ;
12061235 buf [0 ] = 0 ;
12071236 buf [1 ] = DHCPV6_OPT_RECONF_ACCEPT ;
@@ -1217,74 +1246,110 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12171246 1 ,
12181247 {0 }
12191248 };
1249+
12201250 memcpy (auth .key , a -> key , sizeof (a -> key ));
12211251 memcpy (buf + handshake_len , & auth , sizeof (auth ));
12221252 handshake_len += sizeof (auth );
12231253 }
12241254
1225-
12261255 buf += handshake_len ;
12271256 buflen -= handshake_len ;
12281257 response_len += handshake_len ;
12291258
12301259 first = a ;
12311260 }
12321261
1233- ia_response_len = build_ia (buf , buflen , status , ia , a , iface ,
1234- hdr -> msg_type == DHCPV6_MSG_REBIND ? false : true);
1262+ ia_response_len = build_ia (
1263+ buf , buflen , status , ia , a , iface ,
1264+ hdr -> msg_type != DHCPV6_MSG_REBIND );
12351265
12361266 /* Was only a solicitation: mark binding for removal in 60 seconds */
1237- if (assigned && hdr -> msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit ) {
1238- a -> bound = false;
1239- a -> valid_until = now + 60 ;
1240-
1241- } else if (assigned &&
1242- ((hdr -> msg_type == DHCPV6_MSG_SOLICIT && rapid_commit ) ||
1243- hdr -> msg_type == DHCPV6_MSG_REQUEST ||
1244- hdr -> msg_type == DHCPV6_MSG_REBIND )) {
1245- if (hostname_len > 0 && (!a -> lease_cfg || !a -> lease_cfg -> hostname )) {
1246- char * tmp = realloc (a -> hostname , hostname_len + 1 );
1247- if (tmp ) {
1248- a -> hostname = tmp ;
1249- memcpy (a -> hostname , hostname , hostname_len );
1250- a -> hostname [hostname_len ] = 0 ;
1251- a -> hostname_valid = odhcpd_hostname_valid (a -> hostname );
1267+ if (assigned ) {
1268+ switch (hdr -> msg_type ) {
1269+ case DHCPV6_MSG_SOLICIT :
1270+ if (!rapid_commit ) {
1271+ a -> bound = false;
1272+ a -> valid_until = now + 60 ;
1273+ break ;
1274+ }
1275+
1276+ _o_fallthrough ;
1277+ case DHCPV6_MSG_REQUEST :
1278+ case DHCPV6_MSG_REBIND :
1279+ if (hostname_len > 0 && (!a -> lease_cfg || !a -> lease_cfg -> hostname )) {
1280+
1281+ char * tmp = realloc (a -> hostname , hostname_len + 1 );
1282+ if (tmp ) {
1283+ a -> hostname = tmp ;
1284+ memcpy (a -> hostname , hostname , hostname_len );
1285+ a -> hostname [hostname_len ] = 0 ;
1286+ a -> hostname_valid = odhcpd_hostname_valid (a -> hostname );
1287+ }
12521288 }
1289+
1290+ a -> accept_fr_nonce = accept_reconf ;
1291+ a -> bound = true;
1292+ apply_lease (a , true);
1293+ break ;
1294+
1295+ default :
1296+ break ;
12531297 }
1254- a -> accept_fr_nonce = accept_reconf ;
1255- a -> bound = true;
1256- apply_lease (a , true);
1257- } else if (!assigned ) {
1258- /* Cleanup failed assignment */
1298+ } else {
1299+ /* Clean up failed assignment */
12591300 dhcpv6_free_lease (a );
12601301 a = NULL ;
12611302 }
1262- } else if (hdr -> msg_type == DHCPV6_MSG_RENEW ||
1263- hdr -> msg_type == DHCPV6_MSG_RELEASE ||
1264- hdr -> msg_type == DHCPV6_MSG_REBIND ||
1265- hdr -> msg_type == DHCPV6_MSG_DECLINE ) {
1266- if (!a && hdr -> msg_type != DHCPV6_MSG_REBIND ) {
1303+
1304+ break ;
1305+ }
1306+
1307+ case DHCPV6_MSG_RENEW :
1308+ case DHCPV6_MSG_RELEASE :
1309+ case DHCPV6_MSG_DECLINE : {
1310+ /* RENEW / RELEASE / DECLINE require an existing binding */
1311+ if (!a ) {
12671312 status = DHCPV6_STATUS_NOBINDING ;
12681313 ia_response_len = build_ia (buf , buflen , status , ia , a , iface , false);
1269- } else if (hdr -> msg_type == DHCPV6_MSG_RENEW ||
1270- hdr -> msg_type == DHCPV6_MSG_REBIND ) {
1314+ break ;
1315+ }
1316+
1317+ switch (hdr -> msg_type ) {
1318+ case DHCPV6_MSG_RENEW :
12711319 ia_response_len = build_ia (buf , buflen , status , ia , a , iface , false);
1272- if (a ) {
1273- a -> bound = true;
1274- apply_lease (a , true);
1275- }
1276- } else if (hdr -> msg_type == DHCPV6_MSG_RELEASE ) {
1320+
1321+ a -> bound = true;
1322+ apply_lease (a , true);
1323+ break ;
1324+
1325+ case DHCPV6_MSG_RELEASE :
1326+ /* Immediately expire the lease */
12771327 a -> valid_until = now - 1 ;
1278- } else if ((a -> flags & OAF_DHCPV6_NA ) && hdr -> msg_type == DHCPV6_MSG_DECLINE ) {
1328+ break ;
1329+
1330+ case DHCPV6_MSG_DECLINE :
1331+ /* DECLINE only applies to non-temporary addresses */
1332+ if (!(a -> flags & OAF_DHCPV6_NA ))
1333+ break ;
1334+
12791335 a -> bound = false;
12801336
1281- if (!a -> lease_cfg || a -> lease_cfg -> hostid != a -> assigned_host_id ) {
1282- memset (a -> duid , 0 , a -> duid_len );
1283- a -> valid_until = now + 3600 ; /* Block address for 1h */
1284- } else
1337+ if (a -> lease_cfg &&
1338+ a -> lease_cfg -> hostid == a -> assigned_host_id ) {
1339+ /* Static lease: release immediately */
12851340 a -> valid_until = now - 1 ;
1341+ } else {
1342+ /* Dynamic lease: block address for 1 hour */
1343+ memset (a -> duid , 0 , a -> duid_len );
1344+ a -> valid_until = now + 3600 ;
1345+ }
1346+ break ;
12861347 }
1287- } else if (hdr -> msg_type == DHCPV6_MSG_CONFIRM ) {
1348+
1349+ break ;
1350+ }
1351+
1352+ case DHCPV6_MSG_CONFIRM :
12881353 if (ia_addr_present && !dhcpv6_ia_on_link (ia , a , iface )) {
12891354 notonlink = true;
12901355 break ;
@@ -1294,13 +1359,23 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12941359 response_len = 0 ;
12951360 goto out ;
12961361 }
1362+ break ;
1363+
1364+ default :
1365+ break ;
1366+ }
1367+
1368+ if (hdr -> msg_type == DHCPV6_MSG_REBIND && a ) {
1369+ ia_response_len = build_ia (buf , buflen , status , ia , a , iface , false);
1370+ a -> bound = true;
1371+ apply_lease (a , true);
12971372 }
12981373
12991374 buf += ia_response_len ;
13001375 buflen -= ia_response_len ;
13011376 response_len += ia_response_len ;
13021377 dhcpv6_log (hdr -> msg_type , iface , now , duidbuf , is_pd , a , status );
1303- }
1378+ } /* end dhcpv6_for_each_option */
13041379
13051380 switch (hdr -> msg_type ) {
13061381 case DHCPV6_MSG_RELEASE :
0 commit comments