labelsequence.h 11 KB
Newer Older
Jelte Jansen's avatar
Jelte Jansen committed
1
// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
Jelte Jansen's avatar
Jelte Jansen committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
// 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.

#ifndef __LABELSEQUENCE_H
#define __LABELSEQUENCE_H 1

#include <dns/name.h>
#include <util/buffer.h>

namespace isc {
namespace dns {

Jelte Jansen's avatar
Jelte Jansen committed
24
25
26
/// \brief Light-weight Accessor to Name object
///
/// The purpose of this class is to easily match Names and parts of Names,
Jelte Jansen's avatar
Jelte Jansen committed
27
/// without needing to copy the underlying data on each label strip.
Jelte Jansen's avatar
Jelte Jansen committed
28
29
30
31
32
33
///
/// It can only work on existing Name objects, and the Name object MUST
/// remain in scope during the entire lifetime of its associated
/// LabelSequence(s).
///
/// Upon creation of a LabelSequence, it records the offsets of the
Jelte Jansen's avatar
Jelte Jansen committed
34
35
36
37
/// labels in the wireformat data of the Name. When stripLeft() or
/// stripRight() is called on the LabelSequence, no changes in the
/// Name's data occur, but the internal pointers of the
/// LabelSequence are modified.
Jelte Jansen's avatar
Jelte Jansen committed
38
39
40
41
42
///
/// LabelSequences can be compared to other LabelSequences, and their
/// data can be requested (which then points to part of the original
/// data of the associated Name object).
///
Jelte Jansen's avatar
Jelte Jansen committed
43
class LabelSequence {
44
45
46
    // Name calls the private toText(bool) method of LabelSequence.
    friend std::string Name::toText(bool) const;

Jelte Jansen's avatar
Jelte Jansen committed
47
public:
Jelte Jansen's avatar
Jelte Jansen committed
48
49
50
51
52
53
54
55
    /// \brief Constructs a LabelSequence for the given name
    ///
    /// \note The associated Name MUST remain in scope during the lifetime
    /// of this LabelSequence, since getData() refers to data from the
    /// Name object (the only data the LabelSequence stores are pointers
    /// to the labels in the Name object).
    ///
    /// \param name The Name to construct a LabelSequence for
Jelte Jansen's avatar
Jelte Jansen committed
56
    explicit LabelSequence(const Name& name):
57
58
59
                                     data_(&name.ndata_[0]),
                                     offsets_(&name.offsets_[0]),
                                     offsets_size_(name.offsets_.size()),
Jelte Jansen's avatar
Jelte Jansen committed
60
61
62
                                     first_label_(0),
                                     last_label_(name.getLabelCount())
    {}
Jelte Jansen's avatar
Jelte Jansen committed
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    /// \brief Constructs a LabelSequence for the given data
    ///
    /// \note The associated data MUST remain in scope during the lifetime
    /// of this LabelSequence, since only the pointers are copied.
    ///
    /// \note No validation is done on the given data upon construction;
    ///       use with care.
    ///
    /// \param data The Name data, in wire format
    /// \param offsets The offsets of the labels in the Name, as given
    ///        by the Name object or another LabelSequence
    /// \param offsets_size The size of the offsets data
    LabelSequence(const uint8_t* data,
                  const uint8_t* offsets,
                  size_t offsets_size) : data_(data),
                                         offsets_(offsets),
                                         offsets_size_(offsets_size),
                                         first_label_(0),
                                         last_label_(offsets_size_)
    {}

Jelte Jansen's avatar
Jelte Jansen committed
85
86
87
88
89
90
91
92
93
94
    /// \brief Return the wire-format data for this LabelSequence
    ///
    /// The data, is returned as a pointer to the original wireformat
    /// data of the original Name object, and the given len value is
    /// set to the number of octets that match this labelsequence.
    ///
    /// \note The data pointed to is only valid if the original Name
    /// object is still in scope
    ///
    /// \param len Pointer to a size_t where the length of the data
Jelte Jansen's avatar
Jelte Jansen committed
95
    ///        will be stored (in number of octets)
Jelte Jansen's avatar
Jelte Jansen committed
96
    /// \return Pointer to the wire-format data of this label sequence
97
    const uint8_t* getData(size_t* len) const;
Jelte Jansen's avatar
Jelte Jansen committed
98

99
100
101
102
103
104
105
106
107
108
    /// \brief Return the offset data for this LabelSequence
    ///
    /// The offsets are returned in the <code>placeholder</code> array.
    ///
    /// \param len Pointer to a size_t where the number of offsets
    ///        will be stored
    /// \param placeholder Array where the offset data will be returned
    void getOffsetData(size_t* len,
                       uint8_t placeholder[Name::MAX_LABELS]) const;

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    /// \brief Return the length of the wire-format data of this LabelSequence
    ///
    /// This method returns the number of octets for the data that would
    /// be returned by the \c getData() method.
    ///
    /// Note that the return value of this method is always positive.
    /// Note also that if the return value of this method is 1, it means the
    /// sequence consists of the null label, i.e., a single "dot", and vice
    /// versa.
    ///
    /// \note The data pointed to is only valid if the original Name
    /// object is still in scope
    ///
    /// \return The length of the data of the label sequence in octets.
    size_t getDataLength() const;

125
    /// \brief Compares two label sequences for equality.
Jelte Jansen's avatar
Jelte Jansen committed
126
127
    ///
    /// Performs a (optionally case-insensitive) comparison between this
128
    /// LabelSequence and another LabelSequence for equality.
Jelte Jansen's avatar
Jelte Jansen committed
129
130
131
132
133
    ///
    /// \param other The LabelSequence to compare with
    /// \param case_sensitive If true, comparison is case-insensitive
    /// \return true if The label sequences consist are the same length,
    ///         and contain the same data.
Jelte Jansen's avatar
Jelte Jansen committed
134
135
    bool equals(const LabelSequence& other, bool case_sensitive = false) const;

136
137
138
139
140
141
142
143
144
145
146
147
    /// \brief Compares two label sequences.
    ///
    /// Performs a (optionally case-insensitive) comparison between this
    /// LabelSequence and another LabelSequence.
    ///
    /// \param other The LabelSequence to compare with
    /// \param case_sensitive If true, comparison is case-insensitive
    /// \return a <code>NameComparisonResult</code> object representing the
    /// comparison result.
    NameComparisonResult compare(const LabelSequence& other,
                                 bool case_sensitive = false) const;

Jelte Jansen's avatar
Jelte Jansen committed
148
    /// \brief Remove labels from the front of this LabelSequence
Jelte Jansen's avatar
Jelte Jansen committed
149
    ///
Jelte Jansen's avatar
Jelte Jansen committed
150
151
152
    /// \note No actual memory is changed, this operation merely updates the
    /// internal pointers based on the offsets in the Name object.
    ///
153
    /// \exception OutOfRange if i is greater than or equal to the number
Jelte Jansen's avatar
Jelte Jansen committed
154
155
156
    ///           of labels currently pointed to by this LabelSequence
    ///
    /// \param i The number of labels to remove.
Jelte Jansen's avatar
Jelte Jansen committed
157
    void stripLeft(size_t i);
Jelte Jansen's avatar
Jelte Jansen committed
158
159

    /// \brief Remove labels from the end of this LabelSequence
Jelte Jansen's avatar
Jelte Jansen committed
160
161
    ///
    /// \note No actual memory is changed, this operation merely updates the
Jelte Jansen's avatar
Jelte Jansen committed
162
    /// internal pointers based on the offsets in the Name object.
Jelte Jansen's avatar
Jelte Jansen committed
163
    ///
164
    /// \exception OutOfRange if i is greater than or equal to the number
Jelte Jansen's avatar
Jelte Jansen committed
165
    ///           of labels currently pointed to by this LabelSequence
Jelte Jansen's avatar
Jelte Jansen committed
166
    ///
Jelte Jansen's avatar
Jelte Jansen committed
167
    /// \param i The number of labels to remove.
Jelte Jansen's avatar
Jelte Jansen committed
168
    void stripRight(size_t i);
Jelte Jansen's avatar
Jelte Jansen committed
169

Jelte Jansen's avatar
Jelte Jansen committed
170
171
172
    /// \brief Returns the current number of labels for this LabelSequence
    ///
    /// \return The number of labels
173
    size_t getLabelCount() const { return (last_label_ - first_label_); }
174

175
176
177
178
    /// \brief Convert the LabelSequence to a string.
    ///
    /// This method returns a <code>std::string</code> object representing the
    /// LabelSequence as a string.  The returned string ends with a dot
179
    /// '.' if the label sequence is absolute.
180
181
182
183
184
185
186
187
188
    ///
    /// This function assumes the underlying name is in proper
    /// uncompressed wire format.  If it finds an unexpected label
    /// character including compression pointer, an exception of class
    /// \c BadLabelType will be thrown.  In addition, if resource
    /// allocation for the result string fails, a corresponding standard
    /// exception will be thrown.
    //
    /// \return a string representation of the <code>LabelSequence</code>.
189
    std::string toText() const;
190

191
private:
192
193
    /// \brief Convert the LabelSequence to a string.
    ///
194
195
196
197
    /// This method is a version of the zero-argument toText() method,
    /// that accepts a <code>omit_final_dot</code> argument. The
    /// returned string ends with a dot '.' if
    /// <code>omit_final_dot</code> is <code>false</code>.
198
    ///
199
200
201
    /// This method is used as a helper for <code>Name::toText()</code>
    /// only.
    ///
202
    /// \param omit_final_dot whether to omit the trailing dot in the output.
203
    /// \return a string representation of the <code>LabelSequence</code>.
204
    std::string toText(bool omit_final_dot) const;
205

206
public:
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
    /// \brief Calculate a simple hash for the label sequence.
    ///
    /// This method calculates a hash value for the label sequence as binary
    /// data.  If \c case_sensitive is false, it ignores the case stored in
    /// the labels; specifically, it normalizes the labels by converting all
    /// upper case characters to lower case ones and calculates the hash value
    /// for the result.
    ///
    /// This method is intended to provide a lightweight way to store a
    /// relatively small number of label sequences in a hash table.
    /// For this reason it only takes into account data up to 16 octets
    /// (16 was derived from BIND 9's implementation).  Also, the function does
    /// not provide any unpredictability; a specific sequence will always have
    /// the same hash value.  It should therefore not be used in the context
    /// where an untrusted third party can mount a denial of service attack by
    /// forcing the application to create a very large number of label
    /// sequences that have the same hash value and expected to be stored in
    /// a hash table.
    ///
    /// \exception None
    ///
    /// \param case_sensitive
    /// \return A hash value for this label sequence.
    size_t getHash(bool case_sensitive) const;

Jelte Jansen's avatar
Jelte Jansen committed
232
233
234
235
236
    /// \brief Checks whether the label sequence is absolute
    ///
    /// \return true if the last label is the root label
    bool isAbsolute() const;

Jelte Jansen's avatar
Jelte Jansen committed
237
private:
238
239
240
    const uint8_t* data_;
    const uint8_t* offsets_;
    size_t offsets_size_;
Jelte Jansen's avatar
Jelte Jansen committed
241
242
243
244
245
    size_t first_label_;
    size_t last_label_;
};


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
///
/// \brief Insert the label sequence as a string into stream.
///
/// This method convert the \c label_sequence into a string and inserts
/// it into the output stream \c os.
///
/// This function overloads the global operator<< to behave as described in
/// ostream::operator<< but applied to \c LabelSequence objects.
///
/// \param os A \c std::ostream object on which the insertion operation is
/// performed.
/// \param name The \c LabelSequence object output by the operation.
/// \return A reference to the same \c std::ostream object referenced by
/// parameter \c os after the insertion operation.
std::ostream&
operator<<(std::ostream& os, const LabelSequence& label_sequence);

Jelte Jansen's avatar
Jelte Jansen committed
263
264
265
266
} // end namespace dns
} // end namespace isc

#endif