Kea: option_data_types.cc Source File

| Kea 3.0.3-git

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