Kea  2.1.7-git
rrttl.cc
Go to the documentation of this file.
1 // Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <stdint.h>
10 
11 #include <sstream>
12 #include <ostream>
13 
14 #include <util/buffer.h>
15 #include <dns/messagerenderer.h>
16 #include <dns/rrttl.h>
17 
18 #include <boost/lexical_cast.hpp>
19 #include <algorithm>
20 #include <cctype>
21 
22 using namespace std;
23 using namespace isc::dns;
24 using namespace isc::util;
25 
26 namespace {
27 
28 // We wrap the C isalpha, because it seems to be overloaded with something.
29 // Then the find_if doesn't work.
30 bool
31 myIsalpha(char c) {
32  return (isalpha(c) != 0);
33 }
34 
35 // The conversion of units to their size
36 struct Unit {
37  char unit;
38  uint32_t multiply;
39  uint32_t max_allowed;
40 };
41 
42 Unit units[] = {
43  { 'S', 1, 0xffffffff / 1 },
44  { 'M', 60, 0xffffffff / 60 },
45  { 'H', 60 * 60, 0xffffffff / (60 * 60) },
46  { 'D', 24 * 60 * 60, 0xffffffff / (24 * 60 * 60) },
47  { 'W', 7 * 24 * 60 * 60, 0xffffffff / (7 * 24 * 60 * 60) }
48 };
49 
50 }
51 
52 namespace isc {
53 namespace dns {
54 
55 namespace {
56 bool
57 parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) {
58  if (ttlstr.empty()) {
59  if (error_txt != NULL) {
60  *error_txt = "Empty TTL string";
61  }
62  return (false);
63  }
64 
65  // We use a larger data type to handle negative number cases.
66  uint64_t val = 0;
67  const string::const_iterator end = ttlstr.end();
68  string::const_iterator pos = ttlstr.begin();
69 
70  try {
71  // When we detect we have some units
72  bool units_mode = false;
73 
74  while (pos != end) {
75  // Find the first unit, if there's any.
76  const string::const_iterator unit = find_if(pos, end, myIsalpha);
77  // No unit
78  if (unit == end) {
79  if (units_mode) {
80  // We had some units before. The last one is missing unit.
81  if (error_txt != NULL) {
82  *error_txt = "Missing the last unit: " + ttlstr;
83  }
84  return (false);
85  } else {
86  // Case without any units at all. Just convert and store
87  // it.
88  val = boost::lexical_cast<uint64_t>(ttlstr);
89  break;
90  }
91  }
92  // There's a unit now.
93  units_mode = true;
94  // Find the unit and get the size.
95  uint32_t multiply = 1; // initialize to silence compiler warnings
96  uint32_t max_allowed = 0xffffffff;
97  bool found = false;
98  for (size_t i = 0; i < sizeof(units) / sizeof(*units); ++i) {
99  if (toupper(*unit) == units[i].unit) {
100  found = true;
101  multiply = units[i].multiply;
102  max_allowed = units[i].max_allowed;
103  break;
104  }
105  }
106  if (!found) {
107  if (error_txt != NULL) {
108  *error_txt = "Unknown unit used: " +
109  boost::lexical_cast<string>(*unit) + " in: " + ttlstr;
110  }
111  return (false);
112  }
113  // Now extract the number.
114  if (unit == pos) {
115  if (error_txt != NULL) {
116  *error_txt = "Missing number in TTL: " + ttlstr;
117  }
118  return (false);
119  }
120  const uint64_t value =
121  boost::lexical_cast<uint64_t>(string(pos, unit));
122  if (value > max_allowed) {
123  if (error_txt != NULL) {
124  *error_txt = "Part of TTL out of range: " + ttlstr;
125  }
126  return (false);
127  }
128 
129  // seconds cannot be out of range at this point.
130  const uint64_t seconds = value * multiply;
131  assert(seconds <= 0xffffffff);
132 
133  // Add what we found
134  val += seconds;
135  // Check the partial value is still in range (the value can only
136  // grow, so if we get out of range now, it won't get better, so
137  // there's no need to continue).
138  if (val < seconds || val > 0xffffffff) {
139  if (error_txt != NULL) {
140  *error_txt = "Part of TTL out of range: " + ttlstr;
141  }
142  return (false);
143  }
144  // Move to after the unit.
145  pos = unit + 1;
146  }
147  } catch (const boost::bad_lexical_cast&) {
148  if (error_txt != NULL) {
149  *error_txt = "invalid TTL: " + ttlstr;
150  }
151  return (false);
152  }
153 
154  if (val <= 0xffffffff) {
155  ttlval = val;
156  } else {
157  // This could be due to negative numbers in input, etc.
158  if (error_txt != NULL) {
159  *error_txt = "TTL out of range: " + ttlstr;
160  }
161  return (false);
162  }
163 
164  return (true);
165 }
166 }
167 
168 RRTTL::RRTTL(const std::string& ttlstr) {
169  string error_txt;
170  if (!parseTTLString(ttlstr, ttlval_, &error_txt)) {
171  isc_throw(InvalidRRTTL, error_txt);
172  }
173 }
174 
175 RRTTL*
176 RRTTL::createFromText(const string& ttlstr) {
177  uint32_t ttlval;
178  if (parseTTLString(ttlstr, ttlval, NULL)) {
179  return (new RRTTL(ttlval));
180  }
181  return (NULL);
182 }
183 
184 RRTTL::RRTTL(InputBuffer& buffer) {
185  if (buffer.getLength() - buffer.getPosition() < sizeof(uint32_t)) {
186  isc_throw(IncompleteRRTTL, "incomplete wire-format TTL value");
187  }
188  ttlval_ = buffer.readUint32();
189 }
190 
191 const string
192 RRTTL::toText() const {
193  ostringstream oss;
194  oss << ttlval_;
195  return (oss.str());
196 }
197 
198 void
199 RRTTL::toWire(OutputBuffer& buffer) const {
200  buffer.writeUint32(ttlval_);
201 }
202 
203 void
204 RRTTL::toWire(AbstractMessageRenderer& renderer) const {
205  renderer.writeUint32(ttlval_);
206 }
207 
208 ostream&
209 operator<<(ostream& os, const RRTTL& rrttl) {
210  os << rrttl.toText();
211  return (os);
212 }
213 }
214 }
size_t getPosition() const
Return the current read position.
Definition: buffer.h:102
STL namespace.
void writeUint32(uint32_t data)
Write an unsigned 32-bit integer in host byte order into the internal buffer in network byte order...
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:100
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: edns.h:19
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition: rrttl.h:55
ostream & operator<<(ostream &os, const RRTTL &rrttl)
Insert the RRTTL as a string into stream.
Definition: rrttl.cc:209
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
void writeUint32(uint32_t data)
Write an unsigned 32-bit integer in host byte order into the buffer in network byte order...
Definition: buffer.h:520
Defines the logger used by the top-level component of kea-lfc.
uint32_t readUint32()
Read an unsigned 32-bit integer in network byte order from the buffer, convert it to host byte order...
Definition: buffer.h:162
const std::string toText() const
Convert the RRTTL to a string.
Definition: rrttl.cc:192
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
A standard DNS module exception that is thrown if an RRTTL object is being constructed from an unreco...
Definition: rrttl.h:31
A standard DNS module exception that is thrown if an RRTTL object is being constructed from a incompl...
Definition: rrttl.h:41