Browse Source

[2430] Support nibble mode with $GENERATE

Mukund Sivaraman 11 years ago
parent
commit
79c9b75382
2 changed files with 58 additions and 5 deletions
  1. 39 5
      src/lib/dns/master_loader.cc
  2. 19 0
      src/lib/dns/tests/master_loader_unittest.cc

+ 39 - 5
src/lib/dns/master_loader.cc

@@ -444,6 +444,39 @@ public:
     size_t rr_count_;    // number of RRs successfully loaded
 };
 
+namespace { // begin unnamed namespace
+
+std::string
+genNibbles(int i, unsigned int width, bool uppercase) {
+    static const char *hex = "0123456789abcdef0123456789ABCDEF";
+    std::string rstr;
+
+    do {
+        char ch = hex[(i & 0x0f) + (uppercase ? 16 : 0)];
+        i >>= 4;
+        rstr.push_back(ch);
+
+        if (width > 0) {
+            --width;
+        }
+
+        // If width is non zero then we need to add a label seperator.
+        // If value is non zero then we need to add another label and
+        // that requires a label seperator.
+        if (width > 0 || i != 0) {
+            rstr.push_back('.');
+
+            if (width > 0) {
+                --width;
+            }
+        }
+    } while ((i != 0) || (width > 0));
+
+    return (rstr);
+}
+
+} // end unnamed namespace
+
 std::string
 MasterLoader::MasterLoaderImpl::generateForIter(const std::string& str,
                                                 const int i)
@@ -484,8 +517,7 @@ MasterLoader::MasterLoaderImpl::generateForIter(const std::string& str,
 
               case 3:
                   if ((mode[0] == 'n') || (mode[0] == 'N')) {
-                      // TODO: Handle nibble mode
-                      assert(true);
+                      rstr += genNibbles(i + delta, width, (mode[0] == 'N'));
                   } else {
                       const std::string fmt =
                           boost::str(boost::format("%%0%u%c") % width % mode[0]);
@@ -592,9 +624,11 @@ MasterLoader::MasterLoaderImpl::doGenerate() {
             return;
         }
 
-        const size_t name_length = generated_name.size();
-        last_name_.reset(new Name(generated_name.c_str(), name_length,
-                                  &active_origin_));
+        // generateForIter() can return a string with a trailing '.' in
+        // case of a nibble representation. So we cannot use the
+        // relative Name constructor.
+        last_name_.reset
+            (new Name(Name(generated_name).concatenate(active_origin_)));
         previous_name_ = true;
 
         const rdata::RdataPtr rdata =

+ 19 - 0
src/lib/dns/tests/master_loader_unittest.cc

@@ -514,6 +514,15 @@ TEST_F(MasterLoaderTest, generateWithModifiers) {
         // case.
         "$GENERATE 42-43 host$ TXT \"Value ${0,4,X}\"\n"
         "$GENERATE 45-46 host${0,4,o} A 192.0.2.$\n"
+        // Here, the LHS has a trailing dot (which would result in an
+        // out-of-zone name), but that should be handled as a relative
+        // name.
+        "$GENERATE 90-92 ${0,8,n} A 192.0.2.$\n"
+        // Here, the LHS has no trailing dot, and results in the same
+        // number of labels as width=8 above.
+        "$GENERATE 94-96 ${0,7,n} A 192.0.2.$\n"
+        // Uppercase nibble
+        "$GENERATE 98-98 ${0,10,n} A 192.0.2.$\n"
         // Junk type will not parse and 'd' is assumed.
         "$GENERATE 100-101 host${0,4,j} A 192.0.2.$\n";
     stringstream ss(input);
@@ -545,6 +554,16 @@ TEST_F(MasterLoaderTest, generateWithModifiers) {
     checkRR("host0055.example.org", RRType::A(), "192.0.2.45");
     checkRR("host0056.example.org", RRType::A(), "192.0.2.46");
 
+    checkRR("a.5.0.0.example.org", RRType::A(), "192.0.2.90");
+    checkRR("b.5.0.0.example.org", RRType::A(), "192.0.2.91");
+    checkRR("c.5.0.0.example.org", RRType::A(), "192.0.2.92");
+
+    checkRR("e.5.0.0.example.org", RRType::A(), "192.0.2.94");
+    checkRR("f.5.0.0.example.org", RRType::A(), "192.0.2.95");
+    checkRR("0.6.0.0.example.org", RRType::A(), "192.0.2.96");
+
+    checkRR("2.6.0.0.0.example.org", RRType::A(), "192.0.2.98");
+
     checkRR("host0100.example.org", RRType::A(), "192.0.2.100");
     checkRR("host0101.example.org", RRType::A(), "192.0.2.101");
 }