summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/labelsequence.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/dns/labelsequence.h456
1 files changed, 456 insertions, 0 deletions
diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h
new file mode 100644
index 0000000..91dbe59
--- /dev/null
+++ b/src/lib/dns/labelsequence.h
@@ -0,0 +1,456 @@
+// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef LABELSEQUENCE_H
+#define LABELSEQUENCE_H 1
+
+#include <dns/name.h>
+#include <util/buffer.h>
+
+namespace isc {
+namespace dns {
+
+/// \brief Light-weight Accessor to Name data.
+///
+/// The purpose of this class is to easily match Names and parts of Names,
+/// without needing to copy the underlying data on each label strip.
+///
+/// It can only work on existing Name objects, or data as provided by the
+/// Name object or another LabelSequence, and the data or Name MUST
+/// remain in scope during the entire lifetime of its associated
+/// LabelSequence(s).
+///
+/// Upon creation of a LabelSequence, it records the offsets of the
+/// labels in the wireformat data of the Name. When stripLeft() or
+/// stripRight() is called on the LabelSequence, no changes in the
+/// original data occur, but the internal pointers of the
+/// LabelSequence are modified.
+///
+/// LabelSequences can be compared to other LabelSequences, and their
+/// data can be requested (which then points to part of the original
+/// data of the original Name object).
+class LabelSequence {
+ // Name calls the private toText(bool) method of LabelSequence.
+ friend std::string Name::toText(bool) const;
+
+public:
+ /// \brief Max possible size of serialized image generated by \c serialize
+ ///
+ /// A fixed length buffer of this size can be always passed to
+ /// \c serialize() safely. (But the application shouldn't use the
+ /// specific size value; it must use this constant variable).
+ static const size_t MAX_SERIALIZED_LENGTH =
+ Name::MAX_WIRE + Name::MAX_LABELS + 1;
+
+ ///
+ /// \name Well-known LabelSequence constants
+ ///
+ //@{
+ /// Wildcard label ("*")
+ static const LabelSequence& WILDCARD();
+ //@}
+
+ /// \brief Constructs a LabelSequence for the given name
+ ///
+ /// \note The associated Name MUST remain in scope during the lifetime
+ /// of this LabelSequence, since getData() refers to data from the
+ /// Name object (the only data the LabelSequence stores are pointers
+ /// to the labels in the Name object).
+ ///
+ /// \param name The Name to construct a LabelSequence for
+ explicit LabelSequence(const Name& name):
+ data_(&name.ndata_[0]),
+ offsets_(&name.offsets_[0]),
+ first_label_(0),
+ last_label_(name.getLabelCount() - 1)
+ {}
+
+ /// \brief Constructor from serialized image.
+ ///
+ /// This constructor restores a \c LabelSequence object from a serialized
+ /// binary image previously generated by \c serialize(). Any other input
+ /// to this constructor will result in undefined behavior.
+ ///
+ /// The binary data passed to this constructor MUST remain in scope and
+ /// MUST NOT be modified during the lifetime of this LabelSequence.
+ ///
+ /// As long as the data were previously generated by a call to
+ /// \c serialize() on a valid \c LabelSequence object, this constructor
+ /// should succeed. While any other case is undefined, this constructor
+ /// may perform some validity checks internally for safety. Nevertheless,
+ /// applications must not rely on such checks.
+ ///
+ /// \param buf Pointer to the serialized image generated by \c serialize().
+ explicit LabelSequence(const void* buf);
+
+ /// \brief Construct 'extendable' LabelSequence
+ ///
+ /// This form of LabelSequence copies the data from the given
+ /// labelsequence into the given external buffer, which is subsequently
+ /// extendable by calling extend()
+ ///
+ /// The data is placed into the given buffer as follows:
+ /// - binary sequence of name data, starting at position 0,
+ /// length determined by source LabelSequence
+ /// - offsets, starting at position Name::MAX_WIRE, length
+ /// determined by source LabelSequence
+ /// The offsets are updated to be correct for the potentially partial
+ /// name data (as stripLeft() and stripRight may have been called on
+ /// the source LabelSequence).
+ ///
+ /// \note The given buf MUST remain in scope during the lifetime of
+ /// the LabelSequence created here.
+ /// \note The buffer should never be modified except through
+ /// calls to extend().
+ /// \note Also, only associate the buffer with at most one
+ /// LabelSequence. Behaviour is undefined if two LabelSequences are
+ /// using the same buffer.
+ ///
+ /// \param src LabelSequence to copy the initial data from
+ /// \param buf external buffer to store this labelsequence's data in
+ LabelSequence(const LabelSequence& src, uint8_t buf[MAX_SERIALIZED_LENGTH]);
+
+ /// \brief Copy constructor.
+ ///
+ /// \note The associated data MUST remain in scope during the lifetime
+ /// of this LabelSequence, since only the pointers are copied.
+ ///
+ /// \note No validation is done on the given data upon construction;
+ /// use with care.
+ ///
+ /// \param ls The LabelSequence to construct a LabelSequence from
+ LabelSequence(const LabelSequence& ls):
+ data_(ls.data_),
+ offsets_(ls.offsets_),
+ first_label_(ls.first_label_),
+ last_label_(ls.last_label_)
+ {}
+
+ /// \brief Assignment operator.
+ ///
+ /// \note The associated data MUST remain in scope during the lifetime
+ /// of this LabelSequence, since only the pointers are copied.
+ ///
+ /// \note No validation is done on the given data upon construction;
+ /// use with care.
+ ///
+ /// \param other The LabelSequence to assign a LabelSequence from
+ LabelSequence& operator=(const LabelSequence& other) {
+ if (this != &other) {
+ // Not self-assignment.
+ data_ = other.data_;
+ offsets_ = other.offsets_;
+ first_label_ = other.first_label_;
+ last_label_ = other.last_label_;
+ }
+ return (*this);
+ }
+
+ /// \brief Return the wire-format data for this LabelSequence
+ ///
+ /// The data is returned as a pointer to (the part of) the original
+ /// wireformat data, from either the original Name object, or the
+ /// raw data given in the constructor, and the given len value is
+ /// set to the number of octets that match this labelsequence.
+ ///
+ /// \note The data pointed to is only valid if the original Name
+ /// object or data is still in scope
+ ///
+ /// \param len Pointer to a size_t where the length of the data
+ /// will be stored (in number of octets)
+ /// \return Pointer to the wire-format data of this label sequence
+ const uint8_t* getData(size_t* len) const;
+
+ /// \brief Return the length of the wire-format data of this LabelSequence
+ ///
+ /// This method returns the number of octets for the data that would
+ /// be returned by the \c getData() method.
+ ///
+ /// Note that the return value of this method is always positive.
+ /// Note also that if the return value of this method is 1, it means the
+ /// sequence consists of the null label, i.e., a single "dot", and vice
+ /// versa.
+ ///
+ /// \note The data pointed to is only valid if the original Name
+ /// object or data is still in scope
+ ///
+ /// \return The length of the data of the label sequence in octets.
+ size_t getDataLength() const;
+
+ /// \brief Return the size of serialized image of the \c LabelSequence.
+ ///
+ /// This method calculates the size of necessary storage to store
+ /// serialized image of this \c LabelSequence (which would be dumped by
+ /// \c serialize()) and returns it. The size is in bytes.
+ ///
+ /// \throw none.
+ ///
+ /// \return The size of serialized image of the \c LabelSequence.
+ size_t getSerializedLength() const;
+
+ /// \brief Serialize the \c LabelSequence object in to a buffer.
+ ///
+ /// This method dumps a serialized image of this \c LabelSequence
+ /// that would be restored by the corresponding constructor into the
+ /// given buffer. The buffer size must be at least equal to
+ /// the value returned by getSerializedLength() (it can be larger than
+ /// that).
+ ///
+ /// Be careful about where the buffer is located; due to the nature
+ /// of the buffer, it's quite possible that the memory region is being used
+ /// to construct another active \c LabelSequence. In such a case
+ /// the serialization would silently break that sequence object, and
+ /// it will be very difficult to identify the cause. This method
+ /// has minimal level checks to avoid such disruption: If the serialization
+ /// would break "this" \c LabelSequence object, it doesn't write anything
+ /// to the given buffer and throw a \c isc::BadValue exception.
+ ///
+ /// In general, it should be safe to call this method on a
+ /// \c LabelSequence object constructed from a \c Name object or
+ /// a copy of such \c LabelSequence. When you construct \c LabelSequence
+ /// from pre-serialized data, calling this method on it can be unsafe.
+ /// One safe (but a bit less efficient) way in such a case is to make
+ /// the source \c LabelSequence temporary and immediately create a
+ /// local copy using an explicit buffer, and call this method on the
+ /// latter:
+ /// \code
+ /// // don't do this, it's not safe (and would result in exception):
+ /// // LabelSequence(buf).serialize(buf, buf_len);
+ ///
+ /// // The following are the safe way:
+ /// uint8_t ext_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+ /// LabelSequence seq(LabelSequence(buf), ext_buf);
+ /// ... (strip the labels, etc)
+ /// seq.serialize(buf, buf_len); // it's safe to override buf here
+ /// \endcode
+ ///
+ /// The serialized image would be as follows:
+ /// - olen: number of offsets (1 byte)
+ /// - binary sequence of offsets (olen bytes, verbatim copy of offsets_
+ /// of this size)
+ /// - binary sequence of name data (length determined by itself, verbatim
+ /// copy of data_ of the corresponding size)
+ ///
+ /// Applications must use the resulting image as opaque value and must not
+ /// use it for other purposes than input to the corresponding constructor
+ /// to restore it. Application behavior that assumes the specific
+ /// organization of the image is not guaranteed.
+ ///
+ /// \throw isc::BadValue buf_len is too short (this method never throws
+ /// otherwise) or the serialization would override internal data of
+ /// of the source LabelSequence.
+ ///
+ /// \param buf Pointer to the placeholder to dump the serialized image
+ /// \param buf_len The size of available region in \c buf
+ void serialize(void* buf, size_t buf_len) const;
+
+ /// \brief Compares two label sequences for equality.
+ ///
+ /// Performs a (optionally case-sensitive) comparison between this
+ /// LabelSequence and another LabelSequence for equality.
+ ///
+ /// \param other The LabelSequence to compare with
+ /// \param case_sensitive If true, comparison is case-sensitive
+ /// \return true if The label sequences consist are the same length,
+ /// and contain the same data.
+ bool equals(const LabelSequence& other, bool case_sensitive = false) const;
+
+ /// \brief Compares two label sequences for equality (case ignored).
+ ///
+ /// This is equivalent to <code>this->equals(other)</code>.
+ ///
+ /// The operator version is convenient some specific cases such as in
+ /// unit tests.
+ bool operator==(const LabelSequence& other) const {
+ return (equals(other));
+ }
+
+ /// \brief Compares two label sequences.
+ ///
+ /// Performs a (optionally case-insensitive) comparison between this
+ /// LabelSequence and another LabelSequence.
+ ///
+ /// \param other The LabelSequence to compare with
+ /// \param case_sensitive If true, comparison is case-insensitive
+ /// \return a <code>NameComparisonResult</code> object representing the
+ /// comparison result.
+ NameComparisonResult compare(const LabelSequence& other,
+ bool case_sensitive = false) const;
+
+ /// \brief Remove labels from the front of this LabelSequence
+ ///
+ /// \note No actual memory is changed, this operation merely updates the
+ /// internal pointers based on the offsets in the Name object.
+ ///
+ /// \exception OutOfRange if i is greater than or equal to the number
+ /// of labels currently pointed to by this LabelSequence
+ ///
+ /// \param i The number of labels to remove.
+ void stripLeft(size_t i);
+
+ /// \brief Remove labels from the end of this LabelSequence
+ ///
+ /// \note No actual memory is changed, this operation merely updates the
+ /// internal pointers based on the offsets originally provided.
+ ///
+ /// \exception OutOfRange if i is greater than or equal to the number
+ /// of labels currently pointed to by this LabelSequence
+ ///
+ /// \param i The number of labels to remove.
+ void stripRight(size_t i);
+
+ /// \brief Returns the current number of labels for this LabelSequence
+ ///
+ /// \return The number of labels
+ size_t getLabelCount() const {
+ return (last_label_ - first_label_ + 1);
+ }
+
+ /// \brief Convert the LabelSequence to a string.
+ ///
+ /// This method returns a <code>std::string</code> object representing the
+ /// LabelSequence as a string. The returned string ends with a dot
+ /// '.' if the label sequence is absolute.
+ ///
+ /// This function assumes the underlying data is in proper
+ /// uncompressed wire format. If it finds an unexpected label
+ /// character including compression pointer, an exception of class
+ /// \c BadLabelType will be thrown. In addition, if resource
+ /// allocation for the result string fails, a corresponding standard
+ /// exception will be thrown.
+ ///
+ /// \return a string representation of the <code>LabelSequence</code>.
+ std::string toText() const;
+
+ /// \brief Convert the LabelSequence to a string without escape sequences.
+ ///
+ /// The string returned will contain a single character value for any
+ /// escape sequences in the label(s).
+ ///
+ /// \param omit_final_dot whether to omit the trailing dot in the output.
+ /// \return a string representation of the <code>LabelSequence</code>
+ /// that does not contain escape sequences.
+ std::string toRawText(bool omit_final_dot) const;
+
+ /// \brief Extend this LabelSequence with the given labelsequence
+ ///
+ /// The given labels are appended to the name data, and internal
+ /// offset data is updated accordingly.
+ ///
+ /// The data from the given LabelSequence is copied into the buffer
+ /// associated with this LabelSequence; the appended LabelSequence
+ /// (the 'labels' argument) can be released if it is not needed for
+ /// other operations anymore.
+ ///
+ /// If this LabelSequence is absolute, its root label will be stripped
+ /// before the given LabelSequence is appended; after extend(),
+ /// this LabelSequence will be absolute if, and only if, the appended
+ /// LabelSequence was. A side-effect of this property is that adding
+ /// the root label to an absolute LabelSequence has no effect (the
+ /// root label is stripped, then added again).
+ ///
+ /// Some minimal checking is done on the data, but internal integrity
+ /// is not assumed. Do NOT modify the given buffer except through calls
+ /// to this method, and do NOT call this method if the buffer is
+ /// associated to another LabelSequence (behaviour of the other
+ /// LabelSequence is undefined in that scenario).
+ ///
+ /// \exception BadValue If the buffer does not appear to be associated
+ /// with this LabelSequence, or if the maximum wire length or maximum
+ /// number of labels would be exceeded by this operation
+ ///
+ /// \param labels The labels to append to this LabelSequence
+ /// \param buf The buffer associated with this LabelSequence
+ void extend(const LabelSequence& labels,
+ uint8_t buf[MAX_SERIALIZED_LENGTH]);
+
+private:
+ /// \brief Convert the LabelSequence to a string.
+ ///
+ /// This method is a version of the zero-argument toText() method,
+ /// that accepts a <code>omit_final_dot</code> argument. The
+ /// returned string ends with a dot '.' if
+ /// <code>omit_final_dot</code> is <code>false</code>.
+ ///
+ /// This method is used as a helper for <code>Name::toText()</code>
+ /// only.
+ ///
+ /// \param omit_final_dot whether to omit the trailing dot in the output.
+ /// \return a string representation of the <code>LabelSequence</code>.
+ std::string toText(bool omit_final_dot) const;
+public:
+ /// \brief Calculate a simple hash for the label sequence.
+ ///
+ /// This method calculates a hash value for the label sequence as binary
+ /// data. If \c case_sensitive is false, it ignores the case stored in
+ /// the labels; specifically, it normalizes the labels by converting all
+ /// upper case characters to lower case ones and calculates the hash value
+ /// for the result.
+ ///
+ /// This method is intended to provide a lightweight way to store a
+ /// relatively small number of label sequences in a hash table.
+ /// For this reason it only takes into account data up to 16 octets
+ /// (16 was derived from BIND 9's implementation). Also, the function does
+ /// not provide any unpredictability; a specific sequence will always have
+ /// the same hash value. It should therefore not be used in the context
+ /// where an untrusted third party can mount a denial of service attack by
+ /// forcing the application to create a very large number of label
+ /// sequences that have the same hash value and expected to be stored in
+ /// a hash table.
+ ///
+ /// \exception None
+ ///
+ /// \param case_sensitive
+ /// \return A hash value for this label sequence.
+ size_t getHash(bool case_sensitive) const;
+
+ /// \brief Checks whether the label sequence is absolute
+ ///
+ /// \return true if the last label is the root label
+ bool isAbsolute() const;
+
+private:
+ const uint8_t* data_; // wire-format name data
+ const uint8_t* offsets_; // an array of offsets in data_ for the labels
+ size_t first_label_; // index of offsets_ for the first label
+ size_t last_label_; // index of offsets_ for the last label.
+ // can be equal to first_label_, but must not
+ // be smaller (the class ensures that)
+};
+
+
+///
+/// \brief Insert the label sequence as a string into stream.
+///
+/// This method convert the \c label_sequence into a string and inserts
+/// it into the output stream \c os.
+///
+/// This function overloads the global operator<< to behave as described in
+/// ostream::operator<< but applied to \c LabelSequence objects.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param label_sequence The \c LabelSequence object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream&
+operator<<(std::ostream& os, const LabelSequence& label_sequence);
+
+inline const LabelSequence&
+LabelSequence::WILDCARD() {
+ static const uint8_t wildcard_buf[4] = { 0x01, 0x00, 0x01, '*' };
+ static const LabelSequence wild_ls(wildcard_buf);
+ return (wild_ls);
+}
+
+} // end namespace dns
+} // end namespace isc
+
+#endif
+
+// Local Variables:
+// mode: c++
+// End: