summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/rrttl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dns/rrttl.cc')
-rw-r--r--src/lib/dns/rrttl.cc214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc
new file mode 100644
index 0000000..83877c7
--- /dev/null
+++ b/src/lib/dns/rrttl.cc
@@ -0,0 +1,214 @@
+// Copyright (C) 2010-2015 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/.
+
+#include <config.h>
+
+#include <stdint.h>
+
+#include <sstream>
+#include <ostream>
+
+#include <util/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrttl.h>
+
+#include <boost/lexical_cast.hpp>
+#include <algorithm>
+#include <cctype>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::util;
+
+namespace {
+
+// We wrap the C isalpha, because it seems to be overloaded with something.
+// Then the find_if doesn't work.
+bool
+myIsalpha(char c) {
+ return (isalpha(c) != 0);
+}
+
+// The conversion of units to their size
+struct Unit {
+ char unit;
+ uint32_t multiply;
+ uint32_t max_allowed;
+};
+
+Unit units[] = {
+ { 'S', 1, 0xffffffff / 1 },
+ { 'M', 60, 0xffffffff / 60 },
+ { 'H', 60 * 60, 0xffffffff / (60 * 60) },
+ { 'D', 24 * 60 * 60, 0xffffffff / (24 * 60 * 60) },
+ { 'W', 7 * 24 * 60 * 60, 0xffffffff / (7 * 24 * 60 * 60) }
+};
+
+}
+
+namespace isc {
+namespace dns {
+
+namespace {
+bool
+parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) {
+ if (ttlstr.empty()) {
+ if (error_txt != NULL) {
+ *error_txt = "Empty TTL string";
+ }
+ return (false);
+ }
+
+ // We use a larger data type to handle negative number cases.
+ uint64_t val = 0;
+ const string::const_iterator end = ttlstr.end();
+ string::const_iterator pos = ttlstr.begin();
+
+ try {
+ // When we detect we have some units
+ bool units_mode = false;
+
+ while (pos != end) {
+ // Find the first unit, if there's any.
+ const string::const_iterator unit = find_if(pos, end, myIsalpha);
+ // No unit
+ if (unit == end) {
+ if (units_mode) {
+ // We had some units before. The last one is missing unit.
+ if (error_txt != NULL) {
+ *error_txt = "Missing the last unit: " + ttlstr;
+ }
+ return (false);
+ } else {
+ // Case without any units at all. Just convert and store
+ // it.
+ val = boost::lexical_cast<uint64_t>(ttlstr);
+ break;
+ }
+ }
+ // There's a unit now.
+ units_mode = true;
+ // Find the unit and get the size.
+ uint32_t multiply = 1; // initialize to silence compiler warnings
+ uint32_t max_allowed = 0xffffffff;
+ bool found = false;
+ for (size_t i = 0; i < sizeof(units) / sizeof(*units); ++i) {
+ if (toupper(*unit) == units[i].unit) {
+ found = true;
+ multiply = units[i].multiply;
+ max_allowed = units[i].max_allowed;
+ break;
+ }
+ }
+ if (!found) {
+ if (error_txt != NULL) {
+ *error_txt = "Unknown unit used: " +
+ boost::lexical_cast<string>(*unit) + " in: " + ttlstr;
+ }
+ return (false);
+ }
+ // Now extract the number.
+ if (unit == pos) {
+ if (error_txt != NULL) {
+ *error_txt = "Missing number in TTL: " + ttlstr;
+ }
+ return (false);
+ }
+ const uint64_t value =
+ boost::lexical_cast<uint64_t>(string(pos, unit));
+ if (value > max_allowed) {
+ if (error_txt != NULL) {
+ *error_txt = "Part of TTL out of range: " + ttlstr;
+ }
+ return (false);
+ }
+
+ // seconds cannot be out of range at this point.
+ const uint64_t seconds = value * multiply;
+ assert(seconds <= 0xffffffff);
+
+ // Add what we found
+ val += seconds;
+ // Check the partial value is still in range (the value can only
+ // grow, so if we get out of range now, it won't get better, so
+ // there's no need to continue).
+ if (val < seconds || val > 0xffffffff) {
+ if (error_txt != NULL) {
+ *error_txt = "Part of TTL out of range: " + ttlstr;
+ }
+ return (false);
+ }
+ // Move to after the unit.
+ pos = unit + 1;
+ }
+ } catch (const boost::bad_lexical_cast&) {
+ if (error_txt != NULL) {
+ *error_txt = "invalid TTL: " + ttlstr;
+ }
+ return (false);
+ }
+
+ if (val <= 0xffffffff) {
+ ttlval = val;
+ } else {
+ // This could be due to negative numbers in input, etc.
+ if (error_txt != NULL) {
+ *error_txt = "TTL out of range: " + ttlstr;
+ }
+ return (false);
+ }
+
+ return (true);
+}
+}
+
+RRTTL::RRTTL(const std::string& ttlstr) {
+ string error_txt;
+ if (!parseTTLString(ttlstr, ttlval_, &error_txt)) {
+ isc_throw(InvalidRRTTL, error_txt);
+ }
+}
+
+RRTTL*
+RRTTL::createFromText(const string& ttlstr) {
+ uint32_t ttlval;
+ if (parseTTLString(ttlstr, ttlval, NULL)) {
+ return (new RRTTL(ttlval));
+ }
+ return (NULL);
+}
+
+RRTTL::RRTTL(InputBuffer& buffer) {
+ if (buffer.getLength() - buffer.getPosition() < sizeof(uint32_t)) {
+ isc_throw(IncompleteRRTTL, "incomplete wire-format TTL value");
+ }
+ ttlval_ = buffer.readUint32();
+}
+
+const string
+RRTTL::toText() const {
+ ostringstream oss;
+ oss << ttlval_;
+ return (oss.str());
+}
+
+void
+RRTTL::toWire(OutputBuffer& buffer) const {
+ buffer.writeUint32(ttlval_);
+}
+
+void
+RRTTL::toWire(AbstractMessageRenderer& renderer) const {
+ renderer.writeUint32(ttlval_);
+}
+
+ostream&
+operator<<(ostream& os, const RRTTL& rrttl) {
+ os << rrttl.toText();
+ return (os);
+}
+}
+}