Kea 2.7.0
rrttl.cc
Go to the documentation of this file.
1// Copyright (C) 2010-2024 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
10#include <dns/messagerenderer.h>
11#include <dns/rrttl.h>
12#include <util/buffer.h>
13
14#include <algorithm>
15#include <cctype>
16#include <stdint.h>
17#include <sstream>
18#include <ostream>
19
20#include <boost/lexical_cast.hpp>
21
22using namespace std;
23using namespace isc::dns;
24using namespace isc::util;
25
26namespace {
27
28// We wrap the C isalpha, because it seems to be overloaded with something.
29// Then the find_if doesn't work.
30bool
31myIsalpha(char c) {
32 return (isalpha(c) != 0);
33}
34
35// The conversion of units to their size
36struct Unit {
37 char unit;
38 uint32_t multiply;
39 uint32_t max_allowed;
40};
41
42Unit 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
52namespace isc {
53namespace dns {
54
55namespace {
56bool
57parseTTLString(const string& ttlstr, uint32_t& ttlval, string* error_txt) {
58 if (ttlstr.empty()) {
59 if (error_txt) {
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) {
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) {
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) {
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) {
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 isc_throw_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) {
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) {
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) {
159 *error_txt = "TTL out of range: " + ttlstr;
160 }
161 return (false);
162 }
163
164 return (true);
165}
166}
167
168RRTTL::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
175RRTTL*
176RRTTL::createFromText(const string& ttlstr) {
177 uint32_t ttlval;
178 if (parseTTLString(ttlstr, ttlval, 0)) {
179 return (new RRTTL(ttlval));
180 }
181 return (0);
182}
183
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
191const string
193 ostringstream oss;
194 oss << ttlval_;
195 return (oss.str());
196}
197
198void
200 buffer.writeUint32(ttlval_);
201}
202
203void
205 renderer.writeUint32(ttlval_);
206}
207
208ostream&
209operator<<(ostream& os, const RRTTL& rrttl) {
210 os << rrttl.toText();
211 return (os);
212}
213}
214}
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
A standard DNS module exception that is thrown if an RRTTL object is being constructed from a incompl...
Definition rrttl.h:37
A standard DNS module exception that is thrown if an RRTTL object is being constructed from an unreco...
Definition rrttl.h:27
The RRTTL class encapsulates TTLs used in DNS resource records.
Definition rrttl.h:51
void toWire(AbstractMessageRenderer &renderer) const
Render the RRTTL in the wire format.
Definition rrttl.cc:204
static RRTTL * createFromText(const std::string &ttlstr)
A separate factory of RRTTL from text.
Definition rrttl.cc:176
RRTTL(uint32_t ttlval)
Constructor from an integer TTL value.
Definition rrttl.h:64
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
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:343
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition isc_assert.h:18
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
Definition edns.cc:163
Defines the logger used by the top-level component of kea-lfc.