Parcourir la source

[master] Merge branch 'trac1602'

Jelte Jansen il y a 13 ans
Parent
commit
b33929ed5d

+ 2 - 0
src/lib/dns/Makefile.am

@@ -91,6 +91,7 @@ libdns___la_LDFLAGS = -no-undefined -version-info 1:0:1
 libdns___la_SOURCES =
 libdns___la_SOURCES += edns.h edns.cc
 libdns___la_SOURCES += exceptions.h exceptions.cc
+libdns___la_SOURCES += labelsequence.h labelsequence.cc
 libdns___la_SOURCES += masterload.h masterload.cc
 libdns___la_SOURCES += message.h message.cc
 libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
@@ -140,6 +141,7 @@ libdns___includedir = $(includedir)/dns
 libdns___include_HEADERS = \
 	edns.h \
 	exceptions.h \
+	labelsequence.h \
 	message.h \
 	messagerenderer.h \
 	name.h \

+ 77 - 0
src/lib/dns/labelsequence.cc

@@ -0,0 +1,77 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/labelsequence.h>
+#include <exceptions/exceptions.h>
+
+#include <iostream>
+namespace isc {
+namespace dns {
+
+const char*
+LabelSequence::getData(size_t *len) const {
+    // If the labelsequence is absolute, the current last_label_ falls
+    // out of the vector (since it points to the 'label' after the
+    // root label, which doesn't exist; in that case, return
+    // the length for the 'previous' label (the root label) plus
+    // one (for the root label zero octet)
+    if (isAbsolute()) {
+        *len = name_.offsets_[last_label_ - 1] - name_.offsets_[first_label_] + 1;
+    } else {
+        *len = name_.offsets_[last_label_] - name_.offsets_[first_label_];
+    }
+    return (&name_.ndata_[name_.offsets_[first_label_]]);
+}
+
+bool
+LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
+    size_t len, other_len;
+    const char* data = getData(&len);
+    const char* other_data = other.getData(&other_len);
+
+    if (len != other_len) {
+        return (false);
+    }
+    if (case_sensitive) {
+        return (strncasecmp(data, other_data, len) == 0);
+    } else {
+        return (strncmp(data, other_data, len) == 0);
+    }
+}
+
+void
+LabelSequence::stripLeft(size_t i) {
+    if (i >= getLabelCount()) {
+        isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
+                              " (labelcount: " << getLabelCount() << ")");
+    }
+    first_label_ += i;
+}
+
+void
+LabelSequence::stripRight(size_t i) {
+    if (i >= getLabelCount()) {
+        isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
+                              " (labelcount: " << getLabelCount() << ")");
+    }
+    last_label_ -= i;
+}
+
+bool
+LabelSequence::isAbsolute() const {
+    return (last_label_ == name_.offsets_.size());
+}
+
+} // end namespace dns
+} // end namespace isc

+ 136 - 0
src/lib/dns/labelsequence.h

@@ -0,0 +1,136 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#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 object
+///
+/// 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, and the Name object 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
+/// Name's 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 associated Name object).
+///
+class LabelSequence {
+public:
+    /// \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
+    LabelSequence(const Name& name): name_(name),
+                                     first_label_(0),
+                                     last_label_(name.getLabelCount())
+    {}
+
+    /// \brief Return the wire-format data for this LabelSequence
+    ///
+    /// The data, is returned as a pointer to the original wireformat
+    /// data of the original Name object, 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 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 char* getData(size_t* len) const;
+
+    /// \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 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 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.
+    ///
+    /// \exeption 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 in the Name object.
+    ///
+    /// \exeption 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_; }
+
+    /// \brief Returns the original Name object associated with this
+    ///        LabelSequence
+    ///
+    /// While the Name should still be in scope during the lifetime of
+    /// the LabelSequence, it can still be useful to have access to it,
+    /// for instance in helper functions that are only passed the
+    /// LabelSequence itself.
+    ///
+    /// \return Reference to the original Name object
+    const Name& getName() const { return name_; }
+
+    /// \brief Checks whether the label sequence is absolute
+    ///
+    /// \return true if the last label is the root label
+    bool isAbsolute() const;
+
+private:
+    const Name& name_;
+    size_t first_label_;
+    size_t last_label_;
+};
+
+
+} // end namespace dns
+} // end namespace isc
+
+#endif

+ 6 - 0
src/lib/dns/name.h

@@ -210,6 +210,11 @@ private:
 /// names as a special case.
 ///
 class Name {
+    // LabelSequences use knowledge about the internal data structure
+    // of this class for efficiency (they use the offsets_ vector and
+    // the ndata_ string)
+    friend class LabelSequence;
+
     ///
     /// \name Constructors and Destructor
     ///
@@ -298,6 +303,7 @@ public:
         }
         return (ndata_[pos]);
     }
+
     /// \brief Gets the length of the <code>Name</code> in its wire format.
     ///
     /// This method never throws an exception.

+ 1 - 0
src/lib/dns/tests/Makefile.am

@@ -19,6 +19,7 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES = unittest_util.h unittest_util.cc
 run_unittests_SOURCES += edns_unittest.cc
+run_unittests_SOURCES += labelsequence_unittest.cc
 run_unittests_SOURCES += messagerenderer_unittest.cc
 run_unittests_SOURCES += name_unittest.cc
 run_unittests_SOURCES += nsec3hash_unittest.cc

+ 253 - 0
src/lib/dns/tests/labelsequence_unittest.cc

@@ -0,0 +1,253 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/labelsequence.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::dns;
+
+class LabelSequenceTest : public ::testing::Test {
+public:
+    LabelSequenceTest() : n1("example.org"), n2("example.com"),
+                          n3("example.org"), n4("foo.bar.test.example"),
+                          n5("example.ORG"), n6("ExAmPlE.org"),
+                          n7("."), n8("foo.example.org.bar"),
+                          ls1(n1), ls2(n2), ls3(n3), ls4(n4), ls5(n5),
+                          ls6(n6), ls7(n7), ls8(n8)
+    {};
+    // Need to keep names in scope for at least the lifetime of
+    // the labelsequences
+    Name n1, n2, n3, n4, n5, n6, n7, n8;
+
+    LabelSequence ls1, ls2, ls3, ls4, ls5, ls6, ls7, ls8;
+};
+
+// Basic equality tests
+TEST_F(LabelSequenceTest, equals_sensitive) {
+    EXPECT_TRUE(ls1.equals(ls1));
+    EXPECT_FALSE(ls1.equals(ls2));
+    EXPECT_TRUE(ls1.equals(ls3));
+    EXPECT_FALSE(ls1.equals(ls4));
+    EXPECT_FALSE(ls1.equals(ls5));
+    EXPECT_FALSE(ls1.equals(ls6));
+    EXPECT_FALSE(ls1.equals(ls7));
+    EXPECT_FALSE(ls1.equals(ls8));
+
+    EXPECT_FALSE(ls2.equals(ls1));
+    EXPECT_TRUE(ls2.equals(ls2));
+    EXPECT_FALSE(ls2.equals(ls3));
+    EXPECT_FALSE(ls2.equals(ls4));
+    EXPECT_FALSE(ls2.equals(ls5));
+    EXPECT_FALSE(ls2.equals(ls6));
+    EXPECT_FALSE(ls2.equals(ls7));
+    EXPECT_FALSE(ls2.equals(ls8));
+
+    EXPECT_FALSE(ls4.equals(ls1));
+    EXPECT_FALSE(ls4.equals(ls2));
+    EXPECT_FALSE(ls4.equals(ls3));
+    EXPECT_TRUE(ls4.equals(ls4));
+    EXPECT_FALSE(ls4.equals(ls5));
+    EXPECT_FALSE(ls4.equals(ls6));
+    EXPECT_FALSE(ls4.equals(ls7));
+    EXPECT_FALSE(ls4.equals(ls8));
+
+    EXPECT_FALSE(ls5.equals(ls1));
+    EXPECT_FALSE(ls5.equals(ls2));
+    EXPECT_FALSE(ls5.equals(ls3));
+    EXPECT_FALSE(ls5.equals(ls4));
+    EXPECT_TRUE(ls5.equals(ls5));
+    EXPECT_FALSE(ls5.equals(ls6));
+    EXPECT_FALSE(ls5.equals(ls7));
+    EXPECT_FALSE(ls5.equals(ls8));
+}
+
+TEST_F(LabelSequenceTest, equals_insensitive) {
+    EXPECT_TRUE(ls1.equals(ls1, true));
+    EXPECT_FALSE(ls1.equals(ls2, true));
+    EXPECT_TRUE(ls1.equals(ls3, true));
+    EXPECT_FALSE(ls1.equals(ls4, true));
+    EXPECT_TRUE(ls1.equals(ls5, true));
+    EXPECT_TRUE(ls1.equals(ls6, true));
+    EXPECT_FALSE(ls1.equals(ls7, true));
+
+    EXPECT_FALSE(ls2.equals(ls1, true));
+    EXPECT_TRUE(ls2.equals(ls2, true));
+    EXPECT_FALSE(ls2.equals(ls3, true));
+    EXPECT_FALSE(ls2.equals(ls4, true));
+    EXPECT_FALSE(ls2.equals(ls5, true));
+    EXPECT_FALSE(ls2.equals(ls6, true));
+    EXPECT_FALSE(ls2.equals(ls7, true));
+
+    EXPECT_TRUE(ls3.equals(ls1, true));
+    EXPECT_FALSE(ls3.equals(ls2, true));
+    EXPECT_TRUE(ls3.equals(ls3, true));
+    EXPECT_FALSE(ls3.equals(ls4, true));
+    EXPECT_TRUE(ls3.equals(ls5, true));
+    EXPECT_TRUE(ls3.equals(ls6, true));
+    EXPECT_FALSE(ls3.equals(ls7, true));
+
+    EXPECT_FALSE(ls4.equals(ls1, true));
+    EXPECT_FALSE(ls4.equals(ls2, true));
+    EXPECT_FALSE(ls4.equals(ls3, true));
+    EXPECT_TRUE(ls4.equals(ls4, true));
+    EXPECT_FALSE(ls4.equals(ls5, true));
+    EXPECT_FALSE(ls4.equals(ls6, true));
+    EXPECT_FALSE(ls4.equals(ls7, true));
+
+    EXPECT_TRUE(ls5.equals(ls1, true));
+    EXPECT_FALSE(ls5.equals(ls2, true));
+    EXPECT_TRUE(ls5.equals(ls3, true));
+    EXPECT_FALSE(ls5.equals(ls4, true));
+    EXPECT_TRUE(ls5.equals(ls5, true));
+    EXPECT_TRUE(ls5.equals(ls6, true));
+    EXPECT_FALSE(ls5.equals(ls7, true));
+}
+
+void
+getDataCheck(const char* expected_data, size_t expected_len,
+             const LabelSequence& ls)
+{
+    size_t len;
+    const char* data = ls.getData(&len);
+    ASSERT_EQ(expected_len, len) << "Expected data: " << expected_data <<
+                                    " name: " << ls.getName().toText();
+    for (size_t i = 0; i < len; ++i) {
+        EXPECT_EQ(expected_data[i], data[i]) << "Difference at pos " << i <<
+                                                ": Expected data: " <<
+                                                expected_data <<
+                                                " name: " <<
+                                                ls.getName().toText();;
+    }
+}
+
+TEST_F(LabelSequenceTest, getData) {
+    getDataCheck("\007example\003org\000", 13, ls1);
+    getDataCheck("\007example\003com\000", 13, ls2);
+    getDataCheck("\007example\003org\000", 13, ls3);
+    getDataCheck("\003foo\003bar\004test\007example\000", 22, ls4);
+    getDataCheck("\007example\003ORG\000", 13, ls5);
+    getDataCheck("\007ExAmPlE\003org\000", 13, ls6);
+    getDataCheck("\000", 1, ls7);
+};
+
+TEST_F(LabelSequenceTest, stripLeft) {
+    EXPECT_TRUE(ls1.equals(ls3));
+    ls1.stripLeft(0);
+    getDataCheck("\007example\003org\000", 13, ls1);
+    EXPECT_TRUE(ls1.equals(ls3));
+    ls1.stripLeft(1);
+    getDataCheck("\003org\000", 5, ls1);
+    EXPECT_FALSE(ls1.equals(ls3));
+    ls1.stripLeft(1);
+    getDataCheck("\000", 1, ls1);
+    EXPECT_TRUE(ls1.equals(ls7));
+
+    ls2.stripLeft(2);
+    getDataCheck("\000", 1, ls2);
+    EXPECT_TRUE(ls2.equals(ls7));
+}
+
+TEST_F(LabelSequenceTest, stripRight) {
+    EXPECT_TRUE(ls1.equals(ls3));
+    ls1.stripRight(1);
+    getDataCheck("\007example\003org", 12, ls1);
+    EXPECT_FALSE(ls1.equals(ls3));
+    ls1.stripRight(1);
+    getDataCheck("\007example", 8, ls1);
+    EXPECT_FALSE(ls1.equals(ls3));
+
+    ASSERT_FALSE(ls1.equals(ls2));
+    ls2.stripRight(2);
+    getDataCheck("\007example", 8, ls2);
+    EXPECT_TRUE(ls1.equals(ls2));
+}
+
+TEST_F(LabelSequenceTest, stripOutOfRange) {
+    EXPECT_THROW(ls1.stripLeft(100), isc::OutOfRange);
+    EXPECT_THROW(ls1.stripLeft(5), isc::OutOfRange);
+    EXPECT_THROW(ls1.stripLeft(4), isc::OutOfRange);
+    EXPECT_THROW(ls1.stripLeft(3), isc::OutOfRange);
+    getDataCheck("\007example\003org\000", 13, ls1);
+
+    EXPECT_THROW(ls1.stripRight(100), isc::OutOfRange);
+    EXPECT_THROW(ls1.stripRight(5), isc::OutOfRange);
+    EXPECT_THROW(ls1.stripRight(4), isc::OutOfRange);
+    EXPECT_THROW(ls1.stripRight(3), isc::OutOfRange);
+    getDataCheck("\007example\003org\000", 13, ls1);
+}
+
+TEST_F(LabelSequenceTest, getLabelCount) {
+    EXPECT_EQ(3, ls1.getLabelCount());
+    ls1.stripLeft(0);
+    EXPECT_EQ(3, ls1.getLabelCount());
+    ls1.stripLeft(1);
+    EXPECT_EQ(2, ls1.getLabelCount());
+    ls1.stripLeft(1);
+    EXPECT_EQ(1, ls1.getLabelCount());
+
+    EXPECT_EQ(3, ls2.getLabelCount());
+    ls2.stripRight(1);
+    EXPECT_EQ(2, ls2.getLabelCount());
+    ls2.stripRight(1);
+    EXPECT_EQ(1, ls2.getLabelCount());
+
+    EXPECT_EQ(3, ls3.getLabelCount());
+    ls3.stripRight(2);
+    EXPECT_EQ(1, ls3.getLabelCount());
+
+    EXPECT_EQ(5, ls4.getLabelCount());
+    ls4.stripRight(3);
+    EXPECT_EQ(2, ls4.getLabelCount());
+
+    EXPECT_EQ(3, ls5.getLabelCount());
+    ls5.stripLeft(2);
+    EXPECT_EQ(1, ls5.getLabelCount());
+}
+
+TEST_F(LabelSequenceTest, comparePart) {
+    EXPECT_FALSE(ls1.equals(ls8));
+
+    // strip root label from example.org.
+    ls1.stripRight(1);
+    // strip foo from foo.example.org.bar.
+    ls8.stripLeft(1);
+    // strip bar. (i.e. bar and root) too
+    ls8.stripRight(2);
+
+    EXPECT_TRUE(ls1.equals(ls8));
+
+    // Data comparison
+    size_t len;
+    const char* data = ls1.getData(&len);
+    getDataCheck(data, len, ls8);
+}
+
+TEST_F(LabelSequenceTest, isAbsolute) {
+    ASSERT_TRUE(ls1.isAbsolute());
+
+    ls1.stripLeft(1);
+    ASSERT_TRUE(ls1.isAbsolute());
+    ls1.stripRight(1);
+    ASSERT_FALSE(ls1.isAbsolute());
+
+    ASSERT_TRUE(ls2.isAbsolute());
+    ls2.stripRight(1);
+    ASSERT_FALSE(ls2.isAbsolute());
+
+    ASSERT_TRUE(ls3.isAbsolute());
+    ls3.stripLeft(2);
+    ASSERT_TRUE(ls3.isAbsolute());
+}