Kea 2.5.8
char_string.cc
Go to the documentation of this file.
1// Copyright (C) 2012-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
11#include <dns/exceptions.h>
12#include <dns/rdata.h>
13#include <dns/master_lexer.h>
14#include <dns/char_string.h>
15#include <util/buffer.h>
16
17#include <boost/lexical_cast.hpp>
18
19#include <cctype>
20#include <cstring>
21#include <vector>
22
23#include <stdint.h>
24
25namespace isc {
26namespace dns {
27namespace rdata {
28namespace generic {
29namespace detail {
30
31namespace {
32// Convert a DDD form to the corresponding integer
33int
34decimalToNumber(const char* s, const char* s_end) {
35 if (s_end - s < 3) {
36 isc_throw(InvalidRdataText, "Escaped digits too short");
37 }
38
39 const std::string num_str(s, s + 3);
40 try {
41 const int i = boost::lexical_cast<int>(num_str);
42 if (i > 255) {
43 isc_throw(InvalidRdataText, "Escaped digits too large: "
44 << num_str);
45 }
46 return (i);
47 } catch (const boost::bad_lexical_cast&) {
49 "Invalid form for escaped digits: " << num_str);
50 }
51}
52}
53
54void
56 CharString& result) {
57 // make a space for the 1-byte length field; filled in at the end
58 result.push_back(0);
59
60 bool escape = false;
61 const char* s = str_region.beg;
62 const char* const s_end = str_region.beg + str_region.len;
63
64 for (size_t n = str_region.len; n != 0; --n, ++s) {
65 int c = (*s & 0xff);
66 if (escape && std::isdigit(c) != 0) {
67 c = decimalToNumber(s, s_end);
68 // decimalToNumber() already throws if (s_end - s) is less
69 // than 3. 'n' is an unsigned type (size_t) and can underflow.
70 // 'n' and 's' are also updated by 1 in the for statement's
71 // expression, so we update them by 2 instead of 3 here.
72 n -= 2;
73 s += 2;
74 } else if (!escape && c == '\\') {
75 escape = true;
76 continue;
77 }
78 escape = false;
79 result.push_back(c);
80 }
81 if (escape) { // terminated by non-escaped '\'
82 isc_throw(InvalidRdataText, "character-string ends with '\\'");
83 }
84 if (result.size() > MAX_CHARSTRING_LEN + 1) { // '+ 1' due to the len field
85 isc_throw(CharStringTooLong, "character-string is too long: " <<
86 (result.size() - 1) << "(+1) characters");
87 }
88 result[0] = result.size() - 1;
89}
90
91void
93 CharStringData& result) {
94 bool escape = false;
95 const char* s = str_region.beg;
96 const char* const s_end = str_region.beg + str_region.len;
97
98 for (size_t n = str_region.len; n != 0; --n, ++s) {
99 int c = (*s & 0xff);
100 if (escape && std::isdigit(c) != 0) {
101 c = decimalToNumber(s, s_end);
102 // decimalToNumber() already throws if (s_end - s) is less
103 // than 3. 'n' is an unsigned type (size_t) and can underflow.
104 // 'n' and 's' are also updated by 1 in the for statement's
105 // expression, so we update them by 2 instead of 3 here.
106 n -= 2;
107 s += 2;
108 } else if (!escape && c == '\\') {
109 escape = true;
110 continue;
111 }
112 escape = false;
113 result.push_back(c);
114 }
115 if (escape) { // terminated by non-escaped '\'
116 isc_throw(InvalidRdataText, "character-string ends with '\\'");
117 }
118}
119
120std::string
121charStringToString(const CharString& char_string) {
122 std::string s;
123 bool first = true;
124 for (auto const& it : char_string) {
125 if (first) {
126 first = false;
127 continue;
128 }
129 const uint8_t ch = it;
130 if ((ch < 0x20) || (ch >= 0x7f)) {
131 // convert to escaped \xxx (decimal) format
132 s.push_back('\\');
133 s.push_back('0' + ((ch / 100) % 10));
134 s.push_back('0' + ((ch / 10) % 10));
135 s.push_back('0' + (ch % 10));
136 continue;
137 }
138 if ((ch == '"') || (ch == ';') || (ch == '\\')) {
139 s.push_back('\\');
140 }
141 s.push_back(ch);
142 }
143
144 return (s);
145}
146
147std::string
149 std::string s;
150 for (auto const& it : char_string) {
151 const uint8_t ch = it;
152 if ((ch < 0x20) || (ch >= 0x7f)) {
153 // convert to escaped \xxx (decimal) format
154 s.push_back('\\');
155 s.push_back('0' + ((ch / 100) % 10));
156 s.push_back('0' + ((ch / 10) % 10));
157 s.push_back('0' + (ch % 10));
158 continue;
159 }
160 if ((ch == '"') || (ch == ';') || (ch == '\\')) {
161 s.push_back('\\');
162 }
163 s.push_back(ch);
164 }
165
166 return (s);
167}
168
170 const detail::CharString& other) {
171 if (self.size() == 0 && other.size() == 0) {
172 return (0);
173 }
174 if (self.size() == 0) {
175 return (-1);
176 }
177 if (other.size() == 0) {
178 return (1);
179 }
180 const size_t self_len = self[0];
181 const size_t other_len = other[0];
182 const size_t cmp_len = std::min(self_len, other_len);
183 if (cmp_len == 0) {
184 if (self_len < other_len) {
185 return (-1);
186 } else if (self_len > other_len) {
187 return (1);
188 } else {
189 return (0);
190 }
191 }
192 const int cmp = std::memcmp(&self[1], &other[1], cmp_len);
193 if (cmp < 0) {
194 return (-1);
195 } else if (cmp > 0) {
196 return (1);
197 } else if (self_len < other_len) {
198 return (-1);
199 } else if (self_len > other_len) {
200 return (1);
201 } else {
202 return (0);
203 }
204}
205
207 const detail::CharStringData& other) {
208 if (self.size() == 0 && other.size() == 0) {
209 return (0);
210 }
211 if (self.size() == 0) {
212 return (-1);
213 }
214 if (other.size() == 0) {
215 return (1);
216 }
217 const size_t self_len = self.size();
218 const size_t other_len = other.size();
219 const size_t cmp_len = std::min(self_len, other_len);
220 const int cmp = std::memcmp(&self[0], &other[0], cmp_len);
221 if (cmp < 0) {
222 return (-1);
223 } else if (cmp > 0) {
224 return (1);
225 } else if (self_len < other_len) {
226 return (-1);
227 } else if (self_len > other_len) {
228 return (1);
229 } else {
230 return (0);
231 }
232}
233
234size_t
236 CharString& target) {
237 if (rdata_len < 1 || buffer.getLength() - buffer.getPosition() < 1) {
239 "insufficient data to read character-string length");
240 }
241 const uint8_t len = buffer.readUint8();
242 if (rdata_len < len + 1) {
244 "character string length is too large: " <<
245 static_cast<int>(len));
246 }
247 if (buffer.getLength() - buffer.getPosition() < len) {
249 "not enough data in buffer to read character-string of len"
250 << static_cast<int>(len));
251 }
252
253 target.resize(len + 1);
254 target[0] = len;
255 buffer.readData(&target[0] + 1, len);
256
257 return (len + 1);
258}
259
260} // end of detail
261} // end of generic
262} // end of rdata
263} // end of dns
264} // end of isc
A standard DNS module exception that is thrown if RDATA parser encounters a character-string (as defi...
Definition: rdata.h:55
A standard DNS module exception that is thrown if RDATA parser fails to recognize a given textual rep...
Definition: rdata.h:44
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
size_t getPosition() const
Return the current read position.
Definition: buffer.h:101
uint8_t readUint8()
Read an unsigned 8-bit integer from the buffer and return it.
Definition: buffer.h:138
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:96
void readData(void *data, size_t len)
Read data of the specified length from the buffer and copy it to the caller supplied buffer.
Definition: buffer.h:226
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::string charStringToString(const CharString &char_string)
Convert a CharString into a textual DNS character-string.
Definition: char_string.cc:121
int compareCharStrings(const detail::CharString &self, const detail::CharString &other)
Compare two CharString objects.
Definition: char_string.cc:169
int compareCharStringDatas(const detail::CharStringData &self, const detail::CharStringData &other)
Compare two CharStringData objects.
Definition: char_string.cc:206
void stringToCharString(const MasterToken::StringRegion &str_region, CharString &result)
Convert a DNS character-string into corresponding binary data.
Definition: char_string.cc:55
std::vector< uint8_t > CharStringData
Type for DNS character string without the length prefix.
Definition: char_string.h:30
void stringToCharStringData(const MasterToken::StringRegion &str_region, CharStringData &result)
Convert a DNS character-string into corresponding binary data.
Definition: char_string.cc:92
size_t bufferToCharString(isc::util::InputBuffer &buffer, size_t rdata_len, CharString &target)
Convert a buffer containing a character-string to CharString.
Definition: char_string.cc:235
std::string charStringDataToString(const CharStringData &char_string)
Convert a CharStringData into a textual DNS character-string.
Definition: char_string.cc:148
std::vector< uint8_t > CharString
Type for DNS character string.
Definition: char_string.h:27
const unsigned int MAX_CHARSTRING_LEN
The maximum allowable length of character-string containing in RDATA as defined in RFC1035,...
Definition: rdata.h:77
Defines the logger used by the top-level component of kea-lfc.
A simple representation of a range of a string.
Definition: master_lexer.h:96
size_t len
The length of the string in bytes.
Definition: master_lexer.h:98
const char * beg
The start address of the string.
Definition: master_lexer.h:97