Kea 2.6.2
dhcp4/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 <dhcp4/dhcp4_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 DHCP4_NAME = "kea-dhcp4";
43
47void
48usage() {
49 cerr << "Kea DHCPv4 server, "
50 << "version " << VERSION
51 << " (" << PACKAGE_VERSION_TYPE << ")"
52 << endl;
53 cerr << endl;
54 cerr << "Usage: " << DHCP4_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 = DHCP4_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 << Dhcpv4Srv::getVersion(false) << endl;
94 return (EXIT_SUCCESS);
95
96 case 'V':
97 cout << Dhcpv4Srv::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 DHCPv4 server
166 CfgMgr::instance().setFamily(AF_INET);
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 Parser4Context parser;
178 ConstElementPtr json;
179 json = parser.parseFile(config_file, Parser4Context::PARSER_DHCP4);
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 dhcp4 = json->get("Dhcp4");
190 if (!dhcp4) {
191 cerr << "Missing mandatory Dhcp4 element" << endl;
192 return (EXIT_FAILURE);
193 }
196
197 server.setProcName(DHCP4_NAME);
198
199 // Now we pass the Dhcp4 configuration to the server, but
200 // tell it to check the configuration only (check_only = true)
201 answer = configureDhcp4Server(server, dhcp4, 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 ControlledDhcpv4Srv 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(DHCP4_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(dhcp4_logger, DHCP4_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(dhcp4_logger, DHCP4_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(dhcp4_logger, DHCP4_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 << DHCP4_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(DHCP4_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 << DHCP4_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 << DHCP4_NAME << ": Fatal error during start up"
317 << endl;
318 ret = EXIT_FAILURE;
319 }
320
321 return (ret);
322}
it forwards queries to a single upstream resolver and passes the answers back to the client It is constructed with the address of the forward server Queries are initiated with the question to ask the forward server
Definition asiodns.dox:60
it forwards queries to a single upstream resolver and passes the answers back to the client It is constructed with the address of the forward server Queries are initiated with the question to ask the forward a buffer into which to write the answer
Definition asiodns.dox:60
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:230
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:28
Controlled version of the DHCPv4 server.
static std::string getVersion(bool extended)
returns Kea version on stdout and exit.
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_DHCP4
This parser will parse the content as Dhcp4 config wrapped in a map (that's the regular config file)
void process(T start, T finish)
Process Specifications.
Exception thrown when the PID file points to a live PID.
Definition daemon.h:25
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
int main(int argc, char *argv[])
Definition dhcp4/main.cc:73
Contains declarations for loggers used by the DHCPv4 server component.
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)
Parses a standard config/command level answer and returns arguments or text status code.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
std::string getConfigReport()
Definition cfgrpt.cc:20
const char * DHCP4_ROOT_LOGGER_NAME
Defines the name of the root level (default) logger.
Definition dhcp4_log.cc:26
const isc::log::MessageID DHCP4_ALREADY_RUNNING
const isc::log::MessageID DHCP4_STARTED
const isc::log::MessageID DHCP4_START_INFO
const isc::log::MessageID DHCP4_SERVER_FAILED
const isc::log::MessageID DHCP4_INIT_FAIL
isc::data::ConstElementPtr configureDhcp4Server(Dhcpv4Srv &server, isc::data::ConstElementPtr config_set, bool check_only, bool extra_checks)
Configure DHCPv4 server (Dhcpv4Srv) with a set of configuration values.
const isc::log::MessageID DHCP4_SHUTDOWN
const isc::log::MessageID DHCP4_STARTING
isc::log::Logger dhcp4_logger(DHCP4_APP_LOGGER_NAME)
Base logger for DHCPv4 server.
Definition dhcp4_log.h:90
const isc::log::MessageID DHCP4_DEVELOPMENT_VERSION
const int DBG_DHCP4_START
Debug level used to log information during server startup.
Definition dhcp4_log.h:24