dhcid_49.cc 6.05 KB
Newer Older
1
// Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
Dima Volodin's avatar
Dima Volodin committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//
// 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 <stdint.h>
#include <string.h>

#include <exceptions/exceptions.h>

#include <util/buffer.h>
21
#include <util/encode/base64.h>
Dima Volodin's avatar
Dima Volodin committed
22
23
24
25
26
27
28
#include <dns/exceptions.h>
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>

using namespace std;
using namespace isc::util;
29
using namespace isc::util::encode;
Dima Volodin's avatar
Dima Volodin committed
30
31
32
33

// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE

34
35
void
DHCID::createFromLexer(MasterLexer& lexer) {
36
37
38
39
40
41
42
43
44
    string digest_txt = lexer.getNextToken(MasterToken::STRING).getString();
    while (true) {
        const MasterToken& token = lexer.getNextToken();
        if (token.getType() != MasterToken::STRING) {
            break;
        }
        digest_txt.append(token.getString());
    }
    lexer.ungetToken();
45
46
47
48
49
50
51
52
53
54
55
56
    decodeBase64(digest_txt, digest_);

    // RFC4701 states DNS software should consider the RDATA section to
    // be opaque, but there must be at least three bytes in the data:
    // < 2 octets >    Identifier type code
    // < 1 octet >     Digest type code
    if (digest_.size() < 3) {
        isc_throw(InvalidRdataLength, "DHCID length " << digest_.size() <<
                  " too short, need at least 3 bytes");
    }
}

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/// \brief Constructor from string.
///
/// \param dhcid_str A base-64 representation of the DHCID binary data.
/// The data is considered to be opaque, but a sanity check is performed.
///
/// <b>Exceptions</b>
///
/// \c dhcid_str must be a valid  BASE-64 string, otherwise an exception
/// of class \c isc::BadValue will be thrown;
/// the binary data should consist of at leat of 3 octets as per RFC4701:
///           < 2 octets >    Identifier type code
///           < 1 octet >     Digest type code
///           < n octets >    Digest (length depends on digest type)
/// If the data is less than 3 octets (i.e. it cannot contain id type code and
/// digest type code), an exception of class \c InvalidRdataLength is thrown.
72
DHCID::DHCID(const std::string& dhcid_str) {
73
74
75
76
    try {
        std::istringstream iss(dhcid_str);
        MasterLexer lexer;
        lexer.pushSource(iss);
77
78
79
80
81
82
        createFromLexer(lexer);
        // RFC4701 says we have to support white-space-separated substrings,
        // so we have to read to the end of input. Therefore, we can't detect
        // extra input past the end of the digest. OTOH, extra text is likely
        // to result in a base64 decoding error, so BadValue will be thrown in
        // that case.
83
84
85
    } catch (const MasterLexer::LexerError& ex) {
        isc_throw(InvalidRdataText, "Failed to construct DHCID from '" <<
                  dhcid_str << "': " << ex.what());
Dima Volodin's avatar
Dima Volodin committed
86
87
88
    }
}

89
90
91
92
93
94
95
96
97
98
99
100
101
102
/// \brief Constructor with a context of MasterLexer.
///
/// The \c lexer should point to the beginning of valid textual representation
/// of a DHCID RDATA.
///
/// \throw MasterLexer::LexerError General parsing error such as missing field.
///
/// \param lexer A \c MasterLexer object parsing a master file for the
/// RDATA to be created
DHCID::DHCID(MasterLexer& lexer, const Name*,
             MasterLoader::Options, MasterLoaderCallbacks&) {
    createFromLexer(lexer);
}

103
104
105
106
107
108
109
/// \brief Constructor from wire-format data.
///
/// \param buffer A buffer storing the wire format data.
/// \param rdata_len The length of the RDATA in bytes
///
/// <b>Exceptions</b>
/// \c InvalidRdataLength is thrown if \c rdata_len is than minimum of 3 octets
Dima Volodin's avatar
Dima Volodin committed
110
111
DHCID::DHCID(InputBuffer& buffer, size_t rdata_len) {
    if (rdata_len < 3) {
112
113
        isc_throw(InvalidRdataLength, "DHCID length " << rdata_len <<
                  " too short, need at least 3 bytes");
Dima Volodin's avatar
Dima Volodin committed
114
115
116
117
118
119
    }

    digest_.resize(rdata_len);
    buffer.readData(&digest_[0], rdata_len);
}

120
121
122
/// \brief The copy constructor.
///
/// This trivial copy constructor never throws an exception.
Dima Volodin's avatar
Dima Volodin committed
123
124
125
DHCID::DHCID(const DHCID& other) : Rdata(), digest_(other.digest_)
{}

126
127
128
/// \brief Render the \c DHCID in the wire format.
///
/// \param buffer An output buffer to store the wire data.
Dima Volodin's avatar
Dima Volodin committed
129
130
131
132
133
void
DHCID::toWire(OutputBuffer& buffer) const {
    buffer.writeData(&digest_[0], digest_.size());
}

134
135
136
137
138
/// \brief Render the \c DHCID in the wire format into a
/// \c MessageRenderer object.
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer in which the \c DHCID is to be stored.
Dima Volodin's avatar
Dima Volodin committed
139
140
141
142
143
void
DHCID::toWire(AbstractMessageRenderer& renderer) const {
    renderer.writeData(&digest_[0], digest_.size());
}

144
145
146
147
148
/// \brief Convert the \c DHCID to a string.
///
/// This method returns a \c std::string object representing the \c DHCID.
///
/// \return A string representation of \c DHCID.
Dima Volodin's avatar
Dima Volodin committed
149
150
string
DHCID::toText() const {
151
    return (encodeBase64(digest_));
Dima Volodin's avatar
Dima Volodin committed
152
153
}

154
155
156
/// \brief Compare two instances of \c DHCID RDATA.
///
/// See documentation in \c Rdata.
Dima Volodin's avatar
Dima Volodin committed
157
158
159
160
161
162
163
164
165
int
DHCID::compare(const Rdata& other) const {
    const DHCID& other_dhcid = dynamic_cast<const DHCID&>(other);

    size_t this_len = digest_.size();
    size_t other_len = other_dhcid.digest_.size();
    size_t cmplen = min(this_len, other_len);
    int cmp = memcmp(&digest_[0], &other_dhcid.digest_[0], cmplen);
    if (cmp != 0) {
166
        return (cmp);
Dima Volodin's avatar
Dima Volodin committed
167
    } else {
168
        return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1);
Dima Volodin's avatar
Dima Volodin committed
169
170
    }
}
171

172
173
174
/// \brief Accessor method to get the DHCID digest
///
/// \return A reference to the binary DHCID data
175
176
177
178
179
const std::vector<uint8_t>&
DHCID::getDigest() const {
    return (digest_);
}

Dima Volodin's avatar
Dima Volodin committed
180
181
// END_RDATA_NAMESPACE
// END_ISC_NAMESPACE