dhclient.c 147 KB
Newer Older
1
/* dhclient.c
2

3
   DHCP Client. */
4
5

/*
6
 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1995-2003 by Internet Software Consortium
8
 *
9
10
11
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
12
 *
13
14
15
16
17
18
19
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 *
21
22
23
24
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
25
 *   https://www.isc.org/
Ted Lemon's avatar
Ted Lemon committed
26
 *
27
28
29
30
 * This code is based on the original client state machine that was
 * written by Elliot Poger.  The code has been extensively hacked on
 * by Ted Lemon since then, so any mistakes you find are probably his
 * fault and not Elliot's.
31
32
 */

33
#include "dhcpd.h"
34
35
36
#include <syslog.h>
#include <signal.h>
#include <errno.h>
Francis Dupont's avatar
Francis Dupont committed
37
#include <sys/time.h>
38
#include <sys/wait.h>
Shane Kerr's avatar
Shane Kerr committed
39
#include <limits.h>
Francis Dupont's avatar
Francis Dupont committed
40
#include <isc/file.h>
41
#include <dns/result.h>
Ted Lemon's avatar
Ted Lemon committed
42

43
44
45
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */

46
const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
David Hankins's avatar
David Hankins committed
47
48
const char *path_dhclient_db = NULL;
const char *path_dhclient_pid = NULL;
Francis Dupont's avatar
Francis Dupont committed
49
static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
50
char *path_dhclient_script = path_dhclient_script_array;
51
const char *path_dhclient_duid = NULL;
52

53
54
55
/* False (default) => we write and use a pid file */
isc_boolean_t no_pid_file = ISC_FALSE;

56
57
int dhcp_max_agent_option_packet_length = 0;

58
59
int interfaces_requested = 0;

60
61
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
62
struct in_addr inaddr_any;
63
struct sockaddr_in sockaddr_broadcast;
64
struct in_addr giaddr;
David Hankins's avatar
David Hankins committed
65
struct data_string default_duid;
66
int duid_type = 0;
Shawn Routhier's avatar
Shawn Routhier committed
67
68
int duid_v4 = 0;
int std_dhcid = 0;
69

70
71
72
/* ASSERT_STATE() does nothing now; it used to be
   assert (state_is == state_shouldbe). */
#define ASSERT_STATE(state_is, state_shouldbe) {}
73

74
#ifndef UNIT_TEST
75
static const char copyright[] = "Copyright 2004-2016 Internet Systems Consortium.";
76
77
static const char arr [] = "All rights reserved.";
static const char message [] = "Internet Systems Consortium DHCP Client";
78
static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/";
79
#endif /* UNIT_TEST */
80

Francis Dupont's avatar
Francis Dupont committed
81
82
u_int16_t local_port = 0;
u_int16_t remote_port = 0;
83
84
85
#if defined(DHCPv6) && defined(DHCP4o6)
int dhcp4o6_state = -1; /* -1 = stopped, 0 = polling, 1 = started */
#endif
Francis Dupont's avatar
Francis Dupont committed
86
int no_daemon = 0;
87
int dfd[2] = { -1, -1 };
Francis Dupont's avatar
Francis Dupont committed
88
89
90
91
92
93
94
95
96
struct string_list *client_env = NULL;
int client_env_count = 0;
int onetry = 0;
int quiet = 1;
int nowait = 0;
int stateless = 0;
int wanted_ia_na = -1;		/* the absolute value is the real one. */
int wanted_ia_ta = 0;
int wanted_ia_pd = 0;
97
98
99
int require_all_ias = 0;	/* If the user requires all of the IAs to
				   be available before accepting a lease
				   0 = no, 1 = requries */
David Hankins's avatar
David Hankins committed
100
char *mockup_relay = NULL;
101

Francis Dupont's avatar
Francis Dupont committed
102
103
char *progname = NULL;

104
void run_stateless(int exit_mode, u_int16_t port);
Francis Dupont's avatar
Francis Dupont committed
105

David Hankins's avatar
David Hankins committed
106
static isc_result_t write_duid(struct data_string *duid);
107
static void add_reject(struct packet *packet);
David Hankins's avatar
David Hankins committed
108

109
110
111
112
113
static int check_domain_name(const char *ptr, size_t len, int dots);
static int check_domain_name_list(const char *ptr, size_t len, int dots);
static int check_option_values(struct universe *universe, unsigned int opt,
			       const char *ptr, size_t len);

114
115
116
static void dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb,
                                   char* file, int line);

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*!
 *
 * \brief Print the generic usage message
 *
 * If the user has provided an incorrect command line print out
 * the description of the command line.  The arguments provide
 * a way for the caller to request more specific information about
 * the error be printed as well.  Mostly this will be that some
 * comamnd doesn't include its argument.
 *
 * \param sfmt - The basic string and format for the specific error
 * \param sarg - Generally the offending argument from the comamnd line.
 *
 * \return Nothing
 */

133
134
135
136
137
138
139
140
141
142
143
#if defined(DHCPv6) && defined(DHCP4o6)
static void dhcp4o6_poll(void *dummy);
static void dhcp4o6_resume(void);
static void recv_dhcpv4_response(struct data_string *raw);
static int send_dhcpv4_query(struct client_state *client, int broadcast);

static void dhcp4o6_stop(void);
static void forw_dhcpv4_response(struct packet *packet);
static void forw_dhcpv4_query(struct data_string *raw);
#endif

144
145
146
147
148
#ifndef UNIT_TEST
/* These are only used when we call usage() from the main routine
 * which isn't compiled when building for unit tests
 */
static const char use_noarg[] = "No argument for command: %s";
149
#ifdef DHCPv6
150
static const char use_v6command[] = "Command not used for DHCPv4: %s";
151
#endif
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#ifdef DHCPv6
#ifdef DHCP4o6
#define DHCLIENT_USAGE0 \
"[-4|-6] [-SNTPRI1dvrxi] [-nw] -4o6 <port>]\n" \
"                [-p <port>] [-D LL|LLT] \n"
#else /* DHCP4o6 */
#define DHCLIENT_USAGE0 \
"[-4|-6] [-SNTPRI1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#endif
#else /* DHCPv6 */
#define DHCLIENT_USAGE0 \
"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#endif

#define DHCLIENT_USAGEC \
"                [-s server-addr] [-cf config-file]\n" \
"                [-df duid-file] [-lf lease-file]\n" \
"                [-pf pid-file] [--no-pid] [-e VAR=val]\n" \
"                [-sf script-file] [interface]*"

#define DHCLIENT_USAGEH "{--version|--help|-h}"

175
176
177
178
179
180
181
182
183
184
185
186
187
188
static void
usage(const char *sfmt, const char *sarg)
{
	log_info("%s %s", message, PACKAGE_VERSION);
	log_info(copyright);
	log_info(arr);
	log_info(url);

	/* If desired print out the specific error message */
#ifdef PRINT_SPECIFIC_CL_ERRORS
	if (sfmt != NULL)
		log_error(sfmt, sarg);
#endif

189
	log_fatal("Usage: %s %s%s\n       %s %s",
190
191
192
193
194
		  isc_file_basename(progname),
		  DHCLIENT_USAGE0,
		  DHCLIENT_USAGEC,
		  isc_file_basename(progname),
		  DHCLIENT_USAGEH);
195
196
}

Francis Dupont's avatar
Francis Dupont committed
197
int
David Hankins's avatar
David Hankins committed
198
main(int argc, char **argv) {
199
	int fd;
200
	int i;
201
	struct interface_info *ip;
Ted Lemon's avatar
Ted Lemon committed
202
	struct client_state *client;
203
	unsigned seed;
Francis Dupont's avatar
Francis Dupont committed
204
	char *server = NULL;
205
	isc_result_t status;
Francis Dupont's avatar
Francis Dupont committed
206
207
	int exit_mode = 0;
	int release_mode = 0;
Francis Dupont's avatar
Francis Dupont committed
208
	struct timeval tv;
209
210
	omapi_object_t *listener;
	isc_result_t result;
211
	int persist = 0;
212
213
214
	int no_dhclient_conf = 0;
	int no_dhclient_db = 0;
	int no_dhclient_pid = 0;
215
	int no_dhclient_script = 0;
216
#ifdef DHCPv6
David Hankins's avatar
David Hankins committed
217
	int local_family_set = 0;
218
219
220
#ifdef DHCP4o6
	u_int16_t dhcp4o6_port = 0;
#endif /* DHCP4o6 */
221
#endif /* DHCPv6 */
222
	char *s;
Ted Lemon's avatar
Ted Lemon committed
223

Francis Dupont's avatar
Francis Dupont committed
224
225
226
227
228
229
#ifdef OLD_LOG_NAME
	progname = "dhclient";
#else
	progname = argv[0];
#endif

David Hankins's avatar
David Hankins committed
230
231
232
	/* Initialize client globals. */
	memset(&default_duid, 0, sizeof(default_duid));

Francis Dupont's avatar
Francis Dupont committed
233
234
235
236
237
238
239
240
241
242
243
244
	/* Make sure that file descriptors 0 (stdin), 1, (stdout), and
	   2 (stderr) are open. To do this, we assume that when we
	   open a file the lowest available file descriptor is used. */
	fd = open("/dev/null", O_RDWR);
	if (fd == 0)
		fd = open("/dev/null", O_RDWR);
	if (fd == 1)
		fd = open("/dev/null", O_RDWR);
	if (fd == 2)
		log_perror = 0; /* No sense logging to /dev/null. */
	else if (fd != -1)
		close(fd);
245

Francis Dupont's avatar
Francis Dupont committed
246
	openlog(isc_file_basename(progname), DHCP_LOG_OPTIONS, LOG_DAEMON);
247

Francis Dupont's avatar
Francis Dupont committed
248
249
#if !(defined(DEBUG) || defined(__CYGWIN32__))
	setlogmask(LOG_UPTO(LOG_INFO));
Francis Dupont's avatar
Francis Dupont committed
250
#endif
251

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
	/* Parse arguments changing no_daemon */
	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "-r")) {
			no_daemon = 1;
		} else if (!strcmp(argv[i], "-x")) {
			no_daemon = 0;
		} else if (!strcmp(argv[i], "-d")) {
			no_daemon = 1;
		} else if (!strcmp(argv[i], "--version")) {
			const char vstring[] = "isc-dhclient-";
			IGNORE_RET(write(STDERR_FILENO, vstring,
					 strlen(vstring)));
			IGNORE_RET(write(STDERR_FILENO,
					 PACKAGE_VERSION,
					 strlen(PACKAGE_VERSION)));
			IGNORE_RET(write(STDERR_FILENO, "\n", 1));
			exit(0);
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
		} else if (!strcmp(argv[i], "--help") ||
			   !strcmp(argv[i], "-h")) {
			const char *pname = isc_file_basename(progname);
			IGNORE_RET(write(STDERR_FILENO, "Usage: ", 7));
			IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
			IGNORE_RET(write(STDERR_FILENO, " ", 1));
			IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGE0,
					 strlen(DHCLIENT_USAGE0)));
			IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGEC,
					 strlen(DHCLIENT_USAGEC)));
			IGNORE_RET(write(STDERR_FILENO, "\n", 1));
			IGNORE_RET(write(STDERR_FILENO, "       ", 7));
			IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
			IGNORE_RET(write(STDERR_FILENO, " ", 1));
			IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGEH,
					 strlen(DHCLIENT_USAGEH)));
			IGNORE_RET(write(STDERR_FILENO, "\n", 1));
			exit(0);
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
		}
	}
	/* When not forbidden prepare to become a daemon */
	if (!no_daemon) {
		int pid;

		if (pipe(dfd) == -1)
			log_fatal("Can't get pipe: %m");
		if ((pid = fork ()) < 0)
			log_fatal("Can't fork daemon: %m");
		if (pid != 0) {
			/* Parent: wait for the child to start */
			int n;

			(void) close(dfd[1]);
			do {
				char buf;

				n = read(dfd[0], &buf, 1);
				if (n == 1)
					_exit((int)buf);
			} while (n == -1 && errno == EINTR);
			_exit(1);
		}
		/* Child */
		(void) close(dfd[0]);
	}

315
	/* Set up the isc and dns library managers */
316
317
	status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
				     NULL, NULL);
318
319
320
321
	if (status != ISC_R_SUCCESS)
		log_fatal("Can't initialize context: %s",
			  isc_result_totext(status));

322
	/* Set up the OMAPI. */
Francis Dupont's avatar
Francis Dupont committed
323
	status = omapi_init();
324
	if (status != ISC_R_SUCCESS)
Francis Dupont's avatar
Francis Dupont committed
325
326
		log_fatal("Can't initialize OMAPI: %s",
			  isc_result_totext(status));
327
328
329

	/* Set up the OMAPI wrappers for various server database internal
	   objects. */
Francis Dupont's avatar
Francis Dupont committed
330
	dhcp_common_objects_setup();
331
332
333

	dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
	dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
334
	dhcp_interface_startup_hook = dhclient_interface_startup_hook;
335

336
	for (i = 1; i < argc; i++) {
Francis Dupont's avatar
Francis Dupont committed
337
		if (!strcmp(argv[i], "-r")) {
338
			release_mode = 1;
339
			/* no_daemon = 1; */
340
341
#ifdef DHCPv6
		} else if (!strcmp(argv[i], "-4")) {
David Hankins's avatar
David Hankins committed
342
343
344
345
346
347
348
349
350
351
352
			if (local_family_set && local_family != AF_INET)
				log_fatal("Client can only do v4 or v6, not "
					  "both.");
			local_family_set = 1;
			local_family = AF_INET;
		} else if (!strcmp(argv[i], "-6")) {
			if (local_family_set && local_family != AF_INET6)
				log_fatal("Client can only do v4 or v6, not "
					  "both.");
			local_family_set = 1;
			local_family = AF_INET6;
353
354
355
356
357
358
359
360
361
362
363
#ifdef DHCP4o6
		} else if (!strcmp(argv[i], "-4o6")) {
			if (++i == argc)
				usage(use_noarg, argv[i-1]);
			dhcp4o6_port = validate_port_pair(argv[i]);

			log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d",
				  ntohs(dhcp4o6_port),
				  ntohs(dhcp4o6_port) + 1);
			dhcpv4_over_dhcpv6 = 1;
#endif /* DHCP4o6 */
364
#endif /* DHCPv6 */
Francis Dupont's avatar
Francis Dupont committed
365
		} else if (!strcmp(argv[i], "-x")) { /* eXit, no release */
Francis Dupont's avatar
Francis Dupont committed
366
			release_mode = 0;
367
			/* no_daemon = 0; */
Francis Dupont's avatar
Francis Dupont committed
368
			exit_mode = 1;
Francis Dupont's avatar
Francis Dupont committed
369
		} else if (!strcmp(argv[i], "-p")) {
370
			if (++i == argc)
371
				usage(use_noarg, argv[i-1]);
372
			local_port = validate_port(argv[i]);
Francis Dupont's avatar
Francis Dupont committed
373
374
375
			log_debug("binding to user-specified port %d",
				  ntohs(local_port));
		} else if (!strcmp(argv[i], "-d")) {
376
			/* no_daemon = 1; */
377
			quiet = 0;
Francis Dupont's avatar
Francis Dupont committed
378
		} else if (!strcmp(argv[i], "-pf")) {
Francis Dupont's avatar
Francis Dupont committed
379
			if (++i == argc)
380
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
381
			path_dhclient_pid = argv[i];
382
			no_dhclient_pid = 1;
383
384
		} else if (!strcmp(argv[i], "--no-pid")) {
			no_pid_file = ISC_TRUE;
Francis Dupont's avatar
Francis Dupont committed
385
		} else if (!strcmp(argv[i], "-cf")) {
Francis Dupont's avatar
Francis Dupont committed
386
			if (++i == argc)
387
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
388
			path_dhclient_conf = argv[i];
389
			no_dhclient_conf = 1;
390
391
		} else if (!strcmp(argv[i], "-df")) {
			if (++i == argc)
392
				usage(use_noarg, argv[i-1]);
393
			path_dhclient_duid = argv[i];
Francis Dupont's avatar
Francis Dupont committed
394
		} else if (!strcmp(argv[i], "-lf")) {
Francis Dupont's avatar
Francis Dupont committed
395
			if (++i == argc)
396
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
397
			path_dhclient_db = argv[i];
398
			no_dhclient_db = 1;
Francis Dupont's avatar
Francis Dupont committed
399
		} else if (!strcmp(argv[i], "-sf")) {
400
			if (++i == argc)
401
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
402
			path_dhclient_script = argv[i];
403
			no_dhclient_script = 1;
Francis Dupont's avatar
Francis Dupont committed
404
		} else if (!strcmp(argv[i], "-1")) {
405
			onetry = 1;
Francis Dupont's avatar
Francis Dupont committed
406
		} else if (!strcmp(argv[i], "-q")) {
Ted Lemon's avatar
Ted Lemon committed
407
			quiet = 1;
Francis Dupont's avatar
Francis Dupont committed
408
		} else if (!strcmp(argv[i], "-s")) {
409
			if (++i == argc)
410
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
411
412
			server = argv[i];
		} else if (!strcmp(argv[i], "-g")) {
413
			if (++i == argc)
414
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
415
416
			mockup_relay = argv[i];
		} else if (!strcmp(argv[i], "-nw")) {
417
			nowait = 1;
Francis Dupont's avatar
Francis Dupont committed
418
		} else if (!strcmp(argv[i], "-n")) {
419
			/* do not start up any interfaces */
Francis Dupont's avatar
Francis Dupont committed
420
			interfaces_requested = -1;
Francis Dupont's avatar
Francis Dupont committed
421
		} else if (!strcmp(argv[i], "-w")) {
422
423
			/* do not exit if there are no broadcast interfaces. */
			persist = 1;
Francis Dupont's avatar
Francis Dupont committed
424
		} else if (!strcmp(argv[i], "-e")) {
Ted Lemon's avatar
Ted Lemon committed
425
426
			struct string_list *tmp;
			if (++i == argc)
427
				usage(use_noarg, argv[i-1]);
Francis Dupont's avatar
Francis Dupont committed
428
			tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL);
Ted Lemon's avatar
Ted Lemon committed
429
			if (!tmp)
Francis Dupont's avatar
Francis Dupont committed
430
431
432
				log_fatal("No memory for %s", argv[i]);
			strcpy(tmp->string, argv[i]);
			tmp->next = client_env;
Ted Lemon's avatar
Ted Lemon committed
433
434
			client_env = tmp;
			client_env_count++;
Francis Dupont's avatar
Francis Dupont committed
435
#ifdef DHCPv6
Francis Dupont's avatar
Francis Dupont committed
436
437
		} else if (!strcmp(argv[i], "-S")) {
			if (local_family_set && (local_family == AF_INET)) {
438
				usage(use_v6command, argv[i]);
Francis Dupont's avatar
Francis Dupont committed
439
440
441
			}
			local_family_set = 1;
			local_family = AF_INET6;
Francis Dupont's avatar
Francis Dupont committed
442
			wanted_ia_na = 0;
Francis Dupont's avatar
Francis Dupont committed
443
			stateless = 1;
Francis Dupont's avatar
Francis Dupont committed
444
445
		} else if (!strcmp(argv[i], "-N")) {
			if (local_family_set && (local_family == AF_INET)) {
446
				usage(use_v6command, argv[i]);
Francis Dupont's avatar
Francis Dupont committed
447
448
449
450
451
452
453
454
455
			}
			local_family_set = 1;
			local_family = AF_INET6;
			if (wanted_ia_na < 0) {
				wanted_ia_na = 0;
			}
			wanted_ia_na++;
		} else if (!strcmp(argv[i], "-T")) {
			if (local_family_set && (local_family == AF_INET)) {
456
				usage(use_v6command, argv[i]);
Francis Dupont's avatar
Francis Dupont committed
457
458
459
460
461
462
463
464
465
			}
			local_family_set = 1;
			local_family = AF_INET6;
			if (wanted_ia_na < 0) {
				wanted_ia_na = 0;
			}
			wanted_ia_ta++;
		} else if (!strcmp(argv[i], "-P")) {
			if (local_family_set && (local_family == AF_INET)) {
466
				usage(use_v6command, argv[i]);
Francis Dupont's avatar
Francis Dupont committed
467
468
469
470
471
472
473
			}
			local_family_set = 1;
			local_family = AF_INET6;
			if (wanted_ia_na < 0) {
				wanted_ia_na = 0;
			}
			wanted_ia_pd++;
474
475
		} else if (!strcmp(argv[i], "-R")) {
			if (local_family_set && (local_family == AF_INET)) {
476
				usage(use_v6command, argv[i]);
477
478
479
480
			}
			local_family_set = 1;
			local_family = AF_INET6;
			require_all_ias = 1;
Shawn Routhier's avatar
Shawn Routhier committed
481
#endif /* DHCPv6 */
482
		} else if (!strcmp(argv[i], "-D")) {
Shawn Routhier's avatar
Shawn Routhier committed
483
			duid_v4 = 1;
484
			if (++i == argc)
485
				usage(use_noarg, argv[i-1]);
486
487
488
489
490
			if (!strcasecmp(argv[i], "LL")) {
				duid_type = DUID_LL;
			} else if (!strcasecmp(argv[i], "LLT")) {
				duid_type = DUID_LLT;
			} else {
491
				usage("Unknown argument to -D: %s", argv[i]);
492
			}
Shawn Routhier's avatar
Shawn Routhier committed
493
494
495
496
497
498
		} else if (!strcmp(argv[i], "-i")) {
			/* enable DUID support for DHCPv4 clients */
			duid_v4 = 1;
		} else if (!strcmp(argv[i], "-I")) {
			/* enable standard DHCID support for DDNS updates */
			std_dhcid = 1;
499
500
		} else if (!strcmp(argv[i], "-v")) {
			quiet = 0;
Francis Dupont's avatar
Francis Dupont committed
501
		} else if (argv[i][0] == '-') {
502
			usage("Unknown command: %s", argv[i]);
Francis Dupont's avatar
Francis Dupont committed
503
		} else if (interfaces_requested < 0) {
504
505
			usage("No interfaces comamnd -n and "
			      " requested interface %s", argv[i]);
506
		} else {
Francis Dupont's avatar
Francis Dupont committed
507
508
509
		    struct interface_info *tmp = NULL;

		    status = interface_allocate(&tmp, MDL);
Francis Dupont's avatar
Francis Dupont committed
510
		    if (status != ISC_R_SUCCESS)
Francis Dupont's avatar
Francis Dupont committed
511
512
			log_fatal("Can't record interface %s:%s",
				  argv[i], isc_result_totext(status));
513
514
		    if (strlen(argv[i]) >= sizeof(tmp->name))
			    log_fatal("%s: interface name too long (is %ld)",
Francis Dupont's avatar
Francis Dupont committed
515
				      argv[i], (long)strlen(argv[i]));
516
		    strcpy(tmp->name, argv[i]);
517
		    if (interfaces) {
Francis Dupont's avatar
Francis Dupont committed
518
519
520
			    interface_reference(&tmp->next,
						interfaces, MDL);
			    interface_dereference(&interfaces, MDL);
521
		    }
Francis Dupont's avatar
Francis Dupont committed
522
523
		    interface_reference(&interfaces, tmp, MDL);
		    tmp->flags = INTERFACE_REQUESTED;
Francis Dupont's avatar
Francis Dupont committed
524
525
		    interfaces_requested++;
		}
526
	}
Ted Lemon's avatar
Ted Lemon committed
527

Francis Dupont's avatar
Francis Dupont committed
528
529
530
531
532
533
	if (wanted_ia_na < 0) {
		wanted_ia_na = 1;
	}

	/* Support only one (requested) interface for Prefix Delegation. */
	if (wanted_ia_pd && (interfaces_requested != 1)) {
534
		usage("PD %s only supports one requested interface", "-P");
Francis Dupont's avatar
Francis Dupont committed
535
536
	}

537
538
539
540
541
542
543
544
545
546
547
#if defined(DHCPv6) && defined(DHCP4o6)
	if ((local_family == AF_INET6) && dhcpv4_over_dhcpv6 &&
	    (exit_mode || release_mode))
		log_error("Can't relay DHCPv4-over-DHCPv6 "
			  "without a persistent DHCPv6 client");
	if ((local_family == AF_INET) && dhcpv4_over_dhcpv6 &&
	    (interfaces_requested != 1))
		log_fatal("DHCPv4-over-DHCPv6 requires an explicit "
			  "interface on which to be applied");
#endif

Francis Dupont's avatar
Francis Dupont committed
548
	if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) {
549
550
		path_dhclient_conf = s;
	}
Francis Dupont's avatar
Francis Dupont committed
551
	if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) {
552
553
		path_dhclient_db = s;
	}
Francis Dupont's avatar
Francis Dupont committed
554
	if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) {
555
556
		path_dhclient_pid = s;
	}
Francis Dupont's avatar
Francis Dupont committed
557
	if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) {
558
559
		path_dhclient_script = s;
	}
560

David Hankins's avatar
David Hankins committed
561
562
563
564
565
566
	/* Set up the initial dhcp option universe. */
	initialize_common_option_spaces();

	/* Assign v4 or v6 specific running parameters. */
	if (local_family == AF_INET)
		dhcpv4_client_assignments();
567
#ifdef DHCPv6
David Hankins's avatar
David Hankins committed
568
569
	else if (local_family == AF_INET6)
		dhcpv6_client_assignments();
570
#endif /* DHCPv6 */
David Hankins's avatar
David Hankins committed
571
572
573
	else
		log_fatal("Impossible condition at %s:%d.", MDL);

574
575
576
577
578
	/*
	 * convert relative path names to absolute, for files that need
	 * to be reopened after chdir() has been called
	 */
	if (path_dhclient_db[0] != '/') {
579
580
		const char *old_path = path_dhclient_db;
		path_dhclient_db = realpath(path_dhclient_db, NULL);
581
		if (path_dhclient_db == NULL)
582
			log_fatal("Failed to get realpath for %s: %s", old_path, strerror(errno));
583
	}
Francis Dupont's avatar
Francis Dupont committed
584

585
	if (path_dhclient_script[0] != '/') {
586
587
		const char *old_path = path_dhclient_script;
		path_dhclient_script = realpath(path_dhclient_script, NULL);
588
		if (path_dhclient_script == NULL)
589
			log_fatal("Failed to get realpath for %s: %s", old_path, strerror(errno));
590
	}
Francis Dupont's avatar
Francis Dupont committed
591

592
593
594
595
596
597
598
	/*
	 * See if we should  kill off any currently running client
	 * we don't try to kill it off if the user told us not
	 * to write a pid file - we assume they are controlling
	 * the process in some other fashion.
	 */
	if ((release_mode || exit_mode) && (no_pid_file == ISC_FALSE)) {
599
600
601
602
603
604
605
606
607
		FILE *pidfd;
		pid_t oldpid;
		long temp;
		int e;

		if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
			e = fscanf(pidfd, "%ld\n", &temp);
			oldpid = (pid_t)temp;

608
609
610
611
			if (e != 0 && e != EOF && oldpid) {
				if (kill(oldpid, SIGTERM) == 0) {
					log_info("Killed old client process");
					(void) unlink(path_dhclient_pid);
Shawn Routhier's avatar
Shawn Routhier committed
612
613
614
615
616
617
618
619
					/*
					 * wait for the old process to
					 * cleanly terminate.
					 * Note kill() with sig=0 could
					 * detect termination but only
					 * the parent can be signaled...
					 */
					sleep(1);
620
621
622
				} else if (errno == ESRCH) {
					log_info("Removed stale PID file");
					(void) unlink(path_dhclient_pid);
Shawn Routhier's avatar
Shawn Routhier committed
623
				}
624
625
626
			}
			fclose(pidfd);
		}
627
628
	}

Ted Lemon's avatar
Ted Lemon committed
629
	if (!quiet) {
Francis Dupont's avatar
Francis Dupont committed
630
631
632
633
634
		log_info("%s %s", message, PACKAGE_VERSION);
		log_info(copyright);
		log_info(arr);
		log_info(url);
		log_info("%s", "");
635
	} else {
Ted Lemon's avatar
Ted Lemon committed
636
		log_perror = 0;
637
638
		quiet_interface_discovery = 1;
	}
Ted Lemon's avatar
Ted Lemon committed
639

640
641
	/* If we're given a relay agent address to insert, for testing
	   purposes, figure out what it is. */
David Hankins's avatar
David Hankins committed
642
	if (mockup_relay) {
Francis Dupont's avatar
Francis Dupont committed
643
		if (!inet_aton(mockup_relay, &giaddr)) {
644
			struct hostent *he;
Francis Dupont's avatar
Francis Dupont committed
645
			he = gethostbyname(mockup_relay);
646
			if (he) {
Francis Dupont's avatar
Francis Dupont committed
647
648
				memcpy(&giaddr, he->h_addr_list[0],
				       sizeof giaddr);
649
			} else {
Francis Dupont's avatar
Francis Dupont committed
650
				log_fatal("%s: no such host", mockup_relay);
651
652
653
654
			}
		}
	}

655
	/* Get the current time... */
Francis Dupont's avatar
Francis Dupont committed
656
	gettimeofday(&cur_tv, NULL);
657

658
	sockaddr_broadcast.sin_family = AF_INET;
659
	sockaddr_broadcast.sin_port = remote_port;
660
	if (server) {
Francis Dupont's avatar
Francis Dupont committed
661
		if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) {
662
			struct hostent *he;
Francis Dupont's avatar
Francis Dupont committed
663
			he = gethostbyname(server);
664
			if (he) {
Francis Dupont's avatar
Francis Dupont committed
665
666
667
				memcpy(&sockaddr_broadcast.sin_addr,
				       he->h_addr_list[0],
				       sizeof sockaddr_broadcast.sin_addr);
668
669
670
671
672
673
674
			} else
				sockaddr_broadcast.sin_addr.s_addr =
					INADDR_BROADCAST;
		}
	} else {
		sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
	}
675

676
	inaddr_any.s_addr = INADDR_ANY;
677

Francis Dupont's avatar
Francis Dupont committed
678
679
	/* Stateless special case. */
	if (stateless) {
Francis Dupont's avatar
Francis Dupont committed
680
681
682
		if (release_mode || (wanted_ia_na > 0) ||
		    wanted_ia_ta || wanted_ia_pd ||
		    (interfaces_requested != 1)) {
683
			usage("Stateless command: %s incompatibile with "
684
			      "other commands", "-S");
Francis Dupont's avatar
Francis Dupont committed
685
		}
686
687
688
689
690
#if defined(DHCPv6) && defined(DHCP4o6)
		run_stateless(exit_mode, dhcp4o6_port);
#else
		run_stateless(exit_mode, 0);
#endif
691
		finish(0);
Francis Dupont's avatar
Francis Dupont committed
692
693
	}

694
	/* Discover all the network interfaces. */
Francis Dupont's avatar
Francis Dupont committed
695
	discover_interfaces(DISCOVER_UNCONFIGURED);
696

697
	/* Parse the dhclient.conf file. */
Francis Dupont's avatar
Francis Dupont committed
698
	read_client_conf();
699

700
	/* Parse the lease database. */
Francis Dupont's avatar
Francis Dupont committed
701
	read_client_leases();
702

703
704
705
706
707
	/* If desired parse the secondary lease database for a DUID */
	if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) {
		read_client_duid();
	}

708
	/* Rewrite the lease database... */
Francis Dupont's avatar
Francis Dupont committed
709
	rewrite_client_leases();
710

711
712
713
	/* XXX */
/* 	config_counter(&snd_counter, &rcv_counter); */

Francis Dupont's avatar
Francis Dupont committed
714
715
716
717
	/*
	 * If no broadcast interfaces were discovered, call the script
	 * and tell it so.
	 */
718
	if (!interfaces) {
Francis Dupont's avatar
Francis Dupont committed
719
720
721
722
723
724
725
726
727
728
729
		/*
		 * Call dhclient-script with the NBI flag,
		 * in case somebody cares.
		 */
		script_init(NULL, "NBI", NULL);
		script_go(NULL);

		/*
		 * If we haven't been asked to persist, waiting for new
		 * interfaces, then just exit.
		 */
730
731
		if (!persist) {
			/* Nothing more to do. */
Francis Dupont's avatar
Francis Dupont committed
732
			log_info("No broadcast interfaces found - exiting.");
733
			finish(0);
734
		}
735
	} else if (!release_mode && !exit_mode) {
736
		/* Call the script with the list of interfaces. */
Francis Dupont's avatar
Francis Dupont committed
737
738
739
740
741
		for (ip = interfaces; ip; ip = ip->next) {
			/*
			 * If interfaces were specified, don't configure
			 * interfaces that weren't specified!
			 */
Francis Dupont's avatar
Francis Dupont committed
742
			if ((interfaces_requested > 0) &&
Francis Dupont's avatar
Francis Dupont committed
743
744
			    ((ip->flags & (INTERFACE_REQUESTED |
					   INTERFACE_AUTOMATIC)) !=
Ted Lemon's avatar
Ted Lemon committed
745
			     INTERFACE_REQUESTED))
746
				continue;
David Hankins's avatar
David Hankins committed
747
748
749
750
751
752
753
754
755
756

			if (local_family == AF_INET6) {
				script_init(ip->client, "PREINIT6", NULL);
			} else {
				script_init(ip->client, "PREINIT", NULL);
			    	if (ip->client->alias != NULL)
					script_write_params(ip->client,
							    "alias_",
							    ip->client->alias);
			}
Francis Dupont's avatar
Francis Dupont committed
757
			script_go(ip->client);
758
759
		}
	}
760

761
762
763
764
	/* At this point, all the interfaces that the script thinks
	   are relevant should be running, so now we once again call
	   discover_interfaces(), and this time ask it to actually set
	   up the interfaces. */
Francis Dupont's avatar
Francis Dupont committed
765
766
767
	discover_interfaces(interfaces_requested != 0
			    ? DISCOVER_REQUESTED
			    : DISCOVER_RUNNING);
768

769
770
771
772
773
	/* Make up a seed for the random number generator from current
	   time plus the sum of the last four bytes of each
	   interface's hardware address interpreted as an integer.
	   Not much entropy, but we're booting, so we're not likely to
	   find anything better. */
Ted Lemon's avatar
Ted Lemon committed
774
	seed = 0;
Francis Dupont's avatar
Francis Dupont committed
775
	for (ip = interfaces; ip; ip = ip->next) {
776
		int junk;
Francis Dupont's avatar
Francis Dupont committed
777
778
779
		memcpy(&junk,
		       &ip->hw_address.hbuf[ip->hw_address.hlen -
					    sizeof seed], sizeof seed);
780
781
		seed += junk;
	}
Shawn Routhier's avatar
Shawn Routhier committed
782
	srandom(seed + cur_time + (unsigned)getpid());
783

Shawn Routhier's avatar
Shawn Routhier committed
784
785
786
787
788
789
790

	/*
	 * Establish a default DUID.  We always do so for v6 and
	 * do so if desired for v4 via the -D or -i options
	 */
	if ((local_family == AF_INET6) ||
	    ((local_family == AF_INET) && (duid_v4 == 1))) {
David Hankins's avatar
David Hankins committed
791
792
793
794
795
796
797
		if (default_duid.len == 0) {
			if (default_duid.buffer != NULL)
				data_string_forget(&default_duid, MDL);

			form_duid(&default_duid, MDL);
			write_duid(&default_duid);
		}
Shawn Routhier's avatar
Shawn Routhier committed
798
	}
David Hankins's avatar
David Hankins committed
799

800
801
802
803
804
#if defined(DHCPv6) && defined(DHCP4o6)
	if (dhcpv4_over_dhcpv6 && !exit_mode)
		dhcp4o6_setup(dhcp4o6_port);
#endif

Shawn Routhier's avatar
Shawn Routhier committed
805
806
807
	/* Start a configuration state machine for each interface. */
#ifdef DHCPv6
	if (local_family == AF_INET6) {
David Hankins's avatar
David Hankins committed
808
809
810
		for (ip = interfaces ; ip != NULL ; ip = ip->next) {
			for (client = ip->client ; client != NULL ;
			     client = client->next) {
Francis Dupont's avatar
Francis Dupont committed
811
812
813
814
815
816
817
				if (release_mode) {
					start_release6(client);
					continue;
				} else if (exit_mode) {
					unconfigure6(client, "STOP6");
					continue;
				}
818

David Hankins's avatar
David Hankins committed
819
820
821
				/* If we have a previous binding, Confirm
				 * that we can (or can't) still use it.
				 */
822
823
				if ((client->active_lease != NULL) &&
				    !client->active_lease->released)
David Hankins's avatar
David Hankins committed
824
825
826
827
828
					start_confirm6(client);
				else
					start_init6(client);
			}
		}
Francis Dupont's avatar
Francis Dupont committed
829
	} else
830
831
#endif /* DHCPv6 */
	{
David Hankins's avatar
David Hankins committed
832
833
834
835
		for (ip = interfaces ; ip ; ip = ip->next) {
			ip->flags |= INTERFACE_RUNNING;
			for (client = ip->client ; client ;
			     client = client->next) {
Francis Dupont's avatar
Francis Dupont committed
836
837
				if (exit_mode)
					state_stop(client);
838
				if (release_mode)
David Hankins's avatar
David Hankins committed
839
840
841
					do_release(client);
				else {
					client->state = S_INIT;
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863

					if (top_level_config.initial_delay>0)
					{
						tv.tv_sec = 0;
						if (top_level_config.
						    initial_delay>1)
							tv.tv_sec = cur_time
							+ random()
							% (top_level_config.
							   initial_delay-1);
						tv.tv_usec = random()
							% 1000000;
						/*
						 * this gives better
						 * distribution than just
						 *whole seconds
						 */
						add_timeout(&tv, state_reboot,
						            client, 0, 0);
					} else {
						state_reboot(client);
					}
David Hankins's avatar
David Hankins committed
864
				}
865
			}
Ted Lemon's avatar
Ted Lemon committed
866
		}
867
	}
868

Francis Dupont's avatar
Francis Dupont committed
869
	if (exit_mode)
870
		finish(0);
Francis Dupont's avatar
Francis Dupont committed
871
872
	if (release_mode) {
#ifndef DHCPv6
873
		finish(0);
Francis Dupont's avatar
Francis Dupont committed
874
#else
875
		if ((local_family == AF_INET6) || dhcpv4_over_dhcpv6) {
Francis Dupont's avatar
Francis Dupont committed
876
			if (onetry)
877
				finish(0);
Francis Dupont's avatar
Francis Dupont committed
878
		} else
879
			finish(0);
Francis Dupont's avatar
Francis Dupont committed
880
881
#endif /* DHCPv6 */
	}
882
883

	/* Start up a listener for the object management API protocol. */
884
	if (top_level_config.omapi_port != -1) {
Francis Dupont's avatar
Francis Dupont committed
885
886
		listener = NULL;
		result = omapi_generic_new(&listener, MDL);
887
		if (result != ISC_R_SUCCESS)
Francis Dupont's avatar
Francis Dupont committed
888
889
890
891
892
893
			log_fatal("Can't allocate new generic object: %s\n",
				  isc_result_totext(result));
		result = omapi_protocol_listen(listener,
					       (unsigned)
					       top_level_config.omapi_port,
					       1);
894
		if (result != ISC_R_SUCCESS)
Francis Dupont's avatar
Francis Dupont committed
895
896
			log_fatal("Can't start OMAPI protocol: %s",
				  isc_result_totext (result));
897
	}
898

899
900
	/* Set up the bootp packet handler... */
	bootp_packet_handler = do_packet;
901
#ifdef DHCPv6
David Hankins's avatar
David Hankins committed
902
	dhcpv6_packet_handler = do_packet6;
903
#endif /* DHCPv6 */
904

Francis Dupont's avatar
Francis Dupont committed
905
906
#if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
		defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
907
908
909
910
911
	dmalloc_cutoff_generation = dmalloc_generation;
	dmalloc_longterm = dmalloc_outstanding;
	dmalloc_outstanding = 0;
#endif

912
913
#if defined(ENABLE_GENTLE_SHUTDOWN)
	/* no signal handlers until we deal with the side effects */
Shawn Routhier's avatar
Shawn Routhier committed
914
915
916
        /* install signal handlers */
	signal(SIGINT, dhcp_signal_handler);   /* control-c */
	signal(SIGTERM, dhcp_signal_handler);  /* kill */
917
#endif
Shawn Routhier's avatar
Shawn Routhier committed
918

Ted Lemon's avatar
Ted Lemon committed
919
920
921
	/* If we're not supposed to wait before getting the address,
	   don't. */
	if (nowait)
922
		detach();
Ted Lemon's avatar
Ted Lemon committed
923

Ted Lemon's avatar
Ted Lemon committed
924
925
	/* If we're not going to daemonize, write the pid file
	   now. */
Ted Lemon's avatar
Ted Lemon committed
926
	if (no_daemon || nowait)
Francis Dupont's avatar
Francis Dupont committed
927
		write_client_pid_file();
Ted Lemon's avatar
Ted Lemon committed
928

929
	/* Start dispatching packets and timeouts... */
Francis Dupont's avatar
Francis Dupont committed
930
	dispatch();
931

932
	/* In fact dispatch() never returns. */
933
	return 0;
934
935
}

936
937
938
939
940
941
942
943
944
/*
 * \brief Run the DHCPv6 stateless client (dhclient -6 -S)
 *
 * \param exist_mode set to 1 when dhclient was called with -x
 * \param port DHCPv4-over-DHCPv6 client inter-process communication
 *  UDP port pair (port,port+1 with port in network byte order)
 */

void run_stateless(int exit_mode, u_int16_t port)
Francis Dupont's avatar
Francis Dupont committed
945
{
Francis Dupont's avatar
Francis Dupont committed
946
#ifdef DHCPv6
Francis Dupont's avatar
Francis Dupont committed
947
948
949
950
	struct client_state *client;
	omapi_object_t *listener;
	isc_result_t result;

951
952
953
954
#ifndef DHCP4o6
	IGNORE_UNUSED(port);
#endif

Francis Dupont's avatar
Francis Dupont committed
955
956
957
958
	/* Discover the network interface. */
	discover_interfaces(DISCOVER_REQUESTED);

	if (!interfaces)
959
		usage("No interfaces available for stateless command: %s", "-S");
Francis Dupont's avatar
Francis Dupont committed
960
961

	/* Parse the dhclient.conf file. */
962
963
964
965
966
967
#ifdef DHCP4o6
	if (dhcpv4_over_dhcpv6) {
		/* Mark we want to request IRT too! */
		dhcpv4_over_dhcpv6++;
	}
#endif
Francis Dupont's avatar
Francis Dupont committed
968
969
970
971
972
	read_client_conf();

	/* Parse the lease database. */
	read_client_leases();

973
974
975
976
977
	/* If desired parse the secondary lease database for a DUID */
	if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) {
		read_client_duid();
	}

Francis Dupont's avatar
Francis Dupont committed
978
979
980
981
982
983
984
985
	/* Establish a default DUID. */
	if (default_duid.len == 0) {
		if (default_duid.buffer != NULL)
			data_string_forget(&default_duid, MDL);

		form_duid(&default_duid, MDL);
	}

986
987
988
989
990
#ifdef DHCP4o6
	if (dhcpv4_over_dhcpv6 && !exit_mode)
		dhcp4o6_setup(port);
#endif

Francis Dupont's avatar
Francis Dupont committed
991
992
993
994
995
996
997
998
999
1000
	/* Start a configuration state machine. */
	for (client = interfaces->client ;
	     client != NULL ;
	     client = client->next) {
		if (exit_mode) {
			unconfigure6(client, "STOP6");
			continue;
		}
		start_info_request6(client);
	}