| File: | home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmpxsedttj5/../../../src/lib/dhcp/option_data_types.cc |
| Warning: | line 523, column 40 The result of right shift is undefined because the right operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | ||||
| 18 | using namespace isc::asiolink; | |||
| 19 | ||||
| 20 | namespace { | |||
| 21 | /// @brief Bit mask used to compute PSID value. | |||
| 22 | /// | |||
| 23 | /// The mask represents the useful bits of the PSID. The value 0 is a special | |||
| 24 | /// case because the RFC explicitly specifies that PSID value should be ignored | |||
| 25 | /// if psid_len is 0. | |||
| 26 | std::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 | ||||
| 34 | namespace isc { | |||
| 35 | namespace dhcp { | |||
| 36 | ||||
| 37 | OptionDataTypeUtil::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 | |||
| 83 | OptionDataTypeUtil::getDataType(const std::string& data_type) { | |||
| 84 | return (OptionDataTypeUtil::instance().getDataTypeImpl(data_type)); | |||
| 85 | } | |||
| 86 | ||||
| 87 | OptionDataType | |||
| 88 | OptionDataTypeUtil::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 | ||||
| 97 | int | |||
| 98 | OptionDataTypeUtil::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 | ||||
| 128 | const std::string& | |||
| 129 | OptionDataTypeUtil::getDataTypeName(const OptionDataType data_type) { | |||
| 130 | return (OptionDataTypeUtil::instance().getDataTypeNameImpl(data_type)); | |||
| 131 | } | |||
| 132 | ||||
| 133 | const std::string& | |||
| 134 | OptionDataTypeUtil::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 | ||||
| 143 | OptionDataTypeUtil& | |||
| 144 | OptionDataTypeUtil::instance() { | |||
| 145 | static OptionDataTypeUtil instance; | |||
| 146 | return (instance); | |||
| 147 | } | |||
| 148 | ||||
| 149 | asiolink::IOAddress | |||
| 150 | OptionDataTypeUtil::readAddress(const std::vector<uint8_t>& buf, | |||
| 151 | const short family) { | |||
| 152 | using namespace isc::asiolink; | |||
| 153 | if (family == AF_INET2) { | |||
| 154 | if (buf.size() < V4ADDRESS_LEN) { | |||
| 155 | isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " IPv4 address. Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 156, oss__.str().c_str()); } while (1) | |||
| 156 | << " IPv4 address. Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " IPv4 address. Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 156, oss__.str().c_str()); } while (1); | |||
| 157 | } | |||
| 158 | return (IOAddress::fromBytes(AF_INET2, &buf[0])); | |||
| 159 | } else if (family == AF_INET610) { | |||
| 160 | if (buf.size() < V6ADDRESS_LEN) { | |||
| 161 | isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " IPv6 address. Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 162, oss__.str().c_str()); } while (1) | |||
| 162 | << " IPv6 address. Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " IPv6 address. Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 162, oss__.str().c_str()); } while (1); | |||
| 163 | } | |||
| 164 | return (IOAddress::fromBytes(AF_INET610, &buf[0])); | |||
| 165 | } else { | |||
| 166 | isc_throw(BadDataTypeCast, "unable to read data from the buffer as"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " IP address. Invalid family: " << family; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 167, oss__.str().c_str()); } while (1) | |||
| 167 | << " IP address. Invalid family: " << family)do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " IP address. Invalid family: " << family; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 167, oss__.str().c_str()); } while (1); | |||
| 168 | } | |||
| 169 | } | |||
| 170 | ||||
| 171 | void | |||
| 172 | OptionDataTypeUtil::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 | ||||
| 178 | void | |||
| 179 | OptionDataTypeUtil::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_strdo { std::ostringstream oss__; oss__ << "unable to cast " << hex_str << " to binary data type: " << ex .what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 189, oss__.str().c_str()); } while (1) | |||
| 189 | << " to binary data type: " << ex.what())do { std::ostringstream oss__; oss__ << "unable to cast " << hex_str << " to binary data type: " << ex .what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 189, oss__.str().c_str()); } while (1); | |||
| 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 | |||
| 197 | OptionDataTypeUtil::getTupleLenFieldType(Option::Universe u) { | |||
| 198 | if (u == Option::V4) { | |||
| 199 | return (OpaqueDataTuple::LENGTH_1_BYTE); | |||
| 200 | } | |||
| 201 | return (OpaqueDataTuple::LENGTH_2_BYTES); | |||
| 202 | } | |||
| 203 | ||||
| 204 | std::string | |||
| 205 | OptionDataTypeUtil::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"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length). Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 211, oss__.str().c_str()); } while (1) | |||
| 210 | << " tuple (length). Invalid buffer size: "do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length). Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 211, oss__.str().c_str()); } while (1) | |||
| 211 | << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length). Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 211, oss__.str().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length " << static_cast<unsigned> (len) << "). Invalid buffer size: " << buf.size() ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 217, oss__.str().c_str()); } while (1) | |||
| 216 | << " tuple (length " << static_cast<unsigned>(len)do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length " << static_cast<unsigned> (len) << "). Invalid buffer size: " << buf.size() ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 217, oss__.str().c_str()); } while (1) | |||
| 217 | << "). Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length " << static_cast<unsigned> (len) << "). Invalid buffer size: " << buf.size() ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 217, oss__.str().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length). Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 227, oss__.str().c_str()); } while (1) | |||
| 226 | << " tuple (length). Invalid buffer size: "do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length). Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 227, oss__.str().c_str()); } while (1) | |||
| 227 | << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length). Invalid buffer size: " << buf .size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 227, oss__.str().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length " << len << "). Invalid buffer size: " << buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 233, oss__.str().c_str()); } while (1) | |||
| 232 | << " tuple (length " << lendo { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length " << len << "). Invalid buffer size: " << buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 233, oss__.str().c_str()); } while (1) | |||
| 233 | << "). Invalid buffer size: " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple (length " << len << "). Invalid buffer size: " << buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 233, oss__.str().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple. Invalid length type field: " << static_cast <unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 242, oss__.str().c_str()); } while (1) | |||
| 241 | << " tuple. Invalid length type field: "do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple. Invalid length type field: " << static_cast <unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 242, oss__.str().c_str()); } while (1) | |||
| 242 | << static_cast<unsigned>(lengthfieldtype))do { std::ostringstream oss__; oss__ << "unable to read data from the buffer as" << " tuple. Invalid length type field: " << static_cast <unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 242, oss__.str().c_str()); } while (1); | |||
| 243 | } | |||
| 244 | } | |||
| 245 | ||||
| 246 | void | |||
| 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())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 252, oss__.str().c_str()); } while (1); | |||
| 253 | } | |||
| 254 | } | |||
| 255 | ||||
| 256 | void | |||
| 257 | OptionDataTypeUtil::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 "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << value.size() << " larger than " << +std ::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 264, oss__.str ().c_str()); } while (1) | |||
| 263 | << value.size() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << value.size() << " larger than " << +std ::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 264, oss__.str ().c_str()); } while (1) | |||
| 264 | << +std::numeric_limits<uint8_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << value.size() << " larger than " << +std ::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 264, oss__.str ().c_str()); } while (1); | |||
| 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 "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << value.size() << " larger than " << std:: numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 272, oss__.str ().c_str()); } while (1) | |||
| 271 | << value.size() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << value.size() << " larger than " << std:: numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 272, oss__.str ().c_str()); } while (1) | |||
| 272 | << std::numeric_limits<uint16_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << value.size() << " larger than " << std:: numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 272, oss__.str ().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as" << " tuple. Invalid length type field: " << static_cast <unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 280, oss__.str().c_str()); } while (1) | |||
| 279 | << " tuple. Invalid length type field: "do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as" << " tuple. Invalid length type field: " << static_cast <unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 280, oss__.str().c_str()); } while (1) | |||
| 280 | << static_cast<unsigned>(lengthfieldtype))do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as" << " tuple. Invalid length type field: " << static_cast <unsigned>(lengthfieldtype); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 280, oss__.str().c_str()); } while (1); | |||
| 281 | } | |||
| 282 | buf.insert(buf.end(), value.begin(), value.end()); | |||
| 283 | } | |||
| 284 | ||||
| 285 | void | |||
| 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")do { std::ostringstream oss__; oss__ << "invalid empty tuple value" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 289, oss__.str().c_str()); } while (1); | |||
| 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 "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << tuple.getLength() << " larger than " << +std::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 295, oss__.str().c_str()); } while (1) | |||
| 294 | << tuple.getLength() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << tuple.getLength() << " larger than " << +std::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 295, oss__.str().c_str()); } while (1) | |||
| 295 | << +std::numeric_limits<uint8_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << tuple.getLength() << " larger than " << +std::numeric_limits<uint8_t>::max() << ")"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 295, oss__.str().c_str()); } while (1); | |||
| 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 "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << tuple.getLength() << " larger than " << std::numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 303, oss__.str().c_str()); } while (1) | |||
| 302 | << tuple.getLength() << " larger than "do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << tuple.getLength() << " larger than " << std::numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 303, oss__.str().c_str()); } while (1) | |||
| 303 | << std::numeric_limits<uint16_t>::max() << ")")do { std::ostringstream oss__; oss__ << "invalid tuple value (size " << tuple.getLength() << " larger than " << std::numeric_limits<uint16_t>::max() << ")"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 303, oss__.str().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as" << " tuple. Invalid length type field: " << tuple .getLengthFieldType(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 311, oss__.str().c_str()); } while (1) | |||
| 310 | << " tuple. Invalid length type field: "do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as" << " tuple. Invalid length type field: " << tuple .getLengthFieldType(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 311, oss__.str().c_str()); } while (1) | |||
| 311 | << tuple.getLengthFieldType())do { std::ostringstream oss__; oss__ << "unable to write data to the buffer as" << " tuple. Invalid length type field: " << tuple .getLengthFieldType(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 311, oss__.str().c_str()); } while (1); | |||
| 312 | } | |||
| 313 | buf.insert(buf.end(), tuple.getData().begin(), tuple.getData().end()); | |||
| 314 | } | |||
| 315 | ||||
| 316 | bool | |||
| 317 | OptionDataTypeUtil::readBool(const std::vector<uint8_t>& buf) { | |||
| 318 | if (buf.empty()) { | |||
| 319 | isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean" << " value. Invalid buffer size " << buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 320, oss__.str().c_str()); } while (1) | |||
| 320 | << " value. Invalid buffer size " << buf.size())do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean" << " value. Invalid buffer size " << buf.size(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 320, oss__.str().c_str()); } while (1); | |||
| 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"do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean" << " value. Invalid value " << static_cast<int >(buf[0]); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 328, oss__.str().c_str()); } while (1) | |||
| 328 | << " value. Invalid value " << static_cast<int>(buf[0]))do { std::ostringstream oss__; oss__ << "unable to read the buffer as boolean" << " value. Invalid value " << static_cast<int >(buf[0]); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 328, oss__.str().c_str()); } while (1); | |||
| 329 | } | |||
| 330 | ||||
| 331 | void | |||
| 332 | OptionDataTypeUtil::writeBool(const bool value, | |||
| 333 | std::vector<uint8_t>& buf) { | |||
| 334 | buf.push_back(static_cast<uint8_t>(value ? 1 : 0)); | |||
| 335 | } | |||
| 336 | ||||
| 337 | std::string | |||
| 338 | OptionDataTypeUtil::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."do { std::ostringstream oss__; oss__ << "unable to read FQDN from a buffer." << " The buffer is empty."; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 342, oss__.str().c_str()); } while (1) | |||
| 342 | << " The buffer is empty.")do { std::ostringstream oss__; oss__ << "unable to read FQDN from a buffer." << " The buffer is empty."; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 342, oss__.str().c_str()); } while (1); | |||
| 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())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 354, oss__.str().c_str()); } while (1); | |||
| 355 | } | |||
| 356 | } | |||
| 357 | ||||
| 358 | void | |||
| 359 | OptionDataTypeUtil::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())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 371, oss__.str().c_str()); } while (1); | |||
| 372 | } | |||
| 373 | } | |||
| 374 | ||||
| 375 | unsigned int | |||
| 376 | OptionDataTypeUtil::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())do { std::ostringstream oss__; oss__ << ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 389, oss__.str().c_str()); } while (1); | |||
| 390 | } | |||
| 391 | } | |||
| 392 | ||||
| 393 | PrefixTuple | |||
| 394 | OptionDataTypeUtil::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 "do { std::ostringstream oss__; oss__ << "unable to read prefix length from " "a truncated buffer"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 400, oss__.str().c_str()); } while (1) | |||
| 400 | "a truncated buffer")do { std::ostringstream oss__; oss__ << "unable to read prefix length from " "a truncated buffer"; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 400, oss__.str().c_str()); } while (1); | |||
| 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 "do { std::ostringstream oss__; oss__ << "unable to read a prefix having length of " << prefix_len.asUnsigned() << " from a truncated buffer" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 436, oss__.str().c_str()); } while (1) | |||
| 436 | << prefix_len.asUnsigned() << " from a truncated buffer")do { std::ostringstream oss__; oss__ << "unable to read a prefix having length of " << prefix_len.asUnsigned() << " from a truncated buffer" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 436, oss__.str().c_str()); } while (1); | |||
| 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_INET610, &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: "do { std::ostringstream oss__; oss__ << "unable to read a prefix from a buffer: " << ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 485, oss__.str().c_str()); } while (1) | |||
| 485 | << ex.what())do { std::ostringstream oss__; oss__ << "unable to read a prefix from a buffer: " << ex.what(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 485, oss__.str().c_str()); } while (1); | |||
| 486 | } | |||
| 487 | } | |||
| 488 | ||||
| 489 | void | |||
| 490 | OptionDataTypeUtil::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 "do { std::ostringstream oss__; oss__ << "illegal prefix value " << prefix; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 496, oss__.str().c_str()); } while (1) | |||
| 496 | << prefix)do { std::ostringstream oss__; oss__ << "illegal prefix value " << prefix; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 496, oss__.str().c_str()); } while (1); | |||
| 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 | |||
| 528 | OptionDataTypeUtil::readPsid(const std::vector<uint8_t>& buf) { | |||
| 529 | if (buf.size() < 3) { | |||
| 530 | isc_throw(BadDataTypeCast, "unable to read PSID from the buffer."do { std::ostringstream oss__; oss__ << "unable to read PSID from the buffer." << " Invalid buffer size " << buf.size() << ". Expected 3 bytes (PSID length and PSID value)"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 532, oss__.str ().c_str()); } while (1) | |||
| 531 | << " Invalid buffer size " << buf.size()do { std::ostringstream oss__; oss__ << "unable to read PSID from the buffer." << " Invalid buffer size " << buf.size() << ". Expected 3 bytes (PSID length and PSID value)"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 532, oss__.str ().c_str()); } while (1) | |||
| 532 | << ". Expected 3 bytes (PSID length and PSID value)")do { std::ostringstream oss__; oss__ << "unable to read PSID from the buffer." << " Invalid buffer size " << buf.size() << ". Expected 3 bytes (PSID length and PSID value)"; throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 532, oss__.str ().c_str()); } while (1); | |||
| 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 "do { std::ostringstream oss__; oss__ << "invalid PSID length value " << static_cast<unsigned>(psid_len) << ", this value is expected to be in range of 0 to 16" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 542, oss__.str().c_str()); } while (1) | |||
| 541 | << static_cast<unsigned>(psid_len)do { std::ostringstream oss__; oss__ << "invalid PSID length value " << static_cast<unsigned>(psid_len) << ", this value is expected to be in range of 0 to 16" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 542, oss__.str().c_str()); } while (1) | |||
| 542 | << ", this value is expected to be in range of 0 to 16")do { std::ostringstream oss__; oss__ << "invalid PSID length value " << static_cast<unsigned>(psid_len) << ", this value is expected to be in range of 0 to 16" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 542, oss__.str().c_str()); } while (1); | |||
| 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 " << psiddo { std::ostringstream oss__; oss__ << "invalid PSID value " << psid << " for a specified PSID length " << static_cast<unsigned>(psid_len); throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 556, oss__.str ().c_str()); } while (1) | |||
| 555 | << " for a specified PSID length "do { std::ostringstream oss__; oss__ << "invalid PSID value " << psid << " for a specified PSID length " << static_cast<unsigned>(psid_len); throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 556, oss__.str ().c_str()); } while (1) | |||
| 556 | << static_cast<unsigned>(psid_len))do { std::ostringstream oss__; oss__ << "invalid PSID value " << psid << " for a specified PSID length " << static_cast<unsigned>(psid_len); throw BadDataTypeCast ("../../../src/lib/dhcp/option_data_types.cc", 556, oss__.str ().c_str()); } while (1); | |||
| 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 | ||||
| 570 | void | |||
| 571 | OptionDataTypeUtil::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 "do { std::ostringstream oss__; oss__ << "invalid PSID length value " << psid_len.asUnsigned() << ", this value is expected to be in range of 0 to 16" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 576, oss__.str().c_str()); } while (1) | |||
| 575 | << psid_len.asUnsigned()do { std::ostringstream oss__; oss__ << "invalid PSID length value " << psid_len.asUnsigned() << ", this value is expected to be in range of 0 to 16" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 576, oss__.str().c_str()); } while (1) | |||
| 576 | << ", this value is expected to be in range of 0 to 16")do { std::ostringstream oss__; oss__ << "invalid PSID length value " << psid_len.asUnsigned() << ", this value is expected to be in range of 0 to 16" ; throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 576, oss__.str().c_str()); } while (1); | |||
| 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()do { std::ostringstream oss__; oss__ << "invalid PSID value " << psid.asUint16() << " for a specified PSID length " << psid_len.asUnsigned(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 583, oss__.str().c_str()); } while (1) | |||
| 582 | << " for a specified PSID length "do { std::ostringstream oss__; oss__ << "invalid PSID value " << psid.asUint16() << " for a specified PSID length " << psid_len.asUnsigned(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 583, oss__.str().c_str()); } while (1) | |||
| 583 | << psid_len.asUnsigned())do { std::ostringstream oss__; oss__ << "invalid PSID value " << psid.asUint16() << " for a specified PSID length " << psid_len.asUnsigned(); throw BadDataTypeCast("../../../src/lib/dhcp/option_data_types.cc" , 583, oss__.str().c_str()); } while (1); | |||
| 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 | ||||
| 593 | std::string | |||
| 594 | OptionDataTypeUtil::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 "do { std::ostringstream oss__; oss__ << "string value carried by the option " "contained only NULLs"; throw isc::OutOfRange("../../../src/lib/dhcp/option_data_types.cc" , 602, oss__.str().c_str()); } while (1) | |||
| 602 | "contained only NULLs")do { std::ostringstream oss__; oss__ << "string value carried by the option " "contained only NULLs"; throw isc::OutOfRange("../../../src/lib/dhcp/option_data_types.cc" , 602, oss__.str().c_str()); } while (1); | |||
| 603 | } | |||
| 604 | ||||
| 605 | value.insert(value.end(), begin, end); | |||
| 606 | } | |||
| 607 | ||||
| 608 | return (value); | |||
| 609 | } | |||
| 610 | ||||
| 611 | void | |||
| 612 | OptionDataTypeUtil::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 |