zone_data.cc 7.42 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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 <util/memory_segment.h>

17
#include <dns/name.h>
18
#include <dns/rrclass.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
19
#include <dns/rdataclass.h>
20

21
#include "rdataset.h"
22
#include "rdata_serialization.h"
23
#include "zone_data.h"
24
#include "segment_object_holder.h"
25

26
#include <boost/bind.hpp>
27
#include <boost/function.hpp>
28

29
#include <cassert>
30
#include <cstring>
31
#include <new>                  // for the placement new
32
#include <vector>
33

34
using namespace isc::dns;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
35
using namespace isc::dns::rdata;
36

37
38
39
40
namespace isc {
namespace datasrc {
namespace memory {

41
42
43
44
// Definition of a class static constant.  It's public and its address
// could be needed by applications, so we need an explicit definition.
const ZoneNode::Flags ZoneData::DNSSEC_SIGNED;

45
46
47
48
49
namespace {
void
rdataSetDeleter(RRClass rrclass, util::MemorySegment* mem_sgmt,
                RdataSet* rdataset_head)
{
50
    RdataSet* rdataset_next;
51
52
    for (RdataSet* rdataset = rdataset_head;
         rdataset != NULL;
53
54
55
         rdataset = rdataset_next)
    {
        rdataset_next = rdataset->getNext();
56
        RdataSet::destroy(*mem_sgmt, rdataset, rrclass);
57
58
    }
}
59
60
61
62
63
64
65

void
nullDeleter(RdataSet* rdataset_head) {
    assert(rdataset_head == NULL);
}
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
66
67
NSEC3Data*
NSEC3Data::create(util::MemorySegment& mem_sgmt,
68
                  const Name& zone_origin,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
69
                  const generic::NSEC3PARAM& rdata)
70
{
71
72
    return (NSEC3Data::create(mem_sgmt, zone_origin,
                              rdata.getHashalg(), rdata.getFlags(),
73
74
75
76
                              rdata.getIterations(), rdata.getSalt()));
}

NSEC3Data*
77
78
79
80
81
82
NSEC3Data::create(util::MemorySegment& mem_sgmt,
                  const Name& zone_origin,
                  const generic::NSEC3& rdata)
{
    return (NSEC3Data::create(mem_sgmt, zone_origin,
                              rdata.getHashalg(), rdata.getFlags(),
83
84
85
86
                              rdata.getIterations(), rdata.getSalt()));
}

NSEC3Data*
87
88
89
NSEC3Data::create(util::MemorySegment& mem_sgmt,
                  const Name& zone_origin,
                  uint8_t hashalg, uint8_t flags, uint16_t iterations,
90
                  const std::vector<uint8_t>& salt)
JINMEI Tatuya's avatar
JINMEI Tatuya committed
91
{
92
93
94
95
96
97
    // NSEC3Data allocation can throw.  To avoid leaking the tree, we manage
    // it in the holder.
    // Note: we won't add any RdataSet, so we use the NO-OP deleter
    // (with an assertion check for that).
    typedef boost::function<void(RdataSet*)> RdataSetDeleterType;
    detail::SegmentObjectHolder<ZoneTree, RdataSetDeleterType> holder(
98
99
        mem_sgmt, boost::bind(nullDeleter, _1));
    holder.set(ZoneTree::create(mem_sgmt, true));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
100

101
102
103
104
105
    ZoneTree* tree = holder.get();
    const ZoneTree::Result result =
        tree->insert(mem_sgmt, zone_origin, NULL);
    assert(result == ZoneTree::SUCCESS);

106
    const size_t salt_len = salt.size();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
107

108
    void* p = mem_sgmt.allocate(sizeof(NSEC3Data) + 1 + salt_len);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
109
    NSEC3Data* const param_data =
110
        new(p) NSEC3Data(holder.release(), hashalg, flags, iterations);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
111
    uint8_t* dp = param_data->getSaltBuf();
112
    *dp++ = salt_len;
113
    if (salt_len > 0) {
114
        std::memcpy(dp, &salt.at(0), salt_len); // use at for safety
115
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129

    return (param_data);
}

void
NSEC3Data::destroy(util::MemorySegment& mem_sgmt, NSEC3Data* data,
                   RRClass nsec3_class)
{
    ZoneTree::destroy(mem_sgmt, data->nsec3_tree_.get(),
                      boost::bind(rdataSetDeleter, nsec3_class, &mem_sgmt,
                                  _1));
    mem_sgmt.deallocate(data, sizeof(NSEC3Data) + 1 + data->getSaltLen());
}

130
131
132
133
134
135
136
137
void
NSEC3Data::insertName(util::MemorySegment& mem_sgmt, const Name& name,
                      ZoneNode** node)
{
    const ZoneTree::Result result = nsec3_tree_->insert(mem_sgmt, name, node);

    // This should be ensured by the API:
    assert((result == ZoneTree::SUCCESS ||
Mukund Sivaraman's avatar
Mukund Sivaraman committed
138
            result == ZoneTree::ALREADYEXISTS) && node != NULL);
139
140
}

141
142
143
144
namespace {
// A helper to convert a TTL value in network byte order and set it in
// ZoneData::min_ttl_.  We can use util::OutputBuffer, but copy the logic
// here to guarantee it is exception free.
145
146
147
// Note: essentially this function is a local (re)implementation of the
// standard htonl() library function, but we avoid relying on it in case it's
// not available (it's not in the C++ standard library).
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
void
setTTLInNetOrder(uint32_t val, uint32_t* result) {
    uint8_t buf[4];
    buf[0] = static_cast<uint8_t>((val & 0xff000000) >> 24);
    buf[1] = static_cast<uint8_t>((val & 0x00ff0000) >> 16);
    buf[2] = static_cast<uint8_t>((val & 0x0000ff00) >> 8);
    buf[3] = static_cast<uint8_t>(val & 0x000000ff);
    std::memcpy(result, buf, sizeof(*result));
}
}

ZoneData::ZoneData(ZoneTree* zone_tree, ZoneNode* origin_node) :
    zone_tree_(zone_tree), origin_node_(origin_node),
    min_ttl_(0)          // tentatively set to silence static checkers
{
    setTTLInNetOrder(RRTTL::MAX_TTL().getValue(), &min_ttl_);
}

166
167
ZoneData*
ZoneData::create(util::MemorySegment& mem_sgmt, const Name& zone_origin) {
168
169
    // ZoneTree::insert() and ZoneData allocation can throw.  See also
    // NSEC3Data::create().
170
171
    typedef boost::function<void(RdataSet*)> RdataSetDeleterType;
    detail::SegmentObjectHolder<ZoneTree, RdataSetDeleterType> holder(
172
173
        mem_sgmt, boost::bind(nullDeleter, _1));
    holder.set(ZoneTree::create(mem_sgmt, true));
174
175
176
177
178
179
180
181
182
183

    ZoneTree* tree = holder.get();
    ZoneNode* origin_node = NULL;
    const ZoneTree::Result result =
        tree->insert(mem_sgmt, zone_origin, &origin_node);
    assert(result == ZoneTree::SUCCESS);
    void* p = mem_sgmt.allocate(sizeof(ZoneData));
    ZoneData* zone_data = new(p) ZoneData(holder.release(), origin_node);

    return (zone_data);
184
185
}

186
187
188
189
190
191
192
ZoneData*
ZoneData::create(util::MemorySegment& mem_sgmt) {
    ZoneData* zone_data = create(mem_sgmt, Name::ROOT_NAME());
    zone_data->origin_node_->setFlag(EMPTY_ZONE);
    return (zone_data);
}

193
void
194
195
ZoneData::destroy(util::MemorySegment& mem_sgmt, ZoneData* zone_data,
                  RRClass zone_class)
196
197
198
199
{
    ZoneTree::destroy(mem_sgmt, zone_data->zone_tree_.get(),
                      boost::bind(rdataSetDeleter, zone_class, &mem_sgmt,
                                  _1));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
200
201
202
    if (zone_data->nsec3_data_) {
        NSEC3Data::destroy(mem_sgmt, zone_data->nsec3_data_.get(), zone_class);
    }
203
204
205
    mem_sgmt.deallocate(zone_data, sizeof(ZoneData));
}

206
207
208
209
210
211
212
213
void
ZoneData::insertName(util::MemorySegment& mem_sgmt, const Name& name,
                     ZoneNode** node)
{
    const ZoneTree::Result result = zone_tree_->insert(mem_sgmt, name, node);

    // This should be ensured by the API:
    assert((result == ZoneTree::SUCCESS ||
Mukund Sivaraman's avatar
Mukund Sivaraman committed
214
            result == ZoneTree::ALREADYEXISTS) && node != NULL);
215
216
}

217
218
219
220
221
void
ZoneData::setMinTTL(uint32_t min_ttl_val) {
    setTTLInNetOrder(min_ttl_val, &min_ttl_);
}

222
223
224
} // namespace memory
} // namespace datasrc
} // datasrc isc