Kea  2.3.3-git
option_data_types.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2021 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 
141 OptionDataTypeUtil::instance() {
142  static OptionDataTypeUtil instance;
143  return (instance);
144 }
145 
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 
193 std::string
194 OptionDataTypeUtil::readTuple(const std::vector<uint8_t>& buf,
195  OpaqueDataTuple::LengthFieldType lengthfieldtype) {
196  if (lengthfieldtype == OpaqueDataTuple::LENGTH_1_BYTE) {
197  if (buf.size() < 1) {
198  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
199  << " tuple (length). Invalid buffer size: "
200  << buf.size());
201  }
202  uint8_t len = buf[0];
203  if (buf.size() < 1 + len) {
204  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
205  << " tuple (length " << static_cast<unsigned>(len)
206  << "). Invalid buffer size: " << buf.size());
207  }
208  std::string value;
209  value.resize(len);
210  std::memcpy(&value[0], &buf[1], len);
211  return (value);
212  } else if (lengthfieldtype == OpaqueDataTuple::LENGTH_2_BYTES) {
213  if (buf.size() < 2) {
214  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
215  << " tuple (length). Invalid buffer size: "
216  << buf.size());
217  }
218  uint16_t len = isc::util::readUint16(&buf[0], 2);
219  if (buf.size() < 2 + len) {
220  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
221  << " tuple (length " << len
222  << "). Invalid buffer size: " << buf.size());
223  }
224  std::string value;
225  value.resize(len);
226  std::memcpy(&value[0], &buf[2], len);
227  return (value);
228  } else {
229  isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
230  << " tuple. Invalid length type field: "
231  << static_cast<unsigned>(lengthfieldtype));
232  }
233 }
234 
235 void
236 OptionDataTypeUtil::readTuple(const std::vector<uint8_t>& buf,
237  OpaqueDataTuple& tuple) {
238  try {
239  tuple.unpack(buf.begin(), buf.end());
240  } catch (const OpaqueDataTupleError& ex) {
242  }
243 }
244 
245 void
246 OptionDataTypeUtil::writeTuple(const std::string& value,
247  OpaqueDataTuple::LengthFieldType lengthfieldtype,
248  std::vector<uint8_t>& buf) {
249  if (lengthfieldtype == OpaqueDataTuple::LENGTH_1_BYTE) {
250  if (value.size() > std::numeric_limits<uint8_t>::max()) {
251  isc_throw(BadDataTypeCast, "invalid tuple value (size "
252  << value.size() << " larger than "
253  << +std::numeric_limits<uint8_t>::max() << ")");
254  }
255  buf.push_back(static_cast<uint8_t>(value.size()));
256 
257  } else if (lengthfieldtype == OpaqueDataTuple::LENGTH_2_BYTES) {
258  if (value.size() > std::numeric_limits<uint16_t>::max()) {
259  isc_throw(BadDataTypeCast, "invalid tuple value (size "
260  << value.size() << " larger than "
261  << std::numeric_limits<uint16_t>::max() << ")");
262  }
263  buf.resize(buf.size() + 2);
264  isc::util::writeUint16(static_cast<uint16_t>(value.size()),
265  &buf[buf.size() - 2], 2);
266  } else {
267  isc_throw(BadDataTypeCast, "unable to write data to the buffer as"
268  << " tuple. Invalid length type field: "
269  << static_cast<unsigned>(lengthfieldtype));
270  }
271  buf.insert(buf.end(), value.begin(), value.end());
272 }
273 
274 void
275 OptionDataTypeUtil::writeTuple(const OpaqueDataTuple& tuple,
276  std::vector<uint8_t>& buf) {
277  if (tuple.getLength() == 0) {
278  isc_throw(BadDataTypeCast, "invalid empty tuple value");
279  }
280  if (tuple.getLengthFieldType() == OpaqueDataTuple::LENGTH_1_BYTE) {
281  if (tuple.getLength() > std::numeric_limits<uint8_t>::max()) {
282  isc_throw(BadDataTypeCast, "invalid tuple value (size "
283  << tuple.getLength() << " larger than "
284  << +std::numeric_limits<uint8_t>::max() << ")");
285  }
286  buf.push_back(static_cast<uint8_t>(tuple.getLength()));
287 
288  } else if (tuple.getLengthFieldType() == OpaqueDataTuple::LENGTH_2_BYTES) {
289  if (tuple.getLength() > std::numeric_limits<uint16_t>::max()) {
290  isc_throw(BadDataTypeCast, "invalid tuple value (size "
291  << tuple.getLength() << " larger than "
292  << std::numeric_limits<uint16_t>::max() << ")");
293  }
294  buf.resize(buf.size() + 2);
295  isc::util::writeUint16(static_cast<uint16_t>(tuple.getLength()),
296  &buf[buf.size() - 2], 2);
297  } else {
298  isc_throw(BadDataTypeCast, "unable to write data to the buffer as"
299  << " tuple. Invalid length type field: "
300  << tuple.getLengthFieldType());
301  }
302  buf.insert(buf.end(), tuple.getData().begin(), tuple.getData().end());
303 }
304 
305 bool
306 OptionDataTypeUtil::readBool(const std::vector<uint8_t>& buf) {
307  if (buf.empty()) {
308  isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
309  << " value. Invalid buffer size " << buf.size());
310  }
311  if (buf[0] == 1) {
312  return (true);
313  } else if (buf[0] == 0) {
314  return (false);
315  }
316  isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
317  << " value. Invalid value " << static_cast<int>(buf[0]));
318 }
319 
320 void
321 OptionDataTypeUtil::writeBool(const bool value,
322  std::vector<uint8_t>& buf) {
323  buf.push_back(static_cast<uint8_t>(value ? 1 : 0));
324 }
325 
326 std::string
327 OptionDataTypeUtil::readFqdn(const std::vector<uint8_t>& buf) {
328  // If buffer is empty emit an error.
329  if (buf.empty()) {
330  isc_throw(BadDataTypeCast, "unable to read FQDN from a buffer."
331  << " The buffer is empty.");
332  }
333  // Set up an InputBuffer so as we can use isc::dns::Name object to get the FQDN.
334  isc::util::InputBuffer in_buf(static_cast<const void*>(&buf[0]), buf.size());
335  try {
336  // Try to create an object from the buffer. If exception is thrown
337  // it means that the buffer doesn't hold a valid domain name (invalid
338  // syntax).
339  isc::dns::Name name(in_buf);
340  return (name.toText());
341  } catch (const isc::Exception& ex) {
342  // Unable to convert the data in the buffer into FQDN.
344  }
345 }
346 
347 void
348 OptionDataTypeUtil::writeFqdn(const std::string& fqdn,
349  std::vector<uint8_t>& buf,
350  bool downcase) {
351  try {
352  isc::dns::Name name(fqdn, downcase);
353  isc::dns::LabelSequence labels(name);
354  if (labels.getDataLength() > 0) {
355  size_t read_len = 0;
356  const uint8_t* data = labels.getData(&read_len);
357  buf.insert(buf.end(), data, data + read_len);
358  }
359  } catch (const isc::Exception& ex) {
361  }
362 }
363 
364 unsigned int
365 OptionDataTypeUtil::getLabelCount(const std::string& text_name) {
366  // The isc::dns::Name class doesn't accept empty names. However, in some
367  // cases we may be dealing with empty names (e.g. sent by the DHCP clients).
368  // Empty names should not be sent as hostnames but if they are, for some
369  // reason, we don't want to throw an exception from this function. We
370  // rather want to signal empty name by returning 0 number of labels.
371  if (text_name.empty()) {
372  return (0);
373  }
374  try {
375  isc::dns::Name name(text_name);
376  return (name.getLabelCount());
377  } catch (const isc::Exception& ex) {
379  }
380 }
381 
383 OptionDataTypeUtil::readPrefix(const std::vector<uint8_t>& buf) {
384  // Prefix typically consists of the prefix length and the
385  // actual value. If prefix length is 0, the buffer length should
386  // be at least 1 byte to hold this length value.
387  if (buf.empty()) {
388  isc_throw(BadDataTypeCast, "unable to read prefix length from "
389  "a truncated buffer");
390  }
391 
392  // Surround everything with try-catch to unify exceptions being
393  // thrown by various functions and constructors.
394  try {
395  // Try to create PrefixLen object from the prefix length held
396  // in the buffer. This may cause an exception if the length is
397  // invalid (greater than 128).
398  PrefixLen prefix_len(buf.at(0));
399 
400  // Convert prefix length to bytes, because we operate on bytes,
401  // rather than bits.
402  uint8_t prefix_len_bytes = (prefix_len.asUint8() / 8);
403  // Check if we need to zero pad any bits. This is the case when
404  // the prefix length is not divisible by 8 (bits per byte). The
405  // calculations below may require some explanations. We first
406  // perform prefix_len % 8 to get the number of useful bits beyond
407  // the current prefix_len_bytes value. By substracting it from 8
408  // we get the number of zero padded bits, but with the special
409  // case of 8 when the result of substraction is 0. The value of
410  // 8 really means no padding so we make a modulo division once
411  // again to turn 8s to 0s.
412  const uint8_t zero_padded_bits =
413  static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8);
414  // If there are zero padded bits, it means that we need an extra
415  // byte to be retrieved from the buffer.
416  if (zero_padded_bits > 0) {
417  ++prefix_len_bytes;
418  }
419 
420  // Make sure that the buffer is long enough. We substract 1 to
421  // also account for the fact that the buffer includes a prefix
422  // length besides a prefix.
423  if ((buf.size() - 1) < prefix_len_bytes) {
424  isc_throw(BadDataTypeCast, "unable to read a prefix having length of "
425  << prefix_len.asUnsigned() << " from a truncated buffer");
426  }
427 
428  // It is possible for a prefix to be zero if the prefix length
429  // is zero.
431 
432  // If there is anything more than prefix length is this buffer
433  // we need to read it.
434  if (buf.size() > 1) {
435  // Buffer has to be copied, because we will modify its
436  // contents by setting certain bits to 0, if necessary.
437  std::vector<uint8_t> prefix_buf(buf.begin() + 1, buf.end());
438  // All further conversions require that the buffer length is
439  // 16 bytes.
440  if (prefix_buf.size() < V6ADDRESS_LEN) {
441  prefix_buf.resize(V6ADDRESS_LEN);
442  if (prefix_len_bytes < prefix_buf.size()) {
443  // Zero all bits in the buffer beyond prefix length
444  // position.
445  std::fill(prefix_buf.begin() + prefix_len_bytes,
446  prefix_buf.end(), 0);
447 
448  if (zero_padded_bits) {
449  // There is a byte that require zero padding. We
450  // achieve that by shifting the value of that byte
451  // back and forth by the number of zeroed bits.
452  prefix_buf.at(prefix_len_bytes - 1) =
453  (prefix_buf.at(prefix_len_bytes - 1)
454  >> zero_padded_bits)
455  << zero_padded_bits;
456  }
457  }
458  }
459  // Convert the buffer to the IOAddress object.
460  prefix = IOAddress::fromBytes(AF_INET6, &prefix_buf[0]);
461  }
462 
463  return (std::make_pair(prefix_len, prefix));
464 
465  } catch (const BadDataTypeCast& ex) {
466  // Pass through the BadDataTypeCast exceptions.
467  throw;
468 
469  } catch (const std::exception& ex) {
470  // If an exception of a different type has been thrown, insert
471  // a text that indicates that the failure occurred during reading
472  // the prefix and modify exception type to BadDataTypeCast.
473  isc_throw(BadDataTypeCast, "unable to read a prefix from a buffer: "
474  << ex.what());
475  }
476 }
477 
478 void
479 OptionDataTypeUtil::writePrefix(const PrefixLen& prefix_len,
480  const IOAddress& prefix,
481  std::vector<uint8_t>& buf) {
482  // Prefix must be an IPv6 prefix.
483  if (!prefix.isV6()) {
484  isc_throw(BadDataTypeCast, "illegal prefix value "
485  << prefix);
486  }
487 
488  // We don't need to validate the prefix_len value, because it is
489  // already validated by the PrefixLen class.
490  buf.push_back(prefix_len.asUint8());
491 
492  // Convert the prefix length to a number of bytes.
493  uint8_t prefix_len_bytes = prefix_len.asUint8() / 8;
494  // Check if there are any bits that require zero padding. See the
495  // commentary in readPrefix to see how this is calculated.
496  const uint8_t zero_padded_bits =
497  static_cast<uint8_t>((8 - (prefix_len.asUint8() % 8)) % 8);
498  // If zero padding is needed it means that we need to extend the
499  // buffer to hold the "partially occupied" byte.
500  if (zero_padded_bits > 0) {
501  ++prefix_len_bytes;
502  }
503 
504  // Convert the prefix to byte representation and append it to
505  // our output buffer.
506  std::vector<uint8_t> prefix_bytes = prefix.toBytes();
507  buf.insert(buf.end(), prefix_bytes.begin(),
508  prefix_bytes.begin() + prefix_len_bytes);
509  // If the last byte requires zero padding we achieve that by shifting
510  // bits back and forth by the number of insignificant bits.
511  if (zero_padded_bits) {
512  *buf.rbegin() = (*buf.rbegin() >> zero_padded_bits) << zero_padded_bits;
513  }
514 }
515 
516 PSIDTuple
517 OptionDataTypeUtil::readPsid(const std::vector<uint8_t>& buf) {
518  if (buf.size() < 3) {
519  isc_throw(BadDataTypeCast, "unable to read PSID from the buffer."
520  << " Invalid buffer size " << buf.size()
521  << ". Expected 3 bytes (PSID length and PSID value)");
522  }
523 
524  // Read PSID length.
525  uint8_t psid_len = buf[0];
526 
527  // PSID length must not be greater than 16 bits.
528  if (psid_len > (sizeof(uint16_t) * 8)) {
529  isc_throw(BadDataTypeCast, "invalid PSID length value "
530  << static_cast<unsigned>(psid_len)
531  << ", this value is expected to be in range of 0 to 16");
532  }
533 
534  // Read two bytes of PSID value.
535  uint16_t psid = isc::util::readUint16(&buf[1], 2);
536 
537  // We need to check that the PSID value does not exceed the maximum value
538  // for a specified PSID length. That means that all bits placed further than
539  // psid_len from the left must be set to 0.
540  // The value 0 is a special case because the RFC explicitly says that the
541  // PSID value should be ignored if psid_len is 0.
542  if ((psid & ~psid_bitmask[psid_len]) != 0) {
543  isc_throw(BadDataTypeCast, "invalid PSID value " << psid
544  << " for a specified PSID length "
545  << static_cast<unsigned>(psid_len));
546  }
547 
548  // All is good, so we can convert the PSID value read from the buffer to
549  // the port set number.
550  if (psid_len == 0) {
551  // Shift by 16 always gives zero (CID 1398333)
552  psid = 0;
553  } else {
554  psid >>= (sizeof(psid) * 8 - psid_len);
555  }
556  return (std::make_pair(PSIDLen(psid_len), PSID(psid)));
557 }
558 
559 void
560 OptionDataTypeUtil::writePsid(const PSIDLen& psid_len, const PSID& psid,
561  std::vector<uint8_t>& buf) {
562  if (psid_len.asUint8() > (sizeof(psid) * 8)) {
563  isc_throw(BadDataTypeCast, "invalid PSID length value "
564  << psid_len.asUnsigned()
565  << ", this value is expected to be in range of 0 to 16");
566  }
567 
568  if ((psid_len.asUint8() > 0) &&
569  (psid.asUint16() > (0xFFFF >> (sizeof(uint16_t) * 8 - psid_len.asUint8())))) {
570  isc_throw(BadDataTypeCast, "invalid PSID value " << psid.asUint16()
571  << " for a specified PSID length "
572  << psid_len.asUnsigned());
573  }
574 
575  buf.resize(buf.size() + 3);
576  buf.at(buf.size() - 3) = psid_len.asUint8();
577  isc::util::writeUint16(static_cast<uint16_t>
578  (psid.asUint16() << (sizeof(uint16_t) * 8 - psid_len.asUint8())),
579  &buf[buf.size() - 2], 2);
580 }
581 
582 std::string
583 OptionDataTypeUtil::readString(const std::vector<uint8_t>& buf) {
584  std::string value;
585  if (!buf.empty()) {
586  // Per RFC 2132, section 2 we need to drop trailing NULLs
587  auto begin = buf.begin();
588  auto end = util::str::seekTrimmed(begin, buf.end(), 0x0);
589  if (std::distance(begin, end) == 0) {
590  isc_throw(isc::OutOfRange, "string value carried by the option "
591  "contained only NULLs");
592  }
593 
594  value.insert(value.end(), begin, end);
595  }
596 
597  return (value);
598 }
599 
600 void
601 OptionDataTypeUtil::writeString(const std::string& value,
602  std::vector<uint8_t>& buf) {
603  if (value.size() > 0) {
604  buf.insert(buf.end(), value.begin(), value.end());
605  }
606 }
607 
608 } // end of isc::dhcp namespace
609 } // end of isc namespace
The Name class encapsulates DNS names.
Definition: name.h:223
Encapsulates PSID length.
Utility class for option data types.
std::pair< PrefixLen, asiolink::IOAddress > PrefixTuple
Defines a pair of prefix length / value.
unsigned int getLabelCount() const
Returns the number of labels contained in the Name.
Definition: name.h:370
uint16_t asUint16() const
Returns PSID value as a number.
size_t getDataLength() const
Return the length of the wire-format data of this LabelSequence.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void unpack(InputIterator begin, InputIterator end)
Parses wire data and creates a tuple from it.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
LengthFieldType getLengthFieldType() const
Returns tuple length data field type.
uint8_t asUint8() const
Returns prefix length as uint8_t value.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
OptionDataType
Data types of DHCP option fields.
uint8_t * writeUint16(uint16_t value, void *buffer, size_t length)
Write Unsigned 16-Bit Integer to Buffer.
Definition: io_utilities.h:55
Encapsulates PSID value.
const uint8_t * getData(size_t *len) const
Return the wire-format data for this LabelSequence.
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 (&#39;hex&#39;) format into the original data.
Definition: base_n.cc:474
uint8_t asUint8() const
Returns PSID length as uint8_t value.
std::string toText(bool omit_final_dot=false) const
Convert the Name to a string.
Definition: name.cc:507
LengthFieldType
Size of the length field in the tuple.
std::pair< PSIDLen, PSID > PSIDTuple
Defines a pair of PSID length / value.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-lfc.
uint16_t readUint16(const void *buffer, size_t length)
Read Unsigned 16-Bit Integer from Buffer.
Definition: io_utilities.h:28
const Buffer & getData() const
Returns a reference to the buffer holding tuple data.
Represents a single instance of the opaque data preceded by length.
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
size_t getLength() const
Returns the length of the data in the tuple.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Iterator seekTrimmed(Iterator begin, Iterator end, uint8_t trim_val)
Finds the "trimmed" end of a buffer.
Definition: strutil.h:73
Exception to be thrown when cast to the data type was unsuccessful.
unsigned int asUnsigned() const
Returns PSID length as unsigned int.
Encapsulates prefix length.
Light-weight Accessor to Name data.
Definition: labelsequence.h:35
Exception to be thrown when the operation on OpaqueDataTuple object results in an error...