Kea 3.3.1
option_custom.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2026 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#include <dhcp/libdhcp++.h>
10#include <dhcp/option_custom.h>
12#include <util/str.h>
13#include <util/encode/encode.h>
14
15using namespace isc::asiolink;
16using namespace isc::util;
17
18namespace isc {
19namespace dhcp {
20
22 Universe u)
23 : Option(u, def.getCode(), OptionBuffer()),
24 definition_(def) {
26 createBuffers();
27}
28
30 Universe u,
31 const OptionBuffer& data)
32 : Option(u, def.getCode(), data.begin(), data.end()),
33 definition_(def) {
35 createBuffers(getData());
36}
37
39 Universe u,
42 size_t rec_level)
43 : Option(u, def.getCode(), first, last),
44 definition_(def) {
46 createBuffers(getData(), rec_level);
47}
48
53
54void
56 checkArrayType();
57
58 if ((address.isV4() && definition_.getType() != OPT_IPV4_ADDRESS_TYPE) ||
59 (address.isV6() && definition_.getType() != OPT_IPV6_ADDRESS_TYPE)) {
60 isc_throw(BadDataTypeCast, "invalid address specified "
61 << address << ". Expected a valid IPv"
62 << (definition_.getType() == OPT_IPV4_ADDRESS_TYPE ?
63 "4" : "6") << " address.");
64 }
65
66 OptionBuffer buf;
68 buffers_.push_back(buf);
69}
70
71void
72OptionCustom::addArrayDataField(const std::string& value) {
73 checkArrayType();
74
76 OptionBuffer buf;
77 OptionDataTypeUtil::writeTuple(value, lft, buf);
78 buffers_.push_back(buf);
79}
80
81void
83 checkArrayType();
84
85 OptionBuffer buf;
87 buffers_.push_back(buf);
88}
89
90void
92 checkArrayType();
93
94 OptionBuffer buf;
96 buffers_.push_back(buf);
97}
98
99void
101 const asiolink::IOAddress& prefix) {
102 checkArrayType();
103
104 if (definition_.getType() != OPT_IPV6_PREFIX_TYPE) {
105 isc_throw(BadDataTypeCast, "IPv6 prefix can be specified only for"
106 " an option comprising an array of IPv6 prefix values");
107 }
108
109 OptionBuffer buf;
110 OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
111 buffers_.push_back(buf);
112}
113
114void
115OptionCustom::addArrayDataField(const PSIDLen& psid_len, const PSID& psid) {
116 checkArrayType();
117
118 if (definition_.getType() != OPT_PSID_TYPE) {
119 isc_throw(BadDataTypeCast, "PSID value can be specified onlu for"
120 " an option comprising an array of PSID length / value"
121 " tuples");
122 }
123
124 OptionBuffer buf;
125 OptionDataTypeUtil::writePsid(psid_len, psid, buf);
126 buffers_.push_back(buf);
127}
128
129void
130OptionCustom::checkIndex(const uint32_t index) const {
131 if (index >= buffers_.size()) {
132 isc_throw(isc::OutOfRange, "specified data field index " << index
133 << " is out of range.");
134 }
135}
136
137void
138OptionCustom::createBuffer(OptionBuffer& buffer,
139 const OptionDataType data_type) const {
140 // For data types that have a fixed size we can use the
141 // utility function to get the buffer's size.
142 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
143
144 // For variable data sizes the utility function returns zero.
145 // It is ok for string values because the default string
146 // is 'empty'. However for FQDN the empty value is not valid
147 // so we initialize it to '.'. For prefix there is a prefix
148 // length fixed field.
149 if (data_size == 0) {
150 if (data_type == OPT_FQDN_TYPE) {
152
153 } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
156 buffer);
157 }
158 } else {
159 // At this point we can resize the buffer. Note that
160 // for string values we are setting the empty buffer
161 // here.
162 buffer.resize(data_size);
163 }
164}
165
166void
167OptionCustom::createBuffers() {
168 definition_.validate();
169
170 std::vector<OptionBuffer> buffers;
171
172 OptionDataType data_type = definition_.getType();
173 // This function is called when an empty data buffer has been
174 // passed to the constructor. In such cases values for particular
175 // data fields will be set using modifier functions but for now
176 // we need to initialize a set of buffers that are specified
177 // for an option by its definition. Since there is no data yet,
178 // we are going to fill these buffers with default values.
179 if (data_type == OPT_RECORD_TYPE) {
180 // For record types we need to iterate over all data fields
181 // specified in option definition and create corresponding
182 // buffers for each of them.
184 definition_.getRecordFields();
185
186 for (auto const& field : fields) {
187 OptionBuffer buf;
188 createBuffer(buf, field);
189 // We have the buffer with default value prepared so we
190 // add it to the set of buffers.
191 buffers.push_back(buf);
192 }
193 } else if (!definition_.getArrayType() &&
194 data_type != OPT_EMPTY_TYPE) {
195 // For either 'empty' options we don't have to create any buffers
196 // for obvious reason. For arrays we also don't create any buffers
197 // yet because the set of fields that belong to the array is open
198 // ended so we can't allocate required buffers until we know how
199 // many of them are needed.
200 // For non-arrays we have a single value being held by the option
201 // so we have to allocate exactly one buffer.
202 OptionBuffer buf;
203 createBuffer(buf, data_type);
204 // Add a buffer that we have created and leave.
205 buffers.push_back(buf);
206 }
207 // The 'swap' is used here because we want to make sure that we
208 // don't touch buffers_ until we successfully allocate all
209 // buffers to be stored there.
210 std::swap(buffers, buffers_);
211}
212
213size_t
214OptionCustom::bufferLength(const OptionDataType data_type, bool in_array,
215 OptionBuffer::const_iterator begin,
216 OptionBuffer::const_iterator end) const {
217 // For fixed-size data type such as boolean, integer, even
218 // IP address we can use the utility function to get the required
219 // buffer size.
220 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
221
222 // For variable size types (e.g. string) the function above will
223 // return 0 so we need to do a runtime check of the length.
224 if (data_size == 0) {
225 // FQDN is a special data type as it stores variable length data
226 // but the data length is encoded in the buffer. The easiest way
227 // to obtain the length of the data is to read the FQDN. The
228 // utility function will return the size of the buffer on success.
229 if (data_type == OPT_FQDN_TYPE) {
230 try {
231 // Set the raw optional flag as we do not want escapes.
232 std::string fqdn =
234 OptionBuffer(begin, end), true);
235 // The size of the buffer holding an FQDN is always
236 // 1 byte larger than the size of the string
237 // representation of this FQDN.
238 data_size = fqdn.size() + 1;
239 } catch (const std::exception& ex) {
241 isc_throw(SkipThisOptionError, "failed to read "
242 "domain-name from wire format: "
243 << ex.what());
244 }
245
246 throw;
247 }
248 } else if (!definition_.getArrayType() &&
249 ((data_type == OPT_BINARY_TYPE) ||
250 (data_type == OPT_STRING_TYPE))) {
251 // In other case we are dealing with string or binary value
252 // which size can't be determined. Thus we consume the
253 // remaining part of the buffer for it. Note that variable
254 // size data can be laid at the end of the option only and
255 // that the validate() function in OptionDefinition object
256 // should have checked wheter it is a case for this option.
257 data_size = std::distance(begin, end);
258 } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
259 // The size of the IPV6 prefix type is determined as
260 // one byte (which is the size of the prefix in bits)
261 // followed by the prefix bits (right-padded with
262 // zeros to the nearest octet boundary)
263 if ((begin == end) && !in_array)
264 return 0;
265 PrefixTuple prefix =
267 // Data size comprises 1 byte holding a prefix length and the
268 // prefix length (in bytes) rounded to the nearest byte boundary.
269 data_size = sizeof(uint8_t) + (prefix.first.asUint8() + 7) / 8;
270 } else if (data_type == OPT_TUPLE_TYPE) {
273 std::string value =
275 data_size = value.size();
276 // The size of the buffer holding a tuple is always
277 // 1 or 2 byte larger than the size of the string
278 data_size += getUniverse() == Option::V4 ? 1 : 2;
279 } else {
280 // If we reached the end of buffer we assume that this option is
281 // truncated because there is no remaining data to initialize
282 // an option field.
283 isc_throw(OutOfRange, "option buffer truncated");
284 }
285 }
286
287 return data_size;
288}
289
290void
291OptionCustom::createBuffers(const OptionBuffer& data_buf, size_t rec_level) {
292 // Check that the option definition is correct as we are going
293 // to use it to split the data_ buffer into set of sub buffers.
294 definition_.validate();
295
296 std::vector<OptionBuffer> buffers;
297 OptionBuffer::const_iterator data = data_buf.begin();
298
299 OptionDataType data_type = definition_.getType();
300 if (data_type == OPT_RECORD_TYPE) {
301 // An option comprises a record of data fields. We need to
302 // get types of these data fields to allocate enough space
303 // for each buffer.
305 definition_.getRecordFields();
306
307 // Go over all data fields within a record.
308 for (auto const& field : fields) {
309 size_t data_size = bufferLength(field, false,
310 data, data_buf.end());
311
312 // Our data field requires that there is a certain chunk of
313 // data left in the buffer. If not, option is truncated.
314 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
315 isc_throw(OutOfRange, "option buffer truncated");
316 }
317
318 // Store the created buffer.
319 buffers.push_back(OptionBuffer(data, data + data_size));
320 // Proceed to the next data field.
321 data += data_size;
322 }
323
324 // Get extra buffers when the last field is an array.
325 if (definition_.getArrayType()) {
326 while (data != data_buf.end()) {
327 // Code copied from the standard array case
328 size_t data_size = bufferLength(fields.back(), true,
329 data, data_buf.end());
330 isc_throw_assert(data_size > 0);
331 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
332 break;
333 }
334 buffers.push_back(OptionBuffer(data, data + data_size));
335 data += data_size;
336 }
337 }
338
339 // Unpack suboptions if any.
340 else if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
341 unpackOptions(OptionBuffer(data, data_buf.end()), rec_level);
342 }
343
344 } else if (data_type != OPT_EMPTY_TYPE) {
345 // If data_type value is other than OPT_RECORD_TYPE, our option is
346 // empty (have no data at all) or it comprises one or more
347 // data fields of the same type. The type of those fields
348 // is held in the data_type variable so let's use it to determine
349 // a size of buffers.
350 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
351 // The check below will fail if the input buffer is too short
352 // for the data size being held by this option.
353 // Note that data_size returned by getDataTypeLen may be zero
354 // if variable length data is being held by the option but
355 // this will not cause this check to throw exception.
356 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
357 isc_throw(OutOfRange, "option buffer truncated");
358 }
359 // For an array of values we are taking different path because
360 // we have to handle multiple buffers.
361 if (definition_.getArrayType()) {
362 while (data != data_buf.end()) {
363 data_size = bufferLength(data_type, true, data, data_buf.end());
364 // We don't perform other checks for data types that can't be
365 // used together with array indicator such as strings, empty field
366 // etc. This is because OptionDefinition::validate function should
367 // have checked this already. Thus data_size must be greater than
368 // zero.
369 isc_throw_assert(data_size > 0);
370 // Get chunks of data and store as a collection of buffers.
371 // Truncate any remaining part which length is not divisible by
372 // data_size. Note that it is ok to truncate the data if and only
373 // if the data buffer is long enough to keep at least one value.
374 // This has been checked above already.
375 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
376 break;
377 }
378 buffers.push_back(OptionBuffer(data, data + data_size));
379 data += data_size;
380 }
381 } else {
382 // For non-arrays the data_size can be zero because
383 // getDataTypeLen returns zero for variable size data types
384 // such as strings. Simply take whole buffer.
385 data_size = bufferLength(data_type, false, data, data_buf.end());
386 if ((data_size > 0) &&
387 (static_cast<size_t>(std::distance(data, data_buf.end())) >= data_size)) {
388 buffers.push_back(OptionBuffer(data, data + data_size));
389 data += data_size;
390 } else {
391 isc_throw(OutOfRange, "option buffer truncated");
392 }
393
394 // Unpack suboptions if any.
395 if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
396 unpackOptions(OptionBuffer(data, data_buf.end()), rec_level);
397 }
398 }
399 } else {
400 // Unpack suboptions if any.
401 if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
402 unpackOptions(OptionBuffer(data, data_buf.end()), rec_level);
403 }
404 }
405 // If everything went ok we can replace old buffer set with new ones.
406 std::swap(buffers_, buffers);
407}
408
409std::string
410OptionCustom::dataFieldToText(const OptionDataType data_type,
411 const uint32_t index) const {
412 std::ostringstream text;
413
414 // Get the value of the data field.
415 switch (data_type) {
416 case OPT_BINARY_TYPE:
417 {
418 auto data = readBinary(index);
419 if (data.empty()) {
420 text << "''";
421 } else {
422 text << util::encode::encodeHex(data);
423 if (str::isPrintable(data)) {
424 std::string printable(data.cbegin(), data.cend());
425 text << " '" << printable << "'";
426 }
427 }
428 break;
429 }
430 case OPT_BOOLEAN_TYPE:
431 text << (readBoolean(index) ? "true" : "false");
432 break;
433 case OPT_INT8_TYPE:
434 text << static_cast<int>(readInteger<int8_t>(index));
435 break;
436 case OPT_INT16_TYPE:
437 text << readInteger<int16_t>(index);
438 break;
439 case OPT_INT32_TYPE:
440 text << readInteger<int32_t>(index);
441 break;
442 case OPT_UINT8_TYPE:
443 text << static_cast<unsigned>(readInteger<uint8_t>(index));
444 break;
445 case OPT_UINT16_TYPE:
446 text << readInteger<uint16_t>(index);
447 break;
448 case OPT_UINT32_TYPE:
449 text << readInteger<uint32_t>(index);
450 break;
453 text << readAddress(index);
454 break;
455 case OPT_FQDN_TYPE:
456 text << "\"" << readFqdn(index) << "\"";
457 break;
458 case OPT_TUPLE_TYPE:
459 text << "\"" << readTuple(index) << "\"";
460 break;
461 case OPT_STRING_TYPE:
462 text << "\"" << readString(index) << "\"";
463 break;
464 case OPT_PSID_TYPE:
465 {
466 PSIDTuple t = readPsid(index);
467 text << "len=" << t.first.asUnsigned() << ",psid=" << t.second.asUint16();
468 break;
469 }
470 default:
471 break;
472 }
473
474 // Append data field type in brackets.
475 text << " (" << OptionDataTypeUtil::getDataTypeName(data_type) << ")";
476
477 return (text.str());
478}
479
480void
482
483 // Pack DHCP header (V4 or V6).
484 packHeader(buf, check);
485
486 // Write data from buffers.
487 for (auto const& it : buffers_) {
488 // In theory the createBuffers function should have taken
489 // care that there are no empty buffers added to the
490 // collection but it is almost always good to make sure.
491 if (!it.empty()) {
492 buf.writeData(&it[0], it.size());
493 }
494 }
495
496 // Write suboptions.
497 packOptions(buf, check);
498}
499
500
502OptionCustom::readAddress(const uint32_t index) const {
503 checkIndex(index);
504
505 // The address being read can be either IPv4 or IPv6. The decision
506 // is made based on the buffer length. If it holds 4 bytes it is IPv4
507 // address, if it holds 16 bytes it is IPv6.
508 if (buffers_[index].size() == asiolink::V4ADDRESS_LEN) {
509 return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET));
510 } else if (buffers_[index].size() == asiolink::V6ADDRESS_LEN) {
511 return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET6));
512 } else {
513 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
514 << " IP address. Invalid buffer length "
515 << buffers_[index].size() << ".");
516 }
517}
518
519void
521 const uint32_t index) {
522 checkIndex(index);
523
524 if ((address.isV4() && buffers_[index].size() != V4ADDRESS_LEN) ||
525 (address.isV6() && buffers_[index].size() != V6ADDRESS_LEN)) {
526 isc_throw(BadDataTypeCast, "invalid address specified "
527 << address << ". Expected a valid IPv"
528 << (buffers_[index].size() == V4ADDRESS_LEN ? "4" : "6")
529 << " address.");
530 }
531
532 OptionBuffer buf;
534 std::swap(buf, buffers_[index]);
535}
536
537const OptionBuffer&
538OptionCustom::readBinary(const uint32_t index) const {
539 checkIndex(index);
540 return (buffers_[index]);
541}
542
543void
545 const uint32_t index) {
546 checkIndex(index);
547 buffers_[index] = buf;
548}
549
550std::string
551OptionCustom::readTuple(const uint32_t index) const {
552 checkIndex(index);
554 return (OptionDataTypeUtil::readTuple(buffers_[index], lft));
555}
556
557void
559 const uint32_t index) const {
560 checkIndex(index);
561 OptionDataTypeUtil::readTuple(buffers_[index], tuple);
562}
563
564void
565OptionCustom::writeTuple(const std::string& value, const uint32_t index) {
566 checkIndex(index);
567
568 buffers_[index].clear();
570 OptionDataTypeUtil::writeTuple(value, lft, buffers_[index]);
571}
572
573void
574OptionCustom::writeTuple(const OpaqueDataTuple& value, const uint32_t index) {
575 checkIndex(index);
576
577 buffers_[index].clear();
578 OptionDataTypeUtil::writeTuple(value, buffers_[index]);
579}
580
581bool
582OptionCustom::readBoolean(const uint32_t index) const {
583 checkIndex(index);
584 return (OptionDataTypeUtil::readBool(buffers_[index]));
585}
586
587void
588OptionCustom::writeBoolean(const bool value, const uint32_t index) {
589 checkIndex(index);
590
591 buffers_[index].clear();
592 OptionDataTypeUtil::writeBool(value, buffers_[index]);
593}
594
595std::string
596OptionCustom::readFqdn(const uint32_t index) const {
597 checkIndex(index);
598 return (OptionDataTypeUtil::readFqdn(buffers_[index]));
599}
600
601void
602OptionCustom::writeFqdn(const std::string& fqdn, const uint32_t index) {
603 checkIndex(index);
604
605 // Create a temporary buffer where the FQDN will be written.
606 OptionBuffer buf;
607 // Try to write to the temporary buffer rather than to the
608 // buffers_ member directly guarantees that we don't modify
609 // (clear) buffers_ until we are sure that the provided FQDN
610 // is valid.
612 // If we got to this point it means that the FQDN is valid.
613 // We can move the contents of the temporary buffer to the
614 // target buffer.
615 std::swap(buffers_[index], buf);
616}
617
619OptionCustom::readPrefix(const uint32_t index) const {
620 checkIndex(index);
621 return (OptionDataTypeUtil::readPrefix(buffers_[index]));
622}
623
624void
626 const IOAddress& prefix,
627 const uint32_t index) {
628 checkIndex(index);
629
630 OptionBuffer buf;
631 OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
632 // If there are no errors while writing PSID to a buffer, we can
633 // replace the current buffer with a new buffer.
634 std::swap(buffers_[index], buf);
635}
636
637
639OptionCustom::readPsid(const uint32_t index) const {
640 checkIndex(index);
641 return (OptionDataTypeUtil::readPsid(buffers_[index]));
642}
643
644void
645OptionCustom::writePsid(const PSIDLen& psid_len, const PSID& psid,
646 const uint32_t index) {
647 checkIndex(index);
648
649 OptionBuffer buf;
650 OptionDataTypeUtil::writePsid(psid_len, psid, buf);
651 // If there are no errors while writing PSID to a buffer, we can
652 // replace the current buffer with a new buffer.
653 std::swap(buffers_[index], buf);
654}
655
656
657std::string
658OptionCustom::readString(const uint32_t index) const {
659 checkIndex(index);
660 return (OptionDataTypeUtil::readString(buffers_[index]));
661}
662
663void
664OptionCustom::writeString(const std::string& text, const uint32_t index) {
665 checkIndex(index);
666
667 // Let's clear a buffer as we want to replace the value of the
668 // whole buffer. If we fail to clear the buffer the data will
669 // be appended.
670 buffers_[index].clear();
671 // If the text value is empty we can leave because the buffer
672 // is already empty.
673 if (!text.empty()) {
674 OptionDataTypeUtil::writeString(text, buffers_[index]);
675 }
676}
677
678void
683
684uint16_t
686 // The length of the option is a sum of option header ...
687 size_t length = getHeaderLen();
688
689 // ... lengths of all buffers that hold option data ...
690 for (auto const& buf : buffers_) {
691 length += buf.size();
692 }
693
694 // ... and lengths of all suboptions
695 for (auto const& it : options_) {
696 length += it.second->len();
697 }
698
699 return (static_cast<uint16_t>(length));
700}
701
703 const OptionBufferConstIter last) {
704 setData(first, last);
705
706 // Chop the data_ buffer into set of buffers that represent
707 // option fields data.
708 createBuffers(getData());
709}
710
711std::string OptionCustom::toText(int indent) const {
712 std::stringstream output;
713
714 output << headerToText(indent) << ":";
715
716 OptionDataType data_type = definition_.getType();
717 if (data_type == OPT_RECORD_TYPE) {
719 definition_.getRecordFields();
720
721 // For record types we iterate over fields defined in
722 // option definition and match the appropriate buffer
723 // with them.
724 size_t j = 0;
725 for (auto const& field : fields) {
726 output << " " << dataFieldToText(field, j);
727 j++;
728 }
729
730 // If the last record field is an array iterate on extra buffers
731 if (definition_.getArrayType()) {
732 for (unsigned int i = fields.size(); i < getDataFieldsNum(); ++i) {
733 output << " " << dataFieldToText(fields.back(), i);
734 }
735 }
736 } else {
737 // For non-record types we iterate over all buffers
738 // and print the data type set globally for an option
739 // definition. We take the same code path for arrays
740 // and non-arrays as they only differ in such a way that
741 // non-arrays have just single data field.
742 for (unsigned int i = 0; i < getDataFieldsNum(); ++i) {
743 output << " " << dataFieldToText(definition_.getType(), i);
744 }
745 }
746
747 // Append suboptions.
748 output << suboptionsToText(indent + 2);
749
750 return (output.str());
751}
752
753} // end of isc::dhcp namespace
754} // end of isc namespace
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.
Represents a single instance of the opaque data preceded by length.
LengthFieldType
Size of the length field in the tuple.
std::string readString(const uint32_t index=0) const
Read a buffer as string value.
bool readBoolean(const uint32_t index=0) const
Read a buffer as boolean value.
virtual uint16_t len() const
Returns length of the complete option (data length + DHCPv4/DHCPv6 option header).
std::string readTuple(const uint32_t index=0) const
Read a buffer as length and string tuple.
void writeFqdn(const std::string &fqdn, const uint32_t index=0)
Write an FQDN into a buffer.
std::string readFqdn(const uint32_t index=0) const
Read a buffer as FQDN.
void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, const uint32_t index=0)
Write prefix length and value into a buffer.
virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end)
Parses received buffer.
void writeAddress(const asiolink::IOAddress &address, const uint32_t index=0)
Write an IP address into a buffer.
virtual void pack(isc::util::OutputBuffer &buf, bool check=true) const
Writes DHCP option in a wire format to a buffer.
void initialize(const OptionBufferConstIter first, const OptionBufferConstIter last)
Sets content of this option from buffer.
const OptionBuffer & readBinary(const uint32_t index=0) const
Read a buffer as binary data.
PrefixTuple readPrefix(const uint32_t index=0) const
Read a buffer as variable length prefix.
void writePsid(const PSIDLen &psid_len, const PSID &psid, const uint32_t index=0)
Write PSID length / value into a buffer.
void writeBoolean(const bool value, const uint32_t index=0)
Write a boolean value into a buffer.
asiolink::IOAddress readAddress(const uint32_t index=0) const
Read a buffer as IP address.
PSIDTuple readPsid(const uint32_t index=0) const
Read a buffer as a PSID length / value tuple.
void writeString(const std::string &text, const uint32_t index=0)
Write a string value into a buffer.
T readInteger(const uint32_t index=0) const
Read a buffer as integer value.
void writeBinary(const OptionBuffer &buf, const uint32_t index=0)
Write binary data into a buffer.
void addArrayDataField(const asiolink::IOAddress &address)
Create new buffer and set its value as an IP address.
virtual OptionPtr clone() const
Copies this option and returns a pointer to the copy.
void writeTuple(const std::string &value, const uint32_t index=0)
Write a length and string tuple into a buffer.
virtual std::string toText(int indent=0) const
Returns string representation of the option.
OptionCustom(const OptionDefinition &def, Universe u)
Constructor, used for options to be sent.
uint32_t getDataFieldsNum() const
Return a number of the data fields.
static PrefixTuple readPrefix(const std::vector< uint8_t > &buf)
Read prefix from a buffer.
static asiolink::IOAddress readAddress(const std::vector< uint8_t > &buf, const short family)
Read IPv4 or IPv6 address from a buffer.
static void writeFqdn(const std::string &fqdn, std::vector< uint8_t > &buf, const bool downcase=false)
Append FQDN into a buffer.
static void writePrefix(const PrefixLen &prefix_len, const asiolink::IOAddress &prefix, std::vector< uint8_t > &buf)
Append prefix into a buffer.
static const std::string & getDataTypeName(const OptionDataType data_type)
Return option data type name from the data type enumerator.
static int getDataTypeLen(const OptionDataType data_type)
Get data type buffer length.
static std::string readTuple(const std::vector< uint8_t > &buf, OpaqueDataTuple::LengthFieldType lengthfieldtype)
Read length and string tuple from a buffer.
static std::string readFqdn(const std::vector< uint8_t > &buf, bool raw=false)
Read FQDN from a buffer as a string value.
static void writeAddress(const asiolink::IOAddress &address, std::vector< uint8_t > &buf)
Append IPv4 or IPv6 address to a buffer.
static PSIDTuple readPsid(const std::vector< uint8_t > &buf)
Read PSID length / value tuple from a buffer.
static void writePsid(const PSIDLen &psid_len, const PSID &psid, std::vector< uint8_t > &buf)
Append PSID length/value into a buffer.
static void writeString(const std::string &value, std::vector< uint8_t > &buf)
Write UTF8-encoded string into a buffer.
static void writeTuple(const std::string &value, OpaqueDataTuple::LengthFieldType lengthfieldtype, std::vector< uint8_t > &buf)
Append length and string tuple to a buffer.
static OpaqueDataTuple::LengthFieldType getTupleLenFieldType(Option::Universe u)
Returns Length Field Type for a tuple.
static void writeBool(const bool value, std::vector< uint8_t > &buf)
Append boolean value into a buffer.
static bool readBool(const std::vector< uint8_t > &buf)
Read boolean value from a buffer.
static std::string readString(const std::vector< uint8_t > &buf)
Read string value from a buffer.
Base class representing a DHCP option definition.
std::vector< OptionDataType > RecordFieldsCollection
List of fields within the record.
std::string getEncapsulatedSpace() const
Return name of the encapsulated option space.
std::string headerToText(const int indent=0, const std::string &type_name="") const
Returns option header in the textual format.
Definition option.cc:294
std::string suboptionsToText(const int indent=0) const
Returns collection of suboptions in the textual format.
Definition option.cc:313
static bool lenient_parsing_
Governs whether options should be parsed less strictly.
Definition option.h:490
std::string getEncapsulatedSpace() const
Returns the name of the option space encapsulated by this option.
Definition option.h:449
void setEncapsulatedSpace(const std::string &encapsulated_space)
Sets the name of the option space encapsulated by this option.
Definition option.h:442
virtual const OptionBuffer & getData() const
Returns pointer to actual data.
Definition option.h:324
virtual uint16_t getHeaderLen() const
Returns length of header (2 for v4, 4 for v6).
Definition option.cc:327
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
void packOptions(isc::util::OutputBuffer &buf, bool check=true) const
Store sub options in a buffer.
Definition option.cc:136
OptionCollection options_
collection for storing suboptions
Definition option.h:604
void unpackOptions(const OptionBuffer &buf, size_t rec_level=0)
Builds a collection of sub options from the buffer.
Definition option.cc:155
OptionPtr cloneInternal() const
Copies this option and returns a pointer to the copy.
Definition option.h:504
Universe getUniverse() const
returns option universe (V4 or V6)
Definition option.h:240
void packHeader(isc::util::OutputBuffer &buf, bool check=true) const
Store option's header in a buffer.
Definition option.cc:119
Option(Universe u, uint16_t type)
ctor, used for options constructed, usually during transmission
Definition option.cc:39
void check() const
A protected method used for option correctness.
Definition option.cc:90
Encapsulates PSID length.
Encapsulates PSID value.
Encapsulates prefix length.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:355
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:568
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition isc_assert.h:18
std::pair< PSIDLen, PSID > PSIDTuple
Defines a pair of PSID length / value.
OptionBuffer::const_iterator OptionBufferConstIter
const_iterator for walking over OptionBuffer
Definition option.h:30
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
OptionDataType
Data types of DHCP option fields.
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 format.
Definition encode.cc:361
bool isPrintable(const string &content)
Check if a string is printable.
Definition str.cc:310
Defines the logger used by the top-level component of kea-lfc.