host_mgr.cc 16.5 KB
Newer Older
1
// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
2
//
3
4
5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6

7
#include <config.h>
8
9
10
#include <dhcpsrv/cfg_hosts.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/host_mgr.h>
11
#include <dhcpsrv/hosts_log.h>
12
#include <dhcpsrv/host_data_source_factory.h>
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

namespace {

/// @brief Convenience function returning a pointer to the hosts configuration.
///
/// This function is called by the @c HostMgr methods requiring access to the
/// host reservations specified in the DHCP server configuration.
///
/// @return A pointer to the const hosts reservation configuration.
isc::dhcp::ConstCfgHostsPtr getCfgHosts() {
    return (isc::dhcp::CfgMgr::instance().getCurrentCfg()->getCfgHosts());
}

} // end of anonymous namespace

namespace isc {
namespace dhcp {

using namespace isc::asiolink;

boost::scoped_ptr<HostMgr>&
HostMgr::getHostMgrPtr() {
    static boost::scoped_ptr<HostMgr> host_mgr_ptr;
    return (host_mgr_ptr);
}

void
40
HostMgr::create() {
41
    getHostMgrPtr().reset(new HostMgr());
42
}
43

44
45
46
47
48
49
50
51
52
void
HostMgr::addSource(const std::string& access) {
    HostDataSourceFactory::add(getHostMgrPtr()->alternate_sources_, access);
}

bool
HostMgr::delSource(const std::string& db_type) {
    return (HostDataSourceFactory::del(getHostMgrPtr()->alternate_sources_, db_type));
}
53

54
55
56
57
58
59
60
61
62
63
64
void
HostMgr::delAllSources() {
    getHostMgrPtr()->alternate_sources_.clear();
}

HostDataSourcePtr
HostMgr::getHostDataSource() const {
    if (alternate_sources_.empty()) {
        return (HostDataSourcePtr());
    }
    return (alternate_sources_[0]);
65
66
}

67
bool
68
HostMgr::checkCacheSource(bool logging) {
69
70
71
72
73
74
75
76
77
78
79
    if (getHostMgrPtr()->cache_ptr_) {
        return (true);
    }
    HostDataSourceList& sources = getHostMgrPtr()->alternate_sources_;
    if (sources.empty()) {
        return (false);
    }
    CacheHostDataSourcePtr cache_ptr =
        boost::dynamic_pointer_cast<CacheHostDataSource>(sources[0]);
    if (cache_ptr) {
        getHostMgrPtr()->cache_ptr_ = cache_ptr;
80
81
82
83
        if (logging) {
            LOG_INFO(hosts_logger, HOSTS_CFG_CACHE_HOST_DATA_SOURCE)
                .arg(cache_ptr->getType());
        }
84
85
86
87
88
        return (true);
    }
    return (false);
}

89
90
91
92
93
94
95
96
97
98
99
HostMgr&
HostMgr::instance() {
    boost::scoped_ptr<HostMgr>& host_mgr_ptr = getHostMgrPtr();
    if (!host_mgr_ptr) {
        create();
    }
    return (*host_mgr_ptr);
}

ConstHostCollection
HostMgr::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
100
    ConstHostCollection hosts = getCfgHosts()->getAll(hwaddr, duid);
101
102
103
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        ConstHostCollection hosts_plus = (*it)->getAll(hwaddr, duid);
104
105
106
        hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
    }
    return (hosts);
107
108
}

109
110
111
112
113
114
115
ConstHostCollection
HostMgr::getAll(const Host::IdentifierType& identifier_type,
                const uint8_t* identifier_begin,
                const size_t identifier_len) const {
    ConstHostCollection hosts = getCfgHosts()->getAll(identifier_type,
                                                      identifier_begin,
                                                      identifier_len);
116
117
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
118
        ConstHostCollection hosts_plus =
119
            (*it)->getAll(identifier_type, identifier_begin, identifier_len);
120
121
122
123
124
125
        hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
    }
    return (hosts);
}


126
127
ConstHostCollection
HostMgr::getAll4(const IOAddress& address) const {
128
    ConstHostCollection hosts = getCfgHosts()->getAll4(address);
129
130
131
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        ConstHostCollection hosts_plus = (*it)->getAll4(address);
132
133
        hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
    }
134
    return (hosts);
135
136
137
138
139
}

ConstHostPtr
HostMgr::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
              const DuidPtr& duid) const {
140
    ConstHostPtr host = getCfgHosts()->get4(subnet_id, hwaddr, duid);
141
142
143
144
145
146
147
148
    if (host || alternate_sources_.empty()) {
        return (host);
    }
    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID)
        .arg(subnet_id)
        .arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)")
        .arg(duid ? duid->toText() : "(duid)");
149
    for (auto it = alternate_sources_.begin();
150
         !host && it != alternate_sources_.end(); ++it) {
151
        if (hwaddr) {
152
            host = (*it)->get4(subnet_id, hwaddr, DuidPtr());
153
        }
154
155
156
        if (!host && duid) {
            host = (*it)->get4(subnet_id, HWAddrPtr(), duid);
        }
157
158
159
        if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
            cache(host);
        }
160
    }
161
162
163
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
164
    return (host);
165
166
}

167
ConstHostPtr
168
169
170
171
HostMgr::get4Any(const SubnetID& subnet_id,
                 const Host::IdentifierType& identifier_type,
                 const uint8_t* identifier_begin,
                 const size_t identifier_len) const {
172
173
    ConstHostPtr host = getCfgHosts()->get4(subnet_id, identifier_type,
                                            identifier_begin, identifier_len);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
174

175
    // Found it in the config file or there are no backends configured?
Tomek Mrugalski's avatar
Tomek Mrugalski committed
176
    // Then we're done here.
177
178
179
180
181
182
183
184
185
186
    if (host || alternate_sources_.empty()) {
        return (host);
    }

    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER)
        .arg(subnet_id)
        .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
                                       identifier_len));

Tomek Mrugalski's avatar
Tomek Mrugalski committed
187
188
    // Try to find a host in each configured backend. We return as soon
    // as we find first hit.
189
190
191
192
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        host = (*it)->get4(subnet_id, identifier_type,
                           identifier_begin, identifier_len);
193
194
195
196
197

        if (host) {
            LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
                      HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST)
                .arg(subnet_id)
198
199
                .arg(Host::getIdentifierAsText(identifier_type,
                                               identifier_begin,
200
                                               identifier_len))
201
                .arg((*it)->getType())
202
                .arg(host->toText());
203

204
205
206
            if (cache_ptr_ && (it != alternate_sources_.begin())) {
                cache(host);
            }
207
            return (host);
208
        }
209
    }
210
211
212
213
214
    LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
              HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_NULL)
        .arg(subnet_id)
        .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
                                       identifier_len));
215
    // @todo: remove this
216
217
218
219
    if (negative_caching_) {
        cacheNegative(subnet_id, SubnetID(0),
                      identifier_type, identifier_begin, identifier_len);
    }
220
221
222
    return (host);
}

223
224
225
226
227
228
229
230
231
232
233
234
235
ConstHostPtr
HostMgr::get4(const SubnetID& subnet_id,
              const Host::IdentifierType& identifier_type,
              const uint8_t* identifier_begin,
              const size_t identifier_len) const {
    ConstHostPtr host = get4Any(subnet_id, identifier_type,
                                identifier_begin, identifier_len);
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
    return (host);
}
    
236
237
238
239
ConstHostPtr
HostMgr::get4(const SubnetID& subnet_id,
              const asiolink::IOAddress& address) const {
    ConstHostPtr host = getCfgHosts()->get4(subnet_id, address);
240
241
242
243
244
245
246
    if (host || alternate_sources_.empty()) {
        return (host);
    }
    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4)
        .arg(subnet_id)
        .arg(address.toText());
247
    for (auto it = alternate_sources_.begin();
248
         !host && it != alternate_sources_.end(); ++it) {
249
        host = (*it)->get4(subnet_id, address);
250
251
252
        if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
            cache(host);
        }
253
    }
254
255
256
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
257
258
259
260
    return (host);
}


261
262
263
ConstHostPtr
HostMgr::get6(const SubnetID& subnet_id, const DuidPtr& duid,
               const HWAddrPtr& hwaddr) const {
264
    ConstHostPtr host = getCfgHosts()->get6(subnet_id, duid, hwaddr);
265
266
267
268
269
270
271
272
273
    if (host || alternate_sources_.empty()) {
        return (host);
    }
    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR)
        .arg(subnet_id)
        .arg(duid ? duid->toText() : "(duid)")
        .arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)");

274
    for (auto it = alternate_sources_.begin();
275
         !host && it != alternate_sources_.end(); ++it) {
276
        if (duid) {
277
            host = (*it)->get6(subnet_id, duid, HWAddrPtr());
278
279
        }
        if (!host && hwaddr) {
280
            host = (*it)->get6(subnet_id, DuidPtr(), hwaddr);
281
        }
282
283
284
        if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
            cache(host);
        }
285
    }
286
287
288
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
289
    return (host);
290
291
292
293
}

ConstHostPtr
HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
294
    ConstHostPtr host = getCfgHosts()->get6(prefix, prefix_len);
295
296
297
298
299
300
301
    if (host || alternate_sources_.empty()) {
        return (host);
    }
    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET6_PREFIX)
        .arg(prefix.toText())
        .arg(static_cast<int>(prefix_len));
302
    for (auto it = alternate_sources_.begin();
303
         !host && it != alternate_sources_.end(); ++it) {
304
        host = (*it)->get6(prefix, prefix_len);
305
306
307
        if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
            cache(host);
        }
308
    }
309
310
311
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
312
    return (host);
313
314
}

315
ConstHostPtr
316
317
318
319
HostMgr::get6Any(const SubnetID& subnet_id,
                 const Host::IdentifierType& identifier_type,
                 const uint8_t* identifier_begin,
                 const size_t identifier_len) const {
320
321
    ConstHostPtr host = getCfgHosts()->get6(subnet_id, identifier_type,
                                            identifier_begin, identifier_len);
322
323
324
325
326
327
328
329
330
331
    if (host || alternate_sources_.empty()) {
        return (host);
    }

    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER)
        .arg(subnet_id)
        .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
                                       identifier_len));

332
333
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
334

335
336
        host = (*it)->get6(subnet_id, identifier_type,
                           identifier_begin, identifier_len);
337
338

        if (host) {
339
340
341
342
343
344
                LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
                          HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST)
                    .arg(subnet_id)
                    .arg(Host::getIdentifierAsText(identifier_type,
                                                   identifier_begin,
                                                   identifier_len))
345
                    .arg((*it)->getType())
346
                    .arg(host->toText());
347

348
349
350
                if (cache_ptr_ && (it != alternate_sources_.begin())) {
                    cache(host);
                }
351
                return (host);
352
        }
353
    }
354
355
356
357
358
359
360

    LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
              HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL)
        .arg(subnet_id)
        .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
                                       identifier_len));

361
    // @todo: remove this
362
363
364
365
366
    if (negative_caching_) {
        cacheNegative(SubnetID(0), subnet_id,
                      identifier_type, identifier_begin, identifier_len);
    }

367
368
369
    return (host);
}

370
371
372
373
374
375
376
377
378
379
380
381
382
ConstHostPtr
HostMgr::get6(const SubnetID& subnet_id,
              const Host::IdentifierType& identifier_type,
              const uint8_t* identifier_begin,
              const size_t identifier_len) const {
    ConstHostPtr host = get6Any(subnet_id, identifier_type,
                                identifier_begin, identifier_len);
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
    return (host);
}

383
384
385
386
ConstHostPtr
HostMgr::get6(const SubnetID& subnet_id,
              const asiolink::IOAddress& addr) const {
    ConstHostPtr host = getCfgHosts()->get6(subnet_id, addr);
387
388
389
390
391
392
393
    if (host || alternate_sources_.empty()) {
        return (host);
    }
    LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
              HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6)
        .arg(subnet_id)
        .arg(addr.toText());
394
    for (auto it = alternate_sources_.begin();
395
         !host && it != alternate_sources_.end(); ++it) {
396
        host = (*it)->get6(subnet_id, addr);
397
398
399
        if (host && cache_ptr_ && (it != alternate_sources_.begin())) {
            cache(host);
        }
400
    }
401
402
403
    if (host && host->getNegative()) {
        return (ConstHostPtr());
    }
404
405
406
    return (host);
}

407
bool
408
HostMgr::add(const HostPtr& host) {
409
    if (alternate_sources_.empty()) {
410
411
        isc_throw(NoHostDataSourceManager, "Unable to add new host because there is "
                  "no hosts-database configured.");
412
    }
413
414
415
416
417
418
419
420
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        if ((*it)->add(host)) {
            return (true);
        }
    }
    // This should never happen as at least one backend implements addition.
    return (false);
421
422
}

423
424
bool
HostMgr::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
425
    if (alternate_sources_.empty()) {
426
427
        isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
                  "no hosts-database configured.");
428
429
    }

430
431
432
433
434
435
436
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        if ((*it)->del(subnet_id, addr)) {
            return (true);
        }
    }
    return (false);
437
438
439
440
441
}

bool
HostMgr::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
              const uint8_t* identifier_begin, const size_t identifier_len) {
442
    if (alternate_sources_.empty()) {
443
444
        isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
                  "no hosts-database configured.");
445
446
    }

447
448
449
450
451
452
453
454
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        if ((*it)->del4(subnet_id, identifier_type,
                        identifier_begin, identifier_len)) {
            return (true);
        }
    }
    return (false);
455
456
457
458
459
}

bool
HostMgr::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
              const uint8_t* identifier_begin, const size_t identifier_len) {
460
    if (alternate_sources_.empty()) {
461
462
463
464
        isc_throw(NoHostDataSourceManager, "unable to delete a host because there is "
                  "no alternate host data source present");
    }

465
466
467
468
469
470
471
472
    for (auto it = alternate_sources_.begin();
         it != alternate_sources_.end(); ++it) {
        if ((*it)->del6(subnet_id, identifier_type,
                        identifier_begin, identifier_len)) {
            return (true);
        }
    }
    return (false);
473
474
}

475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
void
HostMgr::cache(ConstHostPtr host) const {
    if (cache_ptr_) {
        // Replace any existing value.
        int overwrite = 0;
        // Don't check the result as it does not matter?
        cache_ptr_->insert(host, overwrite);
    }
}

void
HostMgr::cacheNegative(const SubnetID& ipv4_subnet_id,
                       const SubnetID& ipv6_subnet_id,
                       const Host::IdentifierType& identifier_type,
                       const uint8_t* identifier_begin,
                       const size_t identifier_len) const {
    if (cache_ptr_ && negative_caching_) {
        HostPtr host(new Host(identifier_begin, identifier_len,
                              identifier_type,
                              ipv4_subnet_id, ipv6_subnet_id,
                              IOAddress::IPV4_ZERO_ADDRESS()));
        host->setNegative(true);
        // Don't replace any existing value.
        int overwrite = -1;
        // nor matter if it fails.
        cache_ptr_->insert(host, overwrite);
    }
}

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