6 * Copyright (c) 2004-2020 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
25 * https://www.isc.org/
27 * This code is based on the original client state machine that was
28 * written by Elliot Poger. The code has been extensively hacked on
29 * by Ted Lemon since then, so any mistakes you find are probably his
30 * fault and not Elliot's.
36 #include <dns/result.h>
44 TIME default_lease_time
= 43200; /* 12 hours... */
45 TIME max_lease_time
= 86400; /* 24 hours... */
47 const char *path_dhclient_conf
= _PATH_DHCLIENT_CONF
;
48 const char *path_dhclient_db
= NULL
;
49 const char *path_dhclient_pid
= NULL
;
50 static char path_dhclient_script_array
[] = _PATH_DHCLIENT_SCRIPT
;
51 char *path_dhclient_script
= path_dhclient_script_array
;
52 const char *path_dhclient_duid
= NULL
;
54 static void add_to_tail(struct client_lease
** lease_list
, struct client_lease
* lease
);
56 /* False (default) => we write and use a pid file */
57 isc_boolean_t no_pid_file
= ISC_FALSE
;
59 int dhcp_max_agent_option_packet_length
= 0;
61 int interfaces_requested
= 0;
63 struct iaddr iaddr_broadcast
= { 4, { 255, 255, 255, 255 } };
64 struct iaddr iaddr_any
= { 4, { 0, 0, 0, 0 } };
65 struct in_addr inaddr_any
;
66 struct sockaddr_in sockaddr_broadcast
;
67 struct in_addr giaddr
;
68 struct data_string default_duid
;
73 int decline_wait_time
= 10; /* Default to 10 secs per, RFC 2131, 3.1.5 */
75 /* ASSERT_STATE() does nothing now; it used to be
76 assert (state_is == state_shouldbe). */
77 #define ASSERT_STATE(state_is, state_shouldbe) {}
80 static const char copyright
[] = "Copyright 2004-2020 Internet Systems Consortium.";
81 static const char arr
[] = "All rights reserved.";
82 static const char message
[] = "Internet Systems Consortium DHCP Client";
83 static const char url
[] = "For info, please visit https://www.isc.org/software/dhcp/";
84 #endif /* UNIT_TEST */
86 extern u_int16_t local_port
;
87 extern u_int16_t remote_port
;
89 #if defined(DHCPv6) && defined(DHCP4o6)
90 int dhcp4o6_state
= -1; /* -1 = stopped, 0 = polling, 1 = started */
93 int dfd
[2] = { -1, -1 };
94 struct string_list
*client_env
= NULL
;
95 int client_env_count
= 0;
100 int wanted_ia_na
= -1; /* the absolute value is the real one. */
101 int wanted_ia_ta
= 0;
102 int wanted_ia_pd
= 0;
103 int require_all_ias
= 0; /* If the user requires all of the IAs to
104 be available before accepting a lease
105 0 = no, 1 = requries */
107 int dad_wait_time
= 0;
108 int prefix_len_hint
= 0;
111 int address_prefix_len
= DHCLIENT_DEFAULT_PREFIX_LEN
;
112 char *mockup_relay
= NULL
;
114 char *progname
= NULL
;
116 void run_stateless(int exit_mode
, u_int16_t port
);
118 static isc_result_t
write_duid(struct data_string
*duid
);
119 static void add_reject(struct packet
*packet
);
121 static int check_domain_name(const char *ptr
, size_t len
, int dots
);
122 static int check_domain_name_list(const char *ptr
, size_t len
, int dots
);
123 static int check_option_values(struct universe
*universe
, unsigned int opt
,
124 const char *ptr
, size_t len
);
126 #if defined(NSUPDATE)
127 static void dhclient_ddns_cb_free(dhcp_ddns_cb_t
*ddns_cb
,
128 char* file
, int line
);
129 #endif /* defined NSUPDATE */
134 * \brief Print the generic usage message
136 * If the user has provided an incorrect command line print out
137 * the description of the command line. The arguments provide
138 * a way for the caller to request more specific information about
139 * the error be printed as well. Mostly this will be that some
140 * comamnd doesn't include its argument.
142 * \param sfmt - The basic string and format for the specific error
143 * \param sarg - Generally the offending argument from the comamnd line.
148 #if defined(DHCPv6) && defined(DHCP4o6)
149 static void dhcp4o6_poll(void *dummy
);
150 static void dhcp4o6_resume(void);
151 static void recv_dhcpv4_response(struct data_string
*raw
);
152 static int send_dhcpv4_query(struct client_state
*client
, int broadcast
);
154 static void dhcp4o6_stop(void);
155 static void forw_dhcpv4_response(struct packet
*packet
);
156 static void forw_dhcpv4_query(struct data_string
*raw
);
160 /* These are only used when we call usage() from the main routine
161 * which isn't compiled when building for unit tests
163 static const char use_noarg
[] = "No argument for command: %s";
165 static const char use_v6command
[] = "Command not used for DHCPv4: %s";
170 #define DHCLIENT_USAGE0 \
171 "[-4|-6] [-SNTPRI1dvrxi] [-nw] -4o6 <port>] [-p <port>] [-D LL|LLT]\n" \
172 " [--dad-wait-time <seconds>] [--prefix-len-hint <length>]\n" \
173 " [--decline-wait-time <seconds>]\n" \
174 " [--address-prefix-len <length>]\n"
176 #define DHCLIENT_USAGE0 \
177 "[-4|-6] [-SNTPRI1dvrxi] [-nw] [-p <port>] [-D LL|LLT]\n" \
178 " [--dad-wait-time <seconds>] [--prefix-len-hint <length>]\n" \
179 " [--decline-wait-time <seconds>]\n" \
180 " [--address-prefix-len <length>]\n"
183 #define DHCLIENT_USAGE0 \
184 "[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n" \
185 " [--decline-wait-time <seconds>]\n"
188 #define DHCLIENT_USAGEC \
189 " [-s server-addr] [-cf config-file]\n" \
190 " [-df duid-file] [-lf lease-file]\n" \
191 " [-pf pid-file] [--no-pid] [-e VAR=val]\n" \
192 " [-sf script-file] [interface]*"
194 #define DHCLIENT_USAGEH "{--version|--help|-h}"
197 usage(const char *sfmt
, const char *sarg
)
199 log_info("%s %s", message
, PACKAGE_VERSION
);
204 /* If desired print out the specific error message */
205 #ifdef PRINT_SPECIFIC_CL_ERRORS
207 log_error(sfmt
, sarg
);
210 log_fatal("Usage: %s %s%s\n %s %s",
211 isc_file_basename(progname
),
214 isc_file_basename(progname
),
218 extern void initialize_client_option_spaces();
221 main(int argc
, char **argv
) {
224 struct interface_info
*ip
;
225 struct client_state
*client
;
230 int release_mode
= 0;
232 omapi_object_t
*listener
;
235 int no_dhclient_conf
= 0;
236 int no_dhclient_db
= 0;
237 int no_dhclient_pid
= 0;
238 int no_dhclient_script
= 0;
240 int local_family_set
= 0;
242 u_int16_t dhcp4o6_port
= 0;
248 progname
= "dhclient";
252 /* Initialize client globals. */
253 memset(&default_duid
, 0, sizeof(default_duid
));
255 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
256 2 (stderr) are open. To do this, we assume that when we
257 open a file the lowest available file descriptor is used. */
258 fd
= open("/dev/null", O_RDWR
);
260 fd
= open("/dev/null", O_RDWR
);
262 fd
= open("/dev/null", O_RDWR
);
264 log_perror
= 0; /* No sense logging to /dev/null. */
268 openlog(isc_file_basename(progname
), DHCP_LOG_OPTIONS
, LOG_DAEMON
);
270 #if !(defined(DEBUG) || defined(__CYGWIN32__))
271 setlogmask(LOG_UPTO(LOG_INFO
));
274 /* Parse arguments changing no_daemon */
275 for (i
= 1; i
< argc
; i
++) {
276 if (!strcmp(argv
[i
], "-r")) {
278 } else if (!strcmp(argv
[i
], "-x")) {
280 } else if (!strcmp(argv
[i
], "-d")) {
282 } else if (!strcmp(argv
[i
], "--version")) {
283 const char vstring
[] = "isc-dhclient-";
284 IGNORE_RET(write(STDERR_FILENO
, vstring
,
286 IGNORE_RET(write(STDERR_FILENO
,
288 strlen(PACKAGE_VERSION
)));
289 IGNORE_RET(write(STDERR_FILENO
, "\n", 1));
291 } else if (!strcmp(argv
[i
], "--help") ||
292 !strcmp(argv
[i
], "-h")) {
293 const char *pname
= isc_file_basename(progname
);
294 IGNORE_RET(write(STDERR_FILENO
, "Usage: ", 7));
295 IGNORE_RET(write(STDERR_FILENO
, pname
, strlen(pname
)));
296 IGNORE_RET(write(STDERR_FILENO
, " ", 1));
297 IGNORE_RET(write(STDERR_FILENO
, DHCLIENT_USAGE0
,
298 strlen(DHCLIENT_USAGE0
)));
299 IGNORE_RET(write(STDERR_FILENO
, DHCLIENT_USAGEC
,
300 strlen(DHCLIENT_USAGEC
)));
301 IGNORE_RET(write(STDERR_FILENO
, "\n", 1));
302 IGNORE_RET(write(STDERR_FILENO
, " ", 7));
303 IGNORE_RET(write(STDERR_FILENO
, pname
, strlen(pname
)));
304 IGNORE_RET(write(STDERR_FILENO
, " ", 1));
305 IGNORE_RET(write(STDERR_FILENO
, DHCLIENT_USAGEH
,
306 strlen(DHCLIENT_USAGEH
)));
307 IGNORE_RET(write(STDERR_FILENO
, "\n", 1));
311 /* When not forbidden prepare to become a daemon */
316 log_fatal("Can't get pipe: %m");
317 if ((pid
= fork ()) < 0)
318 log_fatal("Can't fork daemon: %m");
320 /* Parent: wait for the child to start */
323 (void) close(dfd
[1]);
327 n
= read(dfd
[0], &buf
, 1);
330 } while (n
== -1 && errno
== EINTR
);
334 (void) close(dfd
[0]);
337 /* Set up the isc and dns library managers */
338 status
= dhcp_context_create(DHCP_CONTEXT_PRE_DB
| DHCP_CONTEXT_POST_DB
339 | DHCP_DNS_CLIENT_LAZY_INIT
, NULL
, NULL
);
340 if (status
!= ISC_R_SUCCESS
)
341 log_fatal("Can't initialize context: %s",
342 isc_result_totext(status
));
344 /* Set up the OMAPI. */
345 status
= omapi_init();
346 if (status
!= ISC_R_SUCCESS
)
347 log_fatal("Can't initialize OMAPI: %s",
348 isc_result_totext(status
));
350 /* Set up the OMAPI wrappers for various server database internal
352 dhcp_common_objects_setup();
354 dhcp_interface_discovery_hook
= dhclient_interface_discovery_hook
;
355 dhcp_interface_shutdown_hook
= dhclient_interface_shutdown_hook
;
356 dhcp_interface_startup_hook
= dhclient_interface_startup_hook
;
358 for (i
= 1; i
< argc
; i
++) {
359 if (!strcmp(argv
[i
], "-r")) {
363 } else if (!strcmp(argv
[i
], "-4")) {
364 if (local_family_set
&& local_family
!= AF_INET
)
365 log_fatal("Client can only do v4 or v6, not "
367 local_family_set
= 1;
368 local_family
= AF_INET
;
369 } else if (!strcmp(argv
[i
], "-6")) {
370 if (local_family_set
&& local_family
!= AF_INET6
)
371 log_fatal("Client can only do v4 or v6, not "
373 local_family_set
= 1;
374 local_family
= AF_INET6
;
376 } else if (!strcmp(argv
[i
], "-4o6")) {
378 usage(use_noarg
, argv
[i
-1]);
379 dhcp4o6_port
= validate_port_pair(argv
[i
]);
381 log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d",
383 ntohs(dhcp4o6_port
) + 1);
384 dhcpv4_over_dhcpv6
= 1;
387 } else if (!strcmp(argv
[i
], "-x")) { /* eXit, no release */
391 } else if (!strcmp(argv
[i
], "-p")) {
393 usage(use_noarg
, argv
[i
-1]);
394 local_port
= validate_port(argv
[i
]);
395 log_debug("binding to user-specified port %d",
397 } else if (!strcmp(argv
[i
], "-d")) {
400 } else if (!strcmp(argv
[i
], "-pf")) {
402 usage(use_noarg
, argv
[i
-1]);
403 path_dhclient_pid
= argv
[i
];
405 } else if (!strcmp(argv
[i
], "--no-pid")) {
406 no_pid_file
= ISC_TRUE
;
407 } else if (!strcmp(argv
[i
], "-cf")) {
409 usage(use_noarg
, argv
[i
-1]);
410 path_dhclient_conf
= argv
[i
];
411 no_dhclient_conf
= 1;
412 } else if (!strcmp(argv
[i
], "-df")) {
414 usage(use_noarg
, argv
[i
-1]);
415 path_dhclient_duid
= argv
[i
];
416 } else if (!strcmp(argv
[i
], "-lf")) {
418 usage(use_noarg
, argv
[i
-1]);
419 path_dhclient_db
= argv
[i
];
421 } else if (!strcmp(argv
[i
], "-sf")) {
423 usage(use_noarg
, argv
[i
-1]);
424 path_dhclient_script
= argv
[i
];
425 no_dhclient_script
= 1;
426 } else if (!strcmp(argv
[i
], "-1")) {
428 } else if (!strcmp(argv
[i
], "-q")) {
430 } else if (!strcmp(argv
[i
], "-s")) {
432 usage(use_noarg
, argv
[i
-1]);
434 } else if (!strcmp(argv
[i
], "-g")) {
436 usage(use_noarg
, argv
[i
-1]);
437 mockup_relay
= argv
[i
];
438 } else if (!strcmp(argv
[i
], "-nw")) {
440 } else if (!strcmp(argv
[i
], "-n")) {
441 /* do not start up any interfaces */
442 interfaces_requested
= -1;
443 } else if (!strcmp(argv
[i
], "-w")) {
444 /* do not exit if there are no broadcast interfaces. */
446 } else if (!strcmp(argv
[i
], "-e")) {
447 struct string_list
*tmp
;
449 usage(use_noarg
, argv
[i
-1]);
450 tmp
= dmalloc(strlen(argv
[i
]) + sizeof *tmp
, MDL
);
452 log_fatal("No memory for %s", argv
[i
]);
453 strcpy(tmp
->string
, argv
[i
]);
454 tmp
->next
= client_env
;
458 } else if (!strcmp(argv
[i
], "-S")) {
459 if (local_family_set
&& (local_family
== AF_INET
)) {
460 usage(use_v6command
, argv
[i
]);
462 local_family_set
= 1;
463 local_family
= AF_INET6
;
466 } else if (!strcmp(argv
[i
], "-N")) {
467 if (local_family_set
&& (local_family
== AF_INET
)) {
468 usage(use_v6command
, argv
[i
]);
470 local_family_set
= 1;
471 local_family
= AF_INET6
;
472 if (wanted_ia_na
< 0) {
476 } else if (!strcmp(argv
[i
], "-T")) {
477 if (local_family_set
&& (local_family
== AF_INET
)) {
478 usage(use_v6command
, argv
[i
]);
480 local_family_set
= 1;
481 local_family
= AF_INET6
;
482 if (wanted_ia_na
< 0) {
486 } else if (!strcmp(argv
[i
], "-P")) {
487 if (local_family_set
&& (local_family
== AF_INET
)) {
488 usage(use_v6command
, argv
[i
]);
490 local_family_set
= 1;
491 local_family
= AF_INET6
;
492 if (wanted_ia_na
< 0) {
496 } else if (!strcmp(argv
[i
], "-R")) {
497 if (local_family_set
&& (local_family
== AF_INET
)) {
498 usage(use_v6command
, argv
[i
]);
500 local_family_set
= 1;
501 local_family
= AF_INET6
;
503 } else if (!strcmp(argv
[i
], "--dad-wait-time")) {
505 usage(use_noarg
, argv
[i
-1]);
508 dad_wait_time
= (int)strtol(argv
[i
], &s
, 10);
509 if (errno
|| (*s
!= '\0') || (dad_wait_time
< 0)) {
510 usage("Invalid value for --dad-wait-time: %s",
513 } else if (!strcmp(argv
[i
], "--prefix-len-hint")) {
515 usage(use_noarg
, argv
[i
-1]);
519 prefix_len_hint
= (int)strtol(argv
[i
], &s
, 10);
520 if (errno
|| (*s
!= '\0') || (prefix_len_hint
< 0)) {
521 usage("Invalid value for --prefix-len-hint: %s",
524 } else if (!strcmp(argv
[i
], "--address-prefix-len")) {
526 usage(use_noarg
, argv
[i
-1]);
529 address_prefix_len
= (int)strtol(argv
[i
], &s
, 10);
530 if (errno
|| (*s
!= '\0') ||
531 (address_prefix_len
< 0)) {
532 usage("Invalid value for"
533 " --address-prefix-len: %s", argv
[i
]);
536 } else if (!strcmp(argv
[i
], "--decline-wait-time")) {
538 usage(use_noarg
, argv
[i
-1]);
542 decline_wait_time
= (int)strtol(argv
[i
], &s
, 10);
543 if (errno
|| (*s
!= '\0') ||
544 (decline_wait_time
< 0)) {
545 usage("Invalid value for "
546 "--decline-wait-time: %s", argv
[i
]);
548 } else if (!strcmp(argv
[i
], "-D")) {
551 usage(use_noarg
, argv
[i
-1]);
552 if (!strcasecmp(argv
[i
], "LL")) {
554 } else if (!strcasecmp(argv
[i
], "LLT")) {
555 duid_type
= DUID_LLT
;
557 usage("Unknown argument to -D: %s", argv
[i
]);
559 } else if (!strcmp(argv
[i
], "-i")) {
560 /* enable DUID support for DHCPv4 clients */
562 } else if (!strcmp(argv
[i
], "-I")) {
563 /* enable standard DHCID support for DDNS updates */
565 } else if (!strcmp(argv
[i
], "-v")) {
567 } else if (argv
[i
][0] == '-') {
568 usage("Unknown command: %s", argv
[i
]);
569 } else if (interfaces_requested
< 0) {
570 usage("No interfaces comamnd -n and "
571 " requested interface %s", argv
[i
]);
573 struct interface_info
*tmp
= NULL
;
575 status
= interface_allocate(&tmp
, MDL
);
576 if (status
!= ISC_R_SUCCESS
)
577 log_fatal("Can't record interface %s:%s",
578 argv
[i
], isc_result_totext(status
));
579 if (strlen(argv
[i
]) >= sizeof(tmp
->name
))
580 log_fatal("%s: interface name too long (is %ld)",
581 argv
[i
], (long)strlen(argv
[i
]));
582 strcpy(tmp
->name
, argv
[i
]);
584 interface_reference(&tmp
->next
,
586 interface_dereference(&interfaces
, MDL
);
588 interface_reference(&interfaces
, tmp
, MDL
);
589 tmp
->flags
= INTERFACE_REQUESTED
;
590 interfaces_requested
++;
594 if (wanted_ia_na
< 0) {
598 /* Support only one (requested) interface for Prefix Delegation. */
599 if (wanted_ia_pd
&& (interfaces_requested
!= 1)) {
600 usage("PD %s only supports one requested interface", "-P");
603 #if defined(DHCPv6) && defined(DHCP4o6)
604 if ((local_family
== AF_INET6
) && dhcpv4_over_dhcpv6
&&
605 (exit_mode
|| release_mode
))
606 log_error("Can't relay DHCPv4-over-DHCPv6 "
607 "without a persistent DHCPv6 client");
608 if ((local_family
== AF_INET
) && dhcpv4_over_dhcpv6
&&
609 (interfaces_requested
!= 1))
610 log_fatal("DHCPv4-over-DHCPv6 requires an explicit "
611 "interface on which to be applied");
614 if (!no_dhclient_conf
&& (s
= getenv("PATH_DHCLIENT_CONF"))) {
615 path_dhclient_conf
= s
;
617 if (!no_dhclient_db
&& (s
= getenv("PATH_DHCLIENT_DB"))) {
618 path_dhclient_db
= s
;
620 if (!no_dhclient_pid
&& (s
= getenv("PATH_DHCLIENT_PID"))) {
621 path_dhclient_pid
= s
;
623 if (!no_dhclient_script
&& (s
= getenv("PATH_DHCLIENT_SCRIPT"))) {
624 path_dhclient_script
= s
;
627 /* Set up the initial dhcp option universe. */
628 initialize_common_option_spaces();
630 /* Set up the initial client option universe. */
631 initialize_client_option_spaces();
633 /* Assign v4 or v6 specific running parameters. */
634 if (local_family
== AF_INET
)
635 dhcpv4_client_assignments();
637 else if (local_family
== AF_INET6
)
638 dhcpv6_client_assignments();
641 log_fatal("Impossible condition at %s:%d.", MDL
);
644 * convert relative path names to absolute, for files that need
645 * to be reopened after chdir() has been called
647 if (path_dhclient_db
[0] != '/') {
648 path_dhclient_db
= absolute_path(path_dhclient_db
);
651 if (path_dhclient_script
[0] != '/') {
652 path_dhclient_script
= absolute_path(path_dhclient_script
);
656 * See if we should kill off any currently running client
657 * we don't try to kill it off if the user told us not
658 * to write a pid file - we assume they are controlling
659 * the process in some other fashion.
661 if ((release_mode
|| exit_mode
) && (no_pid_file
== ISC_FALSE
)) {
667 if ((pidfd
= fopen(path_dhclient_pid
, "r")) != NULL
) {
668 e
= fscanf(pidfd
, "%ld\n", &temp
);
669 oldpid
= (pid_t
)temp
;
671 if (e
!= 0 && e
!= EOF
&& oldpid
) {
672 if (kill(oldpid
, SIGTERM
) == 0) {
673 log_info("Killed old client process");
674 (void) unlink(path_dhclient_pid
);
676 * wait for the old process to
678 * Note kill() with sig=0 could
679 * detect termination but only
680 * the parent can be signaled...
683 } else if (errno
== ESRCH
) {
684 log_info("Removed stale PID file");
685 (void) unlink(path_dhclient_pid
);
693 log_info("%s %s", message
, PACKAGE_VERSION
);
700 quiet_interface_discovery
= 1;
703 /* If we're given a relay agent address to insert, for testing
704 purposes, figure out what it is. */
706 if (!inet_aton(mockup_relay
, &giaddr
)) {
708 he
= gethostbyname(mockup_relay
);
710 memcpy(&giaddr
, he
->h_addr_list
[0],
713 log_fatal("%s: no such host", mockup_relay
);
718 /* Get the current time... */
719 gettimeofday(&cur_tv
, NULL
);
721 sockaddr_broadcast
.sin_family
= AF_INET
;
722 sockaddr_broadcast
.sin_port
= remote_port
;
724 if (!inet_aton(server
, &sockaddr_broadcast
.sin_addr
)) {
726 he
= gethostbyname(server
);
728 memcpy(&sockaddr_broadcast
.sin_addr
,
730 sizeof sockaddr_broadcast
.sin_addr
);
732 sockaddr_broadcast
.sin_addr
.s_addr
=
736 sockaddr_broadcast
.sin_addr
.s_addr
= INADDR_BROADCAST
;
739 inaddr_any
.s_addr
= INADDR_ANY
;
741 /* Stateless special case. */
743 if (release_mode
|| (wanted_ia_na
> 0) ||
744 wanted_ia_ta
|| wanted_ia_pd
||
745 (interfaces_requested
!= 1)) {
746 usage("Stateless command: %s incompatibile with "
747 "other commands", "-S");
749 #if defined(DHCPv6) && defined(DHCP4o6)
750 run_stateless(exit_mode
, dhcp4o6_port
);
752 run_stateless(exit_mode
, 0);
757 /* Discover all the network interfaces. */
758 discover_interfaces(DISCOVER_UNCONFIGURED
);
760 /* Parse the dhclient.conf file. */
763 /* Parse the lease database. */
764 read_client_leases();
766 /* If desired parse the secondary lease database for a DUID */
767 if ((default_duid
.len
== 0) && (path_dhclient_duid
!= NULL
)) {
771 /* Rewrite the lease database... */
772 rewrite_client_leases();
775 /* config_counter(&snd_counter, &rcv_counter); */
778 * If no broadcast interfaces were discovered, call the script
783 * Call dhclient-script with the NBI flag,
784 * in case somebody cares.
786 script_init(NULL
, "NBI", NULL
);
790 * If we haven't been asked to persist, waiting for new
791 * interfaces, then just exit.
794 /* Nothing more to do. */
795 log_info("No broadcast interfaces found - exiting.");
798 } else if (!release_mode
&& !exit_mode
) {
799 /* Call the script with the list of interfaces. */
800 for (ip
= interfaces
; ip
; ip
= ip
->next
) {
802 * If interfaces were specified, don't configure
803 * interfaces that weren't specified!
805 if ((interfaces_requested
> 0) &&
806 ((ip
->flags
& (INTERFACE_REQUESTED
|
807 INTERFACE_AUTOMATIC
)) !=
808 INTERFACE_REQUESTED
))
811 if (local_family
== AF_INET6
) {
812 script_init(ip
->client
, "PREINIT6", NULL
);
814 script_init(ip
->client
, "PREINIT", NULL
);
815 if (ip
->client
->alias
!= NULL
)
816 script_write_params(ip
->client
,
820 script_go(ip
->client
);
824 /* At this point, all the interfaces that the script thinks
825 are relevant should be running, so now we once again call
826 discover_interfaces(), and this time ask it to actually set
827 up the interfaces. */
828 discover_interfaces(interfaces_requested
!= 0
832 /* Make up a seed for the random number generator from current
833 time plus the sum of the last four bytes of each
834 interface's hardware address interpreted as an integer.
835 Not much entropy, but we're booting, so we're not likely to
836 find anything better. */
838 for (ip
= interfaces
; ip
; ip
= ip
->next
) {
841 &ip
->hw_address
.hbuf
[ip
->hw_address
.hlen
-
842 sizeof seed
], sizeof seed
);
845 srandom(seed
+ cur_time
+ (unsigned)getpid());
849 * Establish a default DUID. We always do so for v6 and
850 * do so if desired for v4 via the -D or -i options
852 if ((local_family
== AF_INET6
) ||
853 ((local_family
== AF_INET
) && (duid_v4
== 1))) {
854 if (default_duid
.len
== 0) {
855 if (default_duid
.buffer
!= NULL
)
856 data_string_forget(&default_duid
, MDL
);
858 form_duid(&default_duid
, MDL
);
859 write_duid(&default_duid
);
863 #if defined(DHCPv6) && defined(DHCP4o6)
864 if (dhcpv4_over_dhcpv6
&& !exit_mode
)
865 dhcp4o6_setup(dhcp4o6_port
);
868 /* Start a configuration state machine for each interface. */
870 if (local_family
== AF_INET6
) {
871 for (ip
= interfaces
; ip
!= NULL
; ip
= ip
->next
) {
872 for (client
= ip
->client
; client
!= NULL
;
873 client
= client
->next
) {
875 start_release6(client
);
877 } else if (exit_mode
) {
878 unconfigure6(client
, "STOP6");
882 /* If we have a previous binding, Confirm
883 * that we can (or can't) still use it.
885 if ((client
->active_lease
!= NULL
) &&
886 !client
->active_lease
->released
)
887 start_confirm6(client
);
895 for (ip
= interfaces
; ip
; ip
= ip
->next
) {
896 ip
->flags
|= INTERFACE_RUNNING
;
897 for (client
= ip
->client
; client
;
898 client
= client
->next
) {
904 client
->state
= S_INIT
;
906 if (top_level_config
.initial_delay
>0)
909 if (top_level_config
.
915 tv
.tv_usec
= random()
919 * distribution than just
922 add_timeout(&tv
, state_reboot
,
925 state_reboot(client
);
938 if ((local_family
== AF_INET6
) || dhcpv4_over_dhcpv6
) {
946 /* Start up a listener for the object management API protocol. */
947 if (top_level_config
.omapi_port
!= -1) {
949 result
= omapi_generic_new(&listener
, MDL
);
950 if (result
!= ISC_R_SUCCESS
)
951 log_fatal("Can't allocate new generic object: %s\n",
952 isc_result_totext(result
));
953 result
= omapi_protocol_listen(listener
,
955 top_level_config
.omapi_port
,
957 if (result
!= ISC_R_SUCCESS
)
958 log_fatal("Can't start OMAPI protocol: %s",
959 isc_result_totext (result
));
962 /* Set up the bootp packet handler... */
963 bootp_packet_handler
= do_packet
;
965 dhcpv6_packet_handler
= do_packet6
;
968 #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
969 defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
970 dmalloc_cutoff_generation
= dmalloc_generation
;
971 dmalloc_longterm
= dmalloc_outstanding
;
972 dmalloc_outstanding
= 0;
975 #if defined(ENABLE_GENTLE_SHUTDOWN)
976 /* no signal handlers until we deal with the side effects */
977 /* install signal handlers */
978 signal(SIGINT
, dhcp_signal_handler
); /* control-c */
979 signal(SIGTERM
, dhcp_signal_handler
); /* kill */
982 /* If we're not supposed to wait before getting the address,
987 /* If we're not going to daemonize, write the pid file
989 if (no_daemon
|| nowait
)
990 write_client_pid_file();
992 /* Start dispatching packets and timeouts... */
995 /* In fact dispatch() never returns. */
1000 * \brief Run the DHCPv6 stateless client (dhclient -6 -S)
1002 * \param exist_mode set to 1 when dhclient was called with -x
1003 * \param port DHCPv4-over-DHCPv6 client inter-process communication
1004 * UDP port pair (port,port+1 with port in network byte order)
1007 void run_stateless(int exit_mode
, u_int16_t port
)
1010 struct client_state
*client
;
1011 omapi_object_t
*listener
;
1012 isc_result_t result
;
1015 IGNORE_UNUSED(port
);
1018 /* Discover the network interface. */
1019 discover_interfaces(DISCOVER_REQUESTED
);
1022 usage("No interfaces available for stateless command: %s", "-S");
1024 /* Parse the dhclient.conf file. */
1026 if (dhcpv4_over_dhcpv6
) {
1027 /* Mark we want to request IRT too! */
1028 dhcpv4_over_dhcpv6
++;
1033 /* Parse the lease database. */
1034 read_client_leases();
1036 /* If desired parse the secondary lease database for a DUID */
1037 if ((default_duid
.len
== 0) && (path_dhclient_duid
!= NULL
)) {
1041 /* Establish a default DUID. */
1042 if (default_duid
.len
== 0) {
1043 if (default_duid
.buffer
!= NULL
)
1044 data_string_forget(&default_duid
, MDL
);
1046 form_duid(&default_duid
, MDL
);
1050 if (dhcpv4_over_dhcpv6
&& !exit_mode
)
1051 dhcp4o6_setup(port
);
1054 /* Start a configuration state machine. */
1055 for (client
= interfaces
->client
;
1057 client
= client
->next
) {
1059 unconfigure6(client
, "STOP6");
1062 start_info_request6(client
);
1067 /* Start up a listener for the object management API protocol. */
1068 if (top_level_config
.omapi_port
!= -1) {
1070 result
= omapi_generic_new(&listener
, MDL
);
1071 if (result
!= ISC_R_SUCCESS
)
1072 log_fatal("Can't allocate new generic object: %s\n",
1073 isc_result_totext(result
));
1074 result
= omapi_protocol_listen(listener
,
1076 top_level_config
.omapi_port
,
1078 if (result
!= ISC_R_SUCCESS
)
1079 log_fatal("Can't start OMAPI protocol: %s",
1080 isc_result_totext(result
));
1083 /* Set up the packet handler... */
1084 dhcpv6_packet_handler
= do_packet6
;
1086 #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
1087 defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1088 dmalloc_cutoff_generation
= dmalloc_generation
;
1089 dmalloc_longterm
= dmalloc_outstanding
;
1090 dmalloc_outstanding
= 0;
1093 /* If we're not supposed to wait before getting the address,
1098 /* If we're not going to daemonize, write the pid file
1100 if (no_daemon
|| nowait
)
1101 write_client_pid_file();
1103 /* Start dispatching packets and timeouts... */
1109 #endif /* !UNIT_TEST */
1111 isc_result_t
find_class (struct class **c
,
1112 const char *s
, const char *file
, int line
)
1117 int check_collection (packet
, lease
, collection
)
1118 struct packet
*packet
;
1119 struct lease
*lease
;
1120 struct collection
*collection
;
1125 void classify (packet
, class)
1126 struct packet
*packet
;
1127 struct class *class;
1131 void unbill_class (lease
)
1132 struct lease
*lease
;
1136 int find_subnet (struct subnet
**sp
,
1137 struct iaddr addr
, const char *file
, int line
)
1142 /* Individual States:
1144 * Each routine is called from the dhclient_state_machine() in one of
1146 * -> entering INIT state
1147 * -> recvpacket_flag == 0: timeout in this state
1148 * -> otherwise: received a packet in this state
1150 * Return conditions as handled by dhclient_state_machine():
1151 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
1152 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
1153 * Returns 0: finish the nap which was interrupted for no good reason.
1155 * Several per-interface variables are used to keep track of the process:
1156 * active_lease: the lease that is being used on the interface
1157 * (null pointer if not configured yet).
1158 * offered_leases: leases corresponding to DHCPOFFER messages that have
1159 * been sent to us by DHCP servers.
1160 * acked_leases: leases corresponding to DHCPACK messages that have been
1161 * sent to us by DHCP servers.
1162 * sendpacket: DHCP packet we're trying to send.
1163 * destination: IP address to send sendpacket to
1164 * In addition, there are several relevant per-lease variables.
1165 * T1_expiry, T2_expiry, lease_expiry: lease milestones
1166 * In the active lease, these control the process of renewing the lease;
1167 * In leases on the acked_leases list, this simply determines when we
1168 * can no longer legitimately use the lease.
1171 void state_reboot (cpp
)
1174 struct client_state
*client
= cpp
;
1176 #if defined(DHCPv6) && defined(DHCP4o6)
1177 if (dhcpv4_over_dhcpv6
&& (dhcp4o6_state
<= 0)) {
1178 if (dhcp4o6_state
< 0)
1180 client
->pending
= P_REBOOT
;
1185 client
->pending
= P_NONE
;
1187 /* If we don't remember an active lease, go straight to INIT. */
1188 if (!client
-> active
||
1189 client
-> active
-> is_bootp
||
1190 client
-> active
-> expiry
<= cur_time
) {
1191 state_init (client
);
1195 /* We are in the rebooting state. */
1196 client
-> state
= S_REBOOTING
;
1199 * make_request doesn't initialize xid because it normally comes
1200 * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
1201 * so pick an xid now.
1203 client
-> xid
= random ();
1206 * Make a DHCPREQUEST packet, and set
1207 * appropriate per-interface flags.
1209 make_request (client
, client
-> active
);
1210 client
-> destination
= iaddr_broadcast
;
1211 client
-> first_sending
= cur_time
;
1212 client
-> interval
= client
-> config
-> initial_interval
;
1214 /* Zap the medium list... */
1215 client
-> medium
= NULL
;
1217 /* Send out the first DHCPREQUEST packet. */
1218 send_request (client
);
1221 /* Called when a lease has completely expired and we've been unable to
1224 void state_init (cpp
)
1227 struct client_state
*client
= cpp
;
1229 ASSERT_STATE(state
, S_INIT
);
1231 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
1233 make_discover (client
, client
-> active
);
1234 client
-> xid
= client
-> packet
.xid
;
1235 client
-> destination
= iaddr_broadcast
;
1236 client
-> state
= S_SELECTING
;
1237 client
-> first_sending
= cur_time
;
1238 client
-> interval
= client
-> config
-> initial_interval
;
1240 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
1242 send_discover (client
);
1245 /* check_v6only is called by dhcpoffer and dhcpack. It checks if a
1246 * requested v6-only-preferred option is present and returned the
1247 * V6ONLY_WAIT delay to suspend DHCPv4. */
1249 uint32_t check_v6only(packet
, client
)
1250 struct packet
*packet
;
1251 struct client_state
*client
;
1254 struct option
**req
;
1255 isc_boolean_t found
= ISC_FALSE
;
1256 struct option_cache
*oc
;
1257 struct data_string data
;
1258 uint32_t v6only_wait
= 0;
1260 /* Check if the v6-only-preferred was requested. */
1261 req
= client
->config
->requested_options
;
1266 for (i
= 0 ; req
[i
] != NULL
; i
++) {
1267 if ((req
[i
]->universe
== &dhcp_universe
) &&
1268 (req
[i
]->code
== DHO_V6_ONLY_PREFERRED
)) {
1274 if (found
== ISC_FALSE
)
1277 /* Get the V6ONLY_WAIT timer. */
1278 oc
= lookup_option(&dhcp_universe
, packet
->options
,
1279 DHO_V6_ONLY_PREFERRED
);
1283 memset(&data
, 0, sizeof(data
));
1285 if (evaluate_option_cache(&data
, packet
, (struct lease
*)0, client
,
1286 packet
->options
, (struct option_state
*)0,
1287 &global_scope
, oc
, MDL
)) {
1289 v6only_wait
= getULong(data
.data
);
1290 if (v6only_wait
< MIN_V6ONLY_WAIT
)
1291 v6only_wait
= MIN_V6ONLY_WAIT
;
1293 data_string_forget(&data
, MDL
);
1296 return (v6only_wait
);
1299 /* finish_v6only is called when the V6ONLY_WAIT timer expired. */
1301 void finish_v6only(cpp
)
1304 struct client_state
*client
= cpp
;
1305 client
->state
= S_INIT
;
1310 * start_v6only is called when a requested v6-only-preferred option was
1311 * returned by the server. */
1313 void start_v6only(client
, v6only_wait
)
1314 struct client_state
*client
;
1315 uint32_t v6only_wait
;
1319 /* Enter V6ONLY state. */
1321 client
->state
= S_V6ONLY
;
1323 /* Run the client script. */
1324 script_init(client
, "V6ONLY", NULL
);
1325 if (client
->active
) {
1326 script_write_params(client
, "old_", client
->active
);
1327 destroy_client_lease(client
->active
);
1328 client
->active
= NULL
;
1330 script_write_requested(client
);
1331 client_envadd(client
, "", "v6-only-preferred", "%lu",
1332 (long unsigned)v6only_wait
);
1335 /* Trigger finish_v6only after V6ONLY_WAIT seconds. */
1336 tv
.tv_sec
= cur_tv
.tv_sec
+ v6only_wait
;
1337 tv
.tv_usec
= cur_tv
.tv_usec
;
1339 add_timeout(&tv
, finish_v6only
, client
, 0, 0);
1343 * state_selecting is called when one or more DHCPOFFER packets have been
1344 * received and a configurable period of time has passed.
1347 void state_selecting (cpp
)
1350 struct client_state
*client
= cpp
;
1351 struct client_lease
*lp
, *next
, *picked
;
1354 ASSERT_STATE(state
, S_SELECTING
);
1357 * Cancel state_selecting and send_discover timeouts, since either
1358 * one could have got us here.
1360 cancel_timeout (state_selecting
, client
);
1361 cancel_timeout (send_discover
, client
);
1364 * We have received one or more DHCPOFFER packets. Currently,
1365 * the only criterion by which we judge leases is whether or
1366 * not we get a response when we arp for them.
1369 for (lp
= client
-> offered_leases
; lp
; lp
= next
) {
1373 * Check to see if we got an ARPREPLY for the address
1374 * in this particular lease.
1378 picked
-> next
= NULL
;
1380 destroy_client_lease (lp
);
1383 client
-> offered_leases
= NULL
;
1386 * If we just tossed all the leases we were offered, go back
1390 client
-> state
= S_INIT
;
1391 state_init (client
);
1395 /* If it was a BOOTREPLY, we can just take the address right now. */
1396 if (picked
-> is_bootp
) {
1397 client
-> new = picked
;
1399 /* Make up some lease expiry times
1400 XXX these should be configurable. */
1401 client
-> new -> expiry
= cur_time
+ 12000;
1402 client
-> new -> renewal
+= cur_time
+ 8000;
1403 client
-> new -> rebind
+= cur_time
+ 10000;
1405 client
-> state
= S_REQUESTING
;
1407 /* Bind to the address we received. */
1408 bind_lease (client
);
1412 /* Go to the REQUESTING state. */
1413 client
-> destination
= iaddr_broadcast
;
1414 client
-> state
= S_REQUESTING
;
1415 client
-> first_sending
= cur_time
;
1416 client
-> interval
= client
-> config
-> initial_interval
;
1418 /* Make a DHCPREQUEST packet from the lease we picked. */
1419 make_request (client
, picked
);
1420 client
-> xid
= client
-> packet
.xid
;
1422 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
1423 destroy_client_lease (picked
);
1425 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
1426 send_request (client
);
1429 /* state_requesting is called when we receive a DHCPACK message after
1430 having sent out one or more DHCPREQUEST packets. */
1432 void dhcpack (packet
)
1433 struct packet
*packet
;
1435 struct interface_info
*ip
= packet
-> interface
;
1436 struct client_state
*client
;
1437 uint32_t v6only_wait
;
1438 struct client_lease
*lease
;
1439 struct option_cache
*oc
;
1440 struct data_string ds
;
1442 /* If we're not receptive to an offer right now, or if the offer
1443 has an unrecognizable transaction id, then just drop it. */
1444 for (client
= ip
-> client
; client
; client
= client
-> next
) {
1445 if (client
-> xid
== packet
-> raw
-> xid
)
1449 (packet
-> interface
-> hw_address
.hlen
- 1 !=
1450 packet
-> raw
-> hlen
) ||
1451 (memcmp (&packet
-> interface
-> hw_address
.hbuf
[1],
1452 packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
))) {
1454 log_debug ("DHCPACK in wrong transaction.");
1459 if (client
-> state
!= S_REBOOTING
&&
1460 client
-> state
!= S_REQUESTING
&&
1461 client
-> state
!= S_RENEWING
&&
1462 client
-> state
!= S_REBINDING
) {
1464 log_debug ("DHCPACK in wrong state.");
1469 log_info ("DHCPACK of %s from %s",
1470 inet_ntoa(packet
->raw
->yiaddr
),
1471 piaddr (packet
->client_addr
));
1473 /* Check v6only first. */
1474 v6only_wait
= check_v6only(packet
, client
);
1475 if (v6only_wait
> 0) {
1476 log_info("v6 only preferred for %lu.",
1477 (long unsigned)v6only_wait
);
1478 start_v6only(client
, v6only_wait
);
1482 lease
= packet_to_lease (packet
, client
);
1484 log_info ("packet_to_lease failed.");
1488 client
-> new = lease
;
1490 /* Stop resending DHCPREQUEST. */
1491 cancel_timeout (send_request
, client
);
1493 /* Figure out the lease time. */
1494 oc
= lookup_option (&dhcp_universe
, client
-> new -> options
,
1495 DHO_DHCP_LEASE_TIME
);
1496 memset (&ds
, 0, sizeof ds
);
1498 evaluate_option_cache (&ds
, packet
, (struct lease
*)0, client
,
1499 packet
-> options
, client
-> new -> options
,
1500 &global_scope
, oc
, MDL
)) {
1502 client
-> new -> expiry
= getULong (ds
.data
);
1504 client
-> new -> expiry
= 0;
1505 data_string_forget (&ds
, MDL
);
1507 client
-> new -> expiry
= 0;
1509 if (client
->new->expiry
== 0) {
1512 log_error ("no expiry time on offered lease.");
1514 /* Quench this (broken) server. Return to INIT to reselect. */
1517 /* 1/2 second delay to restart at INIT. */
1518 tv
.tv_sec
= cur_tv
.tv_sec
;
1519 tv
.tv_usec
= cur_tv
.tv_usec
+ 500000;
1521 if (tv
.tv_usec
>= 1000000) {
1523 tv
.tv_usec
-= 1000000;
1526 add_timeout(&tv
, state_init
, client
, 0, 0);
1531 * A number that looks negative here is really just very large,
1532 * because the lease expiry offset is unsigned.
1534 if (client
->new->expiry
< 0)
1535 client
->new->expiry
= TIME_MAX
;
1537 /* Take the server-provided renewal time if there is one. */
1538 oc
= lookup_option (&dhcp_universe
, client
-> new -> options
,
1539 DHO_DHCP_RENEWAL_TIME
);
1541 evaluate_option_cache (&ds
, packet
, (struct lease
*)0, client
,
1542 packet
-> options
, client
-> new -> options
,
1543 &global_scope
, oc
, MDL
)) {
1545 client
-> new -> renewal
= getULong (ds
.data
);
1547 client
-> new -> renewal
= 0;
1548 data_string_forget (&ds
, MDL
);
1550 client
-> new -> renewal
= 0;
1552 /* If it wasn't specified by the server, calculate it. */
1553 if (!client
-> new -> renewal
)
1554 client
-> new -> renewal
= client
-> new -> expiry
/ 2 + 1;
1556 if (client
-> new -> renewal
<= 0)
1557 client
-> new -> renewal
= TIME_MAX
;
1559 /* Now introduce some randomness to the renewal time: */
1560 if (client
->new->renewal
<= ((TIME_MAX
/ 3) - 3))
1561 client
->new->renewal
= (((client
->new->renewal
* 3) + 3) / 4) +
1562 (((random() % client
->new->renewal
) + 3) / 4);
1564 /* Same deal with the rebind time. */
1565 oc
= lookup_option (&dhcp_universe
, client
-> new -> options
,
1566 DHO_DHCP_REBINDING_TIME
);
1568 evaluate_option_cache (&ds
, packet
, (struct lease
*)0, client
,
1569 packet
-> options
, client
-> new -> options
,
1570 &global_scope
, oc
, MDL
)) {
1572 client
-> new -> rebind
= getULong (ds
.data
);
1574 client
-> new -> rebind
= 0;
1575 data_string_forget (&ds
, MDL
);
1577 client
-> new -> rebind
= 0;
1579 if (client
-> new -> rebind
<= 0) {
1580 if (client
-> new -> expiry
<= TIME_MAX
/ 7)
1581 client
-> new -> rebind
=
1582 client
-> new -> expiry
* 7 / 8;
1584 client
-> new -> rebind
=
1585 client
-> new -> expiry
/ 8 * 7;
1588 /* Make sure our randomness didn't run the renewal time past the
1590 if (client
-> new -> renewal
> client
-> new -> rebind
) {
1591 if (client
-> new -> rebind
<= TIME_MAX
/ 3)
1592 client
-> new -> renewal
=
1593 client
-> new -> rebind
* 3 / 4;
1595 client
-> new -> renewal
=
1596 client
-> new -> rebind
/ 4 * 3;
1599 client
-> new -> expiry
+= cur_time
;
1600 /* Lease lengths can never be negative. */
1601 if (client
-> new -> expiry
< cur_time
)
1602 client
-> new -> expiry
= TIME_MAX
;
1603 client
-> new -> renewal
+= cur_time
;
1604 if (client
-> new -> renewal
< cur_time
)
1605 client
-> new -> renewal
= TIME_MAX
;
1606 client
-> new -> rebind
+= cur_time
;
1607 if (client
-> new -> rebind
< cur_time
)
1608 client
-> new -> rebind
= TIME_MAX
;
1610 bind_lease (client
);
1613 void bind_lease (client
)
1614 struct client_state
*client
;
1618 /* Remember the medium. */
1619 client
->new->medium
= client
->medium
;
1621 /* Run the client script with the new parameters. */
1622 script_init(client
, (client
->state
== S_REQUESTING
? "BOUND" :
1623 (client
->state
== S_RENEWING
? "RENEW" :
1624 (client
->state
== S_REBOOTING
? "REBOOT" :
1626 client
->new->medium
);
1627 if (client
->active
&& client
->state
!= S_REBOOTING
)
1628 script_write_params(client
, "old_", client
->active
);
1629 script_write_params(client
, "new_", client
->new);
1630 script_write_requested(client
);
1632 script_write_params(client
, "alias_", client
->alias
);
1634 /* If the BOUND/RENEW code detects another machine using the
1635 offered address, it exits nonzero. We need to send a
1636 DHCPDECLINE and toss the lease. */
1637 if (script_go(client
)) {
1638 make_decline(client
, client
->new);
1639 send_decline(client
);
1640 destroy_client_lease(client
->new);
1644 log_info("Unable to obtain a lease on first "
1645 "try (declined). Exiting.");
1648 #if defined (CALL_SCRIPT_ON_ONETRY_FAIL)
1649 /* Let's call a script and we're done */
1650 script_init(client
, "FAIL", (struct string_list
*)0);
1656 tv
.tv_sec
= cur_tv
.tv_sec
+ decline_wait_time
;
1657 tv
.tv_usec
= cur_tv
.tv_usec
;
1658 add_timeout(&tv
, state_init
, client
, 0, 0);
1663 /* Write out the new lease if it has been long enough. */
1664 if (!client
->last_write
||
1665 (cur_time
- client
->last_write
) >= MIN_LEASE_WRITE
)
1666 write_client_lease(client
, client
->new, 0, 1);
1668 /* Replace the old active lease with the new one. */
1669 if (client
->active
) {
1670 if (client
->active
->is_static
) {
1671 // We need to preserve the fallback lease in case
1672 // we lose DHCP service again.
1673 add_to_tail(&client
->leases
, client
->active
);
1675 destroy_client_lease(client
->active
);
1679 client
->active
= client
->new;
1682 /* Set up a timeout to start the renewal process. */
1683 tv
.tv_sec
= client
->active
->renewal
;
1684 tv
.tv_usec
= ((client
->active
->renewal
- cur_tv
.tv_sec
) > 1) ?
1685 random() % 1000000 : cur_tv
.tv_usec
;
1686 add_timeout(&tv
, state_bound
, client
, 0, 0);
1688 log_info("bound to %s -- renewal in %ld seconds.",
1689 piaddr(client
->active
->address
),
1690 (long)(client
->active
->renewal
- cur_time
));
1691 client
->state
= S_BOUND
;
1692 reinitialize_interfaces();
1694 #if defined (NSUPDATE)
1695 if (client
->config
->do_forward_update
)
1696 dhclient_schedule_updates(client
, &client
->active
->address
, 1);
1697 #endif /* defined NSUPDATE */
1701 /* state_bound is called when we've successfully bound to a particular
1702 lease, but the renewal time on that lease has expired. We are
1703 expected to unicast a DHCPREQUEST to the server that gave us our
1706 void state_bound (cpp
)
1709 struct client_state
*client
= cpp
;
1710 struct option_cache
*oc
;
1711 struct data_string ds
;
1713 ASSERT_STATE(state
, S_BOUND
);
1715 /* T1 has expired. */
1716 make_request (client
, client
-> active
);
1717 client
-> xid
= client
-> packet
.xid
;
1719 memset (&ds
, 0, sizeof ds
);
1720 oc
= lookup_option (&dhcp_universe
, client
-> active
-> options
,
1721 DHO_DHCP_SERVER_IDENTIFIER
);
1723 evaluate_option_cache (&ds
, (struct packet
*)0, (struct lease
*)0,
1724 client
, (struct option_state
*)0,
1725 client
-> active
-> options
,
1726 &global_scope
, oc
, MDL
)) {
1728 memcpy (client
-> destination
.iabuf
, ds
.data
, 4);
1729 client
-> destination
.len
= 4;
1731 client
-> destination
= iaddr_broadcast
;
1733 data_string_forget (&ds
, MDL
);
1735 client
-> destination
= iaddr_broadcast
;
1737 client
-> first_sending
= cur_time
;
1738 client
-> interval
= client
-> config
-> initial_interval
;
1739 client
-> state
= S_RENEWING
;
1741 /* Send the first packet immediately. */
1742 send_request (client
);
1745 /* state_stop is called when we've been told to shut down. We unconfigure
1746 the interfaces, and then stop operating until told otherwise. */
1748 void state_stop (cpp
)
1751 struct client_state
*client
= cpp
;
1753 client
->pending
= P_NONE
;
1755 /* Cancel all timeouts. */
1756 cancel_timeout(state_selecting
, client
);
1757 cancel_timeout(send_discover
, client
);
1758 cancel_timeout(send_request
, client
);
1759 cancel_timeout(state_bound
, client
);
1760 cancel_timeout(finish_v6only
, client
);
1762 /* If we have an address, unconfigure it. */
1763 if (client
->active
) {
1764 script_init(client
, "STOP", client
->active
->medium
);
1765 script_write_params(client
, "old_", client
->active
);
1766 script_write_requested(client
);
1768 script_write_params(client
, "alias_", client
->alias
);
1773 int commit_leases ()
1778 int write_lease (lease
)
1779 struct lease
*lease
;
1784 int write_host (host
)
1785 struct host_decl
*host
;
1790 void db_startup (testp
)
1796 struct packet
*packet
;
1798 struct iaddrmatchlist
*ap
;
1802 if (packet
-> raw
-> op
!= BOOTREPLY
)
1805 /* If there's a reject list, make sure this packet's sender isn't
1807 for (ap
= packet
-> interface
-> client
-> config
-> reject_list
;
1808 ap
; ap
= ap
-> next
) {
1809 if (addr_match(&packet
->client_addr
, &ap
->match
)) {
1811 /* piaddr() returns its result in a static
1812 buffer sized 4*16 (see common/inet.c). */
1814 strcpy(addrbuf
, piaddr(ap
->match
.addr
));
1815 strcpy(maskbuf
, piaddr(ap
->match
.mask
));
1817 log_info("BOOTREPLY from %s rejected by rule %s "
1818 "mask %s.", piaddr(packet
->client_addr
),
1829 struct packet
*packet
;
1831 struct iaddrmatchlist
*ap
;
1832 void (*handler
) (struct packet
*);
1837 switch (packet
-> packet_type
) {
1839 handler
= dhcpoffer
;
1857 /* If there's a reject list, make sure this packet's sender isn't
1859 for (ap
= packet
-> interface
-> client
-> config
-> reject_list
;
1860 ap
; ap
= ap
-> next
) {
1861 if (addr_match(&packet
->client_addr
, &ap
->match
)) {
1863 /* piaddr() returns its result in a static
1864 buffer sized 4*16 (see common/inet.c). */
1866 strcpy(addrbuf
, piaddr(ap
->match
.addr
));
1867 strcpy(maskbuf
, piaddr(ap
->match
.mask
));
1869 log_info("%s from %s rejected by rule %s mask %s.",
1870 type
, piaddr(packet
->client_addr
),
1875 (*handler
) (packet
);
1880 dhcpv6(struct packet
*packet
) {
1881 struct iaddrmatchlist
*ap
;
1882 struct client_state
*client
;
1883 char addrbuf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
1885 /* Silently drop bogus messages. */
1886 if (packet
->dhcpv6_msg_type
>= dhcpv6_type_name_max
)
1889 /* Discard, with log, packets from quenched sources. */
1890 for (ap
= packet
->interface
->client
->config
->reject_list
;
1891 ap
; ap
= ap
->next
) {
1892 if (addr_match(&packet
->client_addr
, &ap
->match
)) {
1893 strcpy(addrbuf
, piaddr(packet
->client_addr
));
1894 log_info("%s from %s rejected by rule %s",
1895 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1897 piaddrmask(&ap
->match
.addr
, &ap
->match
.mask
));
1902 /* Screen out nonsensical messages. */
1903 switch(packet
->dhcpv6_msg_type
) {
1905 case DHCPV6_DHCPV4_RESPONSE
:
1906 if (dhcpv4_over_dhcpv6
) {
1907 log_info("RCV: %s message on %s from %s.",
1908 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1909 packet
->interface
->name
,
1910 piaddr(packet
->client_addr
));
1911 forw_dhcpv4_response(packet
);
1915 case DHCPV6_ADVERTISE
:
1916 case DHCPV6_RECONFIGURE
:
1921 log_info("RCV: %s message on %s from %s.",
1922 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1923 packet
->interface
->name
, piaddr(packet
->client_addr
));
1930 /* Find a client state that matches the incoming XID. */
1931 for (client
= packet
->interface
->client
; client
;
1932 client
= client
->next
) {
1933 if (memcmp(&client
->dhcpv6_transaction_id
,
1934 packet
->dhcpv6_transaction_id
, 3) == 0) {
1935 client
->v6_handler(packet
, client
);
1940 /* XXX: temporary log for debugging */
1941 log_info("Packet received, but nothing done with it.");
1946 * \brief Forward a DHCPv4-response to the DHCPv4 client.
1947 * (DHCPv6 client function)
1949 * The DHCPv6 client receives a DHCPv4-response which is forwarded
1950 * to the DHCPv4 client.
1951 * Format: address:16 + DHCPv4 message content
1952 * (we have no state to keep the address so it is transported in
1953 * DHCPv6 <-> DHCPv6 inter-process messages)
1955 * \param packet the DHCPv4-response packet
1957 static void forw_dhcpv4_response(struct packet
*packet
)
1959 struct option_cache
*oc
;
1960 struct data_string enc_opt_data
;
1961 struct data_string ds
;
1965 * Discard if relay is not ready.
1967 if (dhcp4o6_state
== -1) {
1968 log_info("forw_dhcpv4_response: not ready.");
1972 if (packet
->client_addr
.len
!= 16) {
1973 log_error("forw_dhcpv4_response: bad address");
1978 * Get our encapsulated DHCPv4 message.
1980 oc
= lookup_option(&dhcpv6_universe
, packet
->options
, D6O_DHCPV4_MSG
);
1982 log_info("DHCPv4-response from %s missing "
1983 "DHCPv4 Message option.",
1984 piaddr(packet
->client_addr
));
1988 memset(&enc_opt_data
, 0, sizeof(enc_opt_data
));
1989 if (!evaluate_option_cache(&enc_opt_data
, NULL
, NULL
, NULL
,
1990 NULL
, NULL
, &global_scope
, oc
, MDL
)) {
1991 log_error("forw_dhcpv4_response: error evaluating "
1993 data_string_forget(&enc_opt_data
, MDL
);
1997 if (enc_opt_data
.len
< DHCP_FIXED_NON_UDP
) {
1998 log_error("forw_dhcpv4_response: "
1999 "no memory for encapsulated packet.");
2000 data_string_forget(&enc_opt_data
, MDL
);
2007 memset(&ds
, 0, sizeof(ds
));
2008 if (!buffer_allocate(&ds
.buffer
, enc_opt_data
.len
+ 16, MDL
)) {
2009 log_error("forw_dhcpv4_response: no memory buffer.");
2010 data_string_forget(&enc_opt_data
, MDL
);
2013 ds
.data
= ds
.buffer
->data
;
2014 ds
.len
= enc_opt_data
.len
+ 16;
2015 memcpy(ds
.buffer
->data
, enc_opt_data
.data
, enc_opt_data
.len
);
2016 memcpy(ds
.buffer
->data
+ enc_opt_data
.len
,
2017 packet
->client_addr
.iabuf
, 16);
2018 data_string_forget(&enc_opt_data
, MDL
);
2023 cc
= send(dhcp4o6_fd
, ds
.data
, ds
.len
, 0);
2025 log_error("forw_dhcpv4_response: send(): %m");
2027 data_string_forget(&ds
, MDL
);
2031 * \brief Receive a DHCPv4-response from the DHCPv6 client.
2032 * (DHCPv4 client function)
2034 * The DHCPv4 client receives a DHCPv4-response forwarded
2035 * by the DHCPv6 client (using \ref forw_dhcpv4_response())
2037 * \param raw the DHCPv4-response raw packet
2039 static void recv_dhcpv4_response(struct data_string
*raw
)
2041 struct packet
*packet
;
2044 if (interfaces
== NULL
) {
2045 log_error("recv_dhcpv4_response: no interfaces.");
2050 memcpy(from
.iabuf
, raw
->data
+ (raw
->len
- 16), 16);
2053 * Build a packet structure.
2056 if (!packet_allocate(&packet
, MDL
)) {
2057 log_error("recv_dhcpv4_response: no memory for packet.");
2061 packet
->raw
= (struct dhcp_packet
*) raw
->data
;
2062 packet
->packet_length
= raw
->len
- 16;
2063 packet
->client_port
= remote_port
;
2064 packet
->client_addr
= from
;
2065 interface_reference(&packet
->interface
, interfaces
, MDL
);
2067 /* Allocate packet->options now so it is non-null for all packets */
2068 if (!option_state_allocate (&packet
->options
, MDL
)) {
2069 log_error("recv_dhcpv4_response: no memory for options.");
2070 packet_dereference (&packet
, MDL
);
2074 /* If there's an option buffer, try to parse it. */
2075 if (packet
->packet_length
>= DHCP_FIXED_NON_UDP
+ 4) {
2076 struct option_cache
*op
;
2077 if (!parse_options(packet
)) {
2078 if (packet
->options
)
2079 option_state_dereference
2080 (&packet
->options
, MDL
);
2081 packet_dereference (&packet
, MDL
);
2085 if (packet
->options_valid
&&
2086 (op
= lookup_option(&dhcp_universe
,
2088 DHO_DHCP_MESSAGE_TYPE
))) {
2089 struct data_string dp
;
2090 memset(&dp
, 0, sizeof dp
);
2091 evaluate_option_cache(&dp
, packet
, NULL
, NULL
,
2092 packet
->options
, NULL
,
2095 packet
->packet_type
= dp
.data
[0];
2097 packet
->packet_type
= 0;
2098 data_string_forget(&dp
, MDL
);
2102 if (validate_packet(packet
) != 0) {
2103 if (packet
->packet_type
)
2109 /* If the caller kept the packet, they'll have upped the refcnt. */
2110 packet_dereference(&packet
, MDL
);
2112 #endif /* DHCP4o6 */
2115 void dhcpoffer (packet
)
2116 struct packet
*packet
;
2118 struct interface_info
*ip
= packet
-> interface
;
2119 struct client_state
*client
;
2120 uint32_t v6only_wait
;
2121 struct client_lease
*lease
, *lp
;
2122 struct option
**req
;
2125 const char *name
= packet
-> packet_type
? "DHCPOFFER" : "BOOTREPLY";
2130 dump_packet (packet
);
2133 /* Find a client state that matches the xid... */
2134 for (client
= ip
-> client
; client
; client
= client
-> next
)
2135 if (client
-> xid
== packet
-> raw
-> xid
)
2138 /* If we're not receptive to an offer right now, or if the offer
2139 has an unrecognizable transaction id, then just drop it. */
2141 client
-> state
!= S_SELECTING
||
2142 (packet
-> interface
-> hw_address
.hlen
- 1 !=
2143 packet
-> raw
-> hlen
) ||
2144 (memcmp (&packet
-> interface
-> hw_address
.hbuf
[1],
2145 packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
))) {
2147 log_debug ("%s in wrong transaction.", name
);
2152 sprintf (obuf
, "%s of %s from %s", name
,
2153 inet_ntoa(packet
->raw
->yiaddr
),
2154 piaddr(packet
->client_addr
));
2156 /* Check v6only first. */
2157 v6only_wait
= check_v6only(packet
, client
);
2158 if (v6only_wait
> 0) {
2159 log_info("%s: v6 only preferred for %lu.", obuf
,
2160 (long unsigned)v6only_wait
);
2161 start_v6only(client
, v6only_wait
);
2165 /* If this lease doesn't supply the minimum required DHCPv4 parameters,
2168 req
= client
->config
->required_options
;
2170 for (i
= 0 ; req
[i
] != NULL
; i
++) {
2171 if ((req
[i
]->universe
== &dhcp_universe
) &&
2172 !lookup_option(&dhcp_universe
, packet
->options
,
2174 struct option
*option
= NULL
;
2175 unsigned code
= req
[i
]->code
;
2177 option_code_hash_lookup(&option
,
2178 dhcp_universe
.code_hash
,
2182 log_info("%s: no %s option.", obuf
,
2185 log_info("%s: no unknown-%u option.",
2188 option_dereference(&option
, MDL
);
2195 /* If we've already seen this lease, don't record it again. */
2196 for (lease
= client
-> offered_leases
; lease
; lease
= lease
-> next
) {
2197 if (lease
-> address
.len
== sizeof packet
-> raw
-> yiaddr
&&
2198 !memcmp (lease
-> address
.iabuf
,
2199 &packet
-> raw
-> yiaddr
, lease
-> address
.len
)) {
2200 log_debug ("%s: already seen.", obuf
);
2205 lease
= packet_to_lease (packet
, client
);
2207 log_info ("%s: packet_to_lease failed.", obuf
);
2211 /* log it now, so it emits before the request goes out */
2212 log_info("%s", obuf
);
2214 /* If this lease was acquired through a BOOTREPLY, record that
2216 if (!packet
-> options_valid
|| !packet
-> packet_type
)
2217 lease
-> is_bootp
= 1;
2219 /* Record the medium under which this lease was offered. */
2220 lease
-> medium
= client
-> medium
;
2222 /* Figure out when we're supposed to stop selecting. */
2223 stop_selecting
= (client
-> first_sending
+
2224 client
-> config
-> select_interval
);
2226 /* If this is the lease we asked for, put it at the head of the
2227 list, and don't mess with the arp request timeout. */
2228 if (lease
-> address
.len
== client
-> requested_address
.len
&&
2229 !memcmp (lease
-> address
.iabuf
,
2230 client
-> requested_address
.iabuf
,
2231 client
-> requested_address
.len
)) {
2232 lease
-> next
= client
-> offered_leases
;
2233 client
-> offered_leases
= lease
;
2235 /* Put the lease at the end of the list. */
2236 lease
-> next
= (struct client_lease
*)0;
2237 if (!client
-> offered_leases
)
2238 client
-> offered_leases
= lease
;
2240 for (lp
= client
-> offered_leases
; lp
-> next
;
2247 /* If the selecting interval has expired, go immediately to
2248 state_selecting(). Otherwise, time out into
2249 state_selecting at the select interval. */
2250 if (stop_selecting
<= cur_tv
.tv_sec
)
2251 state_selecting (client
);
2253 tv
.tv_sec
= stop_selecting
;
2254 tv
.tv_usec
= cur_tv
.tv_usec
;
2255 add_timeout(&tv
, state_selecting
, client
, 0, 0);
2256 cancel_timeout(send_discover
, client
);
2260 /* Allocate a client_lease structure and initialize it from the parameters
2261 in the specified packet. */
2263 struct client_lease
*packet_to_lease (packet
, client
)
2264 struct packet
*packet
;
2265 struct client_state
*client
;
2267 struct client_lease
*lease
;
2269 struct option_cache
*oc
;
2270 struct option
*option
= NULL
;
2271 struct data_string data
;
2273 lease
= (struct client_lease
*)new_client_lease (MDL
);
2276 log_error("packet_to_lease: no memory to record lease.\n");
2280 memset(lease
, 0, sizeof(*lease
));
2282 /* Copy the lease options. */
2283 option_state_reference(&lease
->options
, packet
->options
, MDL
);
2285 lease
->address
.len
= sizeof(packet
->raw
->yiaddr
);
2286 memcpy(lease
->address
.iabuf
, &packet
->raw
->yiaddr
,
2287 lease
->address
.len
);
2289 lease
->next_srv_addr
.len
= sizeof(packet
->raw
->siaddr
);
2290 memcpy(lease
->next_srv_addr
.iabuf
, &packet
->raw
->siaddr
,
2291 lease
->next_srv_addr
.len
);
2293 memset(&data
, 0, sizeof(data
));
2295 if (client
-> config
-> vendor_space_name
) {
2296 i
= DHO_VENDOR_ENCAPSULATED_OPTIONS
;
2298 /* See if there was a vendor encapsulation option. */
2299 oc
= lookup_option (&dhcp_universe
, lease
-> options
, i
);
2301 client
-> config
-> vendor_space_name
&&
2302 evaluate_option_cache (&data
, packet
,
2303 (struct lease
*)0, client
,
2304 packet
-> options
, lease
-> options
,
2305 &global_scope
, oc
, MDL
)) {
2307 if (!option_code_hash_lookup(&option
,
2308 dhcp_universe
.code_hash
,
2310 log_fatal("Unable to find VENDOR "
2311 "option (%s:%d).", MDL
);
2312 parse_encapsulated_suboptions
2313 (packet
-> options
, option
,
2314 data
.data
, data
.len
, &dhcp_universe
,
2315 client
-> config
-> vendor_space_name
2318 option_dereference(&option
, MDL
);
2320 data_string_forget (&data
, MDL
);
2325 /* Figure out the overload flag. */
2326 oc
= lookup_option (&dhcp_universe
, lease
-> options
,
2327 DHO_DHCP_OPTION_OVERLOAD
);
2329 evaluate_option_cache (&data
, packet
, (struct lease
*)0, client
,
2330 packet
-> options
, lease
-> options
,
2331 &global_scope
, oc
, MDL
)) {
2336 data_string_forget (&data
, MDL
);
2340 /* If the server name was filled out, copy it. */
2341 if (!(i
& 2) && packet
-> raw
-> sname
[0]) {
2343 /* Don't count on the NUL terminator. */
2344 for (len
= 0; len
< DHCP_SNAME_LEN
; len
++)
2345 if (!packet
-> raw
-> sname
[len
])
2347 lease
-> server_name
= dmalloc (len
+ 1, MDL
);
2348 if (!lease
-> server_name
) {
2349 log_error ("dhcpoffer: no memory for server name.\n");
2350 destroy_client_lease (lease
);
2351 return (struct client_lease
*)0;
2353 memcpy (lease
-> server_name
,
2354 packet
-> raw
-> sname
, len
);
2355 lease
-> server_name
[len
] = 0;
2359 /* Ditto for the filename. */
2360 if (!(i
& 1) && packet
-> raw
-> file
[0]) {
2362 /* Don't count on the NUL terminator. */
2363 for (len
= 0; len
< DHCP_FILE_LEN
; len
++)
2364 if (!packet
-> raw
-> file
[len
])
2366 lease
-> filename
= dmalloc (len
+ 1, MDL
);
2367 if (!lease
-> filename
) {
2368 log_error ("dhcpoffer: no memory for filename.\n");
2369 destroy_client_lease (lease
);
2370 return (struct client_lease
*)0;
2372 memcpy (lease
-> filename
,
2373 packet
-> raw
-> file
, len
);
2374 lease
-> filename
[len
] = 0;
2378 execute_statements_in_scope(NULL
, (struct packet
*)packet
, NULL
,
2379 client
, lease
->options
, lease
->options
,
2380 &global_scope
, client
->config
->on_receipt
,
2386 void dhcpnak (packet
)
2387 struct packet
*packet
;
2389 struct interface_info
*ip
= packet
-> interface
;
2390 struct client_state
*client
;
2392 /* Find a client state that matches the xid... */
2393 for (client
= ip
-> client
; client
; client
= client
-> next
)
2394 if (client
-> xid
== packet
-> raw
-> xid
)
2397 /* If we're not receptive to an offer right now, or if the offer
2398 has an unrecognizable transaction id, then just drop it. */
2400 (packet
-> interface
-> hw_address
.hlen
- 1 !=
2401 packet
-> raw
-> hlen
) ||
2402 (memcmp (&packet
-> interface
-> hw_address
.hbuf
[1],
2403 packet
-> raw
-> chaddr
, packet
-> raw
-> hlen
))) {
2405 log_debug ("DHCPNAK in wrong transaction.");
2410 if (client
-> state
!= S_REBOOTING
&&
2411 client
-> state
!= S_REQUESTING
&&
2412 client
-> state
!= S_RENEWING
&&
2413 client
-> state
!= S_REBINDING
) {
2415 log_debug ("DHCPNAK in wrong state.");
2420 log_info ("DHCPNAK from %s", piaddr (packet
-> client_addr
));
2422 if (!client
-> active
) {
2424 log_info ("DHCPNAK with no active lease.\n");
2429 /* If we get a DHCPNAK, we use the EXPIRE dhclient-script state
2430 * to indicate that we want all old bindings to be removed. (It
2431 * is possible that we may get a NAK while in the RENEW state,
2432 * so we might have bindings active at that time)
2434 script_init(client
, "EXPIRE", NULL
);
2435 script_write_params(client
, "old_", client
->active
);
2436 script_write_requested(client
);
2438 script_write_params(client
, "alias_", client
->alias
);
2441 destroy_client_lease (client
-> active
);
2442 client
-> active
= (struct client_lease
*)0;
2444 /* Stop sending DHCPREQUEST packets... */
2445 cancel_timeout (send_request
, client
);
2447 /* On some scripts, 'EXPIRE' causes the interface to be ifconfig'd
2448 * down (this expunges any routes and arp cache). This makes the
2449 * interface unusable by state_init(), which we call next. So, we
2450 * need to 'PREINIT' the interface to bring it back up.
2452 script_init(client
, "PREINIT", NULL
);
2454 script_write_params(client
, "alias_", client
->alias
);
2457 client
-> state
= S_INIT
;
2458 state_init (client
);
2461 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
2462 one after the right interval has expired. If we don't get an offer by
2463 the time we reach the panic interval, call the panic function. */
2465 void send_discover (cpp
)
2468 struct client_state
*client
= cpp
;
2475 /* Figure out how long it's been since we started transmitting. */
2476 interval
= cur_time
- client
-> first_sending
;
2478 /* If we're past the panic timeout, call the script and tell it
2479 we haven't found anything for this interface yet. */
2480 if (interval
> client
-> config
-> timeout
) {
2481 state_panic (client
);
2485 /* If we're selecting media, try the whole list before doing
2486 the exponential backoff, but if we've already received an
2487 offer, stop looping, because we obviously have it right. */
2488 if (!client
-> offered_leases
&&
2489 client
-> config
-> media
) {
2492 if (client
-> medium
) {
2493 client
-> medium
= client
-> medium
-> next
;
2496 if (!client
-> medium
) {
2498 log_fatal ("No valid media types for %s!",
2499 client
-> interface
-> name
);
2501 client
-> config
-> media
;
2505 log_info ("Trying medium \"%s\" %d",
2506 client
-> medium
-> string
, increase
);
2507 script_init(client
, "MEDIUM", client
-> medium
);
2508 if (script_go(client
)) {
2514 /* If we're supposed to increase the interval, do so. If it's
2515 currently zero (i.e., we haven't sent any packets yet), set
2516 it to initial_interval; otherwise, add to it a random number
2517 between zero and two times itself. On average, this means
2518 that it will double with every transmission. */
2520 if (!client
->interval
)
2521 client
->interval
= client
->config
->initial_interval
;
2523 client
->interval
+= random() % (2 * client
->interval
);
2525 /* Don't backoff past cutoff. */
2526 if (client
->interval
> client
->config
->backoff_cutoff
)
2527 client
->interval
= (client
->config
->backoff_cutoff
/ 2)
2528 + (random() % client
->config
->backoff_cutoff
);
2529 } else if (!client
->interval
)
2530 client
->interval
= client
->config
->initial_interval
;
2532 /* If the backoff would take us to the panic timeout, just use that
2534 if (cur_time
+ client
-> interval
>
2535 client
-> first_sending
+ client
-> config
-> timeout
)
2536 client
-> interval
=
2537 (client
-> first_sending
+
2538 client
-> config
-> timeout
) - cur_time
+ 1;
2540 /* Record the number of seconds since we started sending. */
2541 if (interval
< 65536)
2542 client
-> packet
.secs
= htons (interval
);
2544 client
-> packet
.secs
= htons (65535);
2545 client
-> secs
= client
-> packet
.secs
;
2547 #if defined(DHCPv6) && defined(DHCP4o6)
2548 if (dhcpv4_over_dhcpv6
) {
2549 log_info ("DHCPDISCOVER interval %ld",
2550 (long)(client
-> interval
));
2553 log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
2554 client
-> name
? client
-> name
: client
-> interface
-> name
,
2555 inet_ntoa (sockaddr_broadcast
.sin_addr
),
2556 ntohs (sockaddr_broadcast
.sin_port
), (long)(client
-> interval
));
2558 /* Send out a packet. */
2559 #if defined(DHCPv6) && defined(DHCP4o6)
2560 if (dhcpv4_over_dhcpv6
) {
2561 result
= send_dhcpv4_query(client
, 1);
2564 result
= send_packet(client
->interface
, NULL
, &client
->packet
,
2565 client
->packet_length
, inaddr_any
,
2566 &sockaddr_broadcast
, NULL
);
2568 #if defined(DHCPv6) && defined(DHCP4o6)
2569 if (dhcpv4_over_dhcpv6
) {
2570 log_error("%s:%d: Failed to send %d byte long packet.",
2571 MDL
, client
->packet_length
);
2574 log_error("%s:%d: Failed to send %d byte long packet over %s "
2575 "interface.", MDL
, client
->packet_length
,
2576 client
->interface
->name
);
2580 * If we used 0 microseconds here, and there were other clients on the
2581 * same network with a synchronized local clock (ntp), and a similar
2582 * zero-microsecond-scheduler behavior, then we could be participating
2583 * in a sub-second DOS ttck.
2585 tv
.tv_sec
= cur_tv
.tv_sec
+ client
->interval
;
2586 tv
.tv_usec
= client
->interval
> 1 ? random() % 1000000 : cur_tv
.tv_usec
;
2587 add_timeout(&tv
, send_discover
, client
, 0, 0);
2592 * \brief Remove leases from a list of leases which duplicate a given lease
2594 * Searches through a linked-list of leases, remove the first one matches the
2595 * given lease's address and value of is_static. The latter test is done
2596 * so we only remove leases that are from the same source (i.e server/lease file
2597 * vs config file). This ensures we do not discard "fallback" config file leases
2598 * that happen to match non-config file leases.
2600 * \param lease_list list of leases to clean
2601 * \param lease lease for which duplicates should be removed
2603 void discard_duplicate (struct client_lease
** lease_list
, struct client_lease
* lease
) {
2604 struct client_lease
*cur
, *prev
, *next
;
2606 if (!lease_list
|| !lease
) {
2610 prev
= (struct client_lease
*)0;
2611 for (cur
= *lease_list
; cur
; cur
= next
) {
2613 if ((cur
->is_static
== lease
->is_static
) &&
2614 (cur
->address
.len
== lease
->address
.len
&&
2615 !memcmp (cur
->address
.iabuf
, lease
->address
.iabuf
,
2616 lease
->address
.len
))) {
2622 destroy_client_lease (cur
);
2631 * \brief Add a given lease to the end of list of leases
2633 * Searches through a linked-list of leases, removing any that match the
2634 * given lease's address and value of is_static. The latter test is done
2635 * so we only remove leases that are from the same source (i.e server/lease file
2636 * vs config file). This ensures we do not discard "fallback" config file leases
2637 * that happen to match non-config file leases.
2639 * \param lease_list list of leases to clean
2640 * \param lease lease for which duplicates should be removed
2642 void add_to_tail(struct client_lease
** lease_list
,
2643 struct client_lease
* lease
)
2645 if (!lease_list
|| !lease
) {
2649 /* If there is already a lease for this address and
2650 * is_static value, toss discard it. This ensures
2651 * we only keep one dynamic and/or one static lease
2652 * for a given address. */
2653 discard_duplicate(lease_list
, lease
);
2656 struct client_lease
* tail
;
2657 for (tail
= *lease_list
; tail
&& tail
->next
; tail
= tail
->next
){};
2659 /* Ensure the tail points nowhere. */
2662 /* Add to the tail. */
2664 *lease_list
= lease
;
2671 void dbg_print_lease(char *text
, struct client_lease
* lease
) {
2673 log_debug("%s, lease is null", text
);
2675 log_debug ("%s: %p addr:%s expires:%ld :is_static? %d",
2676 text
, lease
, piaddr (lease
->address
),
2677 (lease
->expiry
- cur_time
),
2683 /* state_panic gets called if we haven't received any offers in a preset
2684 amount of time. When this happens, we try to use existing leases that
2685 haven't yet expired, and failing that, we call the client script and
2686 hope it can do something. */
2688 void state_panic (cpp
)
2691 struct client_state
*client
= cpp
;
2692 struct client_lease
*loop
;
2693 struct client_lease
*lp
;
2696 loop
= lp
= client
-> active
;
2698 log_info ("No DHCPOFFERS received.");
2700 /* We may not have an active lease, but we may have some
2701 predefined leases that we can try. */
2702 if (!client
-> active
&& client
-> leases
)
2705 /* Run through the list of leases and see if one can be used. */
2706 while (client
-> active
) {
2707 if (client
-> active
-> expiry
> cur_time
) {
2708 log_info ("Trying %s lease %s",
2709 (client
-> active
-> is_static
2710 ? "fallback" : "recorded"),
2711 piaddr (client
-> active
-> address
));
2712 /* Run the client script with the existing
2714 script_init(client
, "TIMEOUT",
2715 client
-> active
-> medium
);
2716 script_write_params(client
, "new_", client
-> active
);
2717 script_write_requested(client
);
2718 if (client
-> alias
)
2719 script_write_params(client
, "alias_",
2722 /* If the old lease is still good and doesn't
2723 yet need renewal, go into BOUND state and
2724 timeout at the renewal time. */
2725 if (!script_go(client
)) {
2726 if (cur_time
< client
-> active
-> renewal
) {
2727 client
-> state
= S_BOUND
;
2728 log_info ("bound: renewal in %ld %s.",
2729 (long)(client
-> active
-> renewal
-
2730 cur_time
), "seconds");
2731 tv
.tv_sec
= client
->active
->renewal
;
2732 tv
.tv_usec
= ((client
->active
->renewal
-
2734 random() % 1000000 :
2736 add_timeout(&tv
, state_bound
, client
, 0, 0);
2738 client
-> state
= S_BOUND
;
2739 log_info ("bound: immediate renewal.");
2740 state_bound (client
);
2742 reinitialize_interfaces ();
2748 /* If there are no other leases, give up. */
2749 if (!client
-> leases
) {
2750 client
-> leases
= client
-> active
;
2751 client
-> active
= (struct client_lease
*)0;
2756 /* Otherwise, put the active lease at the end of the
2757 lease list, and try another lease.. */
2758 add_to_tail(&client
->leases
, client
->active
);
2760 client
-> active
= client
-> leases
;
2761 client
-> leases
= client
-> leases
-> next
;
2763 /* If we already tried this lease, we've exhausted the
2764 set of leases, so we might as well give up for
2766 if (client
-> active
== loop
)
2769 loop
= client
-> active
;
2772 /* No leases were available, or what was available didn't work, so
2773 tell the shell script that we failed to allocate an address,
2774 and try again later. */
2777 log_info ("Unable to obtain a lease on first try.%s",
2781 #if defined (CALL_SCRIPT_ON_ONETRY_FAIL)
2782 /* Let's call a script and we're done */
2783 script_init(client
, "FAIL", (struct string_list
*)0);
2789 log_info ("No working leases in persistent database - sleeping.");
2790 script_init(client
, "FAIL", (struct string_list
*)0);
2791 if (client
-> alias
)
2792 script_write_params(client
, "alias_", client
-> alias
);
2794 client
-> state
= S_INIT
;
2795 tv
.tv_sec
= cur_tv
.tv_sec
+ ((client
->config
->retry_interval
+ 1) / 2 +
2796 (random() % client
->config
->retry_interval
));
2797 tv
.tv_usec
= ((tv
.tv_sec
- cur_tv
.tv_sec
) > 1) ?
2798 random() % 1000000 : cur_tv
.tv_usec
;
2799 add_timeout(&tv
, state_init
, client
, 0, 0);
2803 void send_request (cpp
)
2806 struct client_state
*client
= cpp
;
2810 struct sockaddr_in destination
;
2811 struct in_addr from
;
2814 const char* rip_str
= "";
2816 /* Figure out how long it's been since we started transmitting. */
2817 interval
= cur_time
- client
-> first_sending
;
2819 /* If we're in the INIT-REBOOT or REQUESTING state and we're
2820 past the reboot timeout, go to INIT and see if we can
2821 DISCOVER an address... */
2822 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
2823 means either that we're on a network with no DHCP server,
2824 or that our server is down. In the latter case, assuming
2825 that there is a backup DHCP server, DHCPDISCOVER will get
2826 us a new address, but we could also have successfully
2827 reused our old address. In the former case, we're hosed
2828 anyway. This is not a win-prone situation. */
2829 if ((client
-> state
== S_REBOOTING
||
2830 client
-> state
== S_REQUESTING
) &&
2831 interval
> client
-> config
-> reboot_timeout
) {
2833 client
-> state
= S_INIT
;
2834 cancel_timeout (send_request
, client
);
2835 state_init (client
);
2839 /* If we're in the reboot state, make sure the media is set up
2841 if (client
-> state
== S_REBOOTING
&&
2842 !client
-> medium
&&
2843 client
-> active
-> medium
) {
2844 script_init(client
, "MEDIUM", client
-> active
-> medium
);
2846 /* If the medium we chose won't fly, go to INIT state. */
2847 if (script_go(client
))
2850 /* Record the medium. */
2851 client
-> medium
= client
-> active
-> medium
;
2854 /* If the lease has expired, relinquish the address and go back
2855 to the INIT state. */
2856 if (client
-> state
!= S_REQUESTING
&&
2857 cur_time
> client
-> active
-> expiry
) {
2858 /* Run the client script with the new parameters. */
2859 script_init(client
, "EXPIRE", (struct string_list
*)0);
2860 script_write_params(client
, "old_", client
-> active
);
2861 script_write_requested(client
);
2862 if (client
-> alias
)
2863 script_write_params(client
, "alias_",
2867 /* Now do a preinit on the interface so that we can
2868 discover a new address. */
2869 script_init(client
, "PREINIT", (struct string_list
*)0);
2870 if (client
-> alias
)
2871 script_write_params(client
, "alias_",
2875 client
-> state
= S_INIT
;
2876 state_init (client
);
2880 /* Do the exponential backoff... */
2881 if (!client
-> interval
)
2882 client
-> interval
= client
-> config
-> initial_interval
;
2884 client
-> interval
+= ((random () >> 2) %
2885 (2 * client
-> interval
));
2888 /* Don't backoff past cutoff. */
2889 if (client
-> interval
>
2890 client
-> config
-> backoff_cutoff
)
2891 client
-> interval
=
2892 ((client
-> config
-> backoff_cutoff
/ 2)
2893 + ((random () >> 2) %
2894 client
-> config
-> backoff_cutoff
));
2896 /* If the backoff would take us to the expiry time, just set the
2897 timeout to the expiry time. */
2898 if (client
-> state
!= S_REQUESTING
&&
2899 cur_time
+ client
-> interval
> client
-> active
-> expiry
)
2900 client
-> interval
=
2901 client
-> active
-> expiry
- cur_time
+ 1;
2903 /* If the lease T2 time has elapsed, or if we're not yet bound,
2904 broadcast the DHCPREQUEST rather than unicasting. */
2905 if (client
-> state
== S_REQUESTING
||
2906 client
-> state
== S_REBOOTING
||
2907 cur_time
> client
-> active
-> rebind
)
2908 destination
.sin_addr
= sockaddr_broadcast
.sin_addr
;
2910 memcpy (&destination
.sin_addr
.s_addr
,
2911 client
-> destination
.iabuf
,
2912 sizeof destination
.sin_addr
.s_addr
);
2913 destination
.sin_port
= remote_port
;
2914 destination
.sin_family
= AF_INET
;
2916 destination
.sin_len
= sizeof destination
;
2919 if (client
-> state
== S_RENEWING
||
2920 client
-> state
== S_REBINDING
)
2921 memcpy (&from
, client
-> active
-> address
.iabuf
,
2924 from
.s_addr
= INADDR_ANY
;
2926 /* Record the number of seconds since we started sending. */
2927 if (client
-> state
== S_REQUESTING
)
2928 client
-> packet
.secs
= client
-> secs
;
2930 if (interval
< 65536)
2931 client
-> packet
.secs
= htons (interval
);
2933 client
-> packet
.secs
= htons (65535);
2936 #if defined(DHCPv6) && defined(DHCP4o6)
2937 if (dhcpv4_over_dhcpv6
) {
2938 log_info ("DHCPREQUEST");
2941 memset(rip_buf
, 0x0, sizeof(rip_buf
));
2942 if (client
->state
== S_BOUND
|| client
->state
== S_RENEWING
||
2943 client
->state
== S_REBINDING
) {
2944 rip_str
= inet_ntoa(client
->packet
.ciaddr
);
2946 rip_str
= piaddr(client
->requested_address
);
2949 strncpy(rip_buf
, rip_str
, sizeof(rip_buf
)-1);
2950 log_info ("DHCPREQUEST for %s on %s to %s port %d", rip_buf
,
2951 client
->name
? client
->name
: client
->interface
->name
,
2952 inet_ntoa(destination
.sin_addr
),
2953 ntohs (destination
.sin_port
));
2955 #if defined(DHCPv6) && defined(DHCP4o6)
2956 if (dhcpv4_over_dhcpv6
) {
2958 if (destination
.sin_addr
.s_addr
== INADDR_BROADCAST
)
2960 result
= send_dhcpv4_query(client
, broadcast
);
2962 log_error("%s:%d: Failed to send %d byte long packet.",
2963 MDL
, client
->packet_length
);
2967 if (destination
.sin_addr
.s_addr
!= INADDR_BROADCAST
&&
2968 fallback_interface
) {
2969 result
= send_packet(fallback_interface
, NULL
, &client
->packet
,
2970 client
->packet_length
, from
, &destination
,
2973 log_error("%s:%d: Failed to send %d byte long packet "
2974 "over %s interface.", MDL
,
2975 client
->packet_length
,
2976 fallback_interface
->name
);
2980 /* Send out a packet. */
2981 result
= send_packet(client
->interface
, NULL
, &client
->packet
,
2982 client
->packet_length
, from
, &destination
,
2985 log_error("%s:%d: Failed to send %d byte long packet"
2986 " over %s interface.", MDL
,
2987 client
->packet_length
,
2988 client
->interface
->name
);
2992 tv
.tv_sec
= cur_tv
.tv_sec
+ client
->interval
;
2993 tv
.tv_usec
= ((tv
.tv_sec
- cur_tv
.tv_sec
) > 1) ?
2994 random() % 1000000 : cur_tv
.tv_usec
;
2995 add_timeout(&tv
, send_request
, client
, 0, 0);
2998 void send_decline (cpp
)
3001 struct client_state
*client
= cpp
;
3005 #if defined(DHCPv6) && defined(DHCP4o6)
3006 if (dhcpv4_over_dhcpv6
) {
3007 log_info ("DHCPDECLINE");
3010 log_info ("DHCPDECLINE of %s on %s to %s port %d",
3011 piaddr(client
->requested_address
),
3012 (client
->name
? client
->name
: client
->interface
->name
),
3013 inet_ntoa(sockaddr_broadcast
.sin_addr
),
3014 ntohs(sockaddr_broadcast
.sin_port
));
3016 /* Send out a packet. */
3017 #if defined(DHCPv6) && defined(DHCP4o6)
3018 if (dhcpv4_over_dhcpv6
) {
3019 result
= send_dhcpv4_query(client
, 1);
3022 result
= send_packet(client
->interface
, NULL
, &client
->packet
,
3023 client
->packet_length
, inaddr_any
,
3024 &sockaddr_broadcast
, NULL
);
3026 #if defined(DHCPv6) && defined(DHCP4o6)
3027 if (dhcpv4_over_dhcpv6
) {
3028 log_error("%s:%d: Failed to send %d byte long packet.",
3029 MDL
, client
->packet_length
);
3032 log_error("%s:%d: Failed to send %d byte long packet over %s"
3033 " interface.", MDL
, client
->packet_length
,
3034 client
->interface
->name
);
3038 void send_release (cpp
)
3041 struct client_state
*client
= cpp
;
3044 struct sockaddr_in destination
;
3045 struct in_addr from
;
3047 memcpy (&from
, client
-> active
-> address
.iabuf
,
3049 memcpy (&destination
.sin_addr
.s_addr
,
3050 client
-> destination
.iabuf
,
3051 sizeof destination
.sin_addr
.s_addr
);
3052 destination
.sin_port
= remote_port
;
3053 destination
.sin_family
= AF_INET
;
3055 destination
.sin_len
= sizeof destination
;
3058 /* Set the lease to end now, so that we don't accidentally
3059 reuse it if we restart before the old expiry time. */
3060 client
-> active
-> expiry
=
3061 client
-> active
-> renewal
=
3062 client
-> active
-> rebind
= cur_time
;
3063 if (!write_client_lease (client
, client
-> active
, 1, 1)) {
3064 log_error ("Can't release lease: lease write failed.");
3068 #if defined(DHCPv6) && defined(DHCP4o6)
3069 if (dhcpv4_over_dhcpv6
) {
3070 log_info ("DHCPRELEASE");
3073 log_info ("DHCPRELEASE of %s on %s to %s port %d",
3074 piaddr(client
->active
->address
),
3075 client
->name
? client
->name
: client
->interface
->name
,
3076 inet_ntoa (destination
.sin_addr
),
3077 ntohs (destination
.sin_port
));
3079 #if defined(DHCPv6) && defined(DHCP4o6)
3080 if (dhcpv4_over_dhcpv6
) {
3082 if (destination
.sin_addr
.s_addr
== INADDR_BROADCAST
)
3084 result
= send_dhcpv4_query(client
, broadcast
);
3086 log_error("%s:%d: Failed to send %d byte long packet.",
3087 MDL
, client
->packet_length
);
3091 if (fallback_interface
) {
3092 result
= send_packet(fallback_interface
, NULL
, &client
->packet
,
3093 client
->packet_length
, from
, &destination
,
3096 log_error("%s:%d: Failed to send %d byte long packet"
3097 " over %s interface.", MDL
,
3098 client
->packet_length
,
3099 fallback_interface
->name
);
3102 /* Send out a packet. */
3103 result
= send_packet(client
->interface
, NULL
, &client
->packet
,
3104 client
->packet_length
, from
, &destination
,
3107 log_error ("%s:%d: Failed to send %d byte long packet"
3108 " over %s interface.", MDL
,
3109 client
->packet_length
,
3110 client
->interface
->name
);
3116 #if defined(DHCPv6) && defined(DHCP4o6)
3118 * \brief Send a DHCPv4-query to the DHCPv6 client
3119 * (DHCPv4 client function)
3121 * The DHCPv4 client sends a DHCPv4-query to the DHCPv6 client over
3122 * the inter-process communication socket.
3124 * \param client the DHCPv4 client state
3125 * \param broadcast the broadcast flag
3126 * \return the sent byte count (-1 on error)
3128 static int send_dhcpv4_query(struct client_state
*client
, int broadcast
) {
3129 struct data_string ds
;
3130 struct dhcpv4_over_dhcpv6_packet
*query
;
3133 if (dhcp4o6_state
<= 0) {
3134 log_info("send_dhcpv4_query: not ready.");
3139 * Compute buffer length and allocate it.
3141 len
= ofs
= (int)(offsetof(struct dhcpv4_over_dhcpv6_packet
, options
));
3142 len
+= dhcpv6_universe
.tag_size
+ dhcpv6_universe
.length_size
;
3143 len
+= client
->packet_length
;
3144 memset(&ds
, 0, sizeof(ds
));
3145 if (!buffer_allocate(&ds
.buffer
, len
, MDL
)) {
3146 log_error("Unable to allocate memory for DHCPv4-query.");
3149 ds
.data
= ds
.buffer
->data
;
3155 query
= (struct dhcpv4_over_dhcpv6_packet
*)ds
.data
;
3156 query
->msg_type
= DHCPV6_DHCPV4_QUERY
;
3157 query
->flags
[0] = query
->flags
[1] = query
->flags
[2] = 0;
3159 query
->flags
[0] |= DHCP4O6_QUERY_UNICAST
;
3162 * Append DHCPv4 message.
3164 dhcpv6_universe
.store_tag(ds
.buffer
->data
+ ofs
, D6O_DHCPV4_MSG
);
3165 ofs
+= dhcpv6_universe
.tag_size
;
3166 dhcpv6_universe
.store_length(ds
.buffer
->data
+ ofs
,
3167 client
->packet_length
);
3168 ofs
+= dhcpv6_universe
.length_size
;
3169 memcpy(ds
.buffer
->data
+ ofs
, &client
->packet
, client
->packet_length
);
3172 * Send DHCPv6 message.
3174 cc
= send(dhcp4o6_fd
, ds
.data
, ds
.len
, 0);
3176 log_error("send_dhcpv4_query: send(): %m");
3178 data_string_forget(&ds
, MDL
);
3184 * \brief Forward a DHCPv4-query to all DHCPv4 over DHCPv6 server addresses.
3185 * (DHCPv6 client function)
3187 * \param raw the DHCPv6 DHCPv4-query message raw content
3189 static void forw_dhcpv4_query(struct data_string
*raw
) {
3190 struct interface_info
*ip
;
3191 struct client_state
*client
;
3192 struct dhc6_lease
*lease
;
3193 struct option_cache
*oc
;
3194 struct data_string addrs
;
3195 struct sockaddr_in6 sin6
;
3196 int i
, send_ret
, attempt
, success
;
3198 attempt
= success
= 0;
3199 memset(&sin6
, 0, sizeof(sin6
));
3200 sin6
.sin6_family
= AF_INET6
;
3201 sin6
.sin6_port
= remote_port
;
3203 sin6
.sin6_len
= sizeof(sin6
);
3205 memset(&addrs
, 0, sizeof(addrs
));
3206 for (ip
= interfaces
; ip
!= NULL
; ip
= ip
->next
) {
3207 for (client
= ip
->client
; client
!= NULL
;
3208 client
= client
->next
) {
3209 if ((client
->state
!= S_BOUND
) &&
3210 (client
->state
!= S_RENEWING
) &&
3211 (client
->state
!= S_REBINDING
))
3213 lease
= client
->active_lease
;
3214 if ((lease
== NULL
) || lease
->released
)
3216 oc
= lookup_option(&dhcpv6_universe
,
3218 D6O_DHCP4_O_DHCP6_SERVER
);
3220 !evaluate_option_cache(&addrs
, NULL
, NULL
, NULL
,
3221 lease
->options
, NULL
,
3222 &global_scope
, oc
, MDL
) ||
3223 ((addrs
.len
% sizeof(sin6
.sin6_addr
)) != 0)) {
3224 data_string_forget(&addrs
, MDL
);
3227 if (addrs
.len
== 0) {
3228 /* note there is nothing to forget */
3230 All_DHCP_Relay_Agents_and_Servers
,
3233 send_ret
= send_packet6(ip
, raw
->data
,
3235 if (send_ret
== raw
->len
)
3239 for (i
= 0; i
< addrs
.len
;
3240 i
+= sizeof(sin6
.sin6_addr
)) {
3241 memcpy(&sin6
.sin6_addr
, addrs
.data
+ i
,
3242 sizeof(sin6
.sin6_addr
));
3244 send_ret
= send_packet6(ip
, raw
->data
,
3246 if (send_ret
== raw
->len
)
3249 data_string_forget(&addrs
, MDL
);
3253 log_info("forw_dhcpv4_query: sent(%d): %d/%d",
3254 raw
->len
, success
, attempt
);
3262 make_client_options(struct client_state
*client
, struct client_lease
*lease
,
3263 u_int8_t
*type
, struct option_cache
*sid
,
3264 struct iaddr
*rip
, struct option
**prl
,
3265 struct option_state
**op
)
3268 struct option_cache
*oc
;
3269 struct option
*option
= NULL
;
3270 struct buffer
*bp
= NULL
;
3272 /* If there are any leftover options, get rid of them. */
3274 option_state_dereference(op
, MDL
);
3276 /* Allocate space for options. */
3277 option_state_allocate(op
, MDL
);
3279 /* Send the server identifier if provided. */
3281 save_option(&dhcp_universe
, *op
, sid
);
3285 /* Send the requested address if provided. */
3287 client
->requested_address
= *rip
;
3288 i
= DHO_DHCP_REQUESTED_ADDRESS
;
3289 if (!(option_code_hash_lookup(&option
, dhcp_universe
.code_hash
,
3291 make_const_option_cache(&oc
, NULL
, rip
->iabuf
, rip
->len
,
3293 log_error ("can't make requested address cache.");
3295 save_option(&dhcp_universe
, *op
, oc
);
3296 option_cache_dereference(&oc
, MDL
);
3298 option_dereference(&option
, MDL
);
3300 client
->requested_address
.len
= 0;
3303 i
= DHO_DHCP_MESSAGE_TYPE
;
3304 if (!(option_code_hash_lookup(&option
, dhcp_universe
.code_hash
, &i
, 0,
3306 make_const_option_cache(&oc
, NULL
, type
, 1, option
, MDL
)))
3307 log_error("can't make message type.");
3309 save_option(&dhcp_universe
, *op
, oc
);
3310 option_cache_dereference(&oc
, MDL
);
3312 option_dereference(&option
, MDL
);
3317 /* Probe the length of the list. */
3319 for (i
= 0 ; prl
[i
] != NULL
; i
++)
3320 if (prl
[i
]->universe
== &dhcp_universe
)
3323 if (!buffer_allocate(&bp
, len
, MDL
))
3324 log_error("can't make parameter list buffer.");
3326 unsigned code
= DHO_DHCP_PARAMETER_REQUEST_LIST
;
3329 for (i
= 0 ; prl
[i
] != NULL
; i
++)
3330 if (prl
[i
]->universe
== &dhcp_universe
)
3331 bp
->data
[len
++] = prl
[i
]->code
;
3333 if (!(option_code_hash_lookup(&option
,
3334 dhcp_universe
.code_hash
,
3336 make_const_option_cache(&oc
, &bp
, NULL
, len
,
3339 buffer_dereference(&bp
, MDL
);
3340 log_error ("can't make option cache");
3342 save_option(&dhcp_universe
, *op
, oc
);
3343 option_cache_dereference(&oc
, MDL
);
3345 option_dereference(&option
, MDL
);
3350 * If requested (duid_v4 == 1) add an RFC4361 compliant client-identifier
3351 * This can be overridden by including a client id in the configuration
3355 struct data_string client_identifier
;
3358 memset(&client_identifier
, 0, sizeof(client_identifier
));
3359 client_identifier
.len
= 1 + 4 + default_duid
.len
;
3360 if (!buffer_allocate(&client_identifier
.buffer
,
3361 client_identifier
.len
, MDL
))
3362 log_fatal("no memory for default DUID!");
3363 client_identifier
.data
= client_identifier
.buffer
->data
;
3365 i
= DHO_DHCP_CLIENT_IDENTIFIER
;
3367 /* Client-identifier type : 1 byte */
3368 *client_identifier
.buffer
->data
= 255;
3371 * we use the low 4 bytes from the interface address
3373 if (client
->interface
->hw_address
.hlen
> 4) {
3374 hw_idx
= client
->interface
->hw_address
.hlen
- 4;
3378 hw_len
= client
->interface
->hw_address
.hlen
;
3380 memcpy(&client_identifier
.buffer
->data
+ 5 - hw_len
,
3381 client
->interface
->hw_address
.hbuf
+ hw_idx
,
3384 /* Add the default duid */
3385 memcpy(&client_identifier
.buffer
->data
+(1+4),
3386 default_duid
.data
, default_duid
.len
);
3388 /* And save the option */
3389 if (!(option_code_hash_lookup(&option
, dhcp_universe
.code_hash
,
3391 make_const_option_cache(&oc
, NULL
,
3392 (u_int8_t
*)client_identifier
.data
,
3393 client_identifier
.len
,
3395 log_error ("can't make requested client id cache..");
3397 save_option (&dhcp_universe
, *op
, oc
);
3398 option_cache_dereference (&oc
, MDL
);
3400 option_dereference(&option
, MDL
);
3403 /* Run statements that need to be run on transmission. */
3404 if (client
->config
->on_transmission
)
3405 execute_statements_in_scope(NULL
, NULL
, NULL
, client
,
3406 (lease
? lease
->options
: NULL
),
3408 client
->config
->on_transmission
,
3412 void make_discover (client
, lease
)
3413 struct client_state
*client
;
3414 struct client_lease
*lease
;
3416 unsigned char discover
= DHCPDISCOVER
;
3417 struct option_state
*options
= (struct option_state
*)0;
3419 memset (&client
-> packet
, 0, sizeof (client
-> packet
));
3421 make_client_options (client
,
3422 lease
, &discover
, (struct option_cache
*)0,
3423 lease
? &lease
-> address
: (struct iaddr
*)0,
3424 client
-> config
-> requested_options
,
3427 /* Set up the option buffer... */
3428 client
-> packet_length
=
3429 cons_options ((struct packet
*)0, &client
-> packet
,
3430 (struct lease
*)0, client
,
3431 /* maximum packet size */1500,
3432 (struct option_state
*)0,
3434 /* scope */ &global_scope
,
3438 (struct data_string
*)0,
3439 client
-> config
-> vendor_space_name
);
3441 option_state_dereference (&options
, MDL
);
3442 if (client
-> packet_length
< BOOTP_MIN_LEN
)
3443 client
-> packet_length
= BOOTP_MIN_LEN
;
3445 client
-> packet
.op
= BOOTREQUEST
;
3446 client
-> packet
.htype
= client
-> interface
-> hw_address
.hbuf
[0];
3447 /* Assumes hw_address is known, otherwise a random value may result */
3448 client
-> packet
.hlen
= client
-> interface
-> hw_address
.hlen
- 1;
3449 client
-> packet
.hops
= 0;
3450 client
-> packet
.xid
= random ();
3451 client
-> packet
.secs
= 0; /* filled in by send_discover. */
3453 if (can_receive_unicast_unconfigured (client
-> interface
))
3454 client
-> packet
.flags
= 0;
3456 client
-> packet
.flags
= htons (BOOTP_BROADCAST
);
3458 memset (&(client
-> packet
.ciaddr
),
3459 0, sizeof client
-> packet
.ciaddr
);
3460 memset (&(client
-> packet
.yiaddr
),
3461 0, sizeof client
-> packet
.yiaddr
);
3462 memset (&(client
-> packet
.siaddr
),
3463 0, sizeof client
-> packet
.siaddr
);
3464 client
-> packet
.giaddr
= giaddr
;
3465 if (client
-> interface
-> hw_address
.hlen
> 0)
3466 memcpy (client
-> packet
.chaddr
,
3467 &client
-> interface
-> hw_address
.hbuf
[1],
3468 (unsigned)(client
-> interface
-> hw_address
.hlen
- 1));
3471 dump_raw ((unsigned char *)&client
-> packet
, client
-> packet_length
);
3476 void make_request (client
, lease
)
3477 struct client_state
*client
;
3478 struct client_lease
*lease
;
3480 unsigned char request
= DHCPREQUEST
;
3481 struct option_cache
*oc
;
3483 memset (&client
-> packet
, 0, sizeof (client
-> packet
));
3485 if (client
-> state
== S_REQUESTING
)
3486 oc
= lookup_option (&dhcp_universe
, lease
-> options
,
3487 DHO_DHCP_SERVER_IDENTIFIER
);
3489 oc
= (struct option_cache
*)0;
3491 if (client
-> sent_options
)
3492 option_state_dereference (&client
-> sent_options
, MDL
);
3494 make_client_options (client
, lease
, &request
, oc
,
3495 ((client
-> state
== S_REQUESTING
||
3496 client
-> state
== S_REBOOTING
)
3498 : (struct iaddr
*)0),
3499 client
-> config
-> requested_options
,
3500 &client
-> sent_options
);
3502 /* Set up the option buffer... */
3503 client
-> packet_length
=
3504 cons_options ((struct packet
*)0, &client
-> packet
,
3505 (struct lease
*)0, client
,
3506 /* maximum packet size */1500,
3507 (struct option_state
*)0,
3508 client
-> sent_options
,
3509 /* scope */ &global_scope
,
3513 (struct data_string
*)0,
3514 client
-> config
-> vendor_space_name
);
3516 if (client
-> packet_length
< BOOTP_MIN_LEN
)
3517 client
-> packet_length
= BOOTP_MIN_LEN
;
3519 client
-> packet
.op
= BOOTREQUEST
;
3520 client
-> packet
.htype
= client
-> interface
-> hw_address
.hbuf
[0];
3521 /* Assumes hw_address is known, otherwise a random value may result */
3522 client
-> packet
.hlen
= client
-> interface
-> hw_address
.hlen
- 1;
3523 client
-> packet
.hops
= 0;
3524 client
-> packet
.xid
= client
-> xid
;
3525 client
-> packet
.secs
= 0; /* Filled in by send_request. */
3527 /* If we own the address we're requesting, put it in ciaddr;
3528 otherwise set ciaddr to zero. */
3529 if (client
-> state
== S_BOUND
||
3530 client
-> state
== S_RENEWING
||
3531 client
-> state
== S_REBINDING
) {
3532 memcpy (&client
-> packet
.ciaddr
,
3533 lease
-> address
.iabuf
, lease
-> address
.len
);
3534 client
-> packet
.flags
= 0;
3536 memset (&client
-> packet
.ciaddr
, 0,
3537 sizeof client
-> packet
.ciaddr
);
3538 if (can_receive_unicast_unconfigured (client
-> interface
))
3539 client
-> packet
.flags
= 0;
3541 client
-> packet
.flags
= htons (BOOTP_BROADCAST
);
3544 memset (&client
-> packet
.yiaddr
, 0,
3545 sizeof client
-> packet
.yiaddr
);
3546 memset (&client
-> packet
.siaddr
, 0,
3547 sizeof client
-> packet
.siaddr
);
3548 if (client
-> state
!= S_BOUND
&&
3549 client
-> state
!= S_RENEWING
)
3550 client
-> packet
.giaddr
= giaddr
;
3552 memset (&client
-> packet
.giaddr
, 0,
3553 sizeof client
-> packet
.giaddr
);
3554 if (client
-> interface
-> hw_address
.hlen
> 0)
3555 memcpy (client
-> packet
.chaddr
,
3556 &client
-> interface
-> hw_address
.hbuf
[1],
3557 (unsigned)(client
-> interface
-> hw_address
.hlen
- 1));
3560 dump_raw ((unsigned char *)&client
-> packet
, client
-> packet_length
);
3564 void make_decline (client
, lease
)
3565 struct client_state
*client
;
3566 struct client_lease
*lease
;
3568 unsigned char decline
= DHCPDECLINE
;
3569 struct option_cache
*oc
;
3571 struct option_state
*options
= (struct option_state
*)0;
3573 /* Create the options cache. */
3574 oc
= lookup_option (&dhcp_universe
, lease
-> options
,
3575 DHO_DHCP_SERVER_IDENTIFIER
);
3576 make_client_options(client
, lease
, &decline
, oc
, &lease
->address
,
3579 /* Consume the options cache into the option buffer. */
3580 memset (&client
-> packet
, 0, sizeof (client
-> packet
));
3581 client
-> packet_length
=
3582 cons_options ((struct packet
*)0, &client
-> packet
,
3583 (struct lease
*)0, client
, 0,
3584 (struct option_state
*)0, options
,
3585 &global_scope
, 0, 0, 0, (struct data_string
*)0,
3586 client
-> config
-> vendor_space_name
);
3588 /* Destroy the options cache. */
3589 option_state_dereference (&options
, MDL
);
3591 if (client
-> packet_length
< BOOTP_MIN_LEN
)
3592 client
-> packet_length
= BOOTP_MIN_LEN
;
3594 client
-> packet
.op
= BOOTREQUEST
;
3595 client
-> packet
.htype
= client
-> interface
-> hw_address
.hbuf
[0];
3596 /* Assumes hw_address is known, otherwise a random value may result */
3597 client
-> packet
.hlen
= client
-> interface
-> hw_address
.hlen
- 1;
3598 client
-> packet
.hops
= 0;
3599 client
-> packet
.xid
= client
-> xid
;
3600 client
-> packet
.secs
= 0; /* Filled in by send_request. */
3601 if (can_receive_unicast_unconfigured (client
-> interface
))
3602 client
-> packet
.flags
= 0;
3604 client
-> packet
.flags
= htons (BOOTP_BROADCAST
);
3606 /* ciaddr must always be zero. */
3607 memset (&client
-> packet
.ciaddr
, 0,
3608 sizeof client
-> packet
.ciaddr
);
3609 memset (&client
-> packet
.yiaddr
, 0,
3610 sizeof client
-> packet
.yiaddr
);
3611 memset (&client
-> packet
.siaddr
, 0,
3612 sizeof client
-> packet
.siaddr
);
3613 client
-> packet
.giaddr
= giaddr
;
3614 memcpy (client
-> packet
.chaddr
,
3615 &client
-> interface
-> hw_address
.hbuf
[1],
3616 client
-> interface
-> hw_address
.hlen
);
3619 dump_raw ((unsigned char *)&client
-> packet
, client
-> packet_length
);
3623 void make_release (client
, lease
)
3624 struct client_state
*client
;
3625 struct client_lease
*lease
;
3627 unsigned char request
= DHCPRELEASE
;
3628 struct option_cache
*oc
;
3630 struct option_state
*options
= (struct option_state
*)0;
3632 memset (&client
-> packet
, 0, sizeof (client
-> packet
));
3634 oc
= lookup_option (&dhcp_universe
, lease
-> options
,
3635 DHO_DHCP_SERVER_IDENTIFIER
);
3636 make_client_options(client
, lease
, &request
, oc
, NULL
, NULL
, &options
);
3638 /* Set up the option buffer... */
3639 client
-> packet_length
=
3640 cons_options ((struct packet
*)0, &client
-> packet
,
3641 (struct lease
*)0, client
,
3642 /* maximum packet size */1500,
3643 (struct option_state
*)0,
3645 /* scope */ &global_scope
,
3649 (struct data_string
*)0,
3650 client
-> config
-> vendor_space_name
);
3652 if (client
-> packet_length
< BOOTP_MIN_LEN
)
3653 client
-> packet_length
= BOOTP_MIN_LEN
;
3654 option_state_dereference (&options
, MDL
);
3656 client
-> packet
.op
= BOOTREQUEST
;
3657 client
-> packet
.htype
= client
-> interface
-> hw_address
.hbuf
[0];
3658 /* Assumes hw_address is known, otherwise a random value may result */
3659 client
-> packet
.hlen
= client
-> interface
-> hw_address
.hlen
- 1;
3660 client
-> packet
.hops
= 0;
3661 client
-> packet
.xid
= random ();
3662 client
-> packet
.secs
= 0;
3663 client
-> packet
.flags
= 0;
3664 memcpy (&client
-> packet
.ciaddr
,
3665 lease
-> address
.iabuf
, lease
-> address
.len
);
3666 memset (&client
-> packet
.yiaddr
, 0,
3667 sizeof client
-> packet
.yiaddr
);
3668 memset (&client
-> packet
.siaddr
, 0,
3669 sizeof client
-> packet
.siaddr
);
3670 client
-> packet
.giaddr
= giaddr
;
3671 memcpy (client
-> packet
.chaddr
,
3672 &client
-> interface
-> hw_address
.hbuf
[1],
3673 client
-> interface
-> hw_address
.hlen
);
3676 dump_raw ((unsigned char *)&client
-> packet
, client
-> packet_length
);
3680 void destroy_client_lease (lease
)
3681 struct client_lease
*lease
;
3683 if (lease
-> server_name
)
3684 dfree (lease
-> server_name
, MDL
);
3685 if (lease
-> filename
)
3686 dfree (lease
-> filename
, MDL
);
3687 option_state_dereference (&lease
-> options
, MDL
);
3688 free_client_lease (lease
, MDL
);
3691 FILE *leaseFile
= NULL
;
3692 int leases_written
= 0;
3694 void rewrite_client_leases ()
3696 struct interface_info
*ip
;
3697 struct client_state
*client
;
3698 struct client_lease
*lp
;
3700 if (leaseFile
!= NULL
)
3702 leaseFile
= fopen (path_dhclient_db
, "w");
3703 if (leaseFile
== NULL
) {
3704 log_error ("can't create %s: %m", path_dhclient_db
);
3708 /* If there is a default duid, write it out. */
3709 if (default_duid
.len
!= 0)
3710 write_duid(&default_duid
);
3712 /* Write out all the leases attached to configured interfaces that
3714 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
3715 for (client
= ip
-> client
; client
; client
= client
-> next
) {
3716 for (lp
= client
-> leases
; lp
; lp
= lp
-> next
) {
3717 write_client_lease (client
, lp
, 1, 0);
3719 if (client
-> active
)
3720 write_client_lease (client
,
3721 client
-> active
, 1, 0);
3723 if (client
->active_lease
!= NULL
)
3724 write_client6_lease(client
,
3725 client
->active_lease
,
3728 /* Reset last_write after rewrites. */
3729 client
->last_write
= 0;
3733 /* Write out any leases that are attached to interfaces that aren't
3734 currently configured. */
3735 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
) {
3736 for (client
= ip
-> client
; client
; client
= client
-> next
) {
3737 for (lp
= client
-> leases
; lp
; lp
= lp
-> next
) {
3738 write_client_lease (client
, lp
, 1, 0);
3740 if (client
-> active
)
3741 write_client_lease (client
,
3742 client
-> active
, 1, 0);
3744 if (client
->active_lease
!= NULL
)
3745 write_client6_lease(client
,
3746 client
->active_lease
,
3749 /* Reset last_write after rewrites. */
3750 client
->last_write
= 0;
3756 void write_lease_option (struct option_cache
*oc
,
3757 struct packet
*packet
, struct lease
*lease
,
3758 struct client_state
*client_state
,
3759 struct option_state
*in_options
,
3760 struct option_state
*cfg_options
,
3761 struct binding_scope
**scope
,
3762 struct universe
*u
, void *stuff
)
3764 const char *name
, *dot
;
3765 struct data_string ds
;
3766 char *preamble
= stuff
;
3768 memset (&ds
, 0, sizeof ds
);
3770 if (u
!= &dhcp_universe
) {
3777 if (evaluate_option_cache (&ds
, packet
, lease
, client_state
,
3778 in_options
, cfg_options
, scope
, oc
, MDL
)) {
3779 /* The option name */
3780 fprintf(leaseFile
, "%soption %s%s%s", preamble
,
3781 name
, dot
, oc
->option
->name
);
3783 /* The option value if there is one */
3784 if ((oc
->option
->format
== NULL
) ||
3785 (oc
->option
->format
[0] != 'Z')) {
3786 fprintf(leaseFile
, " %s",
3787 pretty_print_option(oc
->option
, ds
.data
,
3791 /* The closing semi-colon and newline */
3792 fprintf(leaseFile
, ";\n");
3794 data_string_forget (&ds
, MDL
);
3798 /* Write an option cache to the lease store. */
3800 write_options(struct client_state
*client
, struct option_state
*options
,
3801 const char *preamble
)
3805 for (i
= 0; i
< options
->universe_count
; i
++) {
3806 option_space_foreach(NULL
, NULL
, client
, NULL
, options
,
3807 &global_scope
, universes
[i
],
3808 (char *)preamble
, write_lease_option
);
3813 * The "best" default DUID, since we cannot predict any information
3814 * about the system (such as whether or not the hardware addresses are
3815 * integrated into the motherboard or similar), is the "LLT", link local
3816 * plus time, DUID. For real stateless "LL" is better.
3818 * Once generated, this duid is stored into the state database, and
3819 * retained across restarts.
3821 * For the time being, there is probably a different state database for
3822 * every daemon, so this winds up being a per-interface identifier...which
3823 * is not how it is intended. Upcoming rearchitecting the client should
3824 * address this "one daemon model."
3827 form_duid(struct data_string
*duid
, const char *file
, int line
)
3829 struct interface_info
*ip
;
3833 /* For now, just use the first interface on the list. */
3837 log_fatal("Impossible condition at %s:%d.", MDL
);
3839 if ((ip
->hw_address
.hlen
== 0) ||
3840 (ip
->hw_address
.hlen
> sizeof(ip
->hw_address
.hbuf
)))
3841 log_fatal("Impossible hardware address length at %s:%d.", MDL
);
3844 duid_type
= stateless
? DUID_LL
: DUID_LLT
;
3847 * 2 bytes for the 'duid type' field.
3848 * 2 bytes for the 'htype' field.
3849 * (DUID_LLT) 4 bytes for the 'current time'.
3850 * enough bytes for the hardware address (note that hw_address has
3851 * the 'htype' on byte zero).
3853 len
= 4 + (ip
->hw_address
.hlen
- 1);
3854 if (duid_type
== DUID_LLT
)
3856 if (!buffer_allocate(&duid
->buffer
, len
, MDL
))
3857 log_fatal("no memory for default DUID!");
3858 duid
->data
= duid
->buffer
->data
;
3861 /* Basic Link Local Address type of DUID. */
3862 if (duid_type
== DUID_LLT
) {
3863 putUShort(duid
->buffer
->data
, DUID_LLT
);
3864 putUShort(duid
->buffer
->data
+ 2, ip
->hw_address
.hbuf
[0]);
3865 putULong(duid
->buffer
->data
+ 4, cur_time
- DUID_TIME_EPOCH
);
3866 memcpy(duid
->buffer
->data
+ 8, ip
->hw_address
.hbuf
+ 1,
3867 ip
->hw_address
.hlen
- 1);
3869 putUShort(duid
->buffer
->data
, DUID_LL
);
3870 putUShort(duid
->buffer
->data
+ 2, ip
->hw_address
.hbuf
[0]);
3871 memcpy(duid
->buffer
->data
+ 4, ip
->hw_address
.hbuf
+ 1,
3872 ip
->hw_address
.hlen
- 1);
3875 /* Now format the output based on lease-id-format */
3876 str
= format_lease_id(duid
->data
, duid
->len
,
3877 top_level_config
.lease_id_format
, MDL
);
3879 log_info("form_duid: Couldn't allocate memory to log duid!");
3881 log_info("Created duid %s.", str
);
3886 /* Write the default DUID to the lease store. */
3888 write_duid(struct data_string
*duid
)
3893 if ((duid
== NULL
) || (duid
->len
<= 2))
3894 return DHCP_R_INVALIDARG
;
3896 if (leaseFile
== NULL
) { /* XXX? */
3897 leaseFile
= fopen(path_dhclient_db
, "w");
3898 if (leaseFile
== NULL
) {
3899 log_error("can't create %s: %m", path_dhclient_db
);
3900 return ISC_R_IOERROR
;
3904 /* Generate a formatted duid string per lease-id-format */
3905 str
= format_lease_id(duid
->data
, duid
->len
,
3906 top_level_config
.lease_id_format
, MDL
);
3908 return ISC_R_NOMEMORY
;
3910 stat
= fprintf(leaseFile
, "default-duid %s;\n", str
);
3913 return ISC_R_IOERROR
;
3915 if (fflush(leaseFile
) != 0)
3916 return ISC_R_IOERROR
;
3918 return ISC_R_SUCCESS
;
3921 /* Write a DHCPv6 lease to the store. */
3923 write_client6_lease(struct client_state
*client
, struct dhc6_lease
*lease
,
3924 int rewrite
, int sync
)
3927 struct dhc6_addr
*addr
;
3931 /* This should include the current lease. */
3932 if (!rewrite
&& (leases_written
++ > 20)) {
3933 rewrite_client_leases();
3935 return ISC_R_SUCCESS
;
3938 if (client
== NULL
|| lease
== NULL
)
3939 return DHCP_R_INVALIDARG
;
3941 if (leaseFile
== NULL
) { /* XXX? */
3942 leaseFile
= fopen(path_dhclient_db
, "w");
3943 if (leaseFile
== NULL
) {
3944 log_error("can't create %s: %m", path_dhclient_db
);
3945 return ISC_R_IOERROR
;
3949 stat
= fprintf(leaseFile
, "lease6 {\n");
3951 return ISC_R_IOERROR
;
3953 stat
= fprintf(leaseFile
, " interface \"%s\";\n",
3954 client
->interface
->name
);
3956 return ISC_R_IOERROR
;
3958 for (ia
= lease
->bindings
; ia
!= NULL
; ia
= ia
->next
) {
3959 switch (ia
->ia_type
) {
3972 /* For some reason IAID was never octal or hex, but string or
3973 * hex. Go figure. So for compatibilty's sake we will either
3974 * do hex or "legacy" i.e string rather than octal. What a
3976 switch(top_level_config
.lease_id_format
) {
3978 char* iaid_str
= format_lease_id(
3979 (const unsigned char *) &ia
->iaid
, 4,
3980 top_level_config
.lease_id_format
, MDL
);
3983 log_error("Can't format iaid");
3984 return ISC_R_IOERROR
;
3987 stat
= fprintf(leaseFile
, " %s %s {\n",
3989 dfree(iaid_str
, MDL
);
3995 stat
= fprintf(leaseFile
, " %s %s {\n", ianame
,
3996 print_hex_1(4, ia
->iaid
, 12));
4001 return ISC_R_IOERROR
;
4003 if (ia
->ia_type
!= D6O_IA_TA
)
4004 stat
= fprintf(leaseFile
, " starts %d;\n"
4007 (int)ia
->starts
, ia
->renew
, ia
->rebind
);
4009 stat
= fprintf(leaseFile
, " starts %d;\n",
4012 return ISC_R_IOERROR
;
4014 for (addr
= ia
->addrs
; addr
!= NULL
; addr
= addr
->next
) {
4015 if (ia
->ia_type
!= D6O_IA_PD
)
4016 stat
= fprintf(leaseFile
,
4018 piaddr(addr
->address
));
4020 stat
= fprintf(leaseFile
,
4021 " iaprefix %s/%d {\n",
4022 piaddr(addr
->address
),
4025 return ISC_R_IOERROR
;
4027 stat
= fprintf(leaseFile
, " starts %d;\n"
4028 " preferred-life %u;\n"
4030 (int)addr
->starts
, addr
->preferred_life
,
4033 return ISC_R_IOERROR
;
4035 if (addr
->options
!= NULL
)
4036 write_options(client
, addr
->options
, " ");
4038 stat
= fprintf(leaseFile
, " }\n");
4040 return ISC_R_IOERROR
;
4043 if (ia
->options
!= NULL
)
4044 write_options(client
, ia
->options
, " ");
4046 stat
= fprintf(leaseFile
, " }\n");
4048 return ISC_R_IOERROR
;
4051 if (lease
->released
) {
4052 stat
= fprintf(leaseFile
, " released;\n");
4054 return ISC_R_IOERROR
;
4057 if (lease
->options
!= NULL
)
4058 write_options(client
, lease
->options
, " ");
4060 stat
= fprintf(leaseFile
, "}\n");
4062 return ISC_R_IOERROR
;
4064 if (fflush(leaseFile
) != 0)
4065 return ISC_R_IOERROR
;
4068 if (fsync(fileno(leaseFile
)) < 0) {
4069 log_error("write_client_lease: fsync(): %m");
4070 return ISC_R_IOERROR
;
4074 return ISC_R_SUCCESS
;
4077 int write_client_lease (client
, lease
, rewrite
, makesure
)
4078 struct client_state
*client
;
4079 struct client_lease
*lease
;
4083 struct data_string ds
;
4089 if (leases_written
++ > 20) {
4090 rewrite_client_leases ();
4095 /* If the lease came from the config file, we don't need to stash
4096 a copy in the lease database. */
4097 if (lease
-> is_static
)
4100 if (leaseFile
== NULL
) { /* XXX */
4101 leaseFile
= fopen (path_dhclient_db
, "w");
4102 if (leaseFile
== NULL
) {
4103 log_error ("can't create %s: %m", path_dhclient_db
);
4109 fprintf (leaseFile
, "lease {\n");
4110 if (lease
-> is_bootp
) {
4111 fprintf (leaseFile
, " bootp;\n");
4117 fprintf (leaseFile
, " interface \"%s\";\n",
4118 client
-> interface
-> name
);
4123 if (client
-> name
) {
4124 fprintf (leaseFile
, " name \"%s\";\n", client
-> name
);
4130 fprintf (leaseFile
, " fixed-address %s;\n",
4131 piaddr (lease
-> address
));
4136 if (lease
-> filename
) {
4137 s
= quotify_string (lease
-> filename
, MDL
);
4139 fprintf (leaseFile
, " filename \"%s\";\n", s
);
4149 if (lease
->server_name
!= NULL
) {
4150 s
= quotify_string(lease
->server_name
, MDL
);
4152 fprintf(leaseFile
, " server-name \"%s\";\n", s
);
4161 if (lease
-> medium
) {
4162 s
= quotify_string (lease
-> medium
-> string
, MDL
);
4164 fprintf (leaseFile
, " medium \"%s\";\n", s
);
4178 memset (&ds
, 0, sizeof ds
);
4180 write_options(client
, lease
->options
, " ");
4182 tval
= print_time(lease
->renewal
);
4184 fprintf(leaseFile
, " renew %s\n", tval
) < 0)
4187 tval
= print_time(lease
->rebind
);
4189 fprintf(leaseFile
, " rebind %s\n", tval
) < 0)
4192 tval
= print_time(lease
->expiry
);
4194 fprintf(leaseFile
, " expire %s\n", tval
) < 0)
4197 if (fprintf(leaseFile
, "}\n") < 0)
4200 if (fflush(leaseFile
) != 0)
4203 client
->last_write
= cur_time
;
4205 if (!errors
&& makesure
) {
4206 if (fsync (fileno (leaseFile
)) < 0) {
4207 log_info ("write_client_lease: %m");
4212 return errors
? 0 : 1;
4215 /* Variables holding name of script and file pointer for writing to
4216 script. Needless to say, this is not reentrant - only one script
4217 can be invoked at a time. */
4218 char scriptName
[256];
4222 * @brief Initializes basic variables for a script
4224 * This function is called as an initial preparation for calling a script.
4225 * It sets up a number of common env. variables that will be passed to
4226 * the script. For actual script calling, see @ref script_go .
4228 * @param client variables will be stored here (if null, the whole function
4230 * @param reason specified the reason for calling a script (must be non-null)
4231 * @param medium if specified, defines medium type (may be null)
4233 void script_init(struct client_state
*client
, const char *reason
,
4234 struct string_list
*medium
)
4236 struct string_list
*sl
, *next
;
4239 for (sl
= client
-> env
; sl
; sl
= next
) {
4243 client
-> env
= (struct string_list
*)0;
4246 if (client
-> interface
) {
4247 client_envadd (client
, "", "interface", "%s",
4248 client
-> interface
-> name
);
4251 client_envadd (client
,
4252 "", "client", "%s", client
-> name
);
4254 client_envadd (client
,
4255 "", "medium", "%s", medium
-> string
);
4257 client_envadd (client
, "", "reason", "%s", reason
);
4258 client_envadd (client
, "", "pid", "%ld", (long int)getpid ());
4260 client_envadd (client
, "", "dad_wait_time", "%ld",
4261 (long int)dad_wait_time
);
4266 void client_option_envadd (struct option_cache
*oc
,
4267 struct packet
*packet
, struct lease
*lease
,
4268 struct client_state
*client_state
,
4269 struct option_state
*in_options
,
4270 struct option_state
*cfg_options
,
4271 struct binding_scope
**scope
,
4272 struct universe
*u
, void *stuff
)
4274 struct envadd_state
*es
= stuff
;
4275 struct data_string data
;
4276 memset (&data
, 0, sizeof data
);
4278 if (evaluate_option_cache (&data
, packet
, lease
, client_state
,
4279 in_options
, cfg_options
, scope
, oc
, MDL
)) {
4282 if (dhcp_option_ev_name (name
, sizeof name
,
4286 value
= pretty_print_option(oc
->option
,
4289 length
= strlen(value
);
4291 if (check_option_values(oc
->option
->universe
,
4293 value
, length
) == 0) {
4294 client_envadd(es
->client
, es
->prefix
,
4297 log_error("suspect value in %s "
4298 "option - discarded",
4304 data_string_forget (&data
, MDL
);
4309 * @brief Adds parameters to environment variables for a script
4311 * This function add details of specified lease to a list of env. variables
4312 * to be passed to a script. The lease details will be prepended with
4313 * specified prefix (e.g. "old_") and added to the list stored in client.
4314 * Following variables may be set:
4318 * - broadcast_address
4323 * @param client env. variables will be stored here
4324 * @param prefix textual prefix to be added to each variable (e.g. "old_")
4325 * @param lease lease details will be extracted from here
4327 void script_write_params(struct client_state
*client
, const char *prefix
,
4328 struct client_lease
*lease
)
4331 struct data_string data
;
4332 struct option_cache
*oc
;
4333 struct envadd_state es
;
4338 client_envadd (client
,
4339 prefix
, "ip_address", "%s", piaddr (lease
-> address
));
4341 /* If we've set the next server address in the lease structure
4342 put it into an environment variable for the script */
4343 if (lease
->next_srv_addr
.len
!= 0) {
4344 client_envadd(client
, prefix
, "next_server", "%s",
4345 piaddr(lease
->next_srv_addr
));
4348 /* For the benefit of Linux (and operating systems which may
4349 have similar needs), compute the network address based on
4350 the supplied ip address and netmask, if provided. Also
4351 compute the broadcast address (the host address all ones
4352 broadcast address, not the host address all zeroes
4353 broadcast address). */
4355 memset (&data
, 0, sizeof data
);
4356 oc
= lookup_option (&dhcp_universe
, lease
-> options
, DHO_SUBNET_MASK
);
4357 if (oc
&& evaluate_option_cache (&data
, (struct packet
*)0,
4358 (struct lease
*)0, client
,
4359 (struct option_state
*)0,
4361 &global_scope
, oc
, MDL
)) {
4363 struct iaddr netmask
, subnet
, broadcast
;
4366 * No matter the length of the subnet-mask option,
4367 * use only the first four octets. Note that
4368 * subnet-mask options longer than 4 octets are not
4369 * in conformance with RFC 2132, but servers with this
4372 memcpy(netmask
.iabuf
, data
.data
, 4);
4374 data_string_forget (&data
, MDL
);
4376 subnet
= subnet_number (lease
-> address
, netmask
);
4378 client_envadd (client
, prefix
, "network_number",
4379 "%s", piaddr (subnet
));
4381 oc
= lookup_option (&dhcp_universe
,
4383 DHO_BROADCAST_ADDRESS
);
4385 !(evaluate_option_cache
4386 (&data
, (struct packet
*)0,
4387 (struct lease
*)0, client
,
4388 (struct option_state
*)0,
4390 &global_scope
, oc
, MDL
))) {
4391 broadcast
= broadcast_addr (subnet
, netmask
);
4392 if (broadcast
.len
) {
4393 client_envadd (client
,
4394 prefix
, "broadcast_address",
4395 "%s", piaddr (broadcast
));
4400 data_string_forget (&data
, MDL
);
4403 if (lease
->filename
) {
4404 if (check_option_values(NULL
, DHO_ROOT_PATH
,
4406 strlen(lease
->filename
)) == 0) {
4407 client_envadd(client
, prefix
, "filename",
4408 "%s", lease
->filename
);
4410 log_error("suspect value in %s "
4411 "option - discarded",
4416 if (lease
->server_name
) {
4417 if (check_option_values(NULL
, DHO_HOST_NAME
,
4419 strlen(lease
->server_name
)) == 0 ) {
4420 client_envadd (client
, prefix
, "server_name",
4421 "%s", lease
->server_name
);
4423 log_error("suspect value in %s "
4424 "option - discarded",
4425 lease
->server_name
);
4429 for (i
= 0; i
< lease
-> options
-> universe_count
; i
++) {
4430 option_space_foreach ((struct packet
*)0, (struct lease
*)0,
4431 client
, (struct option_state
*)0,
4432 lease
-> options
, &global_scope
,
4434 &es
, client_option_envadd
);
4437 client_envadd (client
, prefix
, "expiry", "%lu",
4438 (unsigned long)(lease
-> expiry
));
4442 * @brief Write out the environent variable the client requested.
4443 * Write out the environment variables for the objects that the
4444 * client requested. If the object was requested the variable will be:
4445 * requested_<option_name>=1
4446 * If it wasn't requested there won't be a variable.
4448 * @param client client structure
4450 void script_write_requested(struct client_state
*client
)
4453 struct option
**req
;
4455 req
= client
->config
->requested_options
;
4460 for (i
= 0 ; req
[i
] != NULL
; i
++) {
4461 if ((req
[i
]->universe
== &dhcp_universe
) &&
4462 dhcp_option_ev_name(name
, sizeof(name
), req
[i
])) {
4463 client_envadd(client
, "requested_", name
, "%d", 1);
4469 * @brief Calls external script.
4471 * External script is specified either using -sf command line or
4472 * script parameter in the configuration file.
4474 * @param client specifies client information (environment variables,
4475 * and other parameters will be extracted and passed to the script.
4476 * @return If positive, it contains exit code of the process running script.
4477 * If negative, returns the signal number that cause the script process
4480 int script_go(struct client_state
*client
)
4485 char reason
[] = "REASON=NBI";
4486 static char client_path
[] = CLIENT_PATH
;
4488 struct string_list
*sp
, *next
;
4489 int pid
, wpid
, wstatus
;
4492 scriptName
= client
-> config
-> script_name
;
4494 scriptName
= top_level_config
.script_name
;
4496 envp
= dmalloc (((client
? client
-> envc
: 2) +
4497 client_env_count
+ 2) * sizeof (char *), MDL
);
4499 log_error ("No memory for client script environment.");
4503 /* Copy out the environment specified on the command line,
4505 for (sp
= client_env
; sp
; sp
= sp
-> next
) {
4506 envp
[i
++] = sp
-> string
;
4508 /* Copy out the environment specified by dhclient. */
4510 for (sp
= client
-> env
; sp
; sp
= sp
-> next
) {
4511 envp
[i
++] = sp
-> string
;
4514 envp
[i
++] = reason
;
4517 envp
[i
++] = client_path
;
4518 envp
[i
] = (char *)0;
4520 argv
[0] = scriptName
;
4521 argv
[1] = (char *)0;
4525 log_error ("fork: %m");
4529 wpid
= wait (&wstatus
);
4530 } while (wpid
!= pid
&& wpid
> 0);
4532 log_error ("wait: %m");
4536 /* We don't want to pass an open file descriptor for
4537 * dhclient.leases when executing dhclient-script.
4539 if (leaseFile
!= NULL
)
4541 execve (scriptName
, argv
, envp
);
4542 log_error ("execve (%s, ...): %m", scriptName
);
4547 for (sp
= client
-> env
; sp
; sp
= next
) {
4551 client
-> env
= (struct string_list
*)0;
4555 gettimeofday(&cur_tv
, NULL
);
4556 return (WIFEXITED (wstatus
) ?
4557 WEXITSTATUS (wstatus
) : -WTERMSIG (wstatus
));
4560 void client_envadd (struct client_state
*client
,
4561 const char *prefix
, const char *name
, const char *fmt
, ...)
4566 struct string_list
*val
;
4569 va_start (list
, fmt
);
4570 len
= vsnprintf (spbuf
, sizeof spbuf
, fmt
, list
);
4573 val
= dmalloc (strlen (prefix
) + strlen (name
) + 1 /* = */ +
4574 len
+ sizeof *val
, MDL
);
4576 log_error ("client_envadd: cannot allocate space for variable");
4585 if (len
>= sizeof spbuf
) {
4586 va_start (list
, fmt
);
4587 vsnprintf (s
, len
+ 1, fmt
, list
);
4593 val
-> next
= client
-> env
;
4594 client
-> env
= val
;
4598 int dhcp_option_ev_name (buf
, buflen
, option
)
4601 struct option
*option
;
4607 if (option
-> universe
!= &dhcp_universe
) {
4608 s
= option
-> universe
-> name
;
4617 if (j
+ 1 == buflen
)
4627 if (j
+ 1 == buflen
)
4638 void finish (char ret
)
4640 if (no_daemon
|| dfd
[0] == -1 || dfd
[1] == -1)
4642 if (write(dfd
[1], &ret
, 1) != 1)
4643 log_fatal("write to parent: %m");
4644 (void) close(dfd
[1]);
4645 dfd
[0] = dfd
[1] = -1;
4653 /* Don't become a daemon if the user requested otherwise. */
4655 write_client_pid_file ();
4659 /* Only do it once. */
4660 if (dfd
[0] == -1 || dfd
[1] == -1)
4663 /* Signal parent we started successfully. */
4664 if (write(dfd
[1], &buf
, 1) != 1)
4665 log_fatal("write to parent: %m");
4666 (void) close(dfd
[1]);
4667 dfd
[0] = dfd
[1] = -1;
4669 /* Stop logging to stderr... */
4672 /* Become session leader and get pid... */
4675 /* Close standard I/O descriptors. */
4680 /* Reopen them on /dev/null. */
4681 (void) open("/dev/null", O_RDWR
);
4682 (void) open("/dev/null", O_RDWR
);
4683 (void) open("/dev/null", O_RDWR
);
4685 write_client_pid_file ();
4687 IGNORE_RET (chdir("/"));
4691 void write_client_pid_file ()
4696 /* nothing to do if the user doesn't want a pid file */
4697 if (no_pid_file
== ISC_TRUE
) {
4701 pfdesc
= open (path_dhclient_pid
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0644);
4704 log_error ("Can't create %s: %m", path_dhclient_pid
);
4708 pf
= fdopen (pfdesc
, "w");
4711 log_error ("Can't fdopen %s: %m", path_dhclient_pid
);
4713 fprintf (pf
, "%ld\n", (long)getpid ());
4718 void client_location_changed ()
4720 struct interface_info
*ip
;
4721 struct client_state
*client
;
4723 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
4724 for (client
= ip
-> client
; client
; client
= client
-> next
) {
4725 switch (client
-> state
) {
4727 cancel_timeout (send_discover
, client
);
4731 cancel_timeout (state_bound
, client
);
4737 cancel_timeout (send_request
, client
);
4747 client
-> state
= S_INIT
;
4748 state_reboot (client
);
4753 void do_release(client
)
4754 struct client_state
*client
;
4756 struct data_string ds
;
4757 struct option_cache
*oc
;
4759 #if defined(DHCPv6) && defined(DHCP4o6)
4760 if (dhcpv4_over_dhcpv6
&& (dhcp4o6_state
<= 0)) {
4761 if (dhcp4o6_state
< 0)
4763 client
->pending
= P_RELEASE
;
4768 /* Pick a random xid. */
4769 client
-> xid
= random ();
4771 /* is there even a lease to release? */
4772 if (client
-> active
) {
4773 /* Make a DHCPRELEASE packet, and set appropriate per-interface
4775 make_release (client
, client
-> active
);
4777 memset (&ds
, 0, sizeof ds
);
4778 oc
= lookup_option (&dhcp_universe
,
4779 client
-> active
-> options
,
4780 DHO_DHCP_SERVER_IDENTIFIER
);
4782 evaluate_option_cache (&ds
, (struct packet
*)0,
4783 (struct lease
*)0, client
,
4784 (struct option_state
*)0,
4785 client
-> active
-> options
,
4786 &global_scope
, oc
, MDL
)) {
4788 memcpy (client
-> destination
.iabuf
,
4790 client
-> destination
.len
= 4;
4792 client
-> destination
= iaddr_broadcast
;
4794 data_string_forget (&ds
, MDL
);
4796 client
-> destination
= iaddr_broadcast
;
4797 client
-> first_sending
= cur_time
;
4798 client
-> interval
= client
-> config
-> initial_interval
;
4800 /* Zap the medium list... */
4801 client
-> medium
= (struct string_list
*)0;
4803 /* Send out the first and only DHCPRELEASE packet. */
4804 send_release (client
);
4806 /* Do the client script RELEASE operation. */
4807 script_init (client
,
4808 "RELEASE", (struct string_list
*)0);
4809 if (client
-> alias
)
4810 script_write_params(client
, "alias_",
4812 script_write_params(client
, "old_", client
-> active
);
4813 script_write_requested(client
);
4817 /* Cancel any timeouts. */
4818 cancel_timeout (state_bound
, client
);
4819 cancel_timeout (send_discover
, client
);
4820 cancel_timeout (state_init
, client
);
4821 cancel_timeout (send_request
, client
);
4822 cancel_timeout (state_reboot
, client
);
4823 cancel_timeout (finish_v6only
, client
);
4824 client
-> state
= S_STOPPED
;
4826 #if defined(DHCPv6) && defined(DHCP4o6)
4827 if (dhcpv4_over_dhcpv6
)
4832 int dhclient_interface_shutdown_hook (struct interface_info
*interface
)
4834 do_release (interface
-> client
);
4839 int dhclient_interface_discovery_hook (struct interface_info
*tmp
)
4841 struct interface_info
*last
, *ip
;
4842 /* See if we can find the client from dummy_interfaces */
4844 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
) {
4845 if (!strcmp (ip
-> name
, tmp
-> name
)) {
4846 /* Remove from dummy_interfaces */
4848 ip
= (struct interface_info
*)0;
4849 interface_reference (&ip
, last
-> next
, MDL
);
4850 interface_dereference (&last
-> next
, MDL
);
4852 interface_reference (&last
-> next
,
4854 interface_dereference (&ip
-> next
,
4858 ip
= (struct interface_info
*)0;
4859 interface_reference (&ip
,
4860 dummy_interfaces
, MDL
);
4861 interface_dereference (&dummy_interfaces
, MDL
);
4863 interface_reference (&dummy_interfaces
,
4865 interface_dereference (&ip
-> next
,
4869 /* Copy "client" to tmp */
4871 tmp
-> client
= ip
-> client
;
4872 tmp
-> client
-> interface
= tmp
;
4874 interface_dereference (&ip
, MDL
);
4882 isc_result_t
dhclient_interface_startup_hook (struct interface_info
*interface
)
4884 struct interface_info
*ip
;
4885 struct client_state
*client
;
4887 /* This code needs some rethinking. It doesn't test against
4888 a signal name, and it just kind of bulls into doing something
4889 that may or may not be appropriate. */
4892 interface_reference (&interface
-> next
, interfaces
, MDL
);
4893 interface_dereference (&interfaces
, MDL
);
4895 interface_reference (&interfaces
, interface
, MDL
);
4897 discover_interfaces (DISCOVER_UNCONFIGURED
);
4899 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
4900 /* If interfaces were specified, don't configure
4901 interfaces that weren't specified! */
4902 if (ip
-> flags
& INTERFACE_RUNNING
||
4903 (ip
-> flags
& (INTERFACE_REQUESTED
|
4904 INTERFACE_AUTOMATIC
)) !=
4905 INTERFACE_REQUESTED
)
4907 script_init (ip
-> client
,
4908 "PREINIT", (struct string_list
*)0);
4909 if (ip
-> client
-> alias
)
4910 script_write_params(ip
-> client
, "alias_",
4911 ip
-> client
-> alias
);
4912 script_go(ip
-> client
);
4915 discover_interfaces (interfaces_requested
!= 0
4916 ? DISCOVER_REQUESTED
4917 : DISCOVER_RUNNING
);
4919 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
4920 if (ip
-> flags
& INTERFACE_RUNNING
)
4922 ip
-> flags
|= INTERFACE_RUNNING
;
4923 for (client
= ip
->client
; client
; client
= client
->next
) {
4924 client
->state
= S_INIT
;
4925 state_reboot(client
);
4928 return ISC_R_SUCCESS
;
4931 /* The client should never receive a relay agent information option,
4932 so if it does, log it and discard it. */
4934 int parse_agent_information_option (packet
, len
, data
)
4935 struct packet
*packet
;
4942 /* The client never sends relay agent information options. */
4944 unsigned cons_agent_information_options (cfg_options
, outpacket
,
4946 struct option_state
*cfg_options
;
4947 struct dhcp_packet
*outpacket
;
4954 static void shutdown_exit (void *foo
)
4956 /* get rid of the pid if we can */
4957 if (no_pid_file
== ISC_FALSE
)
4958 (void) unlink(path_dhclient_pid
);
4962 #if defined (NSUPDATE)
4964 * If the first query fails, the updater MUST NOT delete the DNS name. It
4965 * may be that the host whose lease on the server has expired has moved
4966 * to another network and obtained a lease from a different server,
4967 * which has caused the client's A RR to be replaced. It may also be
4968 * that some other client has been configured with a name that matches
4969 * the name of the DHCP client, and the policy was that the last client
4970 * to specify the name would get the name. In this case, the DHCID RR
4971 * will no longer match the updater's notion of the client-identity of
4972 * the host pointed to by the DNS name.
4973 * -- "Interaction between DHCP and DNS"
4976 /* The first and second stages are pretty similar so we combine them */
4978 client_dns_remove_action(dhcp_ddns_cb_t
*ddns_cb
,
4979 isc_result_t eresult
)
4982 isc_result_t result
;
4984 if ((eresult
== ISC_R_SUCCESS
) &&
4985 (ddns_cb
->state
== DDNS_STATE_REM_FW_YXDHCID
)) {
4986 /* Do the second stage of the FWD removal */
4987 ddns_cb
->state
= DDNS_STATE_REM_FW_NXRR
;
4989 result
= ddns_modify_fwd(ddns_cb
, MDL
);
4990 if (result
== ISC_R_SUCCESS
) {
4995 /* If we are done or have an error clean up */
4996 dhclient_ddns_cb_free(ddns_cb
, MDL
);
5001 client_dns_remove(struct client_state
*client
,
5004 dhcp_ddns_cb_t
*ddns_cb
;
5005 isc_result_t result
;
5007 /* if we have an old ddns request for this client, cancel it */
5008 if (client
->ddns_cb
!= NULL
) {
5009 ddns_cancel(client
->ddns_cb
, MDL
);
5010 client
->ddns_cb
= NULL
;
5013 ddns_cb
= ddns_cb_alloc(MDL
);
5014 if (ddns_cb
!= NULL
) {
5015 ddns_cb
->address
= *addr
;
5016 ddns_cb
->timeout
= 0;
5018 ddns_cb
->state
= DDNS_STATE_REM_FW_YXDHCID
;
5019 ddns_cb
->flags
= DDNS_UPDATE_ADDR
;
5020 ddns_cb
->cur_func
= client_dns_remove_action
;
5022 result
= client_dns_update(client
, ddns_cb
);
5024 if (result
!= ISC_R_TIMEDOUT
) {
5025 dhclient_ddns_cb_free(ddns_cb
, MDL
);
5029 #endif /* defined NSUPDATE */
5032 isc_result_t
dhcp_set_control_state (control_object_state_t oldstate
,
5033 control_object_state_t newstate
)
5035 struct interface_info
*ip
;
5036 struct client_state
*client
;
5039 if (newstate
== server_shutdown
) {
5041 if (shutdown_signal
== SIGUSR1
)
5042 return ISC_R_SUCCESS
;
5043 /* Log shutdown on signal. */
5044 if ((shutdown_signal
== SIGINT
) ||
5045 (shutdown_signal
== SIGTERM
)) {
5046 log_info("Received signal %d, initiating shutdown.",
5049 /* Mark it was called. */
5050 shutdown_signal
= SIGUSR1
;
5053 /* Do the right thing for each interface. */
5054 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
5055 for (client
= ip
-> client
; client
; client
= client
-> next
) {
5057 case server_startup
:
5058 return ISC_R_SUCCESS
;
5060 case server_running
:
5061 return ISC_R_SUCCESS
;
5063 case server_shutdown
:
5064 if (client
-> active
&&
5065 client
-> active
-> expiry
> cur_time
) {
5066 #if defined (NSUPDATE)
5067 if (client
->config
->do_forward_update
) {
5068 client_dns_remove(client
,
5069 &client
->active
->address
);
5071 #endif /* defined NSUPDATE */
5073 do_release (client
);
5077 case server_hibernate
:
5078 state_stop (client
);
5082 state_reboot (client
);
5088 if (newstate
== server_shutdown
) {
5089 tv
.tv_sec
= cur_tv
.tv_sec
;
5090 tv
.tv_usec
= cur_tv
.tv_usec
+ 1;
5091 add_timeout(&tv
, shutdown_exit
, 0, 0, 0);
5093 return ISC_R_SUCCESS
;
5096 #if defined (NSUPDATE)
5098 * Called after a timeout if the DNS update failed on the previous try.
5099 * Starts the retry process. If the retry times out it will schedule
5100 * this routine to run again after a 10x wait.
5103 client_dns_update_timeout (void *cp
)
5105 dhcp_ddns_cb_t
*ddns_cb
= (dhcp_ddns_cb_t
*)cp
;
5106 struct client_state
*client
= (struct client_state
*)ddns_cb
->lease
;
5107 isc_result_t status
= ISC_R_FAILURE
;
5109 if ((client
!= NULL
) &&
5110 ((client
->active
!= NULL
) ||
5111 (client
->active_lease
!= NULL
)))
5112 status
= client_dns_update(client
, ddns_cb
);
5115 * A status of timedout indicates that we started the update and
5116 * have released control of the control block. Any other status
5117 * indicates that we should clean up the control block. We either
5118 * got a success which indicates that we didn't really need to
5119 * send an update or some other error in which case we weren't able
5120 * to start the update process. In both cases we still own
5121 * the control block and should free it.
5123 if (status
!= ISC_R_TIMEDOUT
) {
5124 dhclient_ddns_cb_free(ddns_cb
, MDL
);
5129 * If the first query succeeds, the updater can conclude that it
5130 * has added a new name whose only RRs are the A and DHCID RR records.
5131 * The A RR update is now complete (and a client updater is finished,
5132 * while a server might proceed to perform a PTR RR update).
5133 * -- "Interaction between DHCP and DNS"
5135 * If the second query succeeds, the updater can conclude that the current
5136 * client was the last client associated with the domain name, and that
5137 * the name now contains the updated A RR. The A RR update is now
5138 * complete (and a client updater is finished, while a server would
5139 * then proceed to perform a PTR RR update).
5140 * -- "Interaction between DHCP and DNS"
5142 * If the second query fails with NXRRSET, the updater must conclude
5143 * that the client's desired name is in use by another host. At this
5144 * juncture, the updater can decide (based on some administrative
5145 * configuration outside of the scope of this document) whether to let
5146 * the existing owner of the name keep that name, and to (possibly)
5147 * perform some name disambiguation operation on behalf of the current
5148 * client, or to replace the RRs on the name with RRs that represent
5149 * the current client. If the configured policy allows replacement of
5150 * existing records, the updater submits a query that deletes the
5151 * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
5152 * represent the IP address and client-identity of the new client.
5153 * -- "Interaction between DHCP and DNS"
5156 /* The first and second stages are pretty similar so we combine them */
5158 client_dns_update_action(dhcp_ddns_cb_t
*ddns_cb
,
5159 isc_result_t eresult
)
5161 isc_result_t result
;
5167 /* Either we succeeded or broke in a bad way, clean up */
5172 * This is the only difference between the two stages,
5173 * check to see if it is the first stage, in which case
5174 * start the second stage
5176 if (ddns_cb
->state
== DDNS_STATE_ADD_FW_NXDOMAIN
) {
5177 ddns_cb
->state
= DDNS_STATE_ADD_FW_YXDHCID
;
5178 ddns_cb
->cur_func
= client_dns_update_action
;
5180 result
= ddns_modify_fwd(ddns_cb
, MDL
);
5181 if (result
== ISC_R_SUCCESS
) {
5187 case ISC_R_TIMEDOUT
:
5189 * We got a timeout response from the DNS module. Schedule
5190 * another attempt for later. We forget the name, dhcid and
5191 * zone so if it gets changed we will get the new information.
5193 data_string_forget(&ddns_cb
->fwd_name
, MDL
);
5194 data_string_forget(&ddns_cb
->dhcid
, MDL
);
5195 if (ddns_cb
->zone
!= NULL
) {
5196 forget_zone((struct dns_zone
**)&ddns_cb
->zone
);
5199 /* Reset to doing the first stage */
5200 ddns_cb
->state
= DDNS_STATE_ADD_FW_NXDOMAIN
;
5201 ddns_cb
->cur_func
= client_dns_update_action
;
5203 /* and update our timer */
5204 if (ddns_cb
->timeout
< 3600)
5205 ddns_cb
->timeout
*= 10;
5206 tv
.tv_sec
= cur_tv
.tv_sec
+ ddns_cb
->timeout
;
5207 tv
.tv_usec
= cur_tv
.tv_usec
;
5208 add_timeout(&tv
, client_dns_update_timeout
,
5209 ddns_cb
, NULL
, NULL
);
5213 dhclient_ddns_cb_free(ddns_cb
, MDL
);
5217 /* See if we should do a DNS update, and if so, do it. */
5220 client_dns_update(struct client_state
*client
, dhcp_ddns_cb_t
*ddns_cb
)
5222 struct data_string client_identifier
;
5223 struct option_cache
*oc
;
5229 /* If we didn't send an FQDN option, we certainly aren't going to
5230 be doing an update. */
5231 if (!client
-> sent_options
)
5232 return ISC_R_SUCCESS
;
5234 /* If we don't have a lease, we can't do an update. */
5235 if ((client
->active
== NULL
) && (client
->active_lease
== NULL
))
5236 return ISC_R_SUCCESS
;
5238 /* If we set the no client update flag, don't do the update. */
5239 if ((oc
= lookup_option (&fqdn_universe
, client
-> sent_options
,
5240 FQDN_NO_CLIENT_UPDATE
)) &&
5241 evaluate_boolean_option_cache (&ignorep
, (struct packet
*)0,
5242 (struct lease
*)0, client
,
5243 client
-> sent_options
,
5244 (struct option_state
*)0,
5245 &global_scope
, oc
, MDL
))
5246 return ISC_R_SUCCESS
;
5248 /* If we set the "server, please update" flag, or didn't set it
5249 to false, don't do the update. */
5250 if (!(oc
= lookup_option (&fqdn_universe
, client
-> sent_options
,
5251 FQDN_SERVER_UPDATE
)) ||
5252 evaluate_boolean_option_cache (&ignorep
, (struct packet
*)0,
5253 (struct lease
*)0, client
,
5254 client
-> sent_options
,
5255 (struct option_state
*)0,
5256 &global_scope
, oc
, MDL
))
5257 return ISC_R_SUCCESS
;
5259 /* If no FQDN option was supplied, don't do the update. */
5260 if (!(oc
= lookup_option (&fqdn_universe
, client
-> sent_options
,
5262 !evaluate_option_cache (&ddns_cb
->fwd_name
, (struct packet
*)0,
5263 (struct lease
*)0, client
,
5264 client
-> sent_options
,
5265 (struct option_state
*)0,
5266 &global_scope
, oc
, MDL
))
5267 return ISC_R_SUCCESS
;
5270 * Construct the DHCID value for use in the DDNS update process
5271 * We have the newer standard version and the older interim version
5272 * chosen by the '-I' option. The interim version is left as is
5273 * for backwards compatibility. The standard version is based on
5274 * RFC 4701 section 3.3
5279 memset(&client_identifier
, 0, sizeof(client_identifier
));
5281 if (std_dhcid
== 1) {
5282 /* standard style */
5283 ddns_cb
->dhcid_class
= dns_rdatatype_dhcid
;
5287 ddns_cb
->dhcid_class
= dns_rdatatype_txt
;
5288 /* for backwards compatibility */
5289 ddns_v4_type
= DHO_DHCP_CLIENT_IDENTIFIER
;
5291 if (client
->active_lease
!= NULL
) {
5292 /* V6 request, get the client identifier, then
5293 * construct the dhcid for either standard
5295 if (((oc
= lookup_option(&dhcpv6_universe
,
5296 client
->sent_options
,
5297 D6O_CLIENTID
)) != NULL
) &&
5298 evaluate_option_cache(&client_identifier
, NULL
,
5300 client
->sent_options
, NULL
,
5301 &global_scope
, oc
, MDL
)) {
5302 result
= get_dhcid(ddns_cb
, 2,
5303 client_identifier
.data
,
5304 client_identifier
.len
);
5305 data_string_forget(&client_identifier
, MDL
);
5307 log_fatal("Impossible condition at %s:%d.", MDL
);
5310 * V4 request, use the client id if there is one or the
5311 * mac address if there isn't. If we have a client id
5312 * we check to see if it is an embedded DUID.
5314 if (((oc
= lookup_option(&dhcp_universe
,
5315 client
->sent_options
,
5316 DHO_DHCP_CLIENT_IDENTIFIER
)) != NULL
) &&
5317 evaluate_option_cache(&client_identifier
, NULL
,
5319 client
->sent_options
, NULL
,
5320 &global_scope
, oc
, MDL
)) {
5321 if ((std_dhcid
== 1) && (duid_v4
== 1) &&
5322 (client_identifier
.data
[0] == 255)) {
5324 * This appears to be an embedded DUID,
5325 * extract it and treat it as such
5327 if (client_identifier
.len
<= 5)
5328 log_fatal("Impossible condition at %s:%d.",
5330 result
= get_dhcid(ddns_cb
, 2,
5331 client_identifier
.data
+ 5,
5332 client_identifier
.len
- 5);
5334 result
= get_dhcid(ddns_cb
, ddns_v4_type
,
5335 client_identifier
.data
,
5336 client_identifier
.len
);
5338 data_string_forget(&client_identifier
, MDL
);
5340 result
= get_dhcid(ddns_cb
, 0,
5341 client
->interface
->hw_address
.hbuf
,
5342 client
->interface
->hw_address
.hlen
);
5346 return ISC_R_SUCCESS
;
5352 if (ddns_cb
->fwd_name
.len
&& ddns_cb
->dhcid
.len
) {
5353 rcode
= ddns_modify_fwd(ddns_cb
, MDL
);
5355 rcode
= ISC_R_FAILURE
;
5358 * A success from the modify routine means we are performing
5359 * async processing, for which we use the timedout error message.
5361 if (rcode
== ISC_R_SUCCESS
) {
5362 rcode
= ISC_R_TIMEDOUT
;
5370 * Schedule the first update. They will continue to retry occasionally
5371 * until they no longer time out (or fail).
5374 dhclient_schedule_updates(struct client_state
*client
,
5378 dhcp_ddns_cb_t
*ddns_cb
;
5381 if (!client
->config
->do_forward_update
)
5384 /* cancel any outstanding ddns requests */
5385 if (client
->ddns_cb
!= NULL
) {
5386 ddns_cancel(client
->ddns_cb
, MDL
);
5387 client
->ddns_cb
= NULL
;
5390 ddns_cb
= ddns_cb_alloc(MDL
);
5392 if (ddns_cb
!= NULL
) {
5393 ddns_cb
->lease
= (void *)client
;
5394 ddns_cb
->address
= *addr
;
5395 ddns_cb
->timeout
= 1;
5398 * XXX: DNS TTL is a problem we need to solve properly.
5399 * Until that time, 300 is a placeholder default for
5400 * something that is less insane than a value scaled
5405 ddns_cb
->state
= DDNS_STATE_ADD_FW_NXDOMAIN
;
5406 ddns_cb
->cur_func
= client_dns_update_action
;
5407 ddns_cb
->flags
= DDNS_UPDATE_ADDR
| DDNS_INCLUDE_RRSET
;
5409 client
->ddns_cb
= ddns_cb
;
5410 tv
.tv_sec
= cur_tv
.tv_sec
+ offset
;
5411 tv
.tv_usec
= cur_tv
.tv_usec
;
5412 add_timeout(&tv
, client_dns_update_timeout
,
5413 ddns_cb
, NULL
, NULL
);
5415 log_error("Unable to allocate dns update state for %s",
5419 #endif /* defined NSUPDATE */
5422 dhcpv4_client_assignments(void)
5424 struct servent
*ent
;
5426 if (path_dhclient_pid
== NULL
)
5427 path_dhclient_pid
= _PATH_DHCLIENT_PID
;
5428 if (path_dhclient_db
== NULL
)
5429 path_dhclient_db
= _PATH_DHCLIENT_DB
;
5431 /* Default to the DHCP/BOOTP port. */
5433 /* If we're faking a relay agent, and we're not using loopback,
5434 use the server port, not the client port. */
5435 if (mockup_relay
&& giaddr
.s_addr
!= htonl(INADDR_LOOPBACK
)) {
5436 local_port
= htons(67);
5438 ent
= getservbyname("dhcpc", "udp");
5440 ent
= getservbyname("bootpc", "udp");
5442 local_port
= htons(68);
5444 local_port
= ent
->s_port
;
5445 #ifndef __CYGWIN32__
5451 /* If we're faking a relay agent, and we're not using loopback,
5452 we're using the server port, not the client port. */
5453 if (mockup_relay
&& giaddr
.s_addr
!= htonl(INADDR_LOOPBACK
)) {
5454 remote_port
= local_port
;
5456 remote_port
= htons(ntohs(local_port
) - 1); /* XXX */
5460 * The following routines are used to check that certain
5461 * strings are reasonable before we pass them to the scripts.
5462 * This avoids some problems with scripts treating the strings
5463 * as commands - see ticket 23722
5464 * The domain checking code should be done as part of assembling
5465 * the string but we are doing it here for now due to time
5469 static int check_domain_name(const char *ptr
, size_t len
, int dots
)
5473 /* not empty or complete length not over 255 characters */
5474 if ((len
== 0) || (len
> 256))
5477 /* consists of [[:alnum:]-]+ labels separated by [.] */
5478 /* a [_] is against RFC but seems to be "widely used"... */
5479 for (p
=ptr
; (*p
!= 0) && (len
-- > 0); p
++) {
5480 if ((*p
== '-') || (*p
== '_')) {
5481 /* not allowed at begin or end of a label */
5482 if (((p
- ptr
) == 0) || (len
== 0) || (p
[1] == '.'))
5484 } else if (*p
== '.') {
5485 /* each label has to be 1-63 characters;
5486 we allow [.] at the end ('foo.bar.') */
5488 if ((d
<= 0) || (d
>= 64))
5490 ptr
= p
+ 1; /* jump to the next label */
5491 if ((dots
> 0) && (len
> 0))
5493 } else if (isalnum((unsigned char)*p
) == 0) {
5494 /* also numbers at the begin are fine */
5498 return(dots
? -1 : 0);
5501 static int check_domain_name_list(const char *ptr
, size_t len
, int dots
)
5504 int ret
= -1; /* at least one needed */
5506 if ((ptr
== NULL
) || (len
== 0))
5509 for (p
=ptr
; (*p
!= 0) && (len
> 0); p
++, len
--) {
5513 if (check_domain_name(ptr
, p
- ptr
, dots
) != 0)
5520 return(check_domain_name(ptr
, p
- ptr
, dots
));
5525 static int check_option_values(struct universe
*universe
,
5533 /* just reject options we want to protect, will be escaped anyway */
5534 if ((universe
== NULL
) || (universe
== &dhcp_universe
)) {
5536 case DHO_DOMAIN_NAME
:
5537 #ifdef ACCEPT_LIST_IN_DOMAIN_NAME
5538 return check_domain_name_list(ptr
, len
, 0);
5540 return check_domain_name(ptr
, len
, 0);
5543 case DHO_NIS_DOMAIN
:
5544 case DHO_NETBIOS_SCOPE
:
5545 return check_domain_name(ptr
, len
, 0);
5547 case DHO_DOMAIN_SEARCH
:
5548 return check_domain_name_list(ptr
, len
, 0);
5553 for (; (*ptr
!= 0) && (len
-- > 0); ptr
++) {
5554 if(!(isalnum((unsigned char)*ptr
) ||
5555 *ptr
== '#' || *ptr
== '%' ||
5556 *ptr
== '+' || *ptr
== '-' ||
5557 *ptr
== '_' || *ptr
== ':' ||
5558 *ptr
== '.' || *ptr
== ',' ||
5559 *ptr
== '@' || *ptr
== '~' ||
5560 *ptr
== '\\' || *ptr
== '/' ||
5561 *ptr
== '[' || *ptr
== ']' ||
5562 *ptr
== '=' || *ptr
== ' '))
5571 if (universe
== &dhcpv6_universe
) {
5573 case D6O_SIP_SERVERS_DNS
:
5574 case D6O_DOMAIN_SEARCH
:
5575 case D6O_NIS_DOMAIN_NAME
:
5576 case D6O_NISP_DOMAIN_NAME
:
5577 return check_domain_name_list(ptr
, len
, 0);
5587 add_reject(struct packet
*packet
) {
5588 struct iaddrmatchlist
*list
;
5590 list
= dmalloc(sizeof(struct iaddrmatchlist
), MDL
);
5592 log_fatal ("no memory for reject list!");
5595 * client_addr is misleading - it is set to source address in common
5598 list
->match
.addr
= packet
->client_addr
;
5599 /* Set mask to indicate host address. */
5600 list
->match
.mask
.len
= list
->match
.addr
.len
;
5601 memset(list
->match
.mask
.iabuf
, 0xff, sizeof(list
->match
.mask
.iabuf
));
5603 /* Append to reject list for the source interface. */
5604 list
->next
= packet
->interface
->client
->config
->reject_list
;
5605 packet
->interface
->client
->config
->reject_list
= list
;
5608 * We should inform user that we won't be accepting this server
5611 log_info("Server added to list of rejected servers.");
5614 #if defined(NSUPDATE)
5615 /* Wrapper function around common ddns_cb_free function that ensures
5616 * we set the client_state pointer to the control block to NULL. */
5618 dhclient_ddns_cb_free(dhcp_ddns_cb_t
*ddns_cb
, char* file
, int line
) {
5620 struct client_state
*client
= (struct client_state
*)ddns_cb
->lease
;
5621 if (client
!= NULL
) {
5622 client
->ddns_cb
= NULL
;
5625 ddns_cb_free(ddns_cb
, file
, line
);
5628 #endif /* defined NSUPDATE */
5630 #if defined(DHCPv6) && defined(DHCP4o6)
5632 * \brief Omapi I/O handler
5634 * The inter-process communication receive handler.
5636 * On the DHCPv6 side, the message is either a POLL (which is answered
5637 * by a START or a STOP) or a DHCPv4-QUERY (which is forwarded to
5638 * DHCPv4 over DHCPv6 servers by forw_dhcpv4_query()).
5640 * On the DHCPv4 side, the message is either a START, a STOP
5641 * (both for the DHCP4 over DHCPv6 state machine) or a DHCPv4-RESPONSE
5642 * (which is processed by recv_dhcpv4_response()).
5644 * \param h the OMAPI object
5645 * \return a result for I/O success or error (used by the I/O subsystem)
5647 isc_result_t
dhcpv4o6_handler(omapi_object_t
*h
) {
5649 char start_msg
[5] = { 'S', 'T', 'A', 'R', 'T' };
5650 char stop_msg
[4] = { 'S', 'T', 'O', 'P' };
5651 char poll_msg
[4] = { 'P', 'O', 'L', 'L' };
5652 struct data_string raw
;
5655 if (h
->type
!= dhcp4o6_type
)
5656 return DHCP_R_INVALIDARG
;
5658 cc
= recv(dhcp4o6_fd
, buf
, sizeof(buf
), 0);
5660 return ISC_R_UNEXPECTED
;
5662 if (local_family
== AF_INET6
) {
5664 (memcmp(buf
, poll_msg
, sizeof(poll_msg
)) == 0)) {
5665 log_info("RCV: POLL");
5666 if (dhcp4o6_state
< 0)
5667 cc
= send(dhcp4o6_fd
, stop_msg
,
5668 sizeof(stop_msg
), 0);
5670 cc
= send(dhcp4o6_fd
, start_msg
,
5671 sizeof(start_msg
), 0);
5673 log_error("dhcpv4o6_handler: send(): %m");
5674 return ISC_R_IOERROR
;
5677 if (cc
< DHCP_FIXED_NON_UDP
+ 8)
5678 return ISC_R_UNEXPECTED
;
5679 memset(&raw
, 0, sizeof(raw
));
5680 if (!buffer_allocate(&raw
.buffer
, cc
, MDL
)) {
5681 log_error("dhcpv4o6_handler: "
5682 "no memory buffer.");
5683 return ISC_R_NOMEMORY
;
5685 raw
.data
= raw
.buffer
->data
;
5687 memcpy(raw
.buffer
->data
, buf
, cc
);
5689 forw_dhcpv4_query(&raw
);
5691 data_string_forget(&raw
, MDL
);
5695 (memcmp(buf
, stop_msg
, sizeof(stop_msg
)) == 0)) {
5696 log_info("RCV: STOP");
5697 if (dhcp4o6_state
> 0) {
5701 } else if ((cc
== 5) &&
5702 (memcmp(buf
, start_msg
, sizeof(start_msg
)) == 0)) {
5703 log_info("RCV: START");
5704 if (dhcp4o6_state
== 0)
5705 cancel_timeout(dhcp4o6_poll
, NULL
);
5709 if (cc
< DHCP_FIXED_NON_UDP
+ 16)
5710 return ISC_R_UNEXPECTED
;
5711 memset(&raw
, 0, sizeof(raw
));
5712 if (!buffer_allocate(&raw
.buffer
, cc
, MDL
)) {
5713 log_error("dhcpv4o6_handler: "
5714 "no memory buffer.");
5715 return ISC_R_NOMEMORY
;
5717 raw
.data
= raw
.buffer
->data
;
5719 memcpy(raw
.buffer
->data
, buf
, cc
);
5721 recv_dhcpv4_response(&raw
);
5723 data_string_forget(&raw
, MDL
);
5727 return ISC_R_SUCCESS
;
5731 * \brief Poll the DHCPv6 client
5732 * (DHCPv4 client function)
5734 * A POLL message is sent to the DHCPv6 client periodically to check
5735 * if the DHCPv6 is ready (i.e., has a valid DHCPv4-over-DHCPv6 server
5738 static void dhcp4o6_poll(void *dummy
) {
5739 char msg
[4] = { 'P', 'O', 'L', 'L' };
5743 IGNORE_UNUSED(dummy
);
5745 if (dhcp4o6_state
< 0)
5750 cc
= send(dhcp4o6_fd
, msg
, sizeof(msg
), 0);
5752 log_error("dhcp4o6_poll: send(): %m");
5754 tv
.tv_sec
= cur_time
+ 60;
5755 tv
.tv_usec
= random() % 1000000;
5757 add_timeout(&tv
, dhcp4o6_poll
, NULL
, 0, 0);
5761 * \brief Resume pending operations
5762 * (DHCPv4 client function)
5764 * A START message was received from the DHCPv6 client so pending
5765 * operations (RELEASE or REBOOT) must be resumed.
5767 static void dhcp4o6_resume() {
5768 struct interface_info
*ip
;
5769 struct client_state
*client
;
5771 for (ip
= interfaces
; ip
!= NULL
; ip
= ip
->next
) {
5772 for (client
= ip
->client
; client
!= NULL
;
5773 client
= client
->next
) {
5774 if (client
->pending
== P_RELEASE
)
5776 else if (client
->pending
== P_REBOOT
)
5777 state_reboot(client
);
5783 * \brief Send a START to the DHCPv4 client
5784 * (DHCPv6 client function)
5786 * First check if there is a valid DHCPv4-over-DHCPv6 server address option,
5787 * and when found go UP and on a transition from another state send
5788 * a START message to the DHCPv4 client.
5790 void dhcp4o6_start() {
5791 struct interface_info
*ip
;
5792 struct client_state
*client
;
5793 struct dhc6_lease
*lease
;
5794 struct option_cache
*oc
;
5795 struct data_string addrs
;
5796 char msg
[5] = { 'S', 'T', 'A', 'R', 'T' };
5799 memset(&addrs
, 0, sizeof(addrs
));
5800 for (ip
= interfaces
; ip
!= NULL
; ip
= ip
->next
) {
5801 for (client
= ip
->client
; client
!= NULL
;
5802 client
= client
->next
) {
5803 if ((client
->state
!= S_BOUND
) &&
5804 (client
->state
!= S_RENEWING
) &&
5805 (client
->state
!= S_REBINDING
))
5807 lease
= client
->active_lease
;
5808 if ((lease
== NULL
) || lease
->released
)
5810 oc
= lookup_option(&dhcpv6_universe
,
5812 D6O_DHCP4_O_DHCP6_SERVER
);
5814 !evaluate_option_cache(&addrs
, NULL
, NULL
, NULL
,
5815 lease
->options
, NULL
,
5816 &global_scope
, oc
, MDL
))
5818 if ((addrs
.len
% 16) != 0) {
5819 data_string_forget(&addrs
, MDL
);
5822 data_string_forget(&addrs
, MDL
);
5826 log_info("dhcp4o6_start: failed");
5831 if (dhcp4o6_state
== 1)
5833 log_info("dhcp4o6_start: go to UP");
5836 cc
= send(dhcp4o6_fd
, msg
, sizeof(msg
), 0);
5838 log_info("dhcp4o6_start: send(): %m");
5842 * Send a STOP to the DHCPv4 client
5843 * (DHCPv6 client function)
5845 * Go DOWN and on a transition from another state send a STOP message
5846 * to the DHCPv4 client.
5848 static void dhcp4o6_stop() {
5849 char msg
[4] = { 'S', 'T', 'O', 'P' };
5852 if (dhcp4o6_state
== -1)
5855 log_info("dhcp4o6_stop: go to DOWN");
5858 cc
= send(dhcp4o6_fd
, msg
, sizeof(msg
), 0);
5860 log_error("dhcp4o6_stop: send(): %m");
5862 #endif /* DHCPv6 && DHCP4o6 */