// keep them in rdatas_ and rrsigs_ so we can detect and ignore duplicate
// data with the existing one later. We'll also figure out the lengths
// of the RDATA and RRSIG part of the data by iterating over the data
- // fields.
+ // fields. Note that the given old_data shouldn't contain duplicate
+ // Rdata or RRSIG as they should have been generated by this own class,
+ // which ensures that condition; if this assumption doesn't hold, we throw.
size_t total_len = 0;
RdataReader reader(rrclass, rrtype, old_data, old_rdata_count,
old_sig_count,
while (reader.iterateRdata()) {
util::InputBuffer ibuffer(impl_->olddata_buffer_.getData(),
impl_->olddata_buffer_.getLength());
- impl_->rdatas_.insert(createRdata(rrtype, rrclass, ibuffer,
- impl_->olddata_buffer_.getLength()));
+ if (!impl_->rdatas_.insert(
+ createRdata(rrtype, rrclass, ibuffer,
+ impl_->olddata_buffer_.getLength())).second) {
+ isc_throw(Unexpected, "duplicate RDATA found in merging RdataSet");
+ }
impl_->olddata_buffer_.clear();
}
impl_->old_data_len_ = total_len;
while (reader.iterateSingleSig()) {
util::InputBuffer ibuffer(impl_->olddata_buffer_.getData(),
impl_->olddata_buffer_.getLength());
- impl_->rrsigs_.insert(createRdata(RRType::RRSIG(), rrclass, ibuffer,
- impl_->olddata_buffer_.getLength()));
+ if (!impl_->rrsigs_.insert(
+ createRdata(RRType::RRSIG(), rrclass, ibuffer,
+ impl_->olddata_buffer_.getLength())).second) {
+ isc_throw(Unexpected, "duplicate RRSIG found in merging RdataSet");
+ }
impl_->olddata_buffer_.clear();
}
impl_->old_sig_len_ = total_len;
/// for another attempt of encoding, which is unlikely), the caller can
/// modify or destroy the old data.
///
+ /// The caller must also ensure that \c old_data don't contain any
+ /// duplicate Rdata or RRSIG. Normally the caller doesn't have to do
+ /// anything special to meet this requirement, though, as the data
+ /// should have been generated by an \c RdataEncoder object before,
+ /// which guarantees that condition. But this method checks the
+ /// assumption in case it was crafted or otherwise broken data, and
+ /// throws an exception if that is the case.
+ ///
+ /// \throw Unexpected Given encoded data contain duplicate Rdata or RRSIG
+ /// (normally shouldn't happen, see the description).
+ ///
/// \param rrclass The RR class of RDATA to be encoded in the session.
/// \param rrtype The RR type of RDATA to be encoded in the session.
/// \param old_data Point to previously encoded data for the same RR
this->mergeRdataCommon(old_rrsigs, rrsigs);
}
+TEST_F(RdataSerializationTest, mergeRdataFromDuplicate) {
+ // create encoded data containing duplicate Rdata and try to start a
+ // new encoding session in the merge mode with that data. It breaks the
+ // assumption and should result in an exception.
+ const uint8_t data[] = { 192, 0, 2, 1, 192, 0, 2, 1 };
+ EXPECT_THROW(encoder_.start(RRClass::IN(), RRType::A(), data, 2, 0),
+ isc::Unexpected);
+
+ // Same for duplicate RRSIG
+ isc::util::OutputBuffer buffer(0);
+ vector<uint8_t> sigdata;
+ rrsig_rdata_->toWire(buffer);
+ const uint16_t sig_len = buffer.getLength();
+ // Encode lengths of RRSIGs, 2 bytes each, in host byte order
+ const uint8_t* const lp = static_cast<const uint8_t*>(
+ static_cast<const void*>(&sig_len));
+ sigdata.insert(sigdata.end(), lp, lp + sizeof(sig_len));
+ sigdata.insert(sigdata.end(), lp, lp + sizeof(sig_len));
+ // then the RRSIG data
+ const uint8_t* const dp = static_cast<const uint8_t*>(buffer.getData());
+ sigdata.insert(sigdata.end(), dp, dp + sig_len);
+ sigdata.insert(sigdata.end(), dp, dp + sig_len);
+
+ EXPECT_THROW(encoder_.start(RRClass::IN(), RRType::A(), &sigdata[0], 0, 2),
+ isc::Unexpected);
+}
+
void
checkSigData(const ConstRdataPtr& decoded, bool* called, const void* encoded,
size_t length)