Kea 2.2.0
lease_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <cc/data.h>
8#include <dhcp/hwaddr.h>
10#include <dhcpsrv/lease.h>
11#include <dhcpsrv/cfgmgr.h>
13#include <lease_parser.h>
14
15#include <config.h>
16
17using namespace std;
18using namespace isc::dhcp;
19using namespace isc::data;
20using namespace isc::asiolink;
21
22namespace isc {
23namespace lease_cmds {
24
27 const ConstElementPtr& lease_info,
28 bool& force_create) {
29 if (!lease_info) {
30 isc_throw(BadValue, "lease information missing");
31 }
32
33 // These are mandatory parameters.
34 IOAddress addr = getAddress(lease_info, "ip-address");
35 if (!addr.isV4()) {
36 isc_throw(BadValue, "Non-IPv4 address specified: " << addr);
37 }
38
39 // Not a most straightforward conversion, but it works.
40 string hwaddr_txt = getString(lease_info, "hw-address");
41 HWAddr hwaddr = HWAddr::fromText(hwaddr_txt);
42 HWAddrPtr hwaddr_ptr = HWAddrPtr(new HWAddr(hwaddr));
43
44 // Now sort out the subnet-id. If specified, it must have correct value.
45 // If not specified, Kea will try to sort it out.
46 SubnetID subnet_id = 0;
47 if (lease_info->contains("subnet-id")) {
48 subnet_id = getUint32(lease_info, "subnet-id");
49 }
50 ConstSubnet4Ptr subnet;
51 if (subnet_id) {
52 // If subnet-id is specified, it has to match.
53 subnet = cfg->getCfgSubnets4()->getBySubnetId(subnet_id);
54 if (!subnet) {
55 isc_throw(BadValue, "Invalid subnet-id: No IPv4 subnet with subnet-id="
56 << subnet_id << " currently configured.");
57 }
58
59 if (!subnet->inRange(addr)) {
60 isc_throw(BadValue, "The address " << addr.toText() << " does not belong "
61 "to subnet " << subnet->toText() << ", subnet-id=" << subnet_id);
62 }
63
64 } else {
65 // Subnet-id was not specified. Let's try to figure it out on our own.
66 subnet = cfg->getCfgSubnets4()->selectSubnet(addr);
67 if (!subnet) {
68 isc_throw(BadValue, "subnet-id not specified and failed to find a"
69 << " subnet for address " << addr);
70 }
71 subnet_id = subnet->getID();
72 }
73
74 // Client-id is optional.
75 ClientIdPtr client_id;
76 if (lease_info->contains("client-id")) {
77 string txt = getString(lease_info, "client-id");
78 client_id = ClientId::fromText(txt);
79 }
80
81 // These parameters are optional. If not specified, we'll derive them from
82 // the current subnet configuration, if possible.
83 uint32_t valid_lft = 0;
84 if (lease_info->contains("valid-lft")) {
85 valid_lft = getUint32(lease_info, "valid-lft");
86 } else {
87 valid_lft = subnet->getValid();
88 }
89
96 time_t cltt;
97 if (lease_info->contains("expire")) {
98 int64_t expire_time = getInteger(lease_info, "expire");
99 if (expire_time <= 0) {
100 isc_throw(BadValue , "expiration time must be positive for address "
101 << addr);
102
103 } else if (expire_time < valid_lft) {
104 isc_throw(BadValue, "expiration time must be greater than valid lifetime"
105 " for address " << addr);
106 }
107 cltt = static_cast<time_t>(expire_time - valid_lft);
108 } else {
109 cltt = time(NULL);
110 }
111
112 bool fqdn_fwd = false;
113 if (lease_info->contains("fqdn-fwd")) {
114 fqdn_fwd = getBoolean(lease_info, "fqdn-fwd");
115 }
116 bool fqdn_rev = false;
117 if (lease_info->contains("fqdn-rev")) {
118 fqdn_rev = getBoolean(lease_info, "fqdn-rev");
119 }
120 string hostname;
121 if (lease_info->contains("hostname")) {
122 hostname = getString(lease_info, "hostname");
123 }
124 if (hostname.empty() && (fqdn_fwd || fqdn_rev)) {
125 isc_throw(BadValue, "No hostname specified and either forward or reverse"
126 " fqdn was set to true.");
127 }
128
129 uint32_t state = 0;
130 if (lease_info->contains("state")) {
131 state = getUint8(lease_info, "state");
132 }
133
134 // Check if the state value is sane.
135 if (state > Lease::STATE_EXPIRED_RECLAIMED) {
136 isc_throw(BadValue, "Invalid state value: " << state << ", supported "
137 "values are: 0 (default), 1 (declined) and 2 (expired-reclaimed)");
138 }
139
140 // Handle user context.
141 ConstElementPtr ctx = lease_info->get("user-context");
142 if (ctx && (ctx->getType() != Element::map)) {
143 isc_throw(BadValue, "Invalid user context '" << ctx->str()
144 << "' is not a JSON map.");
145 }
146
147 // Handle comment.
148 ConstElementPtr comment = lease_info->get("comment");
149 if (comment) {
150 if (ctx && ctx->contains("comment")) {
151 isc_throw(BadValue, "Duplicated comment entry '" << comment->str()
152 << "' in user context '" << ctx->str() << "'");
153 }
154 ElementPtr copied;
155 if (ctx) {
156 copied = copy(ctx, 0);
157 } else {
158 copied = Element::createMap();
159 }
160 copied->set("comment", comment);
161 ctx = copied;
162 }
163
164 // Let's fabricate some data and we're ready to go.
165
166 Lease4Ptr l(new Lease4(addr, hwaddr_ptr, client_id, valid_lft,
167 cltt, subnet_id,
168 fqdn_fwd, fqdn_rev, hostname));
169 l->state_ = state;
170 l->setContext(ctx);
171
172 // Retrieve the optional flag indicating if the lease must be created when it
173 // doesn't exist during the update.
174 force_create = false;
175 if (lease_info->contains("force-create")) {
176 force_create = getBoolean(lease_info, "force-create");
177 }
178
179 return (l);
180}
181
184 const ConstElementPtr& lease_info,
185 bool& force_create) {
186 if (!lease_info) {
187 isc_throw(BadValue, "lease information missing");
188 }
189
190 // These are mandatory parameters.
191 IOAddress addr = getAddress(lease_info, "ip-address");
192 if (addr.isV4()) {
193 isc_throw(BadValue, "Non-IPv6 address specified: " << addr);
194 }
195
196 // Not a most straightforward conversion, but it works.
197 string duid_txt = getString(lease_info, "duid");
198 DUID duid = DUID::fromText(duid_txt);
199 DuidPtr duid_ptr = DuidPtr(new DUID(duid));
200
201 Lease::Type type = Lease::TYPE_NA;
202 uint8_t prefix_len = 128;
203 if (lease_info->contains("type")) {
204 string txt = getString(lease_info, "type");
205 if (txt == "IA_NA") {
206 type = Lease::TYPE_NA;
207 } else if (txt == "IA_TA") {
208 type = Lease::TYPE_TA;
209 } else if (txt == "IA_PD") {
210 type = Lease::TYPE_PD;
211
212 prefix_len = getUint8(lease_info, "prefix-len");
213 } else {
214 isc_throw(BadValue, "Incorrect lease type: " << txt << ", the only "
215 "supported values are: na, ta and pd");
216 }
217 }
218
219 // Now sort out the subnet-id. If specified, it must have correct value.
220 // If not specified, Kea will try to sort it out.
221 SubnetID subnet_id = 0;
222 if (lease_info->contains("subnet-id")) {
223 subnet_id = getUint32(lease_info, "subnet-id");
224 }
225
226 // Check if the subnet-id specified is sane.
227 ConstSubnet6Ptr subnet;
228 if (subnet_id) {
229 // If subnet-id is specified, it has to match.
230 subnet = cfg->getCfgSubnets6()->getBySubnetId(subnet_id);
231 if (!subnet) {
232 isc_throw(BadValue, "Invalid subnet-id: No IPv6 subnet with subnet-id="
233 << subnet_id << " currently configured.");
234 }
235
236 // Check if the address specified really belongs to the subnet.
237 if ((type == Lease::TYPE_NA) && !subnet->inRange(addr)) {
238 isc_throw(BadValue, "The address " << addr.toText() << " does not belong "
239 "to subnet " << subnet->toText() << ", subnet-id=" << subnet_id);
240 }
241
242 } else {
243 if (type != Lease::TYPE_NA) {
244 isc_throw(BadValue, "Subnet-id is 0 or not specified. This is allowed for"
245 " address leases only, not prefix leases.");
246 }
247 subnet = cfg->getCfgSubnets6()->selectSubnet(addr);
248 if (!subnet) {
249 isc_throw(BadValue, "subnet-id not specified and failed to find a "
250 "subnet for address " << addr);
251 }
252 subnet_id = subnet->getID();
253 }
254
255 uint32_t iaid = getUint32(lease_info, "iaid");
256
257 // Hw-address is optional in v6 leases.
258 HWAddrPtr hwaddr_ptr;
259 if (lease_info->contains("hw-address")) {
260 string hwaddr_txt = getString(lease_info, "hw-address");
261 HWAddr hwaddr = HWAddr::fromText(hwaddr_txt);
262 hwaddr_ptr = HWAddrPtr(new HWAddr(hwaddr));
263 }
264
265 // These parameters are optional. If not specified, we'll derive them
266 // from the current subnet configuration, if possible.
267 uint32_t valid_lft = 0;
268 if (lease_info->contains("valid-lft")) {
269 valid_lft = getUint32(lease_info, "valid-lft");
270 } else {
271 valid_lft = subnet->getValid();
272 }
273
274 // These parameters are optional. If not specified, we'll derive them
275 // from the current subnet configuration, if possible.
276 uint32_t pref_lft = 0;
277 if (lease_info->contains("preferred-lft")) {
278 pref_lft = getUint32(lease_info, "preferred-lft");
279 } else {
280 pref_lft = subnet->getValid();
281 }
282
289 time_t cltt;
290 if (lease_info->contains("expire")) {
291 int64_t expire_time = getInteger(lease_info, "expire");
292 if (expire_time <= 0) {
293 isc_throw(BadValue , "expiration time must be positive for address "
294 << addr);
295
296 } else if (expire_time < valid_lft) {
297 isc_throw(BadValue, "expiration time must be greater than valid lifetime"
298 " for address " << addr);
299 }
300
301 cltt = static_cast<time_t>(expire_time - valid_lft);
302 } else {
303 cltt = time(NULL);
304 }
305
306 bool fqdn_fwd = false;
307 if (lease_info->contains("fqdn-fwd")) {
308 fqdn_fwd = getBoolean(lease_info, "fqdn-fwd");
309 }
310 bool fqdn_rev = false;
311 if (lease_info->contains("fqdn-rev")) {
312 fqdn_rev = getBoolean(lease_info, "fqdn-rev");
313 }
314 string hostname;
315 if (lease_info->contains("hostname")) {
316 hostname = getString(lease_info, "hostname");
317 }
318 if (hostname.empty() && (fqdn_fwd || fqdn_rev)) {
319 isc_throw(BadValue, "No hostname specified and either forward or reverse"
320 " fqdn was set to true.");
321 }
322
323 uint32_t state = 0;
324 if (lease_info->contains("state")) {
325 state = getUint8(lease_info, "state");
326 }
327
328 // Check if the state value is sane.
329 if (state > Lease::STATE_EXPIRED_RECLAIMED) {
330 isc_throw(BadValue, "Invalid state value: " << state << ", supported "
331 "values are: 0 (default), 1 (declined) and 2 (expired-reclaimed)");
332 }
333
334 if ((state == Lease::STATE_DECLINED) && (type == Lease::TYPE_PD)) {
336 "Invalid declined state for PD prefix.");
337 }
338
339 // Handle user context.
340 ConstElementPtr ctx = lease_info->get("user-context");
341 if (ctx && (ctx->getType() != Element::map)) {
342 isc_throw(BadValue, "Invalid user context '" << ctx->str()
343 << "' is not a JSON map.");
344 }
345
346 // Handle comment.
347 ConstElementPtr comment = lease_info->get("comment");
348 if (comment) {
349 if (ctx && ctx->contains("comment")) {
350 isc_throw(BadValue, "Duplicated comment entry '" << comment->str()
351 << "' in user context '" << ctx->str() << "'");
352 }
353 ElementPtr copied;
354 if (ctx) {
355 copied = copy(ctx, 0);
356 } else {
357 copied = Element::createMap();
358 }
359 copied->set("comment", comment);
360 ctx = copied;
361 }
362
363 // Let's fabricate some data and we're ready to go.
364
365 Lease6Ptr l(new Lease6(type, addr, duid_ptr, iaid, pref_lft, valid_lft,
366 subnet_id, fqdn_fwd, fqdn_rev, hostname,
367 hwaddr_ptr, prefix_len));
368 l->cltt_ = cltt;
369 l->state_ = state;
370 l->setContext(ctx);
371
372 // Retrieve the optional flag indicating if the lease must be created when it
373 // doesn't exist during the update.
374 force_create = false;
375 if (lease_info->contains("force-create")) {
376 force_create = getBoolean(lease_info, "force-create");
377 }
378
379 return (l);
380}
381
382} // end of namespace lease_cmds
383} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown if a function is called in a prohibited way.
uint8_t getUint8(ConstElementPtr scope, const std::string &name)
Get an uint8_t value.
static isc::asiolink::IOAddress getAddress(const ConstElementPtr &scope, const std::string &name)
Returns a IOAddress parameter from a scope.
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
virtual isc::dhcp::Lease4Ptr parse(isc::dhcp::ConstSrvConfigPtr &cfg, const isc::data::ConstElementPtr &lease_info, bool &force_create)
Parses Element tree and tries to convert to Lease4.
Definition: lease_parser.cc:26
virtual isc::dhcp::Lease6Ptr parse(isc::dhcp::ConstSrvConfigPtr &cfg, const isc::data::ConstElementPtr &lease_info, bool &force_create)
Parses Element tree and tries to convert to Lease4.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1360
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
boost::shared_ptr< const SrvConfig > ConstSrvConfigPtr
Const pointer to the SrvConfig.
Definition: srv_config.h:1168
boost::shared_ptr< const Subnet6 > ConstSubnet6Ptr
A const pointer to a Subnet6 object.
Definition: subnet.h:666
boost::shared_ptr< const Subnet4 > ConstSubnet4Ptr
A const pointer to a Subnet4 object.
Definition: subnet.h:518
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:503
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition: duid.h:103
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:284
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
Structure that holds a lease for IPv4 address.
Definition: lease.h:295
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:514
Type
Type of lease or pool.
Definition: lease.h:46