option_data_types.cc 9.38 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include <dhcp/option_data_types.h>
16
17
#include <dns/labelsequence.h>
#include <dns/name.h>
18
19
20
21
22
#include <util/encode/hex.h>

namespace isc {
namespace dhcp {

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
OptionDataTypeUtil::OptionDataTypeUtil() {
    data_types_["empty"] = OPT_EMPTY_TYPE;
    data_types_["binary"] = OPT_BINARY_TYPE;
    data_types_["boolean"] = OPT_BOOLEAN_TYPE;
    data_types_["int8"] = OPT_INT8_TYPE;
    data_types_["int16"] = OPT_INT16_TYPE;
    data_types_["int32"] = OPT_INT32_TYPE;
    data_types_["uint8"] = OPT_UINT8_TYPE;
    data_types_["uint16"] = OPT_UINT16_TYPE;
    data_types_["uint32"] = OPT_UINT32_TYPE;
    data_types_["ipv4-address"] = OPT_IPV4_ADDRESS_TYPE;
    data_types_["ipv6-address"] = OPT_IPV6_ADDRESS_TYPE;
    data_types_["string"] = OPT_STRING_TYPE;
    data_types_["fqdn"] = OPT_FQDN_TYPE;
    data_types_["record"] = OPT_RECORD_TYPE;

    data_type_names_[OPT_EMPTY_TYPE] = "empty";
    data_type_names_[OPT_BINARY_TYPE] = "binary";
    data_type_names_[OPT_BOOLEAN_TYPE] = "boolean";
    data_type_names_[OPT_INT8_TYPE] = "int8";
    data_type_names_[OPT_INT16_TYPE] = "int16";
    data_type_names_[OPT_INT32_TYPE] = "int32";
    data_type_names_[OPT_UINT8_TYPE] = "uint8";
    data_type_names_[OPT_UINT16_TYPE] = "uint16";
    data_type_names_[OPT_UINT32_TYPE] = "uint32";
    data_type_names_[OPT_IPV4_ADDRESS_TYPE] = "ipv4-address";
49
    data_type_names_[OPT_IPV6_ADDRESS_TYPE] = "ipv6-address";
50
51
52
    data_type_names_[OPT_STRING_TYPE] = "string";
    data_type_names_[OPT_FQDN_TYPE] = "fqdn";
    data_type_names_[OPT_RECORD_TYPE] = "record";
53
54
55
56
    // The "unknown" data type is declared here so as
    // it can be returned by reference by a getDataTypeName
    // function it no other type is suitable. Other than that
    // this is unused.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    data_type_names_[OPT_UNKNOWN_TYPE] = "unknown";
}

OptionDataType
OptionDataTypeUtil::getDataType(const std::string& data_type) {
    return (OptionDataTypeUtil::instance().getDataTypeImpl(data_type));
}

OptionDataType
OptionDataTypeUtil::getDataTypeImpl(const std::string& data_type) const {
    std::map<std::string, OptionDataType>::const_iterator data_type_it =
        data_types_.find(data_type);
    if (data_type_it != data_types_.end()) {
        return (data_type_it->second);
    }
    return (OPT_UNKNOWN_TYPE);
}

75
76
77
78
79
80
81
int
OptionDataTypeUtil::getDataTypeLen(const OptionDataType data_type) {
    switch (data_type) {
    case OPT_BOOLEAN_TYPE:
    case OPT_INT8_TYPE:
    case OPT_UINT8_TYPE:
        return (1);
82

83
84
85
    case OPT_INT16_TYPE:
    case OPT_UINT16_TYPE:
        return (2);
86

87
88
89
    case OPT_INT32_TYPE:
    case OPT_UINT32_TYPE:
        return (4);
90

91
92
    case OPT_IPV4_ADDRESS_TYPE:
        return (asiolink::V4ADDRESS_LEN);
93

94
95
    case OPT_IPV6_ADDRESS_TYPE:
        return (asiolink::V6ADDRESS_LEN);
96

97
98
99
100
101
102
    default:
        ;
    }
    return (0);
}

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const std::string&
OptionDataTypeUtil::getDataTypeName(const OptionDataType data_type) {
    return (OptionDataTypeUtil::instance().getDataTypeNameImpl(data_type));
}

const std::string&
OptionDataTypeUtil::getDataTypeNameImpl(const OptionDataType data_type) const {
    std::map<OptionDataType, std::string>::const_iterator data_type_it =
        data_type_names_.find(data_type);
    if (data_type_it != data_type_names_.end()) {
        return (data_type_it->second);
    }
    return (data_type_names_.find(OPT_UNKNOWN_TYPE)->second);
}

OptionDataTypeUtil&
OptionDataTypeUtil::instance() {
    static OptionDataTypeUtil instance;
    return (instance);
}

124
asiolink::IOAddress
125
OptionDataTypeUtil::readAddress(const std::vector<uint8_t>& buf,
126
                                const short family) {
127
128
129
    using namespace isc::asiolink;
    if (family == AF_INET) {
        if (buf.size() < V4ADDRESS_LEN) {
130
            isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
131
132
                      << " IPv4 address. Invalid buffer size: " << buf.size());
        }
133
134
        return (IOAddress::fromBytes(AF_INET, &buf[0]));
    } else if (family == AF_INET6) {
135
        if (buf.size() < V6ADDRESS_LEN) {
136
            isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
137
138
                      << " IPv6 address. Invalid buffer size: " << buf.size());
        }
139
        return (IOAddress::fromBytes(AF_INET6, &buf[0]));
140
141
142
143
144
145
146
147
148
    } else {
        isc_throw(BadDataTypeCast, "unable to read data from the buffer as"
                  "IP address. Invalid family: " << family);
    }
}

void
OptionDataTypeUtil::writeAddress(const asiolink::IOAddress& address,
                                 std::vector<uint8_t>& buf) {
149
150
151
    // @todo There is a ticket 2396 submitted, which adds the
    // functionality to return a buffer representation of
    // IOAddress. If so, this function can be simplified.
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    if (address.getAddress().is_v4()) {
        asio::ip::address_v4::bytes_type addr_bytes =
            address.getAddress().to_v4().to_bytes();
        // Increase the buffer size by the size of IPv4 address.
        buf.resize(buf.size() + addr_bytes.size());
        std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
                           buf.end());
    } else if (address.getAddress().is_v6()) {
        asio::ip::address_v6::bytes_type addr_bytes =
            address.getAddress().to_v6().to_bytes();
        // Incresase the buffer size by the size of IPv6 address.
        buf.resize(buf.size() + addr_bytes.size());
        std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
                           buf.end());
    } else {
        isc_throw(BadDataTypeCast, "the address " << address.toText()
                  << " is neither valid IPv4 not IPv6 address.");
    }
}

172
173
174
175
void
OptionDataTypeUtil::writeBinary(const std::string& hex_str,
                                std::vector<uint8_t>& buf) {
    // Binary value means that the value is encoded as a string
176
    // of hexadecimal digits. We need to decode this string
177
178
179
180
181
182
183
184
185
186
187
188
189
    // to the binary format here.
    OptionBuffer binary;
    try {
        util::encode::decodeHex(hex_str, binary);
    } catch (const Exception& ex) {
        isc_throw(BadDataTypeCast, "unable to cast " << hex_str
                  << " to binary data type: " << ex.what());
    }
    // Decode was successful so append decoded binary value
    // to the buffer.
    buf.insert(buf.end(), binary.begin(), binary.end());
}

190
191
192
193
194
195
196
197
198
199
200
201
bool
OptionDataTypeUtil::readBool(const std::vector<uint8_t>& buf) {
    if (buf.size() < 1) {
        isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
                  << " value. Invalid buffer size " << buf.size());
    }
    if (buf[0] == 1) {
        return (true);
    } else if (buf[0] == 0) {
        return (false);
    }
    isc_throw(BadDataTypeCast, "unable to read the buffer as boolean"
202
              << " value. Invalid value " << static_cast<int>(buf[0]));
203
204
}

205
206
207
void
OptionDataTypeUtil::writeBool(const bool value,
                              std::vector<uint8_t>& buf) {
208
    buf.push_back(static_cast<uint8_t>(value ? 1 : 0));
209
210
}

211
std::string
212
OptionDataTypeUtil::readFqdn(const std::vector<uint8_t>& buf) {
213
214
215
    // If buffer is empty emit an error.
    if (buf.empty()) {
        isc_throw(BadDataTypeCast, "unable to read FQDN from a buffer."
216
                  << " The buffer is empty.");
217
    }
218
    // Set up an InputBuffer so as we can use isc::dns::Name object to get the FQDN.
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
    isc::util::InputBuffer in_buf(static_cast<const void*>(&buf[0]), buf.size());
    try {
        // Try to create an object from the buffer. If exception is thrown
        // it means that the buffer doesn't hold a valid domain name (invalid
        // syntax).
        isc::dns::Name name(in_buf);
        return (name.toText());
    } catch (const isc::Exception& ex) {
        // Unable to convert the data in the buffer into FQDN.
        isc_throw(BadDataTypeCast, ex.what());
    }
}

void
OptionDataTypeUtil::writeFqdn(const std::string& fqdn,
                              std::vector<uint8_t>& buf) {
    try {
        isc::dns::Name name(fqdn);
        isc::dns::LabelSequence labels(name);
        if (labels.getDataLength() > 0) {
            size_t read_len = 0;
            const uint8_t* data = labels.getData(&read_len);
241
            buf.insert(buf.end(), data, data + read_len);
242
243
244
245
246
247
        }
    } catch (const isc::Exception& ex) {
        isc_throw(BadDataTypeCast, ex.what());
    }
}

248
249
250
251
252
253
254
std::string
OptionDataTypeUtil::readString(const std::vector<uint8_t>& buf) {
    std::string value;
    if (buf.size() > 0) {
        value.insert(value.end(), buf.begin(), buf.end());
    }
    return (value);
255
256
257
258
259
260
}

void
OptionDataTypeUtil::writeString(const std::string& value,
                                std::vector<uint8_t>& buf) {
    if (value.size() > 0) {
261
        buf.insert(buf.end(), value.begin(), value.end());
262
263
264
265
266
    }
}

} // end of isc::dhcp namespace
} // end of isc namespace