Kea 3.2.0-git
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 std::string fqdn =
233 // The size of the buffer holding an FQDN is always
234 // 1 byte larger than the size of the string
235 // representation of this FQDN.
236 data_size = fqdn.size() + 1;
237 } catch (const std::exception& ex) {
239 isc_throw(SkipThisOptionError, "failed to read "
240 "domain-name from wire format: "
241 << ex.what());
242 }
243
244 throw;
245 }
246 } else if (!definition_.getArrayType() &&
247 ((data_type == OPT_BINARY_TYPE) ||
248 (data_type == OPT_STRING_TYPE))) {
249 // In other case we are dealing with string or binary value
250 // which size can't be determined. Thus we consume the
251 // remaining part of the buffer for it. Note that variable
252 // size data can be laid at the end of the option only and
253 // that the validate() function in OptionDefinition object
254 // should have checked wheter it is a case for this option.
255 data_size = std::distance(begin, end);
256 } else if (data_type == OPT_IPV6_PREFIX_TYPE) {
257 // The size of the IPV6 prefix type is determined as
258 // one byte (which is the size of the prefix in bits)
259 // followed by the prefix bits (right-padded with
260 // zeros to the nearest octet boundary)
261 if ((begin == end) && !in_array)
262 return 0;
263 PrefixTuple prefix =
265 // Data size comprises 1 byte holding a prefix length and the
266 // prefix length (in bytes) rounded to the nearest byte boundary.
267 data_size = sizeof(uint8_t) + (prefix.first.asUint8() + 7) / 8;
268 } else if (data_type == OPT_TUPLE_TYPE) {
271 std::string value =
273 data_size = value.size();
274 // The size of the buffer holding a tuple is always
275 // 1 or 2 byte larger than the size of the string
276 data_size += getUniverse() == Option::V4 ? 1 : 2;
277 } else {
278 // If we reached the end of buffer we assume that this option is
279 // truncated because there is no remaining data to initialize
280 // an option field.
281 isc_throw(OutOfRange, "option buffer truncated");
282 }
283 }
284
285 return data_size;
286}
287
288void
289OptionCustom::createBuffers(const OptionBuffer& data_buf, size_t rec_level) {
290 // Check that the option definition is correct as we are going
291 // to use it to split the data_ buffer into set of sub buffers.
292 definition_.validate();
293
294 std::vector<OptionBuffer> buffers;
295 OptionBuffer::const_iterator data = data_buf.begin();
296
297 OptionDataType data_type = definition_.getType();
298 if (data_type == OPT_RECORD_TYPE) {
299 // An option comprises a record of data fields. We need to
300 // get types of these data fields to allocate enough space
301 // for each buffer.
303 definition_.getRecordFields();
304
305 // Go over all data fields within a record.
306 for (auto const& field : fields) {
307 size_t data_size = bufferLength(field, false,
308 data, data_buf.end());
309
310 // Our data field requires that there is a certain chunk of
311 // data left in the buffer. If not, option is truncated.
312 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
313 isc_throw(OutOfRange, "option buffer truncated");
314 }
315
316 // Store the created buffer.
317 buffers.push_back(OptionBuffer(data, data + data_size));
318 // Proceed to the next data field.
319 data += data_size;
320 }
321
322 // Get extra buffers when the last field is an array.
323 if (definition_.getArrayType()) {
324 while (data != data_buf.end()) {
325 // Code copied from the standard array case
326 size_t data_size = bufferLength(fields.back(), true,
327 data, data_buf.end());
328 isc_throw_assert(data_size > 0);
329 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
330 break;
331 }
332 buffers.push_back(OptionBuffer(data, data + data_size));
333 data += data_size;
334 }
335 }
336
337 // Unpack suboptions if any.
338 else if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
339 unpackOptions(OptionBuffer(data, data_buf.end()), rec_level);
340 }
341
342 } else if (data_type != OPT_EMPTY_TYPE) {
343 // If data_type value is other than OPT_RECORD_TYPE, our option is
344 // empty (have no data at all) or it comprises one or more
345 // data fields of the same type. The type of those fields
346 // is held in the data_type variable so let's use it to determine
347 // a size of buffers.
348 size_t data_size = OptionDataTypeUtil::getDataTypeLen(data_type);
349 // The check below will fail if the input buffer is too short
350 // for the data size being held by this option.
351 // Note that data_size returned by getDataTypeLen may be zero
352 // if variable length data is being held by the option but
353 // this will not cause this check to throw exception.
354 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
355 isc_throw(OutOfRange, "option buffer truncated");
356 }
357 // For an array of values we are taking different path because
358 // we have to handle multiple buffers.
359 if (definition_.getArrayType()) {
360 while (data != data_buf.end()) {
361 data_size = bufferLength(data_type, true, data, data_buf.end());
362 // We don't perform other checks for data types that can't be
363 // used together with array indicator such as strings, empty field
364 // etc. This is because OptionDefinition::validate function should
365 // have checked this already. Thus data_size must be greater than
366 // zero.
367 isc_throw_assert(data_size > 0);
368 // Get chunks of data and store as a collection of buffers.
369 // Truncate any remaining part which length is not divisible by
370 // data_size. Note that it is ok to truncate the data if and only
371 // if the data buffer is long enough to keep at least one value.
372 // This has been checked above already.
373 if (static_cast<size_t>(std::distance(data, data_buf.end())) < data_size) {
374 break;
375 }
376 buffers.push_back(OptionBuffer(data, data + data_size));
377 data += data_size;
378 }
379 } else {
380 // For non-arrays the data_size can be zero because
381 // getDataTypeLen returns zero for variable size data types
382 // such as strings. Simply take whole buffer.
383 data_size = bufferLength(data_type, false, data, data_buf.end());
384 if ((data_size > 0) &&
385 (static_cast<size_t>(std::distance(data, data_buf.end())) >= data_size)) {
386 buffers.push_back(OptionBuffer(data, data + data_size));
387 data += data_size;
388 } else {
389 isc_throw(OutOfRange, "option buffer truncated");
390 }
391
392 // Unpack suboptions if any.
393 if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
394 unpackOptions(OptionBuffer(data, data_buf.end()), rec_level);
395 }
396 }
397 } else {
398 // Unpack suboptions if any.
399 if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
400 unpackOptions(OptionBuffer(data, data_buf.end()), rec_level);
401 }
402 }
403 // If everything went ok we can replace old buffer set with new ones.
404 std::swap(buffers_, buffers);
405}
406
407std::string
408OptionCustom::dataFieldToText(const OptionDataType data_type,
409 const uint32_t index) const {
410 std::ostringstream text;
411
412 // Get the value of the data field.
413 switch (data_type) {
414 case OPT_BINARY_TYPE:
415 {
416 auto data = readBinary(index);
417 if (data.empty()) {
418 text << "''";
419 } else {
420 text << util::encode::encodeHex(data);
421 if (str::isPrintable(data)) {
422 std::string printable(data.cbegin(), data.cend());
423 text << " '" << printable << "'";
424 }
425 }
426 break;
427 }
428 case OPT_BOOLEAN_TYPE:
429 text << (readBoolean(index) ? "true" : "false");
430 break;
431 case OPT_INT8_TYPE:
432 text << static_cast<int>(readInteger<int8_t>(index));
433 break;
434 case OPT_INT16_TYPE:
435 text << readInteger<int16_t>(index);
436 break;
437 case OPT_INT32_TYPE:
438 text << readInteger<int32_t>(index);
439 break;
440 case OPT_UINT8_TYPE:
441 text << static_cast<unsigned>(readInteger<uint8_t>(index));
442 break;
443 case OPT_UINT16_TYPE:
444 text << readInteger<uint16_t>(index);
445 break;
446 case OPT_UINT32_TYPE:
447 text << readInteger<uint32_t>(index);
448 break;
451 text << readAddress(index);
452 break;
453 case OPT_FQDN_TYPE:
454 text << "\"" << readFqdn(index) << "\"";
455 break;
456 case OPT_TUPLE_TYPE:
457 text << "\"" << readTuple(index) << "\"";
458 break;
459 case OPT_STRING_TYPE:
460 text << "\"" << readString(index) << "\"";
461 break;
462 case OPT_PSID_TYPE:
463 {
464 PSIDTuple t = readPsid(index);
465 text << "len=" << t.first.asUnsigned() << ",psid=" << t.second.asUint16();
466 break;
467 }
468 default:
469 break;
470 }
471
472 // Append data field type in brackets.
473 text << " (" << OptionDataTypeUtil::getDataTypeName(data_type) << ")";
474
475 return (text.str());
476}
477
478void
480
481 // Pack DHCP header (V4 or V6).
482 packHeader(buf, check);
483
484 // Write data from buffers.
485 for (auto const& it : buffers_) {
486 // In theory the createBuffers function should have taken
487 // care that there are no empty buffers added to the
488 // collection but it is almost always good to make sure.
489 if (!it.empty()) {
490 buf.writeData(&it[0], it.size());
491 }
492 }
493
494 // Write suboptions.
495 packOptions(buf, check);
496}
497
498
500OptionCustom::readAddress(const uint32_t index) const {
501 checkIndex(index);
502
503 // The address being read can be either IPv4 or IPv6. The decision
504 // is made based on the buffer length. If it holds 4 bytes it is IPv4
505 // address, if it holds 16 bytes it is IPv6.
506 if (buffers_[index].size() == asiolink::V4ADDRESS_LEN) {
507 return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET));
508 } else if (buffers_[index].size() == asiolink::V6ADDRESS_LEN) {
509 return (OptionDataTypeUtil::readAddress(buffers_[index], AF_INET6));
510 } else {
511 isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
512 << " IP address. Invalid buffer length "
513 << buffers_[index].size() << ".");
514 }
515}
516
517void
519 const uint32_t index) {
520 checkIndex(index);
521
522 if ((address.isV4() && buffers_[index].size() != V4ADDRESS_LEN) ||
523 (address.isV6() && buffers_[index].size() != V6ADDRESS_LEN)) {
524 isc_throw(BadDataTypeCast, "invalid address specified "
525 << address << ". Expected a valid IPv"
526 << (buffers_[index].size() == V4ADDRESS_LEN ? "4" : "6")
527 << " address.");
528 }
529
530 OptionBuffer buf;
532 std::swap(buf, buffers_[index]);
533}
534
535const OptionBuffer&
536OptionCustom::readBinary(const uint32_t index) const {
537 checkIndex(index);
538 return (buffers_[index]);
539}
540
541void
543 const uint32_t index) {
544 checkIndex(index);
545 buffers_[index] = buf;
546}
547
548std::string
549OptionCustom::readTuple(const uint32_t index) const {
550 checkIndex(index);
552 return (OptionDataTypeUtil::readTuple(buffers_[index], lft));
553}
554
555void
557 const uint32_t index) const {
558 checkIndex(index);
559 OptionDataTypeUtil::readTuple(buffers_[index], tuple);
560}
561
562void
563OptionCustom::writeTuple(const std::string& value, const uint32_t index) {
564 checkIndex(index);
565
566 buffers_[index].clear();
568 OptionDataTypeUtil::writeTuple(value, lft, buffers_[index]);
569}
570
571void
572OptionCustom::writeTuple(const OpaqueDataTuple& value, const uint32_t index) {
573 checkIndex(index);
574
575 buffers_[index].clear();
576 OptionDataTypeUtil::writeTuple(value, buffers_[index]);
577}
578
579bool
580OptionCustom::readBoolean(const uint32_t index) const {
581 checkIndex(index);
582 return (OptionDataTypeUtil::readBool(buffers_[index]));
583}
584
585void
586OptionCustom::writeBoolean(const bool value, const uint32_t index) {
587 checkIndex(index);
588
589 buffers_[index].clear();
590 OptionDataTypeUtil::writeBool(value, buffers_[index]);
591}
592
593std::string
594OptionCustom::readFqdn(const uint32_t index) const {
595 checkIndex(index);
596 return (OptionDataTypeUtil::readFqdn(buffers_[index]));
597}
598
599void
600OptionCustom::writeFqdn(const std::string& fqdn, const uint32_t index) {
601 checkIndex(index);
602
603 // Create a temporary buffer where the FQDN will be written.
604 OptionBuffer buf;
605 // Try to write to the temporary buffer rather than to the
606 // buffers_ member directly guarantees that we don't modify
607 // (clear) buffers_ until we are sure that the provided FQDN
608 // is valid.
610 // If we got to this point it means that the FQDN is valid.
611 // We can move the contents of the temporary buffer to the
612 // target buffer.
613 std::swap(buffers_[index], buf);
614}
615
617OptionCustom::readPrefix(const uint32_t index) const {
618 checkIndex(index);
619 return (OptionDataTypeUtil::readPrefix(buffers_[index]));
620}
621
622void
624 const IOAddress& prefix,
625 const uint32_t index) {
626 checkIndex(index);
627
628 OptionBuffer buf;
629 OptionDataTypeUtil::writePrefix(prefix_len, prefix, buf);
630 // If there are no errors while writing PSID to a buffer, we can
631 // replace the current buffer with a new buffer.
632 std::swap(buffers_[index], buf);
633}
634
635
637OptionCustom::readPsid(const uint32_t index) const {
638 checkIndex(index);
639 return (OptionDataTypeUtil::readPsid(buffers_[index]));
640}
641
642void
643OptionCustom::writePsid(const PSIDLen& psid_len, const PSID& psid,
644 const uint32_t index) {
645 checkIndex(index);
646
647 OptionBuffer buf;
648 OptionDataTypeUtil::writePsid(psid_len, psid, buf);
649 // If there are no errors while writing PSID to a buffer, we can
650 // replace the current buffer with a new buffer.
651 std::swap(buffers_[index], buf);
652}
653
654
655std::string
656OptionCustom::readString(const uint32_t index) const {
657 checkIndex(index);
658 return (OptionDataTypeUtil::readString(buffers_[index]));
659}
660
661void
662OptionCustom::writeString(const std::string& text, const uint32_t index) {
663 checkIndex(index);
664
665 // Let's clear a buffer as we want to replace the value of the
666 // whole buffer. If we fail to clear the buffer the data will
667 // be appended.
668 buffers_[index].clear();
669 // If the text value is empty we can leave because the buffer
670 // is already empty.
671 if (!text.empty()) {
672 OptionDataTypeUtil::writeString(text, buffers_[index]);
673 }
674}
675
676void
681
682uint16_t
684 // The length of the option is a sum of option header ...
685 size_t length = getHeaderLen();
686
687 // ... lengths of all buffers that hold option data ...
688 for (auto const& buf : buffers_) {
689 length += buf.size();
690 }
691
692 // ... and lengths of all suboptions
693 for (auto const& it : options_) {
694 length += it.second->len();
695 }
696
697 return (static_cast<uint16_t>(length));
698}
699
701 const OptionBufferConstIter last) {
702 setData(first, last);
703
704 // Chop the data_ buffer into set of buffers that represent
705 // option fields data.
706 createBuffers(getData());
707}
708
709std::string OptionCustom::toText(int indent) const {
710 std::stringstream output;
711
712 output << headerToText(indent) << ":";
713
714 OptionDataType data_type = definition_.getType();
715 if (data_type == OPT_RECORD_TYPE) {
717 definition_.getRecordFields();
718
719 // For record types we iterate over fields defined in
720 // option definition and match the appropriate buffer
721 // with them.
722 size_t j = 0;
723 for (auto const& field : fields) {
724 output << " " << dataFieldToText(field, j);
725 j++;
726 }
727
728 // If the last record field is an array iterate on extra buffers
729 if (definition_.getArrayType()) {
730 for (unsigned int i = fields.size(); i < getDataFieldsNum(); ++i) {
731 output << " " << dataFieldToText(fields.back(), i);
732 }
733 }
734 } else {
735 // For non-record types we iterate over all buffers
736 // and print the data type set globally for an option
737 // definition. We take the same code path for arrays
738 // and non-arrays as they only differ in such a way that
739 // non-arrays have just single data field.
740 for (unsigned int i = 0; i < getDataFieldsNum(); ++i) {
741 output << " " << dataFieldToText(definition_.getType(), i);
742 }
743 }
744
745 // Append suboptions.
746 output << suboptionsToText(indent + 2);
747
748 return (output.str());
749}
750
751} // end of isc::dhcp namespace
752} // 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 readFqdn(const std::vector< uint8_t > &buf)
Read FQDN from a buffer as a string value.
static std::string readTuple(const std::vector< uint8_t > &buf, OpaqueDataTuple::LengthFieldType lengthfieldtype)
Read length and string tuple from a buffer.
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:295
std::string suboptionsToText(const int indent=0) const
Returns collection of suboptions in the textual format.
Definition option.cc:314
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:328
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:346
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:559
#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.