Kea  2.3.7
option_data_types.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2023 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/labelsequence.h>
11 #include <dns/name.h>
12 #include <util/strutil.h>
13 #include <util/encode/hex.h>
14 #include <algorithm>
15 #include <limits>
16 
17 using namespace isc::asiolink;
18 
19 namespace {
25 std::vector<uint16_t> psid_bitmask = { 0xffff,
26  0x8000, 0xc000, 0xe000, 0xf000,
27  0xf800, 0xfc00, 0xfe00, 0xff00,
28  0xff80, 0xffc0, 0xffe0, 0xfff0,
29  0xfff8, 0xfffc, 0xfffe, 0xffff
30 };
31 }
32 
33 namespace isc {
34 namespace dhcp {
35 
36 OptionDataTypeUtil::OptionDataTypeUtil() {
37  data_types_["empty"] = OPT_EMPTY_TYPE;
38  data_types_["binary"] = OPT_BINARY_TYPE;
39  data_types_["boolean"] = OPT_BOOLEAN_TYPE;
40  data_types_["int8"] = OPT_INT8_TYPE;
41  data_types_["int16"] = OPT_INT16_TYPE;
42  data_types_["int32"] = OPT_INT32_TYPE;
43  data_types_["uint8"] = OPT_UINT8_TYPE;
44  data_types_["uint16"] = OPT_UINT16_TYPE;
45  data_types_["uint32"] = OPT_UINT32_TYPE;
46  data_types_["ipv4-address"] = OPT_IPV4_ADDRESS_TYPE;
47  data_types_["ipv6-address"] = OPT_IPV6_ADDRESS_TYPE;
48  data_types_["ipv6-prefix"] = OPT_IPV6_PREFIX_TYPE;
49  data_types_["psid"] = OPT_PSID_TYPE;
50  data_types_["string"] = OPT_STRING_TYPE;
51  data_types_["tuple"] = OPT_TUPLE_TYPE;
52  data_types_["fqdn"] = OPT_FQDN_TYPE;
53  data_types_["record"] = OPT_RECORD_TYPE;
54 
55  data_type_names_[OPT_EMPTY_TYPE] = "empty";
56  data_type_names_[OPT_BINARY_TYPE] = "binary";
57  data_type_names_[OPT_BOOLEAN_TYPE] = "boolean";
58  data_type_names_[OPT_INT8_TYPE] = "int8";
59  data_type_names_[OPT_INT16_TYPE] = "int16";
60  data_type_names_[OPT_INT32_TYPE] = "int32";
61  data_type_names_[OPT_UINT8_TYPE] = "uint8";
62  data_type_names_[OPT_UINT16_TYPE] = "uint16";
63  data_type_names_[OPT_UINT32_TYPE] = "uint32";
64  data_type_names_[OPT_IPV4_ADDRESS_TYPE] = "ipv4-address";
65  data_type_names_[OPT_IPV6_ADDRESS_TYPE] = "ipv6-address";
66  data_type_names_[OPT_IPV6_PREFIX_TYPE] = "ipv6-prefix";
67  data_type_names_[OPT_PSID_TYPE] = "psid";
68  data_type_names_[OPT_STRING_TYPE] = "string";
69  data_type_names_[OPT_TUPLE_TYPE] = "tuple";
70  data_type_names_[OPT_FQDN_TYPE] = "fqdn";
71  data_type_names_[OPT_RECORD_TYPE] = "record";
72  // The "unknown" data type is declared here so as
73  // it can be returned by reference by a getDataTypeName
74  // function it no other type is suitable. Other than that
75  // this is unused.
76  data_type_names_[OPT_UNKNOWN_TYPE] = "unknown";
77 }
78 
80 OptionDataTypeUtil::getDataType(const std::string& data_type) {
81  return (OptionDataTypeUtil::instance().getDataTypeImpl(data_type));
82 }
83 
85 OptionDataTypeUtil::getDataTypeImpl(const std::string& data_type) const {
86  std::map<std::string, OptionDataType>::const_iterator data_type_it =
87  data_types_.find(data_type);
88  if (data_type_it != data_types_.end()) {
89  return (data_type_it->second);
90  }
91  return (OPT_UNKNOWN_TYPE);
92 }
93 
94 int
95 OptionDataTypeUtil::getDataTypeLen(const OptionDataType data_type) {
96  switch (data_type) {
97  case OPT_BOOLEAN_TYPE:
98  case OPT_INT8_TYPE:
99  case OPT_UINT8_TYPE:
100  return (1);
101 
102  case OPT_INT16_TYPE:
103  case OPT_UINT16_TYPE:
104  return (2);
105 
106  case OPT_INT32_TYPE:
107  case OPT_UINT32_TYPE:
108  return (4);
109 
111  return (asiolink::V4ADDRESS_LEN);
112 
114  return (asiolink::V6ADDRESS_LEN);
115 
116  case OPT_PSID_TYPE:
117  return (3);
118 
119  default:
120  ;
121  }
122  return (0);
123 }
124 
125 const std::string&
126 OptionDataTypeUtil::getDataTypeName(const OptionDataType data_type) {
127  return (OptionDataTypeUtil::instance().getDataTypeNameImpl(data_type));
128 }
129 
130 const std::string&
131 OptionDataTypeUtil::getDataTypeNameImpl(const OptionDataType data_type) const {
132  std::map<OptionDataType, std::string>::const_iterator data_type_it =
133  data_type_names_.find(data_type);
134  if (data_type_it != data_type_names_.end()) {
135  return (data_type_it->second);
136  }
137  return (data_type_names_.find(OPT_UNKNOWN_TYPE)->second);
138 }
139 
140 OptionDataTypeUtil&
141 OptionDataTypeUtil::instance() {
142  static OptionDataTypeUtil instance;
143  return (instance);
144 }
145 
146 asiolink::IOAddress
147 OptionDataTypeUtil::readAddress(const std::vector<uint8_t>& buf,
148  const short family) {
149  using namespace isc::asiolink;
150  if (family == AF_INET) {
151  if (buf.size() < V4ADDRESS_LEN) {
152  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
153  << " IPv4 address. Invalid buffer size: " << buf.size());
154  }
155  return (IOAddress::fromBytes(AF_INET, &buf[0]));
156  } else if (family == AF_INET6) {
157  if (buf.size() < V6ADDRESS_LEN) {
158  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
159  << " IPv6 address. Invalid buffer size: " << buf.size());
160  }
161  return (IOAddress::fromBytes(AF_INET6, &buf[0]));
162  } else {
163  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
164  << " IP address. Invalid family: " << family);
165  }
166 }
167 
168 void
169 OptionDataTypeUtil::writeAddress(const asiolink::IOAddress& address,
170  std::vector<uint8_t>& buf) {
171  const std::vector<uint8_t>& vec = address.toBytes();
172  buf.insert(buf.end(), vec.begin(), vec.end());
173 }
174 
175 void
176 OptionDataTypeUtil::writeBinary(const std::string& hex_str,
177  std::vector<uint8_t>& buf) {
178  // Binary value means that the value is encoded as a string
179  // of hexadecimal digits. We need to decode this string
180  // to the binary format here.
181  OptionBuffer binary;
182  try {
183  util::encode::decodeHex(hex_str, binary);
184  } catch (const Exception& ex) {
185  isc_throw(BadDataTypeCast, "unable to cast " << hex_str
186  << " to binary data type: " << ex.what());
187  }
188  // Decode was successful so append decoded binary value
189  // to the buffer.
190  buf.insert(buf.end(), binary.begin(), binary.end());
191 }
192 
194 OptionDataTypeUtil::getTupleLenFieldType(Option::Universe u) {
195  if (u == Option::V4) {
196  return (OpaqueDataTuple::LENGTH_1_BYTE);
197  }
198  return (OpaqueDataTuple::LENGTH_2_BYTES);
199 }
200 
201 std::string
202 OptionDataTypeUtil::readTuple(const std::vector<uint8_t>& buf,
203  OpaqueDataTuple::LengthFieldType lengthfieldtype) {
204  if (lengthfieldtype == OpaqueDataTuple::LENGTH_1_BYTE) {
205  if (buf.size() < 1) {
206  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
207  << " tuple (length). Invalid buffer size: "
208  << buf.size());
209  }
210  uint8_t len = buf[0];
211  if (buf.size() < 1 + len) {
212  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
213  << " tuple (length " << static_cast<unsigned>(len)
214  << "). Invalid buffer size: " << buf.size());
215  }
216  std::string value;
217  value.resize(len);
218  std::memcpy(&value[0], &buf[1], len);
219  return (value);
220  } else if (lengthfieldtype == OpaqueDataTuple::LENGTH_2_BYTES) {
221  if (buf.size() < 2) {
222  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
223  << " tuple (length). Invalid buffer size: "
224  << buf.size());
225  }
226  uint16_t len = isc::util::readUint16(&buf[0], 2);
227  if (buf.size() < 2 + len) {
228  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
229  << " tuple (length " << len
230  << "). Invalid buffer size: " << buf.size());
231  }
232  std::string value;
233  value.resize(len);
234  std::memcpy(&value[0], &buf[2], len);
235  return (value);
236  } else {
237  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
238  << " tuple. Invalid length type field: "
239  << static_cast<unsigned>(lengthfieldtype));
240  }
241 }
242 
243 void
244 OptionDataTypeUtil::readTuple(const std::vector<uint8_t>& buf,
245  OpaqueDataTuple& tuple) {
246  try {
247  tuple.unpack(buf.begin(), buf.end());
248  } catch (const OpaqueDataTupleError& ex) {
250  }
251 }
252 
253 void
254 OptionDataTypeUtil::writeTuple(const std::string& value,
255  OpaqueDataTuple::LengthFieldType lengthfieldtype,
256  std::vector<uint8_t>& buf) {
257  if (lengthfieldtype == OpaqueDataTuple::LENGTH_1_BYTE) {
258  if (value.size() > std::numeric_limits<uint8_t>::max()) {
259  isc_throw(BadDataTypeCast, "invalid tuple value (size "
260  << value.size() << " larger than "
261  << +std::numeric_limits<uint8_t>::max() << ")");
262  }
263  buf.push_back(static_cast<uint8_t>(value.size()));
264 
265  } else if (lengthfieldtype == OpaqueDataTuple::LENGTH_2_BYTES) {
266  if (value.size() > std::numeric_limits<uint16_t>::max()) {
267  isc_throw(BadDataTypeCast, "invalid tuple value (size "
268  << value.size() << " larger than "
269  << std::numeric_limits<uint16_t>::max() << ")");
270  }
271  buf.resize(buf.size() + 2);
272  isc::util::writeUint16(static_cast<uint16_t>(value.size()),
273  &buf[buf.size() - 2], 2);
274  } else {
275  isc_throw(BadDataTypeCast, "unable to write data to the buffer as"
276  << " tuple. Invalid length type field: "
277  << static_cast<unsigned>(lengthfieldtype));
278  }
279  buf.insert(buf.end(), value.begin(), value.end());
280 }
281 
282 void
283 OptionDataTypeUtil::writeTuple(const OpaqueDataTuple& tuple,
284  std::vector<uint8_t>& buf) {
285  if (tuple.getLength() == 0) {
286  isc_throw(BadDataTypeCast, "invalid empty tuple value");
287  }
288  if (tuple.getLengthFieldType() == OpaqueDataTuple::LENGTH_1_BYTE) {
289  if (tuple.getLength() > std::numeric_limits<uint8_t>::max()) {
290  isc_throw(BadDataTypeCast, "invalid tuple value (size "
291  << tuple.getLength() << " larger than "
292  << +std::numeric_limits<uint8_t>::max() << ")");
293  }
294  buf.push_back(static_cast<uint8_t>(tuple.getLength()));
295 
296  } else if (tuple.getLengthFieldType() == OpaqueDataTuple::LENGTH_2_BYTES) {
297  if (tuple.getLength() > std::numeric_limits<uint16_t>::max()) {
298  isc_throw(BadDataTypeCast, "invalid tuple value (size "
299  << tuple.getLength() << " larger than "
300  << std::numeric_limits<uint16_t>::max() << ")");
301  }
302  buf.resize(buf.size() + 2);
303  isc::util::writeUint16(static_cast<uint16_t>(tuple.getLength()),
304  &buf[buf.size() - 2], 2);
305  } else {
306  isc_throw(BadDataTypeCast, "unable to write data to the buffer as"
307  << " tuple. Invalid length type field: "
308  << tuple.getLengthFieldType());
309  }
310  buf.insert(buf.end(), tuple.getData().begin(), tuple.getData().end());
311 }
312 
313 bool
314 OptionDataTypeUtil::readBool(const std::vector<uint8_t>& buf) {
315  if (buf.empty()) {
316  isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
317  << " value. Invalid buffer size " << buf.size());
318  }
319  if (buf[0] == 1) {
320  return (true);
321  } else if (buf[0] == 0) {
322  return (false);
323  }
324  isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
325  << " value. Invalid value " << static_cast<int>(buf[0]));
326 }
327 
328 void
329 OptionDataTypeUtil::writeBool(const bool value,
330  std::vector<uint8_t>& buf) {
331  buf.push_back(static_cast<uint8_t>(value ? 1 : 0));
332 }
333 
334 std::string
335 OptionDataTypeUtil::readFqdn(const std::vector<uint8_t>& buf) {
336  // If buffer is empty emit an error.
337  if (buf.empty()) {
338  isc_throw(BadDataTypeCast, "unable to read FQDN from a buffer."
339  << " The buffer is empty.");
340  }
341  // Set up an InputBuffer so as we can use isc::dns::Name object to get the FQDN.
342  isc::util::InputBuffer in_buf(static_cast<const void*>(&buf[0]), buf.size());
343  try {
344  // Try to create an object from the buffer. If exception is thrown
345  // it means that the buffer doesn't hold a valid domain name (invalid
346  // syntax).
347  isc::dns::Name name(in_buf);
348  return (name.toText());
349  } catch (const isc::Exception& ex) {
350  // Unable to convert the data in the buffer into FQDN.
352  }
353 }
354 
355 void
356 OptionDataTypeUtil::writeFqdn(const std::string& fqdn,
357  std::vector<uint8_t>& buf,
358  bool downcase) {
359  try {
360  isc::dns::Name name(fqdn, downcase);
361  isc::dns::LabelSequence labels(name);
362  if (labels.getDataLength() > 0) {
363  size_t read_len = 0;
364  const uint8_t* data = labels.getData(&read_len);
365  buf.insert(buf.end(), data, data + read_len);
366  }
367  } catch (const isc::Exception& ex) {
369  }
370 }
371 
372 unsigned int
373 OptionDataTypeUtil::getLabelCount(const std::string& text_name) {
374  // The isc::dns::Name class doesn't accept empty names. However, in some
375  // cases we may be dealing with empty names (e.g. sent by the DHCP clients).
376  // Empty names should not be sent as hostnames but if they are, for some
377  // reason, we don't want to throw an exception from this function. We
378  // rather want to signal empty name by returning 0 number of labels.
379  if (text_name.empty()) {
380  return (0);
381  }
382  try {
383  isc::dns::Name name(text_name);
384  return (name.getLabelCount());
385  } catch (const isc::Exception& ex) {
387  }
388 }
389 
391 OptionDataTypeUtil::readPrefix(const std::vector<uint8_t>& buf) {
392  // Prefix typically consists of the prefix length and the
393  // actual value. If prefix length is 0, the buffer length should
394  // be at least 1 byte to hold this length value.
395  if (buf.empty()) {
396  isc_throw(BadDataTypeCast, "unable to read prefix length from "
397  "a truncated buffer");
398  }
399 
400  // Surround everything with try-catch to unify exceptions being
401  // thrown by various functions and constructors.
402  try {
403  // Try to create PrefixLen object from the prefix length held
404  // in the buffer. This may cause an exception if the length is
405  // invalid (greater than 128).
406  PrefixLen prefix_len(buf.at(0));
407 
408  // Convert prefix length to bytes, because we operate on bytes,
409  // rather than bits.
410  uint8_t prefix_len_bytes = (prefix_len.asUint8() / 8);
411  // Check if we need to zero pad any bits. This is the case when
412  // the prefix length is not divisible by 8 (bits per byte). The
413  // calculations below may require some explanations. We first
414  // perform prefix_len % 8 to get the number of useful bits beyond
415  // the current prefix_len_bytes value. By substracting it from 8
416  // we get the number of zero padded bits, but with the special
417  // case of 8 when the result of substraction is 0. The value of
418  // 8 really means no padding so we make a modulo division once
419  // again to turn 8s to 0s.
420  const uint8_t zero_padded_bits =
421  static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8);
422  // If there are zero padded bits, it means that we need an extra
423  // byte to be retrieved from the buffer.
424  if (zero_padded_bits > 0) {
425  ++prefix_len_bytes;
426  }
427 
428  // Make sure that the buffer is long enough. We substract 1 to
429  // also account for the fact that the buffer includes a prefix
430  // length besides a prefix.
431  if ((buf.size() - 1) < prefix_len_bytes) {
432  isc_throw(BadDataTypeCast, "unable to read a prefix having length of "
433  << prefix_len.asUnsigned() << " from a truncated buffer");
434  }
435 
436  // It is possible for a prefix to be zero if the prefix length
437  // is zero.
439 
440  // If there is anything more than prefix length is this buffer
441  // we need to read it.
442  if (buf.size() > 1) {
443  // Buffer has to be copied, because we will modify its
444  // contents by setting certain bits to 0, if necessary.
445  std::vector<uint8_t> prefix_buf(buf.begin() + 1, buf.end());
446  // All further conversions require that the buffer length is
447  // 16 bytes.
448  if (prefix_buf.size() < V6ADDRESS_LEN) {
449  prefix_buf.resize(V6ADDRESS_LEN);
450  if (prefix_len_bytes < prefix_buf.size()) {
451  // Zero all bits in the buffer beyond prefix length
452  // position.
453  std::fill(prefix_buf.begin() + prefix_len_bytes,
454  prefix_buf.end(), 0);
455 
456  if (zero_padded_bits) {
457  // There is a byte that require zero padding. We
458  // achieve that by shifting the value of that byte
459  // back and forth by the number of zeroed bits.
460  prefix_buf.at(prefix_len_bytes - 1) =
461  (prefix_buf.at(prefix_len_bytes - 1)
462  >> zero_padded_bits)
463  << zero_padded_bits;
464  }
465  }
466  }
467  // Convert the buffer to the IOAddress object.
468  prefix = IOAddress::fromBytes(AF_INET6, &prefix_buf[0]);
469  }
470 
471  return (std::make_pair(prefix_len, prefix));
472 
473  } catch (const BadDataTypeCast& ex) {
474  // Pass through the BadDataTypeCast exceptions.
475  throw;
476 
477  } catch (const std::exception& ex) {
478  // If an exception of a different type has been thrown, insert
479  // a text that indicates that the failure occurred during reading
480  // the prefix and modify exception type to BadDataTypeCast.
481  isc_throw(BadDataTypeCast, "unable to read a prefix from a buffer: "
482  << ex.what());
483  }
484 }
485 
486 void
487 OptionDataTypeUtil::writePrefix(const PrefixLen& prefix_len,
488  const IOAddress& prefix,
489  std::vector<uint8_t>& buf) {
490  // Prefix must be an IPv6 prefix.
491  if (!prefix.isV6()) {
492  isc_throw(BadDataTypeCast, "illegal prefix value "
493  << prefix);
494  }
495 
496  // We don't need to validate the prefix_len value, because it is
497  // already validated by the PrefixLen class.
498  buf.push_back(prefix_len.asUint8());
499 
500  // Convert the prefix length to a number of bytes.
501  uint8_t prefix_len_bytes = prefix_len.asUint8() / 8;
502  // Check if there are any bits that require zero padding. See the
503  // commentary in readPrefix to see how this is calculated.
504  const uint8_t zero_padded_bits =
505  static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8);
506  // If zero padding is needed it means that we need to extend the
507  // buffer to hold the "partially occupied" byte.
508  if (zero_padded_bits > 0) {
509  ++prefix_len_bytes;
510  }
511 
512  // Convert the prefix to byte representation and append it to
513  // our output buffer.
514  std::vector<uint8_t> prefix_bytes = prefix.toBytes();
515  buf.insert(buf.end(), prefix_bytes.begin(),
516  prefix_bytes.begin() + prefix_len_bytes);
517  // If the last byte requires zero padding we achieve that by shifting
518  // bits back and forth by the number of insignificant bits.
519  if (zero_padded_bits) {
520  *buf.rbegin() = (*buf.rbegin() >> zero_padded_bits) << zero_padded_bits;
521  }
522 }
523 
524 PSIDTuple
525 OptionDataTypeUtil::readPsid(const std::vector<uint8_t>& buf) {
526  if (buf.size() < 3) {
527  isc_throw(BadDataTypeCast, "unable to read PSID from the buffer."
528  << " Invalid buffer size " << buf.size()
529  << ". Expected 3 bytes (PSID length and PSID value)");
530  }
531 
532  // Read PSID length.
533  uint8_t psid_len = buf[0];
534 
535  // PSID length must not be greater than 16 bits.
536  if (psid_len > (sizeof(uint16_t) * 8)) {
537  isc_throw(BadDataTypeCast, "invalid PSID length value "
538  << static_cast<unsigned>(psid_len)
539  << ", this value is expected to be in range of 0 to 16");
540  }
541 
542  // Read two bytes of PSID value.
543  uint16_t psid = isc::util::readUint16(&buf[1], 2);
544 
545  // We need to check that the PSID value does not exceed the maximum value
546  // for a specified PSID length. That means that all bits placed further than
547  // psid_len from the left must be set to 0.
548  // The value 0 is a special case because the RFC explicitly says that the
549  // PSID value should be ignored if psid_len is 0.
550  if ((psid & ~psid_bitmask[psid_len]) != 0) {
551  isc_throw(BadDataTypeCast, "invalid PSID value " << psid
552  << " for a specified PSID length "
553  << static_cast<unsigned>(psid_len));
554  }
555 
556  // All is good, so we can convert the PSID value read from the buffer to
557  // the port set number.
558  if (psid_len == 0) {
559  // Shift by 16 always gives zero (CID 1398333)
560  psid = 0;
561  } else {
562  psid >>= (sizeof(psid) * 8 - psid_len);
563  }
564  return (std::make_pair(PSIDLen(psid_len), PSID(psid)));
565 }
566 
567 void
568 OptionDataTypeUtil::writePsid(const PSIDLen& psid_len, const PSID& psid,
569  std::vector<uint8_t>& buf) {
570  if (psid_len.asUint8() > (sizeof(psid) * 8)) {
571  isc_throw(BadDataTypeCast, "invalid PSID length value "
572  << psid_len.asUnsigned()
573  << ", this value is expected to be in range of 0 to 16");
574  }
575 
576  if ((psid_len.asUint8() > 0) &&
577  (psid.asUint16() > (0xFFFF >> (sizeof(uint16_t) * 8 - psid_len.asUint8())))) {
578  isc_throw(BadDataTypeCast, "invalid PSID value " << psid.asUint16()
579  << " for a specified PSID length "
580  << psid_len.asUnsigned());
581  }
582 
583  buf.resize(buf.size() + 3);
584  buf.at(buf.size() - 3) = psid_len.asUint8();
585  isc::util::writeUint16(static_cast<uint16_t>
586  (psid.asUint16() << (sizeof(uint16_t) * 8 - psid_len.asUint8())),
587  &buf[buf.size() - 2], 2);
588 }
589 
590 std::string
591 OptionDataTypeUtil::readString(const std::vector<uint8_t>& buf) {
592  std::string value;
593  if (!buf.empty()) {
594  // Per RFC 2132, section 2 we need to drop trailing NULLs
595  auto begin = buf.begin();
596  auto end = util::str::seekTrimmed(begin, buf.end(), 0x0);
597  if (std::distance(begin, end) == 0) {
598  isc_throw(isc::OutOfRange, "string value carried by the option "
599  "contained only NULLs");
600  }
601 
602  value.insert(value.end(), begin, end);
603  }
604 
605  return (value);
606 }
607 
608 void
609 OptionDataTypeUtil::writeString(const std::string& value,
610  std::vector<uint8_t>& buf) {
611  if (value.size() > 0) {
612  buf.insert(buf.end(), value.begin(), value.end());
613  }
614 }
615 
616 } // end of isc::dhcp namespace
617 } // end of isc namespace
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Exception to be thrown when cast to the data type was unsuccessful.
Exception to be thrown when the operation on OpaqueDataTuple object results in an error.
Represents a single instance of the opaque data preceded by length.
LengthFieldType
Size of the length field in the tuple.
const Buffer & getData() const
Returns a reference to the buffer holding tuple data.
LengthFieldType getLengthFieldType() const
Returns tuple length data field type.
void unpack(InputIterator begin, InputIterator end)
Parses wire data and creates a tuple from it.
size_t getLength() const
Returns the length of the data in the tuple.
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
Encapsulates PSID length.
uint8_t asUint8() const
Returns PSID length as uint8_t value.
unsigned int asUnsigned() const
Returns PSID length as unsigned int.
Encapsulates PSID value.
uint16_t asUint16() const
Returns PSID value as a number.
Encapsulates prefix length.
unsigned int asUnsigned() const
Returns prefix length as unsigned int.
uint8_t asUint8() const
Returns prefix length as uint8_t value.
Light-weight Accessor to Name data.
Definition: labelsequence.h:35
const uint8_t * getData(size_t *len) const
Return the wire-format data for this LabelSequence.
size_t getDataLength() const
Return the length of the wire-format data of this LabelSequence.
The Name class encapsulates DNS names.
Definition: name.h:223
std::string toText(bool omit_final_dot=false) const
Convert the Name to a string.
Definition: name.cc:507
unsigned int getLabelCount() const
Returns the number of labels contained in the Name.
Definition: name.h:370
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::pair< PSIDLen, PSID > PSIDTuple
Defines a pair of PSID length / value.
OptionDataType
Data types of DHCP option fields.
std::pair< PrefixLen, asiolink::IOAddress > PrefixTuple
Defines a pair of prefix length / value.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 ('hex') format into the original data.
Definition: base_n.cc:488
Iterator seekTrimmed(Iterator begin, Iterator end, uint8_t trim_val)
Finds the "trimmed" end of a buffer.
Definition: strutil.h:73
uint8_t * writeUint16(uint16_t value, void *buffer, size_t length)
Write Unsigned 16-Bit Integer to Buffer.
Definition: io_utilities.h:55
uint16_t readUint16(const void *buffer, size_t length)
Read Unsigned 16-Bit Integer from Buffer.
Definition: io_utilities.h:28
Defines the logger used by the top-level component of kea-lfc.