Kea 1.5.0
pkt_send_co.cc
Go to the documentation of this file.
1// Copyright (C) 2013-2015,2017 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
8
9#include <config.h>
10#include <asiolink/io_address.h>
11#include <hooks/hooks.h>
12#include <dhcp/dhcp4.h>
13#include <dhcp/dhcp6.h>
14#include <dhcp/option_string.h>
15#include <dhcp/option_custom.h>
16#include <dhcp/option6_ia.h>
17#include <dhcp/option6_iaaddr.h>
20#include <dhcp/pkt4.h>
21#include <dhcp/pkt6.h>
22#include <user_chk.h>
23
24using namespace isc::dhcp;
25using namespace isc::hooks;
26using namespace user_chk;
27using namespace std;
28
29// prototypes for local helper functions
30void generate_output_record(const std::string& id_type_str,
31 const std::string& id_val_str,
32 const std::string& addr_str,
33 const bool& registered);
34std::string getV6AddrStr (Pkt6Ptr response);
35std::string getAddrStrIA_NA(OptionPtr options);
36std::string getAddrStrIA_PD(OptionPtr options);
37bool checkIAStatus(boost::shared_ptr<Option6IA>& ia_opt);
38
39void add4Options(Pkt4Ptr& response, const UserPtr& user);
40void add4Option(Pkt4Ptr& response, uint8_t opt_code, std::string& opt_value);
41void add6Options(Pkt6Ptr& response, const UserPtr& user);
42void add6Option(OptionPtr& vendor, uint8_t opt_code, std::string& opt_value);
45
46// Functions accessed by the hooks framework use C linkage to avoid the name
47// mangling that accompanies use of the C++ compiler as well as to avoid
48// issues related to namespaces.
49extern "C" {
50
70 try {
71 Pkt4Ptr response;
72 handle.getArgument("response4", response);
73
74 uint8_t packet_type = response->getType();
75 if (packet_type == DHCPNAK) {
76 std::cout << "DHCP UserCheckHook : pkt4_send"
77 << "skipping packet type: "
78 << static_cast<int>(packet_type) << std::endl;
79 return (0);
80 }
81
82 // Get the user id saved from the query packet.
83 HWAddrPtr hwaddr;
84 handle.getContext(query_user_id_label, hwaddr);
85
86 // Get registered_user pointer.
87 UserPtr registered_user;
88 handle.getContext(registered_user_label, registered_user);
89
90 // Fetch the lease address.
91 isc::asiolink::IOAddress addr = response->getYiaddr();
92
93 if (registered_user) {
94 // add options based on user
95 // then generate registered output record
96 std::cout << "DHCP UserCheckHook : pkt4_send registered_user is: "
97 << registered_user->getUserId() << std::endl;
98
99 // Add the outcome entry to the output file.
101 addr.toText(), true);
102 add4Options(response, registered_user);
103 } else {
104 // add default options based
105 // then generate not registered output record
106 std::cout << "DHCP UserCheckHook : pkt4_send no registered_user"
107 << std::endl;
108 // Add the outcome entry to the output file.
110 addr.toText(), false);
111
112 add4Options(response, getDefaultUser4());
113 }
114 } catch (const std::exception& ex) {
115 std::cout << "DHCP UserCheckHook : pkt4_send unexpected error: "
116 << ex.what() << std::endl;
117 return (1);
118 }
119
120 return (0);
121}
122
141 try {
142 Pkt6Ptr response;
143 handle.getArgument("response6", response);
144
145 // Fetch the lease address as a string
146 std::string addr_str = getV6AddrStr(response);
147 if (addr_str.empty()) {
148 // packet did not contain an address, must be failed.
149 std::cout << "pkt6_send: Skipping packet address is blank"
150 << std::endl;
151 return (0);
152 }
153
154 // Get the user id saved from the query packet.
155 DuidPtr duid;
156 handle.getContext(query_user_id_label, duid);
157
158 // Get registered_user pointer.
159 UserPtr registered_user;
160 handle.getContext(registered_user_label, registered_user);
161
162 if (registered_user) {
163 // add options based on user
164 // then generate registered output record
165 std::cout << "DHCP UserCheckHook : pkt6_send registered_user is: "
166 << registered_user->getUserId() << std::endl;
167 // Add the outcome entry to the output file.
169 addr_str, true);
170 add6Options(response, registered_user);
171 } else {
172 // add default options based
173 // then generate not registered output record
174 std::cout << "DHCP UserCheckHook : pkt6_send no registered_user"
175 << std::endl;
176 // Add the outcome entry to the output file.
178 addr_str, false);
179 add6Options(response, getDefaultUser6());
180 }
181 } catch (const std::exception& ex) {
182 std::cout << "DHCP UserCheckHook : pkt6_send unexpected error: "
183 << ex.what() << std::endl;
184 return (1);
185 }
186
187 return (0);
188}
189
190} // extern C
191
203void add4Options(Pkt4Ptr& response, const UserPtr& user) {
204 // If user is null, do nothing.
205 if (!user) {
206 return;
207 }
208
209 // If the user has bootfile property, update it in the response.
210 std::string opt_value = user->getProperty("bootfile");
211 if (!opt_value.empty()) {
212 std::cout << "DHCP UserCheckHook : add4Options "
213 << "adding boot file:" << opt_value << std::endl;
214
215 // Add boot file to packet.
216 add4Option(response, DHO_BOOT_FILE_NAME, opt_value);
217
218 // Boot file also goes in file field.
219 response->setFile((const uint8_t*)(opt_value.c_str()),
220 opt_value.length());
221 }
222
223 // If the user has tftp server property, update it in the response.
224 opt_value = user->getProperty("tftp_server");
225 if (!opt_value.empty()) {
226 std::cout << "DHCP UserCheckHook : add4Options "
227 << "adding TFTP server:" << opt_value << std::endl;
228
229 // Add tftp server option to packet.
230 add4Option(response, DHO_TFTP_SERVER_NAME, opt_value);
231 }
232 // add next option here
233}
234
240void add4Option(Pkt4Ptr& response, uint8_t opt_code, std::string& opt_value) {
241 // Remove the option if it exists.
242 OptionPtr opt = response->getOption(opt_code);
243 if (opt) {
244 response->delOption(opt_code);
245 }
246
247 // Now add the option.
248 opt.reset(new OptionString(Option::V4, opt_code, opt_value));
249 response->addOption(opt);
250}
251
252
264void add6Options(Pkt6Ptr& response, const UserPtr& user) {
265 if (!user) {
266 return;
267 }
268
271 OptionPtr vendor = response->getOption(D6O_VENDOR_OPTS);
272 if (!vendor) {
273 std::cout << "DHCP UserCheckHook : add6Options "
274 << "response has no vendor option to update" << std::endl;
275 return;
276 }
277
278 // If the user defines bootfile, set the option in response.
279 std::string opt_value = user->getProperty("bootfile");
280 if (!opt_value.empty()) {
281 std::cout << "DHCP UserCheckHook : add6Options "
282 << "adding boot file:" << opt_value << std::endl;
283 add6Option(vendor, DOCSIS3_V6_CONFIG_FILE, opt_value);
284 }
285
286 // If the user defines tftp server, set the option in response.
287 opt_value = user->getProperty("tftp_server");
288 if (!opt_value.empty()) {
289 std::cout << "DHCP UserCheckHook : add6Options "
290 << "adding tftp server:" << opt_value << std::endl;
291
292 add6Option(vendor, DOCSIS3_V6_TFTP_SERVERS, opt_value);
293 }
294
295 // add next option here
296}
297
303void add6Option(OptionPtr& vendor, uint8_t opt_code, std::string& opt_value) {
304 vendor->delOption(opt_code);
305 OptionPtr option(new OptionString(Option::V6, opt_code, opt_value));
306 vendor->addOption(option);
307}
308
309
355void generate_output_record(const std::string& id_type_str,
356 const std::string& id_val_str,
357 const std::string& addr_str,
358 const bool& registered)
359{
360 user_chk_output << "id_type=" << id_type_str << std::endl
361 << "client=" << id_val_str << std::endl
362 << "addr=" << addr_str << std::endl
363 << "registered=" << (registered ? "yes" : "no")
364 << std::endl
365 << std::endl; // extra line in between
366
367 // @todo Flush is here to ensure output is immediate for demo purposes.
368 // Performance would generally dictate not using it.
369 flush(user_chk_output);
370}
371
384std::string getV6AddrStr(Pkt6Ptr response) {
385 OptionPtr tmp = response->getOption(D6O_IA_NA);
386 if (tmp) {
387 return(getAddrStrIA_NA(tmp));
388 }
389
390 // IA_NA not there so try IA_PD
391 tmp = response->getOption(D6O_IA_PD);
392 if (!tmp) {
393 isc_throw (isc::BadValue, "Response has neither IA_NA nor IA_PD");
394 }
395
396 return(getAddrStrIA_PD(tmp));
397}
398
410std::string getAddrStrIA_NA(OptionPtr options) {
411 boost::shared_ptr<Option6IA> ia =
412 boost::dynamic_pointer_cast<Option6IA>(options);
413
414 if (!ia) {
415 isc_throw (isc::BadValue, "D6O_IA_NA option invalid");
416 }
417
418 // If status indicates a failure return a blank string.
419 if (!checkIAStatus(ia)) {
420 return (std::string(""));
421 }
422
423 options = ia->getOption(D6O_IAADDR);
424 if (!options) {
425 isc_throw (isc::BadValue, "D6O_IAADDR option missing");
426 }
427
428 boost::shared_ptr<Option6IAAddr> addr_option;
429 addr_option = boost::dynamic_pointer_cast<Option6IAAddr>(options);
430 if (!addr_option) {
431 isc_throw (isc::BadValue, "D6O_IAADDR Option6IAAddr missing");
432 }
433
434 isc::asiolink::IOAddress addr = addr_option->getAddress();
435 return (addr.toText());
436}
437
449std::string getAddrStrIA_PD(OptionPtr options) {
450 boost::shared_ptr<Option6IA> ia =
451 boost::dynamic_pointer_cast<Option6IA>(options);
452
453 // Make sure we have an IA_PD option.
454 if (!ia) {
455 isc_throw (isc::BadValue, "D6O_IA_PD option invalid");
456 }
457
458 // Check the response for success status. If it isn't a success response
459 // there will not be a lease prefix value which is denoted by returning
460 // an empty string.
461 if (!checkIAStatus(ia)) {
462 return (std::string(""));
463 }
464
465 // Get the prefix option the IA_PD option.
466 options = ia->getOption(D6O_IAPREFIX);
467 if (!options) {
468 isc_throw(isc::BadValue, "D60_IAPREFIX option is missing");
469 }
470
471 boost::shared_ptr<Option6IAPrefix> addr_option;
472 addr_option = boost::dynamic_pointer_cast<Option6IAPrefix>(options);
473 if (!addr_option) {
474 isc_throw (isc::BadValue, "D6O_IA_PD addr option bad");
475 }
476
477 // Get the address and prefix length values.
478 isc::asiolink::IOAddress addr = addr_option->getAddress();
479 uint8_t prefix_len = addr_option->getLength();
480
481 // Build the output string and return it.
482 stringstream buf;
483 buf << addr.toText() << "/" << static_cast<int>(prefix_len);
484 return (buf.str());
485}
486
497bool checkIAStatus(boost::shared_ptr<Option6IA>& ia) {
498 OptionCustomPtr status =
499 boost::dynamic_pointer_cast
500 <OptionCustom>(ia->getOption(D6O_STATUS_CODE));
501
502 // If a non-zero status is present, bail.
503 if (status) {
504 int status_val = status->readInteger<uint16_t>(0);
505 if (status_val != 0) {
506 std::cout << "SKIPPING PACKET STATUS is not success:"
507 << status_val << std::endl;
508 return (false);
509 }
510 }
511
512 return (true);
513}
514
521 return (user_registry->findUser(UserId(UserId::HW_ADDRESS,
523}
524
531 return (user_registry->findUser(UserId(UserId::DUID,
533}
534
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Option with defined data fields represented as buffers that can be accessed using data field index.
Definition: option_custom.h:31
T readInteger(const uint32_t index=0) const
Read a buffer as integer value.
Class which represents an option carrying a single string value.
Definition: option_string.h:27
Per-packet callout handle.
void getContext(const std::string &name, T &value) const
Get context.
void getArgument(const std::string &name, T &value) const
Get argument.
Encapsulates a unique identifier for a DHCP client.
Definition: user.h:27
static const char * DUID_STR
Define the text label DUID id type.
Definition: user.h:42
static const char * HW_ADDRESS_STR
Defines the text label hardware address id type.
Definition: user.h:40
@ HW_ADDRESS
Hardware addresses (MAC) are used for IPv4 clients.
Definition: user.h:34
@ DUID
DUIDs are used for IPv6 clients.
Definition: user.h:36
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
@ D6O_IA_NA
Definition: dhcp6.h:23
@ D6O_IA_PD
Definition: dhcp6.h:45
@ D6O_IAADDR
Definition: dhcp6.h:25
@ D6O_STATUS_CODE
Definition: dhcp6.h:33
@ D6O_IAPREFIX
Definition: dhcp6.h:46
#define DOCSIS3_V6_TFTP_SERVERS
#define DOCSIS3_V6_CONFIG_FILE
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
const char * query_user_id_label
Text label of user id in the inbound query in callout context.
Definition: load_unload.cc:38
std::fstream user_chk_output
Output filestream for recording user check outcomes.
Definition: load_unload.cc:27
UserRegistryPtr user_registry
Pointer to the registry instance.
Definition: load_unload.cc:24
const char * default_user4_id_str
Text id used to identify the default IPv4 user in the registry The format is a string containing an e...
Definition: load_unload.cc:47
const char * registered_user_label
Text label of registered user pointer in callout context.
Definition: load_unload.cc:41
const char * default_user6_id_str
Text id used to identify the default IPv6 user in the registry The format is a string containing an e...
Definition: load_unload.cc:53
@ DHO_TFTP_SERVER_NAME
Definition: dhcp4.h:135
@ DHO_BOOT_FILE_NAME
Definition: dhcp4.h:136
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
Definition: pkt4.h:546
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:21
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
@ DHCPNAK
Definition: dhcp4.h:233
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
Definition: pkt6.h:31
boost::shared_ptr< Option > OptionPtr
Definition: option.h:38
Defines the logger used by the user check hooks library.
Definition: user.cc:19
boost::shared_ptr< User > UserPtr
Defines a smart pointer to a User.
Definition: user.h:241
void add6Options(Pkt6Ptr &response, const UserPtr &user)
Adds IPv6 vendor options to the response packet based on given user.
Definition: pkt_send_co.cc:264
bool checkIAStatus(boost::shared_ptr< Option6IA > &ia_opt)
Tests given IA option set for successful status.
Definition: pkt_send_co.cc:497
void generate_output_record(const std::string &id_type_str, const std::string &id_val_str, const std::string &addr_str, const bool &registered)
Adds an entry to the end of the user check outcome file.
Definition: pkt_send_co.cc:355
std::string getAddrStrIA_NA(OptionPtr options)
Stringify the lease address in an D6O_IA_NA option set.
Definition: pkt_send_co.cc:410
std::string getAddrStrIA_PD(OptionPtr options)
Stringify the lease prefix in an D6O_IA_PD option set.
Definition: pkt_send_co.cc:449
void add6Option(OptionPtr &vendor, uint8_t opt_code, std::string &opt_value)
Adds/updates a specific IPv6 string vendor option.
Definition: pkt_send_co.cc:303
const UserPtr & getDefaultUser4()
Fetches the default IPv4 user from the registry.
Definition: pkt_send_co.cc:520
const UserPtr & getDefaultUser6()
Fetches the default IPv6 user from the registry.
Definition: pkt_send_co.cc:530
int pkt6_send(CalloutHandle &handle)
This callout is called at the "pkt6_send" hook.
Definition: pkt_send_co.cc:140
int pkt4_send(CalloutHandle &handle)
This callout is called at the "pkt4_send" hook.
Definition: pkt_send_co.cc:69
std::string getV6AddrStr(Pkt6Ptr response)
Stringify the lease address or prefix IPv6 response packet.
Definition: pkt_send_co.cc:384
void add4Option(Pkt4Ptr &response, uint8_t opt_code, std::string &opt_value)
Adds/updates are specific IPv4 string option in response packet.
Definition: pkt_send_co.cc:240
void add4Options(Pkt4Ptr &response, const UserPtr &user)
Adds IPv4 options to the response packet based on given user.
Definition: pkt_send_co.cc:203