return 0;
}
-int dhcp6_option_parse_ia(sd_dhcp6_client *client, DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code) {
+int dhcp6_option_parse_ia(
+ sd_dhcp6_client *client,
+ DHCP6Option *iaoption,
+ be32_t iaid,
+ DHCP6IA *ia,
+ uint16_t *ret_status_code) {
+
uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX;
uint16_t iatype, optlen;
size_t iaaddr_offset;
if (len < DHCP6_OPTION_IA_NA_LEN)
return -ENOBUFS;
+ /* According to RFC8415, IAs which do not match the client's IAID should be ignored,
+ * but not necessary to ignore or refuse the whole message. */
+ if (((const struct ia_na*) iaoption->data)->id != iaid)
+ /* ENOANO indicates the option should be ignored. */
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
+ "Received an IA_NA option with a different IAID "
+ "from the one chosen by the client, ignoring.");
+
iaaddr_offset = DHCP6_OPTION_IA_NA_LEN;
memcpy(&ia->ia_na, iaoption->data, sizeof(ia->ia_na));
if (len < sizeof(ia->ia_pd))
return -ENOBUFS;
+ /* According to RFC8415, IAs which do not match the client's IAID should be ignored,
+ * but not necessary to ignore or refuse the whole message. */
+ if (((const struct ia_pd*) iaoption->data)->id != iaid)
+ /* ENOANO indicates the option should be ignored. */
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
+ "Received an IA_PD option with a different IAID "
+ "from the one chosen by the client, ignoring.");
+
iaaddr_offset = sizeof(ia->ia_pd);
memcpy(&ia->ia_pd, iaoption->data, sizeof(ia->ia_pd));
if (len < DHCP6_OPTION_IA_TA_LEN)
return -ENOBUFS;
+ /* According to RFC8415, IAs which do not match the client's IAID should be ignored,
+ * but not necessary to ignore or refuse the whole message. */
+ if (((const struct ia_ta*) iaoption->data)->id != iaid)
+ /* ENOANO indicates the option should be ignored. */
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
+ "Received an IA_TA option with a different IAID "
+ "from the one chosen by the client, ignoring.");
+
iaaddr_offset = DHCP6_OPTION_IA_TA_LEN;
- memcpy(&ia->ia_ta.id, iaoption->data, sizeof(ia->ia_ta));
+ memcpy(&ia->ia_ta, iaoption->data, sizeof(ia->ia_ta));
break;
default:
- return -ENOMSG;
+ return -EINVAL;
}
ia->type = iatype;
while (pos < len) {
DHCP6Option *option = (DHCP6Option *) &message->options[pos];
uint16_t optcode, optlen;
- be32_t iaid_lease;
int status;
uint8_t *optval;
break;
}
- r = dhcp6_option_parse_ia(client, option, &lease->ia, &ia_na_status);
- if (r < 0 && r != -ENOMSG)
+ r = dhcp6_option_parse_ia(client, option, client->ia_pd.ia_na.id, &lease->ia, &ia_na_status);
+ if (r < 0 && r != -ENOANO)
return r;
if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) {
continue;
}
- r = dhcp6_lease_get_iaid(lease, &iaid_lease);
- if (r < 0)
- return r;
-
- if (client->ia_na.ia_na.id != iaid_lease)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has wrong IAID for IA NA",
- dhcp6_message_type_to_string(message->type));
-
if (lease->ia.addresses) {
lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
break;
}
- r = dhcp6_option_parse_ia(client, option, &lease->pd, &ia_pd_status);
- if (r < 0 && r != -ENOMSG)
+ r = dhcp6_option_parse_ia(client, option, client->ia_pd.ia_pd.id, &lease->pd, &ia_pd_status);
+ if (r < 0 && r != -ENOANO)
return r;
if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) {
continue;
}
- r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
- if (r < 0)
- return r;
-
- if (client->ia_pd.ia_pd.id != iaid_lease)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has wrong IAID for IA PD",
- dhcp6_message_type_to_string(message->type));
-
if (lease->pd.addresses) {
lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
};
DHCP6Option *option;
DHCP6IA ia, pd;
+ be32_t iaid;
int r = 0;
log_debug("/* %s */", __func__);
+ memcpy(&iaid, option1 + 4, sizeof(iaid));
+
zero(ia);
option = (DHCP6Option *)option1;
assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, 0, &ia, NULL);
+ assert_se(r == -ENOANO);
+
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r == 0);
assert_se(ia.addresses == NULL);
option->len = htobe16(17);
- r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
option->len = htobe16(sizeof(DHCP6Option));
- r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
option = (DHCP6Option *)option2;
assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses == NULL);
option = (DHCP6Option *)option3;
assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(NULL, option, &ia, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses != NULL);
dhcp6_lease_free_ia(&ia);
option = (DHCP6Option *)option4;
assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(NULL, option, &pd, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &pd, NULL);
assert_se(r >= 0);
assert_se(pd.addresses != NULL);
assert_se(memcmp(&pd.ia_pd.id, &option4[4], 4) == 0);
option = (DHCP6Option *)option5;
assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(NULL, option, &pd, NULL);
+ r = dhcp6_option_parse_ia(NULL, option, iaid, &pd, NULL);
assert_se(r >= 0);
assert_se(pd.addresses != NULL);
dhcp6_lease_free_ia(&pd);
opt_clientid = true;
break;
- case SD_DHCP6_OPTION_IA_NA:
+ case SD_DHCP6_OPTION_IA_NA: {
+ be32_t iaid = htobe32(0x0ecfa37d);
+
assert_se(optlen == 94);
assert_se(optval == &msg_advertise[26]);
assert_se(!memcmp(optval, &msg_advertise[26], optlen));
- val = htobe32(0x0ecfa37d);
- assert_se(!memcmp(optval, &val, sizeof(val)));
+ assert_se(!memcmp(optval, &iaid, sizeof(val)));
val = htobe32(80);
assert_se(!memcmp(optval + 4, &val, sizeof(val)));
val = htobe32(120);
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
- assert_se(dhcp6_option_parse_ia(NULL, option, &lease->ia, NULL) >= 0);
+ assert_se(dhcp6_option_parse_ia(NULL, option, iaid, &lease->ia, NULL) >= 0);
break;
-
+ }
case SD_DHCP6_OPTION_SERVERID:
assert_se(optlen == 14);
assert_se(optval == &msg_advertise[179]);
static int test_client_send_reply(DHCP6Message *request) {
DHCP6Message reply;
+ log_debug("/* %s */", __func__);
+
reply.transaction_id = request->transaction_id;
reply.type = DHCP6_REPLY;
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
/* Then, this should refuse all addresses. */
- assert_se(dhcp6_option_parse_ia(NULL, option, &lease->ia, NULL) >= 0);
+ assert_se(dhcp6_option_parse_ia(NULL, option, test_iaid, &lease->ia, NULL) >= 0);
break;
static int test_client_send_advertise(DHCP6Message *solicit) {
DHCP6Message advertise;
+ log_debug("/* %s */", __func__);
+
advertise.transaction_id = solicit->transaction_id;
advertise.type = DHCP6_ADVERTISE;
IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
DHCP6Message *message;
+ log_debug("/* %s */", __func__);
+
assert_se(s == test_dhcp_fd[0]);
assert_se(server_address);
assert_se(packet);