Kea 2.5.8
dhcp6/main.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2023 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 <config.h>
8#include <kea_version.h>
9
11#include <dhcp6/dhcp6_log.h>
14#include <dhcpsrv/cfgmgr.h>
16#include <log/logger_support.h>
17#include <log/logger_manager.h>
18#include <log/output_option.h>
20#include <process/daemon.h>
21
22#include <boost/lexical_cast.hpp>
23
24#include <iostream>
25
26using namespace isc::data;
27using namespace isc::dhcp;
28using namespace isc::process;
29using namespace std;
30
39
40namespace {
41
42const char* const DHCP6_NAME = "kea-dhcp6";
43
47void
48usage() {
49 cerr << "Kea DHCPv6 server, "
50 << "version " << VERSION
51 << " (" << PACKAGE_VERSION_TYPE << ")"
52 << endl;
53 cerr << endl;
54 cerr << "Usage: " << DHCP6_NAME
55 << " -[v|V|W] [-d] [-{c|t|T} cfgfile] [-p number] [-P number]" << endl;
56 cerr << " -v: print version number and exit" << endl;
57 cerr << " -V: print extended version and exit" << endl;
58 cerr << " -W: display the configuration report and exit" << endl;
59 cerr << " -d: debug mode with extra verbosity (former -v)" << endl;
60 cerr << " -c file: specify configuration file" << endl;
61 cerr << " -t file: check the configuration file syntax and exit" << endl;
62 cerr << " -T file: check the configuration file doing hooks load and extra "
63 << "checks and exit" << endl;
64 cerr << " -p number: specify non-standard server port number 1-65535 "
65 << "(useful for testing only)" << endl;
66 cerr << " -P number: specify non-standard client port number 1-65535 "
67 << "(useful for testing only)" << endl;
68 exit(EXIT_FAILURE);
69}
70} // namespace
71
72int
73main(int argc, char* argv[]) {
74 int ch;
75 // The default. Any other values are useful for testing only.
76 int server_port_number = DHCP6_SERVER_PORT;
77 // Not zero values are useful for testing only.
78 int client_port_number = 0;
79 bool verbose_mode = false; // Should server be verbose?
80 bool check_mode = false; // Check syntax
81 bool load_hooks = false; // Check hooks config
82
83 // The standard config file
84 std::string config_file("");
85
86 while ((ch = getopt(argc, argv, "dvVWc:p:P:t:T:")) != -1) {
87 switch (ch) {
88 case 'd':
89 verbose_mode = true;
90 break;
91
92 case 'v':
93 cout << Dhcpv6Srv::getVersion(false) << endl;
94 return (EXIT_SUCCESS);
95
96 case 'V':
97 cout << Dhcpv6Srv::getVersion(true) << endl;
98 return (EXIT_SUCCESS);
99
100 case 'W':
101 cout << isc::detail::getConfigReport() << endl;
102 return (EXIT_SUCCESS);
103
104 case 'T':
105 load_hooks = true;
106 check_mode = true;
107 config_file = optarg;
108 break;
109
110 case 't':
111 check_mode = true;
112 config_file = optarg;
113 break;
114
115 case 'c': // config file
116 config_file = optarg;
117 break;
118
119 case 'p': // server port number
120 try {
121 server_port_number = boost::lexical_cast<int>(optarg);
122 } catch (const boost::bad_lexical_cast &) {
123 cerr << "Failed to parse server port number: [" << optarg
124 << "], 1-65535 allowed." << endl;
125 usage();
126 }
127 if (server_port_number <= 0 || server_port_number > 65535) {
128 cerr << "Failed to parse server port number: [" << optarg
129 << "], 1-65535 allowed." << endl;
130 usage();
131 }
132 break;
133
134 case 'P': // client port number
135 try {
136 client_port_number = boost::lexical_cast<int>(optarg);
137 } catch (const boost::bad_lexical_cast &) {
138 cerr << "Failed to parse client port number: [" << optarg
139 << "], 1-65535 allowed." << endl;
140 usage();
141 }
142 if (client_port_number <= 0 || client_port_number > 65535) {
143 cerr << "Failed to parse client port number: [" << optarg
144 << "], 1-65535 allowed." << endl;
145 usage();
146 }
147 break;
148
149 default:
150 usage();
151 }
152 }
153
154 // Check for extraneous parameters.
155 if (argc > optind) {
156 usage();
157 }
158
159 // Configuration file is required.
160 if (config_file.empty()) {
161 cerr << "Configuration file not specified." << endl;
162 usage();
163 }
164
165 // This is the DHCPv6 server
166 CfgMgr::instance().setFamily(AF_INET6);
167
168 if (check_mode) {
169 try {
170 // We need to initialize logging, in case any error messages are to be printed.
171 // This is just a test, so we don't care about lockfile.
172 setenv("KEA_LOCKFILE_DIR", "none", 0);
175
176 // Check the syntax first.
177 Parser6Context parser;
178 ConstElementPtr json;
179 json = parser.parseFile(config_file, Parser6Context::PARSER_DHCP6);
180 if (!json) {
181 cerr << "No configuration found" << endl;
182 return (EXIT_FAILURE);
183 }
184 if (verbose_mode) {
185 cerr << "Syntax check OK" << endl;
186 }
187
188 // Check the logic next.
189 ConstElementPtr dhcp6 = json->get("Dhcp6");
190 if (!dhcp6) {
191 cerr << "Missing mandatory Dhcp6 element" << endl;
192 return (EXIT_FAILURE);
193 }
194 ControlledDhcpv6Srv server(0);
195 ConstElementPtr answer;
196
197 server.setProcName(DHCP6_NAME);
198
199 // Now we pass the Dhcp6 configuration to the server, but
200 // tell it to check the configuration only (check_only = true)
201 answer = configureDhcp6Server(server, dhcp6, true, load_hooks);
202
203 int status_code = 0;
204 answer = isc::config::parseAnswer(status_code, answer);
205 if (status_code == 0) {
206 return (EXIT_SUCCESS);
207 } else {
208 cerr << "Error encountered: " << answer->stringValue() << endl;
209 return (EXIT_FAILURE);
210 }
211 } catch (const std::exception& ex) {
212 cerr << "Syntax check failed with: " << ex.what() << endl;
213 }
214 return (EXIT_FAILURE);
215 }
216
217 int ret = EXIT_SUCCESS;
218 try {
219 // It is important that we set a default logger name because this name
220 // will be used when the user doesn't provide the logging configuration
221 // in the Kea configuration file.
223
224 // Initialize logging. If verbose, we'll use maximum verbosity.
227 .arg(getpid())
228 .arg(server_port_number)
229 .arg(client_port_number)
230 .arg(verbose_mode ? "yes" : "no");
231
233 .arg(VERSION)
234 .arg(PACKAGE_VERSION_TYPE);
235
236 if (string(PACKAGE_VERSION_TYPE) == "development") {
238 }
239
240 // Create the server instance.
241 ControlledDhcpv6Srv server(server_port_number, client_port_number);
242
243 // Remember verbose-mode
244 server.setVerbose(verbose_mode);
245
246 // Create our PID file.
247 server.setProcName(DHCP6_NAME);
248 server.setConfigFile(config_file);
249 server.createPIDFile();
250
251 try {
252 // Initialize the server.
253 server.init(config_file);
254 } catch (const std::exception& ex) {
255
256 // Let's log out what went wrong.
257 try {
258 // Log with the current logger, but only if it's not
259 // configured with console output so as to not log twice.
261 LOG_ERROR(dhcp6_logger, DHCP6_INIT_FAIL).arg(ex.what());
262 }
263
264 // Log on the console as well.
265 isc::log::LoggerManager log_manager;
266 log_manager.process();
267 LOG_ERROR(dhcp6_logger, DHCP6_INIT_FAIL).arg(ex.what());
268 } catch (...) {
269 // The exception thrown during the initialization could
270 // originate from logger subsystem. Therefore LOG_ERROR()
271 // may fail as well.
272 cerr << "Failed to initialize server: " << ex.what() << endl;
273 }
274
275 return (EXIT_FAILURE);
276 }
277
278 // Tell the admin we are ready to process packets
279 LOG_INFO(dhcp6_logger, DHCP6_STARTED).arg(VERSION);
280
281 // And run the main loop of the server.
282 ret = server.run();
283
285
286 } catch (const isc::process::DaemonPIDExists& ex) {
287 // First, we print the error on stderr (that should always work)
288 cerr << DHCP6_NAME << " already running? " << ex.what()
289 << endl;
290
291 // Let's also try to log it using logging system, but we're not
292 // sure if it's usable (the exception may have been thrown from
293 // the logger subsystem)
294 try {
296 .arg(DHCP6_NAME).arg(ex.what());
297 } catch (...) {
298 // Already logged so ignore
299 }
300 ret = EXIT_FAILURE;
301 } catch (const std::exception& ex) {
302 // First, we print the error on stderr (that should always work)
303 cerr << DHCP6_NAME << ": Fatal error during start up: " << ex.what()
304 << endl;
305
306 // Let's also try to log it using logging system, but we're not
307 // sure if it's usable (the exception may have been thrown from
308 // the logger subsystem)
309 try {
311 } catch (...) {
312 // Already logged so ignore
313 }
314 ret = EXIT_FAILURE;
315 } catch (...) {
316 cerr << DHCP6_NAME << ": Fatal error during start up"
317 << endl;
318 ret = EXIT_FAILURE;
319 }
320
321 return (ret);
322}
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
void setFamily(uint16_t family)
Sets address family (AF_INET or AF_INET6)
Definition: cfgmgr.h:275
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
Controlled version of the DHCPv6 server.
void init(const std::string &config_file)
Initializes the server.
int run()
Main server processing loop.
Definition: dhcp6_srv.cc:598
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
Definition: dhcp6_srv.cc:4674
Evaluation context, an interface to the expression evaluation.
isc::data::ElementPtr parseFile(const std::string &filename, ParserType parser_type)
Run the parser on the file specified.
@ PARSER_DHCP6
This parser will parse the content as Dhcp6 config wrapped in a map (that's the regular config file)
void process(T start, T finish)
Process Specifications.
bool hasAppender(OutputOption::Destination const destination)
Check if this logger has an appender of the given type.
Definition: log/logger.cc:206
Exception thrown when the PID file points to a live PID.
Definition: daemon.h:25
static void setVerbose(const bool verbose)
Sets or clears verbose mode.
Definition: daemon.cc:79
static void loggerInit(const char *log_name, bool verbose)
Initializes logger.
Definition: daemon.cc:88
static void setDefaultLoggerName(const std::string &logger)
Sets the default logger name.
Definition: daemon.h:215
static void setProcName(const std::string &proc_name)
Sets the process name.
Definition: daemon.cc:134
void createPIDFile(int pid=0)
Creates the PID file.
Definition: daemon.cc:202
void setConfigFile(const std::string &config_file)
Sets the configuration file name.
Definition: daemon.cc:109
int main(int argc, char *argv[])
Definition: dhcp6/main.cc:73
void usage()
Print Usage.
Logging initialization functions.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_FATAL(LOGGER, MESSAGE)
Macro to conveniently test fatal output and log it.
Definition: macros.h:38
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
std::string getConfigReport()
Definition: cfgrpt.cc:20
isc::data::ConstElementPtr configureDhcp6Server(Dhcpv6Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv6 server (Dhcpv6Srv) with a set of configuration values.
const isc::log::MessageID DHCP6_INIT_FAIL
const int DBG_DHCP6_START
Debug level used to log information during server startup.
Definition: dhcp6_log.h:22
const isc::log::MessageID DHCP6_SERVER_FAILED
const isc::log::MessageID DHCP6_DEVELOPMENT_VERSION
const isc::log::MessageID DHCP6_SHUTDOWN
const isc::log::MessageID DHCP6_STARTED
const isc::log::MessageID DHCP6_STARTING
const isc::log::MessageID DHCP6_START_INFO
const isc::log::MessageID DHCP6_ALREADY_RUNNING
const char * DHCP6_ROOT_LOGGER_NAME
Defines the name of the root level (default) logger.
Definition: dhcp6_log.cc:26
isc::log::Logger dhcp6_logger(DHCP6_APP_LOGGER_NAME)
Base logger for DHCPv6 server.
Definition: dhcp6_log.h:88