Wed May 26 22:52:32 2021 UTC ()
merge local changes between dhcp-4.4.2 and dhcp-4.4.2-P1


(christos)
diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/client/dhclient.c
diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/common/parse.c
diff -r1.2 -r1.3 src/external/mpl/dhcp/dist/common/tests/option_unittest.c
diff -r1.4 -r1.5 src/external/mpl/dhcp/dist/relay/dhcrelay.c
diff -r1.2 -r1.3 src/external/mpl/dhcp/dist/relay/tests/relay_unittests.c
diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/server/dhcpd.c

cvs diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/client/dhclient.c (switch to unified diff)

--- src/external/mpl/dhcp/dist/client/dhclient.c 2020/08/03 21:10:56 1.3
+++ src/external/mpl/dhcp/dist/client/dhclient.c 2021/05/26 22:52:31 1.4
@@ -1,2232 +1,2232 @@ @@ -1,2232 +1,2232 @@
1/* $NetBSD: dhclient.c,v 1.3 2020/08/03 21:10:56 christos Exp $ */ 1/* $NetBSD: dhclient.c,v 1.4 2021/05/26 22:52:31 christos Exp $ */
2 2
3/* dhclient.c 3/* dhclient.c
4 4
5 DHCP Client. */ 5 DHCP Client. */
6 6
7/* 7/*
8 * Copyright (c) 2004-2020 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004-2021 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1995-2003 by Internet Software Consortium 9 * Copyright (c) 1995-2003 by Internet Software Consortium
10 * 10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public 11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this 12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 * 14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * 22 *
23 * Internet Systems Consortium, Inc. 23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street 24 * 950 Charter Street
25 * Redwood City, CA 94063 25 * Redwood City, CA 94063
26 * <info@isc.org> 26 * <info@isc.org>
27 * https://www.isc.org/ 27 * https://www.isc.org/
28 * 28 *
29 * This code is based on the original client state machine that was 29 * This code is based on the original client state machine that was
30 * written by Elliot Poger. The code has been extensively hacked on 30 * written by Elliot Poger. The code has been extensively hacked on
31 * by Ted Lemon since then, so any mistakes you find are probably his 31 * by Ted Lemon since then, so any mistakes you find are probably his
32 * fault and not Elliot's. 32 * fault and not Elliot's.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36__RCSID("$NetBSD: dhclient.c,v 1.3 2020/08/03 21:10:56 christos Exp $"); 36__RCSID("$NetBSD: dhclient.c,v 1.4 2021/05/26 22:52:31 christos Exp $");
37 37
38#include "dhcpd.h" 38#include "dhcpd.h"
39#include <isc/util.h> 39#include <isc/util.h>
40#include <isc/file.h> 40#include <isc/file.h>
41#include <dns/result.h> 41#include <dns/result.h>
42#include <syslog.h> 42#include <syslog.h>
43#include <signal.h> 43#include <signal.h>
44#include <errno.h> 44#include <errno.h>
45#include <sys/time.h> 45#include <sys/time.h>
46#include <sys/wait.h> 46#include <sys/wait.h>
47#include <limits.h> 47#include <limits.h>
48 48
49TIME default_lease_time = 43200; /* 12 hours... */ 49TIME default_lease_time = 43200; /* 12 hours... */
50TIME max_lease_time = 86400; /* 24 hours... */ 50TIME max_lease_time = 86400; /* 24 hours... */
51 51
52const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; 52const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
53const char *path_dhclient_db = NULL; 53const char *path_dhclient_db = NULL;
54const char *path_dhclient_pid = NULL; 54const char *path_dhclient_pid = NULL;
55static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT; 55static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
56char *path_dhclient_script = path_dhclient_script_array; 56char *path_dhclient_script = path_dhclient_script_array;
57const char *path_dhclient_duid = NULL; 57const char *path_dhclient_duid = NULL;
58 58
59static void add_to_tail(struct client_lease** lease_list, struct client_lease* lease); 59static void add_to_tail(struct client_lease** lease_list, struct client_lease* lease);
60 60
61/* False (default) => we write and use a pid file */ 61/* False (default) => we write and use a pid file */
62isc_boolean_t no_pid_file = ISC_FALSE; 62isc_boolean_t no_pid_file = ISC_FALSE;
63isc_boolean_t hw_mismatch_drop = ISC_TRUE; 63isc_boolean_t hw_mismatch_drop = ISC_TRUE;
64 64
65int dhcp_max_agent_option_packet_length = 0; 65int dhcp_max_agent_option_packet_length = 0;
66 66
67int interfaces_requested = 0; 67int interfaces_requested = 0;
68int interfaces_left = 0; 68int interfaces_left = 0;
69 69
70struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; 70struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
71struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; 71struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
72struct in_addr inaddr_any; 72struct in_addr inaddr_any;
73struct sockaddr_in sockaddr_broadcast; 73struct sockaddr_in sockaddr_broadcast;
74struct in_addr giaddr; 74struct in_addr giaddr;
75struct data_string default_duid; 75struct data_string default_duid;
76int duid_type = 0; 76int duid_type = 0;
77int duid_v4 = 0; 77int duid_v4 = 0;
78int std_dhcid = 0; 78int std_dhcid = 0;
79 79
80int decline_wait_time = 10; /* Default to 10 secs per, RFC 2131, 3.1.5 */ 80int decline_wait_time = 10; /* Default to 10 secs per, RFC 2131, 3.1.5 */
81 81
82/* ASSERT_STATE() does nothing now; it used to be 82/* ASSERT_STATE() does nothing now; it used to be
83 assert (state_is == state_shouldbe). */ 83 assert (state_is == state_shouldbe). */
84#define ASSERT_STATE(state_is, state_shouldbe) {} 84#define ASSERT_STATE(state_is, state_shouldbe) {}
85 85
86#ifndef UNIT_TEST 86#ifndef UNIT_TEST
87static const char copyright[] = "Copyright 2004-2020 Internet Systems Consortium."; 87static const char copyright[] = "Copyright 2004-2021 Internet Systems Consortium.";
88static const char arr [] = "All rights reserved."; 88static const char arr [] = "All rights reserved.";
89static const char message [] = "Internet Systems Consortium DHCP Client"; 89static const char message [] = "Internet Systems Consortium DHCP Client";
90static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/"; 90static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/";
91#endif /* UNIT_TEST */ 91#endif /* UNIT_TEST */
92 92
93u_int16_t local_port = 0; 93u_int16_t local_port = 0;
94u_int16_t remote_port = 0; 94u_int16_t remote_port = 0;
95#if defined(DHCPv6) && defined(DHCP4o6) 95#if defined(DHCPv6) && defined(DHCP4o6)
96int dhcp4o6_state = -1; /* -1 = stopped, 0 = polling, 1 = started */ 96int dhcp4o6_state = -1; /* -1 = stopped, 0 = polling, 1 = started */
97#endif 97#endif
98int no_daemon = 0; 98int no_daemon = 0;
99int dfd[2] = { -1, -1 }; 99int dfd[2] = { -1, -1 };
100struct string_list *client_env = NULL; 100struct string_list *client_env = NULL;
101int client_env_count = 0; 101int client_env_count = 0;
102int onetry = 0; 102int onetry = 0;
103int quiet = 1; 103int quiet = 1;
104int nowait = 0; 104int nowait = 0;
105int stateless = 0; 105int stateless = 0;
106int wanted_ia_na = -1; /* the absolute value is the real one. */ 106int wanted_ia_na = -1; /* the absolute value is the real one. */
107int wanted_ia_ta = 0; 107int wanted_ia_ta = 0;
108int wanted_ia_pd = 0; 108int wanted_ia_pd = 0;
109int require_all_ias = 0; /* If the user requires all of the IAs to 109int require_all_ias = 0; /* If the user requires all of the IAs to
110 be available before accepting a lease 110 be available before accepting a lease
111 0 = no, 1 = requries */ 111 0 = no, 1 = requries */
112#if defined(DHCPv6) 112#if defined(DHCPv6)
113int dad_wait_time = 0; 113int dad_wait_time = 0;
114int prefix_len_hint = 0; 114int prefix_len_hint = 0;
115#endif 115#endif
116 116
117int address_prefix_len = DHCLIENT_DEFAULT_PREFIX_LEN; 117int address_prefix_len = DHCLIENT_DEFAULT_PREFIX_LEN;
118char *mockup_relay = NULL; 118char *mockup_relay = NULL;
119 119
120libdhcp_callbacks_t dhclient_callbacks = { 120libdhcp_callbacks_t dhclient_callbacks = {
121 &local_port, 121 &local_port,
122 &remote_port, 122 &remote_port,
123 classify, 123 classify,
124 check_collection, 124 check_collection,
125 dhcp, 125 dhcp,
126#ifdef DHCPv6 126#ifdef DHCPv6
127 dhcpv6, 127 dhcpv6,
128#endif /* DHCPv6 */ 128#endif /* DHCPv6 */
129 bootp, 129 bootp,
130 find_class, 130 find_class,
131 parse_allow_deny, 131 parse_allow_deny,
132 dhcp_set_control_state, 132 dhcp_set_control_state,
133}; 133};
134 134
135char *progname = NULL; 135char *progname = NULL;
136 136
137void run_stateless(int exit_mode, u_int16_t port); 137void run_stateless(int exit_mode, u_int16_t port);
138 138
139static isc_result_t write_duid(struct data_string *duid); 139static isc_result_t write_duid(struct data_string *duid);
140static void add_reject(struct packet *packet); 140static void add_reject(struct packet *packet);
141 141
142static int check_domain_name(const char *ptr, size_t len, int dots); 142static int check_domain_name(const char *ptr, size_t len, int dots);
143static int check_domain_name_list(const char *ptr, size_t len, int dots); 143static int check_domain_name_list(const char *ptr, size_t len, int dots);
144static int check_option_values(struct universe *universe, unsigned int opt, 144static int check_option_values(struct universe *universe, unsigned int opt,
145 const char *ptr, size_t len); 145 const char *ptr, size_t len);
146 146
147#if defined(NSUPDATE) 147#if defined(NSUPDATE)
148static void dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, 148static void dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb,
149 char* file, int line); 149 char* file, int line);
150#endif /* defined NSUPDATE */ 150#endif /* defined NSUPDATE */
151 151
152static void 152static void
153setup(void) { 153setup(void) {
154 isc_result_t status; 154 isc_result_t status;
155 /* Set up the isc and dns library managers */ 155 /* Set up the isc and dns library managers */
156 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL); 156 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL);
157 if (status != ISC_R_SUCCESS) 157 if (status != ISC_R_SUCCESS)
158 log_fatal("Can't initialize context: %s", 158 log_fatal("Can't initialize context: %s",
159 isc_result_totext(status)); 159 isc_result_totext(status));
160 160
161 /* Set up the OMAPI. */ 161 /* Set up the OMAPI. */
162 status = omapi_init(); 162 status = omapi_init();
163 if (status != ISC_R_SUCCESS) 163 if (status != ISC_R_SUCCESS)
164 log_fatal("Can't initialize OMAPI: %s", 164 log_fatal("Can't initialize OMAPI: %s",
165 isc_result_totext(status)); 165 isc_result_totext(status));
166 166
167 /* Set up the OMAPI wrappers for various server database internal 167 /* Set up the OMAPI wrappers for various server database internal
168 objects. */ 168 objects. */
169 dhcp_common_objects_setup(); 169 dhcp_common_objects_setup();
170 170
171 dhcp_interface_discovery_hook = dhclient_interface_discovery_hook; 171 dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
172 dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook; 172 dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
173 dhcp_interface_startup_hook = dhclient_interface_startup_hook; 173 dhcp_interface_startup_hook = dhclient_interface_startup_hook;
174} 174}
175 175
176static void 176static void
177go_daemon(void) 177go_daemon(void)
178{ 178{
179 int pid; 179 int pid;
180 180
181 if (pipe(dfd) == -1) 181 if (pipe(dfd) == -1)
182 log_fatal("Can't get pipe: %m"); 182 log_fatal("Can't get pipe: %m");
183 if ((pid = fork ()) < 0) 183 if ((pid = fork ()) < 0)
184 log_fatal("Can't fork daemon: %m"); 184 log_fatal("Can't fork daemon: %m");
185 if (pid != 0) { 185 if (pid != 0) {
186 /* Parent: wait for the child to start */ 186 /* Parent: wait for the child to start */
187 int n; 187 int n;
188 188
189 (void) close(dfd[1]); 189 (void) close(dfd[1]);
190 do { 190 do {
191 char buf; 191 char buf;
192 192
193 n = read(dfd[0], &buf, 1); 193 n = read(dfd[0], &buf, 1);
194 if (n == 1) 194 if (n == 1)
195 _exit((int)buf); 195 _exit((int)buf);
196 } while (n == -1 && errno == EINTR); 196 } while (n == -1 && errno == EINTR);
197 _exit(1); 197 _exit(1);
198 } 198 }
199 /* Child */ 199 /* Child */
200 (void) close(dfd[0]); 200 (void) close(dfd[0]);
201} 201}
202 202
203static void 203static void
204add_interfaces(char **ifaces, int nifaces) 204add_interfaces(char **ifaces, int nifaces)
205{ 205{
206 isc_result_t status; 206 isc_result_t status;
207 207
208 for (int i = 0; i < nifaces; i++) { 208 for (int i = 0; i < nifaces; i++) {
209 struct interface_info *tmp = NULL; 209 struct interface_info *tmp = NULL;
210 status = interface_allocate(&tmp, MDL); 210 status = interface_allocate(&tmp, MDL);
211 if (status != ISC_R_SUCCESS) 211 if (status != ISC_R_SUCCESS)
212 log_fatal("Can't record interface %s:%s", 212 log_fatal("Can't record interface %s:%s",
213 ifaces[i], isc_result_totext(status)); 213 ifaces[i], isc_result_totext(status));
214 if (strlen(ifaces[i]) >= sizeof(tmp->name)) 214 if (strlen(ifaces[i]) >= sizeof(tmp->name))
215 log_fatal("%s: interface name too long (is %ld)", 215 log_fatal("%s: interface name too long (is %ld)",
216 ifaces[i], (long)strlen(ifaces[i])); 216 ifaces[i], (long)strlen(ifaces[i]));
217 strcpy(tmp->name, ifaces[i]); 217 strcpy(tmp->name, ifaces[i]);
218 if (interfaces) { 218 if (interfaces) {
219 interface_reference(&tmp->next, interfaces, MDL); 219 interface_reference(&tmp->next, interfaces, MDL);
220 interface_dereference(&interfaces, MDL); 220 interface_dereference(&interfaces, MDL);
221 } 221 }
222 interface_reference(&interfaces, tmp, MDL); 222 interface_reference(&interfaces, tmp, MDL);
223 tmp->flags = INTERFACE_REQUESTED; 223 tmp->flags = INTERFACE_REQUESTED;
224 } 224 }
225} 225}
226 226
227/*! 227/*!
228 * 228 *
229 * \brief Print the generic usage message 229 * \brief Print the generic usage message
230 * 230 *
231 * If the user has provided an incorrect command line print out 231 * If the user has provided an incorrect command line print out
232 * the description of the command line. The arguments provide 232 * the description of the command line. The arguments provide
233 * a way for the caller to request more specific information about 233 * a way for the caller to request more specific information about
234 * the error be printed as well. Mostly this will be that some 234 * the error be printed as well. Mostly this will be that some
235 * comamnd doesn't include its argument. 235 * comamnd doesn't include its argument.
236 * 236 *
237 * \param sfmt - The basic string and format for the specific error 237 * \param sfmt - The basic string and format for the specific error
238 * \param sarg - Generally the offending argument from the comamnd line. 238 * \param sarg - Generally the offending argument from the comamnd line.
239 * 239 *
240 * \return Nothing 240 * \return Nothing
241 */ 241 */
242 242
243#include <sys/cdefs.h> 243#include <sys/cdefs.h>
244__RCSID("$NetBSD: dhclient.c,v 1.3 2020/08/03 21:10:56 christos Exp $"); 244__RCSID("$NetBSD: dhclient.c,v 1.4 2021/05/26 22:52:31 christos Exp $");
245 245
246#if defined(DHCPv6) && defined(DHCP4o6) 246#if defined(DHCPv6) && defined(DHCP4o6)
247static void dhcp4o6_poll(void *dummy); 247static void dhcp4o6_poll(void *dummy);
248static void dhcp4o6_resume(void); 248static void dhcp4o6_resume(void);
249static void recv_dhcpv4_response(struct data_string *raw); 249static void recv_dhcpv4_response(struct data_string *raw);
250static int send_dhcpv4_query(struct client_state *client, int broadcast); 250static int send_dhcpv4_query(struct client_state *client, int broadcast);
251 251
252static void dhcp4o6_stop(void); 252static void dhcp4o6_stop(void);
253static void forw_dhcpv4_response(struct packet *packet); 253static void forw_dhcpv4_response(struct packet *packet);
254static void forw_dhcpv4_query(struct data_string *raw); 254static void forw_dhcpv4_query(struct data_string *raw);
255#endif 255#endif
256 256
257#ifndef UNIT_TEST 257#ifndef UNIT_TEST
258/* These are only used when we call usage() from the main routine 258/* These are only used when we call usage() from the main routine
259 * which isn't compiled when building for unit tests 259 * which isn't compiled when building for unit tests
260 */ 260 */
261static const char use_noarg[] = "No argument for command: %s"; 261static const char use_noarg[] = "No argument for command: %s";
262#ifdef DHCPv6 262#ifdef DHCPv6
263static const char use_v6command[] = "Command not used for DHCPv4: %s"; 263static const char use_v6command[] = "Command not used for DHCPv4: %s";
264#endif 264#endif
265 265
266#ifdef DHCPv6 266#ifdef DHCPv6
267#ifdef DHCP4o6 267#ifdef DHCP4o6
268#define DHCLIENT_USAGE0 \ 268#define DHCLIENT_USAGE0 \
269"[-4|-6] [-SNTPRI1dvrxi] [-nw] -4o6 <port>] [-p <port>] [-D LL|LLT]\n" \ 269"[-4|-6] [-SNTPRI1dvrxi] [-nw] -4o6 <port>] [-p <port>] [-D LL|LLT]\n" \
270" [--dad-wait-time <seconds>] [--prefix-len-hint <length>]\n" \ 270" [--dad-wait-time <seconds>] [--prefix-len-hint <length>]\n" \
271" [--decline-wait-time <seconds>]\n" \ 271" [--decline-wait-time <seconds>]\n" \
272" [--address-prefix-len <length>]\n" 272" [--address-prefix-len <length>]\n"
273#else /* DHCP4o6 */ 273#else /* DHCP4o6 */
274#define DHCLIENT_USAGE0 \ 274#define DHCLIENT_USAGE0 \
275"[-4|-6] [-SNTPRI1dvrxi] [-nw] [-p <port>] [-D LL|LLT]\n" \ 275"[-4|-6] [-SNTPRI1dvrxi] [-nw] [-p <port>] [-D LL|LLT]\n" \
276" [--dad-wait-time <seconds>] [--prefix-len-hint <length>]\n" \ 276" [--dad-wait-time <seconds>] [--prefix-len-hint <length>]\n" \
277" [--decline-wait-time <seconds>]\n" \ 277" [--decline-wait-time <seconds>]\n" \
278" [--address-prefix-len <length>]\n" 278" [--address-prefix-len <length>]\n"
279#endif 279#endif
280#else /* DHCPv6 */ 280#else /* DHCPv6 */
281#define DHCLIENT_USAGE0 \ 281#define DHCLIENT_USAGE0 \
282"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n" \ 282"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n" \
283" [--decline-wait-time <seconds>]\n" 283" [--decline-wait-time <seconds>]\n"
284#endif 284#endif
285 285
286#define DHCLIENT_USAGEC \ 286#define DHCLIENT_USAGEC \
287" [-s server-addr] [-cf config-file]\n" \ 287" [-s server-addr] [-cf config-file]\n" \
288" [-df duid-file] [-lf lease-file]\n" \ 288" [-df duid-file] [-lf lease-file]\n" \
289" [-pf pid-file] [--no-pid] [-e VAR=val]\n" \ 289" [-pf pid-file] [--no-pid] [-e VAR=val]\n" \
290" [-sf script-file] [interface]*" 290" [-sf script-file] [interface]*"
291 291
292#define DHCLIENT_USAGEH "{--version|--help|-h}" 292#define DHCLIENT_USAGEH "{--version|--help|-h}"
293 293
294static void 294static void
295usage(const char *sfmt, const char *sarg) 295usage(const char *sfmt, const char *sarg)
296{ 296{
297 log_info("%s %s", message, PACKAGE_VERSION); 297 log_info("%s %s", message, PACKAGE_VERSION);
298 log_info(copyright); 298 log_info(copyright);
299 log_info(arr); 299 log_info(arr);
300 log_info(url); 300 log_info(url);
301 301
302 /* If desired print out the specific error message */ 302 /* If desired print out the specific error message */
303#ifdef PRINT_SPECIFIC_CL_ERRORS 303#ifdef PRINT_SPECIFIC_CL_ERRORS
304 if (sfmt != NULL) 304 if (sfmt != NULL)
305 log_error(sfmt, sarg); 305 log_error(sfmt, sarg);
306#endif 306#endif
307 307
308 log_fatal("Usage: %s %s%s\n %s %s", 308 log_fatal("Usage: %s %s%s\n %s %s",
309 isc_file_basename(progname), 309 isc_file_basename(progname),
310 DHCLIENT_USAGE0, 310 DHCLIENT_USAGE0,
311 DHCLIENT_USAGEC, 311 DHCLIENT_USAGEC,
312 isc_file_basename(progname), 312 isc_file_basename(progname),
313 DHCLIENT_USAGEH); 313 DHCLIENT_USAGEH);
314} 314}
315 315
316extern void initialize_client_option_spaces(void); 316extern void initialize_client_option_spaces(void);
317 317
318int 318int
319main(int argc, char **argv) { 319main(int argc, char **argv) {
320 int fd; 320 int fd;
321 int i; 321 int i;
322 struct interface_info *ip; 322 struct interface_info *ip;
323 struct client_state *client; 323 struct client_state *client;
324 unsigned seed; 324 unsigned seed;
325 char *server = NULL; 325 char *server = NULL;
326 int exit_mode = 0; 326 int exit_mode = 0;
327 int release_mode = 0; 327 int release_mode = 0;
328 struct timeval tv; 328 struct timeval tv;
329 omapi_object_t *listener; 329 omapi_object_t *listener;
330 isc_result_t result; 330 isc_result_t result;
331 int persist = 0; 331 int persist = 0;
332 int no_dhclient_conf = 0; 332 int no_dhclient_conf = 0;
333 int no_dhclient_db = 0; 333 int no_dhclient_db = 0;
334 int no_dhclient_pid = 0; 334 int no_dhclient_pid = 0;
335 int no_dhclient_script = 0; 335 int no_dhclient_script = 0;
336#ifdef DHCPv6 336#ifdef DHCPv6
337 int local_family_set = 0; 337 int local_family_set = 0;
338#ifdef DHCP4o6 338#ifdef DHCP4o6
339 u_int16_t dhcp4o6_port = 0; 339 u_int16_t dhcp4o6_port = 0;
340#endif /* DHCP4o6 */ 340#endif /* DHCP4o6 */
341#endif /* DHCPv6 */ 341#endif /* DHCPv6 */
342 char *s; 342 char *s;
343 char **ifaces; 343 char **ifaces;
344 344
345 libdhcp_callbacks_register(&dhclient_callbacks); 345 libdhcp_callbacks_register(&dhclient_callbacks);
346 346
347#ifdef OLD_LOG_NAME 347#ifdef OLD_LOG_NAME
348 progname = "dhclient"; 348 progname = "dhclient";
349#else 349#else
350 progname = argv[0]; 350 progname = argv[0];
351#endif 351#endif
352 /* Initialize client globals. */ 352 /* Initialize client globals. */
353 memset(&default_duid, 0, sizeof(default_duid)); 353 memset(&default_duid, 0, sizeof(default_duid));
354 354
355 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and 355 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
356 2 (stderr) are open. To do this, we assume that when we 356 2 (stderr) are open. To do this, we assume that when we
357 open a file the lowest available file descriptor is used. */ 357 open a file the lowest available file descriptor is used. */
358 fd = open("/dev/null", O_RDWR); 358 fd = open("/dev/null", O_RDWR);
359 if (fd == 0) 359 if (fd == 0)
360 fd = open("/dev/null", O_RDWR); 360 fd = open("/dev/null", O_RDWR);
361 if (fd == 1) 361 if (fd == 1)
362 fd = open("/dev/null", O_RDWR); 362 fd = open("/dev/null", O_RDWR);
363 if (fd == 2) 363 if (fd == 2)
364 log_perror = 0; /* No sense logging to /dev/null. */ 364 log_perror = 0; /* No sense logging to /dev/null. */
365 else if (fd != -1) 365 else if (fd != -1)
366 close(fd); 366 close(fd);
367 367
368 openlog(isc_file_basename(progname), DHCP_LOG_OPTIONS, LOG_DAEMON); 368 openlog(isc_file_basename(progname), DHCP_LOG_OPTIONS, LOG_DAEMON);
369 369
370#if !(defined(DEBUG) || defined(__CYGWIN32__)) 370#if !(defined(DEBUG) || defined(__CYGWIN32__))
371 setlogmask(LOG_UPTO(LOG_INFO)); 371 setlogmask(LOG_UPTO(LOG_INFO));
372#endif 372#endif
373 373
374 if ((ifaces = malloc(sizeof(*ifaces) * argc)) == NULL) { 374 if ((ifaces = malloc(sizeof(*ifaces) * argc)) == NULL) {
375 log_fatal("Can't allocate memory"); 375 log_fatal("Can't allocate memory");
376 return 1; 376 return 1;
377 } 377 }
378 378
379 /* Parse arguments changing no_daemon */ 379 /* Parse arguments changing no_daemon */
380 for (i = 1; i < argc; i++) { 380 for (i = 1; i < argc; i++) {
381 if (!strcmp(argv[i], "-r")) { 381 if (!strcmp(argv[i], "-r")) {
382 no_daemon = 1; 382 no_daemon = 1;
383 } else if (!strcmp(argv[i], "-x")) { 383 } else if (!strcmp(argv[i], "-x")) {
384 no_daemon = 0; 384 no_daemon = 0;
385 } else if (!strcmp(argv[i], "-d")) { 385 } else if (!strcmp(argv[i], "-d")) {
386 no_daemon = 1; 386 no_daemon = 1;
387 } else if (!strcmp(argv[i], "--version")) { 387 } else if (!strcmp(argv[i], "--version")) {
388 const char vstring[] = "isc-dhclient-"; 388 const char vstring[] = "isc-dhclient-";
389 IGNORE_RET(write(STDERR_FILENO, vstring, 389 IGNORE_RET(write(STDERR_FILENO, vstring,
390 strlen(vstring))); 390 strlen(vstring)));
391 IGNORE_RET(write(STDERR_FILENO, 391 IGNORE_RET(write(STDERR_FILENO,
392 PACKAGE_VERSION, 392 PACKAGE_VERSION,
393 strlen(PACKAGE_VERSION))); 393 strlen(PACKAGE_VERSION)));
394 IGNORE_RET(write(STDERR_FILENO, "\n", 1)); 394 IGNORE_RET(write(STDERR_FILENO, "\n", 1));
395 exit(0); 395 exit(0);
396 } else if (!strcmp(argv[i], "--help") || 396 } else if (!strcmp(argv[i], "--help") ||
397 !strcmp(argv[i], "-h")) { 397 !strcmp(argv[i], "-h")) {
398 const char *pname = isc_file_basename(progname); 398 const char *pname = isc_file_basename(progname);
399 IGNORE_RET(write(STDERR_FILENO, "Usage: ", 7)); 399 IGNORE_RET(write(STDERR_FILENO, "Usage: ", 7));
400 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname))); 400 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
401 IGNORE_RET(write(STDERR_FILENO, " ", 1)); 401 IGNORE_RET(write(STDERR_FILENO, " ", 1));
402 IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGE0, 402 IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGE0,
403 strlen(DHCLIENT_USAGE0))); 403 strlen(DHCLIENT_USAGE0)));
404 IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGEC, 404 IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGEC,
405 strlen(DHCLIENT_USAGEC))); 405 strlen(DHCLIENT_USAGEC)));
406 IGNORE_RET(write(STDERR_FILENO, "\n", 1)); 406 IGNORE_RET(write(STDERR_FILENO, "\n", 1));
407 IGNORE_RET(write(STDERR_FILENO, " ", 7)); 407 IGNORE_RET(write(STDERR_FILENO, " ", 7));
408 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname))); 408 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
409 IGNORE_RET(write(STDERR_FILENO, " ", 1)); 409 IGNORE_RET(write(STDERR_FILENO, " ", 1));
410 IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGEH, 410 IGNORE_RET(write(STDERR_FILENO, DHCLIENT_USAGEH,
411 strlen(DHCLIENT_USAGEH))); 411 strlen(DHCLIENT_USAGEH)));
412 IGNORE_RET(write(STDERR_FILENO, "\n", 1)); 412 IGNORE_RET(write(STDERR_FILENO, "\n", 1));
413 exit(0); 413 exit(0);
414 } 414 }
415 } 415 }
416 /* When not forbidden prepare to become a daemon */ 416 /* When not forbidden prepare to become a daemon */
417 if (!no_daemon) { 417 if (!no_daemon) {
418 go_daemon(); 418 go_daemon();
419 } 419 }
420 420
421 setup(); 421 setup();
422 422
423 for (i = 1; i < argc; i++) { 423 for (i = 1; i < argc; i++) {
424 if (!strcmp(argv[i], "-r")) { 424 if (!strcmp(argv[i], "-r")) {
425 release_mode = 1; 425 release_mode = 1;
426 /* no_daemon = 1; */ 426 /* no_daemon = 1; */
427#ifdef DHCPv6 427#ifdef DHCPv6
428 } else if (!strcmp(argv[i], "-4")) { 428 } else if (!strcmp(argv[i], "-4")) {
429 if (local_family_set && local_family != AF_INET) 429 if (local_family_set && local_family != AF_INET)
430 log_fatal("Client can only do v4 or v6, not " 430 log_fatal("Client can only do v4 or v6, not "
431 "both."); 431 "both.");
432 local_family_set = 1; 432 local_family_set = 1;
433 local_family = AF_INET; 433 local_family = AF_INET;
434 } else if (!strcmp(argv[i], "-6")) { 434 } else if (!strcmp(argv[i], "-6")) {
435 if (local_family_set && local_family != AF_INET6) 435 if (local_family_set && local_family != AF_INET6)
436 log_fatal("Client can only do v4 or v6, not " 436 log_fatal("Client can only do v4 or v6, not "
437 "both."); 437 "both.");
438 local_family_set = 1; 438 local_family_set = 1;
439 local_family = AF_INET6; 439 local_family = AF_INET6;
440#ifdef DHCP4o6 440#ifdef DHCP4o6
441 } else if (!strcmp(argv[i], "-4o6")) { 441 } else if (!strcmp(argv[i], "-4o6")) {
442 if (++i == argc) 442 if (++i == argc)
443 usage(use_noarg, argv[i-1]); 443 usage(use_noarg, argv[i-1]);
444 dhcp4o6_port = validate_port_pair(argv[i]); 444 dhcp4o6_port = validate_port_pair(argv[i]);
445 445
446 log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d", 446 log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d",
447 ntohs(dhcp4o6_port), 447 ntohs(dhcp4o6_port),
448 ntohs(dhcp4o6_port) + 1); 448 ntohs(dhcp4o6_port) + 1);
449 dhcpv4_over_dhcpv6 = 1; 449 dhcpv4_over_dhcpv6 = 1;
450#endif /* DHCP4o6 */ 450#endif /* DHCP4o6 */
451#endif /* DHCPv6 */ 451#endif /* DHCPv6 */
452 } else if (!strcmp(argv[i], "-x")) { /* eXit, no release */ 452 } else if (!strcmp(argv[i], "-x")) { /* eXit, no release */
453 release_mode = 0; 453 release_mode = 0;
454 /* no_daemon = 0; */ 454 /* no_daemon = 0; */
455 exit_mode = 1; 455 exit_mode = 1;
456 } else if (!strcmp(argv[i], "-p")) { 456 } else if (!strcmp(argv[i], "-p")) {
457 if (++i == argc) 457 if (++i == argc)
458 usage(use_noarg, argv[i-1]); 458 usage(use_noarg, argv[i-1]);
459 local_port = validate_port(argv[i]); 459 local_port = validate_port(argv[i]);
460 log_debug("binding to user-specified port %d", 460 log_debug("binding to user-specified port %d",
461 ntohs(local_port)); 461 ntohs(local_port));
462 } else if (!strcmp(argv[i], "-d")) { 462 } else if (!strcmp(argv[i], "-d")) {
463 /* no_daemon = 1; */ 463 /* no_daemon = 1; */
464 quiet = 0; 464 quiet = 0;
465 } else if (!strcmp(argv[i], "-pf")) { 465 } else if (!strcmp(argv[i], "-pf")) {
466 if (++i == argc) 466 if (++i == argc)
467 usage(use_noarg, argv[i-1]); 467 usage(use_noarg, argv[i-1]);
468 path_dhclient_pid = argv[i]; 468 path_dhclient_pid = argv[i];
469 no_dhclient_pid = 1; 469 no_dhclient_pid = 1;
470 } else if (!strcmp(argv[i], "--no-pid")) { 470 } else if (!strcmp(argv[i], "--no-pid")) {
471 no_pid_file = ISC_TRUE; 471 no_pid_file = ISC_TRUE;
472 } else if (!strcmp(argv[i], "-cf")) { 472 } else if (!strcmp(argv[i], "-cf")) {
473 if (++i == argc) 473 if (++i == argc)
474 usage(use_noarg, argv[i-1]); 474 usage(use_noarg, argv[i-1]);
475 path_dhclient_conf = argv[i]; 475 path_dhclient_conf = argv[i];
476 no_dhclient_conf = 1; 476 no_dhclient_conf = 1;
477 } else if (!strcmp(argv[i], "-df")) { 477 } else if (!strcmp(argv[i], "-df")) {
478 if (++i == argc) 478 if (++i == argc)
479 usage(use_noarg, argv[i-1]); 479 usage(use_noarg, argv[i-1]);
480 path_dhclient_duid = argv[i]; 480 path_dhclient_duid = argv[i];
481 } else if (!strcmp(argv[i], "-lf")) { 481 } else if (!strcmp(argv[i], "-lf")) {
482 if (++i == argc) 482 if (++i == argc)
483 usage(use_noarg, argv[i-1]); 483 usage(use_noarg, argv[i-1]);
484 path_dhclient_db = argv[i]; 484 path_dhclient_db = argv[i];
485 no_dhclient_db = 1; 485 no_dhclient_db = 1;
486 } else if (!strcmp(argv[i], "-sf")) { 486 } else if (!strcmp(argv[i], "-sf")) {
487 if (++i == argc) 487 if (++i == argc)
488 usage(use_noarg, argv[i-1]); 488 usage(use_noarg, argv[i-1]);
489 path_dhclient_script = argv[i]; 489 path_dhclient_script = argv[i];
490 no_dhclient_script = 1; 490 no_dhclient_script = 1;
491 } else if (!strcmp(argv[i], "-1")) { 491 } else if (!strcmp(argv[i], "-1")) {
492 onetry = 1; 492 onetry = 1;
493 } else if (!strcmp(argv[i], "-q")) { 493 } else if (!strcmp(argv[i], "-q")) {
494 quiet = 1; 494 quiet = 1;
495 } else if (!strcmp(argv[i], "-s")) { 495 } else if (!strcmp(argv[i], "-s")) {
496 if (++i == argc) 496 if (++i == argc)
497 usage(use_noarg, argv[i-1]); 497 usage(use_noarg, argv[i-1]);
498 server = argv[i]; 498 server = argv[i];
499 } else if (!strcmp(argv[i], "-g")) { 499 } else if (!strcmp(argv[i], "-g")) {
500 if (++i == argc) 500 if (++i == argc)
501 usage(use_noarg, argv[i-1]); 501 usage(use_noarg, argv[i-1]);
502 mockup_relay = argv[i]; 502 mockup_relay = argv[i];
503 } else if (!strcmp(argv[i], "-nw")) { 503 } else if (!strcmp(argv[i], "-nw")) {
504 nowait = 1; 504 nowait = 1;
505 } else if (!strcmp(argv[i], "-n")) { 505 } else if (!strcmp(argv[i], "-n")) {
506 /* do not start up any interfaces */ 506 /* do not start up any interfaces */
507 interfaces_requested = -1; 507 interfaces_requested = -1;
508 } else if (!strcmp(argv[i], "-w")) { 508 } else if (!strcmp(argv[i], "-w")) {
509 /* do not exit if there are no broadcast interfaces. */ 509 /* do not exit if there are no broadcast interfaces. */
510 persist = 1; 510 persist = 1;
511 } else if (!strcmp(argv[i], "-e")) { 511 } else if (!strcmp(argv[i], "-e")) {
512 struct string_list *tmp; 512 struct string_list *tmp;
513 if (++i == argc) 513 if (++i == argc)
514 usage(use_noarg, argv[i-1]); 514 usage(use_noarg, argv[i-1]);
515 tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL); 515 tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL);
516 if (!tmp) 516 if (!tmp)
517 log_fatal("No memory for %s", argv[i]); 517 log_fatal("No memory for %s", argv[i]);
518 strcpy(tmp->string, argv[i]); 518 strcpy(tmp->string, argv[i]);
519 tmp->next = client_env; 519 tmp->next = client_env;
520 client_env = tmp; 520 client_env = tmp;
521 client_env_count++; 521 client_env_count++;
522#ifdef DHCPv6 522#ifdef DHCPv6
523 } else if (!strcmp(argv[i], "-S")) { 523 } else if (!strcmp(argv[i], "-S")) {
524 if (local_family_set && (local_family == AF_INET)) { 524 if (local_family_set && (local_family == AF_INET)) {
525 usage(use_v6command, argv[i]); 525 usage(use_v6command, argv[i]);
526 } 526 }
527 local_family_set = 1; 527 local_family_set = 1;
528 local_family = AF_INET6; 528 local_family = AF_INET6;
529 wanted_ia_na = 0; 529 wanted_ia_na = 0;
530 stateless = 1; 530 stateless = 1;
531 } else if (!strcmp(argv[i], "-N")) { 531 } else if (!strcmp(argv[i], "-N")) {
532 if (local_family_set && (local_family == AF_INET)) { 532 if (local_family_set && (local_family == AF_INET)) {
533 usage(use_v6command, argv[i]); 533 usage(use_v6command, argv[i]);
534 } 534 }
535 local_family_set = 1; 535 local_family_set = 1;
536 local_family = AF_INET6; 536 local_family = AF_INET6;
537 if (wanted_ia_na < 0) { 537 if (wanted_ia_na < 0) {
538 wanted_ia_na = 0; 538 wanted_ia_na = 0;
539 } 539 }
540 wanted_ia_na++; 540 wanted_ia_na++;
541 } else if (!strcmp(argv[i], "-T")) { 541 } else if (!strcmp(argv[i], "-T")) {
542 if (local_family_set && (local_family == AF_INET)) { 542 if (local_family_set && (local_family == AF_INET)) {
543 usage(use_v6command, argv[i]); 543 usage(use_v6command, argv[i]);
544 } 544 }
545 local_family_set = 1; 545 local_family_set = 1;
546 local_family = AF_INET6; 546 local_family = AF_INET6;
547 if (wanted_ia_na < 0) { 547 if (wanted_ia_na < 0) {
548 wanted_ia_na = 0; 548 wanted_ia_na = 0;
549 } 549 }
550 wanted_ia_ta++; 550 wanted_ia_ta++;
551 } else if (!strcmp(argv[i], "-P")) { 551 } else if (!strcmp(argv[i], "-P")) {
552 if (local_family_set && (local_family == AF_INET)) { 552 if (local_family_set && (local_family == AF_INET)) {
553 usage(use_v6command, argv[i]); 553 usage(use_v6command, argv[i]);
554 } 554 }
555 local_family_set = 1; 555 local_family_set = 1;
556 local_family = AF_INET6; 556 local_family = AF_INET6;
557 if (wanted_ia_na < 0) { 557 if (wanted_ia_na < 0) {
558 wanted_ia_na = 0; 558 wanted_ia_na = 0;
559 } 559 }
560 wanted_ia_pd++; 560 wanted_ia_pd++;
561 } else if (!strcmp(argv[i], "-R")) { 561 } else if (!strcmp(argv[i], "-R")) {
562 if (local_family_set && (local_family == AF_INET)) { 562 if (local_family_set && (local_family == AF_INET)) {
563 usage(use_v6command, argv[i]); 563 usage(use_v6command, argv[i]);
564 } 564 }
565 local_family_set = 1; 565 local_family_set = 1;
566 local_family = AF_INET6; 566 local_family = AF_INET6;
567 require_all_ias = 1; 567 require_all_ias = 1;
568 } else if (!strcmp(argv[i], "--dad-wait-time")) { 568 } else if (!strcmp(argv[i], "--dad-wait-time")) {
569 if (++i == argc) { 569 if (++i == argc) {
570 usage(use_noarg, argv[i-1]); 570 usage(use_noarg, argv[i-1]);
571 } 571 }
572 errno = 0; 572 errno = 0;
573 dad_wait_time = (int)strtol(argv[i], &s, 10); 573 dad_wait_time = (int)strtol(argv[i], &s, 10);
574 if (errno || (*s != '\0') || (dad_wait_time < 0)) { 574 if (errno || (*s != '\0') || (dad_wait_time < 0)) {
575 usage("Invalid value for --dad-wait-time: %s", 575 usage("Invalid value for --dad-wait-time: %s",
576 argv[i]); 576 argv[i]);
577 } 577 }
578 } else if (!strcmp(argv[i], "--prefix-len-hint")) { 578 } else if (!strcmp(argv[i], "--prefix-len-hint")) {
579 if (++i == argc) { 579 if (++i == argc) {
580 usage(use_noarg, argv[i-1]); 580 usage(use_noarg, argv[i-1]);
581 } 581 }
582 582
583 errno = 0; 583 errno = 0;
584 prefix_len_hint = (int)strtol(argv[i], &s, 10); 584 prefix_len_hint = (int)strtol(argv[i], &s, 10);
585 if (errno || (*s != '\0') || (prefix_len_hint < 0)) { 585 if (errno || (*s != '\0') || (prefix_len_hint < 0)) {
586 usage("Invalid value for --prefix-len-hint: %s", 586 usage("Invalid value for --prefix-len-hint: %s",
587 argv[i]); 587 argv[i]);
588 } 588 }
589 } else if (!strcmp(argv[i], "--address-prefix-len")) { 589 } else if (!strcmp(argv[i], "--address-prefix-len")) {
590 if (++i == argc) { 590 if (++i == argc) {
591 usage(use_noarg, argv[i-1]); 591 usage(use_noarg, argv[i-1]);
592 } 592 }
593 errno = 0; 593 errno = 0;
594 address_prefix_len = (int)strtol(argv[i], &s, 10); 594 address_prefix_len = (int)strtol(argv[i], &s, 10);
595 if (errno || (*s != '\0') || 595 if (errno || (*s != '\0') ||
596 (address_prefix_len < 0)) { 596 (address_prefix_len < 0)) {
597 usage("Invalid value for" 597 usage("Invalid value for"
598 " --address-prefix-len: %s", argv[i]); 598 " --address-prefix-len: %s", argv[i]);
599 } 599 }
600#endif /* DHCPv6 */ 600#endif /* DHCPv6 */
601 } else if (!strcmp(argv[i], "--decline-wait-time")) { 601 } else if (!strcmp(argv[i], "--decline-wait-time")) {
602 if (++i == argc) { 602 if (++i == argc) {
603 usage(use_noarg, argv[i-1]); 603 usage(use_noarg, argv[i-1]);
604 } 604 }
605 605
606 errno = 0; 606 errno = 0;
607 decline_wait_time = (int)strtol(argv[i], &s, 10); 607 decline_wait_time = (int)strtol(argv[i], &s, 10);
608 if (errno || (*s != '\0') || 608 if (errno || (*s != '\0') ||
609 (decline_wait_time < 0)) { 609 (decline_wait_time < 0)) {
610 usage("Invalid value for " 610 usage("Invalid value for "
611 "--decline-wait-time: %s", argv[i]); 611 "--decline-wait-time: %s", argv[i]);
612 } 612 }
613 } else if (!strcmp(argv[i], "-D")) { 613 } else if (!strcmp(argv[i], "-D")) {
614 duid_v4 = 1; 614 duid_v4 = 1;
615 if (++i == argc) 615 if (++i == argc)
616 usage(use_noarg, argv[i-1]); 616 usage(use_noarg, argv[i-1]);
617 if (!strcasecmp(argv[i], "LL")) { 617 if (!strcasecmp(argv[i], "LL")) {
618 duid_type = DUID_LL; 618 duid_type = DUID_LL;
619 } else if (!strcasecmp(argv[i], "LLT")) { 619 } else if (!strcasecmp(argv[i], "LLT")) {
620 duid_type = DUID_LLT; 620 duid_type = DUID_LLT;
621 } else { 621 } else {
622 usage("Unknown argument to -D: %s", argv[i]); 622 usage("Unknown argument to -D: %s", argv[i]);
623 } 623 }
624 } else if (!strcmp(argv[i], "-i")) { 624 } else if (!strcmp(argv[i], "-i")) {
625 /* enable DUID support for DHCPv4 clients */ 625 /* enable DUID support for DHCPv4 clients */
626 duid_v4 = 1; 626 duid_v4 = 1;
627 } else if (!strcmp(argv[i], "-I")) { 627 } else if (!strcmp(argv[i], "-I")) {
628 /* enable standard DHCID support for DDNS updates */ 628 /* enable standard DHCID support for DDNS updates */
629 std_dhcid = 1; 629 std_dhcid = 1;
630 } else if (!strcmp(argv[i], "-m")) { 630 } else if (!strcmp(argv[i], "-m")) {
631 hw_mismatch_drop = ISC_FALSE; 631 hw_mismatch_drop = ISC_FALSE;
632 } else if (!strcmp(argv[i], "-v")) { 632 } else if (!strcmp(argv[i], "-v")) {
633 quiet = 0; 633 quiet = 0;
634 } else if (argv[i][0] == '-') { 634 } else if (argv[i][0] == '-') {
635 usage("Unknown command: %s", argv[i]); 635 usage("Unknown command: %s", argv[i]);
636 } else if (interfaces_requested < 0) { 636 } else if (interfaces_requested < 0) {
637 usage("No interfaces comamnd -n and " 637 usage("No interfaces comamnd -n and "
638 " requested interface %s", argv[i]); 638 " requested interface %s", argv[i]);
639 } else { 639 } else {
640 ifaces[interfaces_requested++] = argv[i]; 640 ifaces[interfaces_requested++] = argv[i];
641 } 641 }
642 } 642 }
643 643
644 /* 644 /*
645 * Do this before setup, otherwise if we are using threads things 645 * Do this before setup, otherwise if we are using threads things
646 * are not going to work 646 * are not going to work
647 */ 647 */
648 if (interfaces_requested > 0) { 648 if (interfaces_requested > 0) {
649 add_interfaces(ifaces, interfaces_requested); 649 add_interfaces(ifaces, interfaces_requested);
650 interfaces_left = interfaces_requested; 650 interfaces_left = interfaces_requested;
651 } 651 }
652 free(ifaces); 652 free(ifaces);
653 653
654 if (wanted_ia_na < 0) { 654 if (wanted_ia_na < 0) {
655 wanted_ia_na = 1; 655 wanted_ia_na = 1;
656 } 656 }
657 657
658 /* Support only one (requested) interface for Prefix Delegation. */ 658 /* Support only one (requested) interface for Prefix Delegation. */
659 if (wanted_ia_pd && (interfaces_requested != 1)) { 659 if (wanted_ia_pd && (interfaces_requested != 1)) {
660 usage("PD %s only supports one requested interface", "-P"); 660 usage("PD %s only supports one requested interface", "-P");
661 } 661 }
662 662
663#if defined(DHCPv6) && defined(DHCP4o6) 663#if defined(DHCPv6) && defined(DHCP4o6)
664 if ((local_family == AF_INET6) && dhcpv4_over_dhcpv6 && 664 if ((local_family == AF_INET6) && dhcpv4_over_dhcpv6 &&
665 (exit_mode || release_mode)) 665 (exit_mode || release_mode))
666 log_error("Can't relay DHCPv4-over-DHCPv6 " 666 log_error("Can't relay DHCPv4-over-DHCPv6 "
667 "without a persistent DHCPv6 client"); 667 "without a persistent DHCPv6 client");
668 if ((local_family == AF_INET) && dhcpv4_over_dhcpv6 && 668 if ((local_family == AF_INET) && dhcpv4_over_dhcpv6 &&
669 (interfaces_requested != 1)) 669 (interfaces_requested != 1))
670 log_fatal("DHCPv4-over-DHCPv6 requires an explicit " 670 log_fatal("DHCPv4-over-DHCPv6 requires an explicit "
671 "interface on which to be applied"); 671 "interface on which to be applied");
672#endif 672#endif
673 673
674 if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) { 674 if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) {
675 path_dhclient_conf = s; 675 path_dhclient_conf = s;
676 } 676 }
677 if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) { 677 if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) {
678 path_dhclient_db = s; 678 path_dhclient_db = s;
679 } 679 }
680 if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) { 680 if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) {
681 path_dhclient_pid = s; 681 path_dhclient_pid = s;
682 } 682 }
683 if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) { 683 if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) {
684 path_dhclient_script = s; 684 path_dhclient_script = s;
685 } 685 }
686 686
687 /* Set up the initial dhcp option universe. */ 687 /* Set up the initial dhcp option universe. */
688 initialize_common_option_spaces(); 688 initialize_common_option_spaces();
689 689
690 /* Set up the initial client option universe. */ 690 /* Set up the initial client option universe. */
691 initialize_client_option_spaces(); 691 initialize_client_option_spaces();
692 692
693 /* Assign v4 or v6 specific running parameters. */ 693 /* Assign v4 or v6 specific running parameters. */
694 if (local_family == AF_INET) 694 if (local_family == AF_INET)
695 dhcpv4_client_assignments(); 695 dhcpv4_client_assignments();
696#ifdef DHCPv6 696#ifdef DHCPv6
697 else if (local_family == AF_INET6) 697 else if (local_family == AF_INET6)
698 dhcpv6_client_assignments(); 698 dhcpv6_client_assignments();
699#endif /* DHCPv6 */ 699#endif /* DHCPv6 */
700 else 700 else
701 log_fatal("Impossible condition at %s:%d.", MDL); 701 log_fatal("Impossible condition at %s:%d.", MDL);
702 702
703 /* 703 /*
704 * convert relative path names to absolute, for files that need 704 * convert relative path names to absolute, for files that need
705 * to be reopened after chdir() has been called 705 * to be reopened after chdir() has been called
706 */ 706 */
707 if (path_dhclient_db[0] != '/') { 707 if (path_dhclient_db[0] != '/') {
708 path_dhclient_db = absolute_path(path_dhclient_db); 708 path_dhclient_db = absolute_path(path_dhclient_db);
709 } 709 }
710 710
711 if (path_dhclient_script[0] != '/') { 711 if (path_dhclient_script[0] != '/') {
712 path_dhclient_script = absolute_path(path_dhclient_script); 712 path_dhclient_script = absolute_path(path_dhclient_script);
713 } 713 }
714 714
715 /* 715 /*
716 * See if we should kill off any currently running client 716 * See if we should kill off any currently running client
717 * we don't try to kill it off if the user told us not 717 * we don't try to kill it off if the user told us not
718 * to write a pid file - we assume they are controlling 718 * to write a pid file - we assume they are controlling
719 * the process in some other fashion. 719 * the process in some other fashion.
720 */ 720 */
721 if (path_dhclient_pid != NULL && 721 if (path_dhclient_pid != NULL &&
722 (release_mode || exit_mode) && (no_pid_file == ISC_FALSE)) { 722 (release_mode || exit_mode) && (no_pid_file == ISC_FALSE)) {
723 FILE *pidfd; 723 FILE *pidfd;
724 pid_t oldpid; 724 pid_t oldpid;
725 long temp; 725 long temp;
726 int e; 726 int e;
727 727
728 if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) { 728 if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
729 e = fscanf(pidfd, "%ld\n", &temp); 729 e = fscanf(pidfd, "%ld\n", &temp);
730 oldpid = (pid_t)temp; 730 oldpid = (pid_t)temp;
731 731
732 if (e != 0 && e != EOF && oldpid) { 732 if (e != 0 && e != EOF && oldpid) {
733 if (kill(oldpid, SIGTERM) == 0) { 733 if (kill(oldpid, SIGTERM) == 0) {
734 log_info("Killed old client process"); 734 log_info("Killed old client process");
735 (void) unlink(path_dhclient_pid); 735 (void) unlink(path_dhclient_pid);
736 /* 736 /*
737 * wait for the old process to 737 * wait for the old process to
738 * cleanly terminate. 738 * cleanly terminate.
739 * Note kill() with sig=0 could 739 * Note kill() with sig=0 could
740 * detect termination but only 740 * detect termination but only
741 * the parent can be signaled... 741 * the parent can be signaled...
742 */ 742 */
743 sleep(1); 743 sleep(1);
744 } else if (errno == ESRCH) { 744 } else if (errno == ESRCH) {
745 log_info("Removed stale PID file"); 745 log_info("Removed stale PID file");
746 (void) unlink(path_dhclient_pid); 746 (void) unlink(path_dhclient_pid);
747 } 747 }
748 } 748 }
749 fclose(pidfd); 749 fclose(pidfd);
750 } 750 }
751 } 751 }
752 752
753 if (!quiet) { 753 if (!quiet) {
754 log_info("%s %s", message, PACKAGE_VERSION); 754 log_info("%s %s", message, PACKAGE_VERSION);
755 log_info(copyright); 755 log_info(copyright);
756 log_info(arr); 756 log_info(arr);
757 log_info(url); 757 log_info(url);
758 log_info("%s", ""); 758 log_info("%s", "");
759 } else { 759 } else {
760 log_perror = 0; 760 log_perror = 0;
761 quiet_interface_discovery = 1; 761 quiet_interface_discovery = 1;
762 } 762 }
763 763
764 /* If we're given a relay agent address to insert, for testing 764 /* If we're given a relay agent address to insert, for testing
765 purposes, figure out what it is. */ 765 purposes, figure out what it is. */
766 if (mockup_relay) { 766 if (mockup_relay) {
767 if (!inet_aton(mockup_relay, &giaddr)) { 767 if (!inet_aton(mockup_relay, &giaddr)) {
768 struct hostent *he; 768 struct hostent *he;
769 he = gethostbyname(mockup_relay); 769 he = gethostbyname(mockup_relay);
770 if (he) { 770 if (he) {
771 memcpy(&giaddr, he->h_addr_list[0], 771 memcpy(&giaddr, he->h_addr_list[0],
772 sizeof giaddr); 772 sizeof giaddr);
773 } else { 773 } else {
774 log_fatal("%s: no such host", mockup_relay); 774 log_fatal("%s: no such host", mockup_relay);
775 } 775 }
776 } 776 }
777 } 777 }
778 778
779 /* Get the current time... */ 779 /* Get the current time... */
780 gettimeofday(&cur_tv, NULL); 780 gettimeofday(&cur_tv, NULL);
781 781
782 sockaddr_broadcast.sin_family = AF_INET; 782 sockaddr_broadcast.sin_family = AF_INET;
783 sockaddr_broadcast.sin_port = remote_port; 783 sockaddr_broadcast.sin_port = remote_port;
784 if (server) { 784 if (server) {
785 if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) { 785 if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) {
786 struct hostent *he; 786 struct hostent *he;
787 he = gethostbyname(server); 787 he = gethostbyname(server);
788 if (he) { 788 if (he) {
789 memcpy(&sockaddr_broadcast.sin_addr, 789 memcpy(&sockaddr_broadcast.sin_addr,
790 he->h_addr_list[0], 790 he->h_addr_list[0],
791 sizeof sockaddr_broadcast.sin_addr); 791 sizeof sockaddr_broadcast.sin_addr);
792 } else 792 } else
793 sockaddr_broadcast.sin_addr.s_addr = 793 sockaddr_broadcast.sin_addr.s_addr =
794 INADDR_BROADCAST; 794 INADDR_BROADCAST;
795 } 795 }
796 } else { 796 } else {
797 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; 797 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
798 } 798 }
799 799
800 inaddr_any.s_addr = INADDR_ANY; 800 inaddr_any.s_addr = INADDR_ANY;
801 801
802 /* Stateless special case. */ 802 /* Stateless special case. */
803 if (stateless) { 803 if (stateless) {
804 if (release_mode || (wanted_ia_na > 0) || 804 if (release_mode || (wanted_ia_na > 0) ||
805 wanted_ia_ta || wanted_ia_pd || 805 wanted_ia_ta || wanted_ia_pd ||
806 (interfaces_requested != 1)) { 806 (interfaces_requested != 1)) {
807 usage("Stateless command: %s incompatibile with " 807 usage("Stateless command: %s incompatibile with "
808 "other commands", "-S"); 808 "other commands", "-S");
809 } 809 }
810#if defined(DHCPv6) && defined(DHCP4o6) 810#if defined(DHCPv6) && defined(DHCP4o6)
811 run_stateless(exit_mode, dhcp4o6_port); 811 run_stateless(exit_mode, dhcp4o6_port);
812#else 812#else
813 run_stateless(exit_mode, 0); 813 run_stateless(exit_mode, 0);
814#endif 814#endif
815 finish(0); 815 finish(0);
816 } 816 }
817 817
818 /* Discover all the network interfaces. */ 818 /* Discover all the network interfaces. */
819 discover_interfaces(DISCOVER_UNCONFIGURED); 819 discover_interfaces(DISCOVER_UNCONFIGURED);
820 820
821 /* Parse the dhclient.conf file. */ 821 /* Parse the dhclient.conf file. */
822 read_client_conf(); 822 read_client_conf();
823 823
824 /* Parse the lease database. */ 824 /* Parse the lease database. */
825 read_client_leases(); 825 read_client_leases();
826 826
827 /* If desired parse the secondary lease database for a DUID */ 827 /* If desired parse the secondary lease database for a DUID */
828 if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) { 828 if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) {
829 read_client_duid(); 829 read_client_duid();
830 } 830 }
831 831
832 /* Rewrite the lease database... */ 832 /* Rewrite the lease database... */
833 rewrite_client_leases(); 833 rewrite_client_leases();
834 834
835 /* XXX */ 835 /* XXX */
836/* config_counter(&snd_counter, &rcv_counter); */ 836/* config_counter(&snd_counter, &rcv_counter); */
837 837
838 /* 838 /*
839 * If no broadcast interfaces were discovered, call the script 839 * If no broadcast interfaces were discovered, call the script
840 * and tell it so. 840 * and tell it so.
841 */ 841 */
842 if (!interfaces) { 842 if (!interfaces) {
843 /* 843 /*
844 * Call dhclient-script with the NBI flag, 844 * Call dhclient-script with the NBI flag,
845 * in case somebody cares. 845 * in case somebody cares.
846 */ 846 */
847 script_init(NULL, "NBI", NULL); 847 script_init(NULL, "NBI", NULL);
848 script_go(NULL); 848 script_go(NULL);
849 849
850 /* 850 /*
851 * If we haven't been asked to persist, waiting for new 851 * If we haven't been asked to persist, waiting for new
852 * interfaces, then just exit. 852 * interfaces, then just exit.
853 */ 853 */
854 if (!persist) { 854 if (!persist) {
855 /* Nothing more to do. */ 855 /* Nothing more to do. */
856 log_info("No broadcast interfaces found - exiting."); 856 log_info("No broadcast interfaces found - exiting.");
857 finish(0); 857 finish(0);
858 } 858 }
859 } else if (!release_mode && !exit_mode) { 859 } else if (!release_mode && !exit_mode) {
860 /* Call the script with the list of interfaces. */ 860 /* Call the script with the list of interfaces. */
861 for (ip = interfaces; ip; ip = ip->next) { 861 for (ip = interfaces; ip; ip = ip->next) {
862 /* 862 /*
863 * If interfaces were specified, don't configure 863 * If interfaces were specified, don't configure
864 * interfaces that weren't specified! 864 * interfaces that weren't specified!
865 */ 865 */
866 if ((interfaces_requested > 0) && 866 if ((interfaces_requested > 0) &&
867 ((ip->flags & (INTERFACE_REQUESTED | 867 ((ip->flags & (INTERFACE_REQUESTED |
868 INTERFACE_AUTOMATIC)) != 868 INTERFACE_AUTOMATIC)) !=
869 INTERFACE_REQUESTED)) 869 INTERFACE_REQUESTED))
870 continue; 870 continue;
871 871
872 if (local_family == AF_INET6) { 872 if (local_family == AF_INET6) {
873 script_init(ip->client, "PREINIT6", NULL); 873 script_init(ip->client, "PREINIT6", NULL);
874 } else { 874 } else {
875 script_init(ip->client, "PREINIT", NULL); 875 script_init(ip->client, "PREINIT", NULL);
876 if (ip->client->alias != NULL) 876 if (ip->client->alias != NULL)
877 script_write_params(ip->client, 877 script_write_params(ip->client,
878 "alias_", 878 "alias_",
879 ip->client->alias); 879 ip->client->alias);
880 } 880 }
881 script_go(ip->client); 881 script_go(ip->client);
882 } 882 }
883 } 883 }
884 884
885 /* At this point, all the interfaces that the script thinks 885 /* At this point, all the interfaces that the script thinks
886 are relevant should be running, so now we once again call 886 are relevant should be running, so now we once again call
887 discover_interfaces(), and this time ask it to actually set 887 discover_interfaces(), and this time ask it to actually set
888 up the interfaces. */ 888 up the interfaces. */
889 discover_interfaces(interfaces_requested != 0 889 discover_interfaces(interfaces_requested != 0
890 ? DISCOVER_REQUESTED 890 ? DISCOVER_REQUESTED
891 : DISCOVER_RUNNING); 891 : DISCOVER_RUNNING);
892 892
893 /* Make up a seed for the random number generator from current 893 /* Make up a seed for the random number generator from current
894 time plus the sum of the last four bytes of each 894 time plus the sum of the last four bytes of each
895 interface's hardware address interpreted as an integer. 895 interface's hardware address interpreted as an integer.
896 Not much entropy, but we're booting, so we're not likely to 896 Not much entropy, but we're booting, so we're not likely to
897 find anything better. */ 897 find anything better. */
898 seed = 0; 898 seed = 0;
899 for (ip = interfaces; ip; ip = ip->next) { 899 for (ip = interfaces; ip; ip = ip->next) {
900 int junk; 900 int junk;
901 memcpy(&junk, 901 memcpy(&junk,
902 &ip->hw_address.hbuf[ip->hw_address.hlen - 902 &ip->hw_address.hbuf[ip->hw_address.hlen -
903 sizeof seed], sizeof seed); 903 sizeof seed], sizeof seed);
904 seed += junk; 904 seed += junk;
905 } 905 }
906 srandom(seed + cur_time + (unsigned)getpid()); 906 srandom(seed + cur_time + (unsigned)getpid());
907 907
908 908
909 /* 909 /*
910 * Establish a default DUID. We always do so for v6 and 910 * Establish a default DUID. We always do so for v6 and
911 * do so if desired for v4 via the -D or -i options 911 * do so if desired for v4 via the -D or -i options
912 */ 912 */
913 if ((local_family == AF_INET6) || 913 if ((local_family == AF_INET6) ||
914 ((local_family == AF_INET) && (duid_v4 == 1))) { 914 ((local_family == AF_INET) && (duid_v4 == 1))) {
915 if (default_duid.len == 0) { 915 if (default_duid.len == 0) {
916 if (default_duid.buffer != NULL) 916 if (default_duid.buffer != NULL)
917 data_string_forget(&default_duid, MDL); 917 data_string_forget(&default_duid, MDL);
918 918
919 form_duid(&default_duid, MDL); 919 form_duid(&default_duid, MDL);
920 write_duid(&default_duid); 920 write_duid(&default_duid);
921 } 921 }
922 } 922 }
923 923
924#if defined(DHCPv6) && defined(DHCP4o6) 924#if defined(DHCPv6) && defined(DHCP4o6)
925 if (dhcpv4_over_dhcpv6 && !exit_mode) 925 if (dhcpv4_over_dhcpv6 && !exit_mode)
926 dhcp4o6_setup(dhcp4o6_port); 926 dhcp4o6_setup(dhcp4o6_port);
927#endif 927#endif
928 928
929 /* Start a configuration state machine for each interface. */ 929 /* Start a configuration state machine for each interface. */
930#ifdef DHCPv6 930#ifdef DHCPv6
931 if (local_family == AF_INET6) { 931 if (local_family == AF_INET6) {
932 for (ip = interfaces ; ip != NULL ; ip = ip->next) { 932 for (ip = interfaces ; ip != NULL ; ip = ip->next) {
933 for (client = ip->client ; client != NULL ; 933 for (client = ip->client ; client != NULL ;
934 client = client->next) { 934 client = client->next) {
935 if (release_mode) { 935 if (release_mode) {
936 start_release6(client); 936 start_release6(client);
937 continue; 937 continue;
938 } else if (exit_mode) { 938 } else if (exit_mode) {
939 unconfigure6(client, "STOP6"); 939 unconfigure6(client, "STOP6");
940 continue; 940 continue;
941 } 941 }
942 942
943 /* If we have a previous binding, Confirm 943 /* If we have a previous binding, Confirm
944 * that we can (or can't) still use it. 944 * that we can (or can't) still use it.
945 */ 945 */
946 if ((client->active_lease != NULL) && 946 if ((client->active_lease != NULL) &&
947 !client->active_lease->released) 947 !client->active_lease->released)
948 start_confirm6(client); 948 start_confirm6(client);
949 else 949 else
950 start_init6(client); 950 start_init6(client);
951 } 951 }
952 } 952 }
953 } else 953 } else
954#endif /* DHCPv6 */ 954#endif /* DHCPv6 */
955 { 955 {
956 for (ip = interfaces ; ip ; ip = ip->next) { 956 for (ip = interfaces ; ip ; ip = ip->next) {
957 ip->flags |= INTERFACE_RUNNING; 957 ip->flags |= INTERFACE_RUNNING;
958 for (client = ip->client ; client ; 958 for (client = ip->client ; client ;
959 client = client->next) { 959 client = client->next) {
960 if (exit_mode) 960 if (exit_mode)
961 state_stop(client); 961 state_stop(client);
962 if (release_mode) 962 if (release_mode)
963 do_release(client); 963 do_release(client);
964 else { 964 else {
965 client->state = S_INIT; 965 client->state = S_INIT;
966 966
967 if (top_level_config.initial_delay>0) 967 if (top_level_config.initial_delay>0)
968 { 968 {
969 tv.tv_sec = 0; 969 tv.tv_sec = 0;
970 if (top_level_config. 970 if (top_level_config.
971 initial_delay>1) 971 initial_delay>1)
972 tv.tv_sec = cur_time 972 tv.tv_sec = cur_time
973 + random() 973 + random()
974 % (top_level_config. 974 % (top_level_config.
975 initial_delay-1); 975 initial_delay-1);
976 tv.tv_usec = random() 976 tv.tv_usec = random()
977 % 1000000; 977 % 1000000;
978 /* 978 /*
979 * this gives better 979 * this gives better
980 * distribution than just 980 * distribution than just
981 *whole seconds 981 *whole seconds
982 */ 982 */
983 add_timeout(&tv, state_reboot, 983 add_timeout(&tv, state_reboot,
984 client, 0, 0); 984 client, 0, 0);
985 } else { 985 } else {
986 state_reboot(client); 986 state_reboot(client);
987 } 987 }
988 } 988 }
989 } 989 }
990 } 990 }
991 } 991 }
992 992
993 if (exit_mode) 993 if (exit_mode)
994 finish(0); 994 finish(0);
995 if (release_mode) { 995 if (release_mode) {
996#ifndef DHCPv6 996#ifndef DHCPv6
997 finish(0); 997 finish(0);
998#else 998#else
999 if ((local_family == AF_INET6) || dhcpv4_over_dhcpv6) { 999 if ((local_family == AF_INET6) || dhcpv4_over_dhcpv6) {
1000 if (onetry) 1000 if (onetry)
1001 finish(0); 1001 finish(0);
1002 } else 1002 } else
1003 finish(0); 1003 finish(0);
1004#endif /* DHCPv6 */ 1004#endif /* DHCPv6 */
1005 } 1005 }
1006 1006
1007 /* Start up a listener for the object management API protocol. */ 1007 /* Start up a listener for the object management API protocol. */
1008 if (top_level_config.omapi_port != -1) { 1008 if (top_level_config.omapi_port != -1) {
1009 listener = NULL; 1009 listener = NULL;
1010 result = omapi_generic_new(&listener, MDL); 1010 result = omapi_generic_new(&listener, MDL);
1011 if (result != ISC_R_SUCCESS) 1011 if (result != ISC_R_SUCCESS)
1012 log_fatal("Can't allocate new generic object: %s\n", 1012 log_fatal("Can't allocate new generic object: %s\n",
1013 isc_result_totext(result)); 1013 isc_result_totext(result));
1014 result = omapi_protocol_listen(listener, 1014 result = omapi_protocol_listen(listener,
1015 (unsigned) 1015 (unsigned)
1016 top_level_config.omapi_port, 1016 top_level_config.omapi_port,
1017 1); 1017 1);
1018 if (result != ISC_R_SUCCESS) 1018 if (result != ISC_R_SUCCESS)
1019 log_fatal("Can't start OMAPI protocol: %s", 1019 log_fatal("Can't start OMAPI protocol: %s",
1020 isc_result_totext (result)); 1020 isc_result_totext (result));
1021 } 1021 }
1022 1022
1023 /* Set up the bootp packet handler... */ 1023 /* Set up the bootp packet handler... */
1024 bootp_packet_handler = do_packet; 1024 bootp_packet_handler = do_packet;
1025#ifdef DHCPv6 1025#ifdef DHCPv6
1026 dhcpv6_packet_handler = do_packet6; 1026 dhcpv6_packet_handler = do_packet6;
1027#endif /* DHCPv6 */ 1027#endif /* DHCPv6 */
1028 1028
1029#if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \ 1029#if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
1030 defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT) 1030 defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1031 dmalloc_cutoff_generation = dmalloc_generation; 1031 dmalloc_cutoff_generation = dmalloc_generation;
1032 dmalloc_longterm = dmalloc_outstanding; 1032 dmalloc_longterm = dmalloc_outstanding;
1033 dmalloc_outstanding = 0; 1033 dmalloc_outstanding = 0;
1034#endif 1034#endif
1035 1035
1036#if defined(ENABLE_GENTLE_SHUTDOWN) 1036#if defined(ENABLE_GENTLE_SHUTDOWN)
1037 /* no signal handlers until we deal with the side effects */ 1037 /* no signal handlers until we deal with the side effects */
1038 /* install signal handlers */ 1038 /* install signal handlers */
1039 signal(SIGINT, dhcp_signal_handler); /* control-c */ 1039 signal(SIGINT, dhcp_signal_handler); /* control-c */
1040 signal(SIGTERM, dhcp_signal_handler); /* kill */ 1040 signal(SIGTERM, dhcp_signal_handler); /* kill */
1041#endif 1041#endif
1042 1042
1043 /* If we're not supposed to wait before getting the address, 1043 /* If we're not supposed to wait before getting the address,
1044 don't. */ 1044 don't. */
1045 if (nowait) 1045 if (nowait)
1046 detach(); 1046 detach();
1047 1047
1048 /* If we're not going to daemonize, write the pid file 1048 /* If we're not going to daemonize, write the pid file
1049 now. */ 1049 now. */
1050 if (no_daemon || nowait) 1050 if (no_daemon || nowait)
1051 write_client_pid_file(); 1051 write_client_pid_file();
1052 1052
1053 /* Start dispatching packets and timeouts... */ 1053 /* Start dispatching packets and timeouts... */
1054 dispatch(); 1054 dispatch();
1055 1055
1056 /* In fact dispatch() never returns. */ 1056 /* In fact dispatch() never returns. */
1057 return 0; 1057 return 0;
1058} 1058}
1059 1059
1060/* 1060/*
1061 * \brief Run the DHCPv6 stateless client (dhclient -6 -S) 1061 * \brief Run the DHCPv6 stateless client (dhclient -6 -S)
1062 * 1062 *
1063 * \param exist_mode set to 1 when dhclient was called with -x 1063 * \param exist_mode set to 1 when dhclient was called with -x
1064 * \param port DHCPv4-over-DHCPv6 client inter-process communication 1064 * \param port DHCPv4-over-DHCPv6 client inter-process communication
1065 * UDP port pair (port,port+1 with port in network byte order) 1065 * UDP port pair (port,port+1 with port in network byte order)
1066 */ 1066 */
1067 1067
1068void run_stateless(int exit_mode, u_int16_t port) 1068void run_stateless(int exit_mode, u_int16_t port)
1069{ 1069{
1070#ifdef DHCPv6 1070#ifdef DHCPv6
1071 struct client_state *client; 1071 struct client_state *client;
1072 omapi_object_t *listener; 1072 omapi_object_t *listener;
1073 isc_result_t result; 1073 isc_result_t result;
1074 1074
1075#ifndef DHCP4o6 1075#ifndef DHCP4o6
1076 IGNORE_UNUSED(port); 1076 IGNORE_UNUSED(port);
1077#endif 1077#endif
1078 1078
1079 /* Discover the network interface. */ 1079 /* Discover the network interface. */
1080 discover_interfaces(DISCOVER_REQUESTED); 1080 discover_interfaces(DISCOVER_REQUESTED);
1081 1081
1082 if (!interfaces) 1082 if (!interfaces)
1083 usage("No interfaces available for stateless command: %s", "-S"); 1083 usage("No interfaces available for stateless command: %s", "-S");
1084 1084
1085 /* Parse the dhclient.conf file. */ 1085 /* Parse the dhclient.conf file. */
1086#ifdef DHCP4o6 1086#ifdef DHCP4o6
1087 if (dhcpv4_over_dhcpv6) { 1087 if (dhcpv4_over_dhcpv6) {
1088 /* Mark we want to request IRT too! */ 1088 /* Mark we want to request IRT too! */
1089 dhcpv4_over_dhcpv6++; 1089 dhcpv4_over_dhcpv6++;
1090 } 1090 }
1091#endif 1091#endif
1092 read_client_conf(); 1092 read_client_conf();
1093 1093
1094 /* Parse the lease database. */ 1094 /* Parse the lease database. */
1095 read_client_leases(); 1095 read_client_leases();
1096 1096
1097 /* If desired parse the secondary lease database for a DUID */ 1097 /* If desired parse the secondary lease database for a DUID */
1098 if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) { 1098 if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) {
1099 read_client_duid(); 1099 read_client_duid();
1100 } 1100 }
1101 1101
1102 /* Establish a default DUID. */ 1102 /* Establish a default DUID. */
1103 if (default_duid.len == 0) { 1103 if (default_duid.len == 0) {
1104 if (default_duid.buffer != NULL) 1104 if (default_duid.buffer != NULL)
1105 data_string_forget(&default_duid, MDL); 1105 data_string_forget(&default_duid, MDL);
1106 1106
1107 form_duid(&default_duid, MDL); 1107 form_duid(&default_duid, MDL);
1108 } 1108 }
1109 1109
1110#ifdef DHCP4o6 1110#ifdef DHCP4o6
1111 if (dhcpv4_over_dhcpv6 && !exit_mode) 1111 if (dhcpv4_over_dhcpv6 && !exit_mode)
1112 dhcp4o6_setup(port); 1112 dhcp4o6_setup(port);
1113#endif 1113#endif
1114 1114
1115 /* Start a configuration state machine. */ 1115 /* Start a configuration state machine. */
1116 for (client = interfaces->client ; 1116 for (client = interfaces->client ;
1117 client != NULL ; 1117 client != NULL ;
1118 client = client->next) { 1118 client = client->next) {
1119 if (exit_mode) { 1119 if (exit_mode) {
1120 unconfigure6(client, "STOP6"); 1120 unconfigure6(client, "STOP6");
1121 continue; 1121 continue;
1122 } 1122 }
1123 start_info_request6(client); 1123 start_info_request6(client);
1124 } 1124 }
1125 if (exit_mode) 1125 if (exit_mode)
1126 return; 1126 return;
1127 1127
1128 /* Start up a listener for the object management API protocol. */ 1128 /* Start up a listener for the object management API protocol. */
1129 if (top_level_config.omapi_port != -1) { 1129 if (top_level_config.omapi_port != -1) {
1130 listener = NULL; 1130 listener = NULL;
1131 result = omapi_generic_new(&listener, MDL); 1131 result = omapi_generic_new(&listener, MDL);
1132 if (result != ISC_R_SUCCESS) 1132 if (result != ISC_R_SUCCESS)
1133 log_fatal("Can't allocate new generic object: %s\n", 1133 log_fatal("Can't allocate new generic object: %s\n",
1134 isc_result_totext(result)); 1134 isc_result_totext(result));
1135 result = omapi_protocol_listen(listener, 1135 result = omapi_protocol_listen(listener,
1136 (unsigned) 1136 (unsigned)
1137 top_level_config.omapi_port, 1137 top_level_config.omapi_port,
1138 1); 1138 1);
1139 if (result != ISC_R_SUCCESS) 1139 if (result != ISC_R_SUCCESS)
1140 log_fatal("Can't start OMAPI protocol: %s", 1140 log_fatal("Can't start OMAPI protocol: %s",
1141 isc_result_totext(result)); 1141 isc_result_totext(result));
1142 } 1142 }
1143 1143
1144 /* Set up the packet handler... */ 1144 /* Set up the packet handler... */
1145 dhcpv6_packet_handler = do_packet6; 1145 dhcpv6_packet_handler = do_packet6;
1146 1146
1147#if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \ 1147#if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \
1148 defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT) 1148 defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1149 dmalloc_cutoff_generation = dmalloc_generation; 1149 dmalloc_cutoff_generation = dmalloc_generation;
1150 dmalloc_longterm = dmalloc_outstanding; 1150 dmalloc_longterm = dmalloc_outstanding;
1151 dmalloc_outstanding = 0; 1151 dmalloc_outstanding = 0;
1152#endif 1152#endif
1153 1153
1154 /* If we're not supposed to wait before getting the address, 1154 /* If we're not supposed to wait before getting the address,
1155 don't. */ 1155 don't. */
1156 if (nowait) 1156 if (nowait)
1157 detach(); 1157 detach();
1158 1158
1159 /* If we're not going to daemonize, write the pid file 1159 /* If we're not going to daemonize, write the pid file
1160 now. */ 1160 now. */
1161 if (no_daemon || nowait) 1161 if (no_daemon || nowait)
1162 write_client_pid_file(); 1162 write_client_pid_file();
1163 1163
1164 /* Start dispatching packets and timeouts... */ 1164 /* Start dispatching packets and timeouts... */
1165 dispatch(); 1165 dispatch();
1166 1166
1167#endif /* DHCPv6 */ 1167#endif /* DHCPv6 */
1168 return; 1168 return;
1169} 1169}
1170#endif /* !UNIT_TEST */ 1170#endif /* !UNIT_TEST */
1171 1171
1172isc_result_t find_class (struct class **c, 1172isc_result_t find_class (struct class **c,
1173 const char *s, const char *file, int line) 1173 const char *s, const char *file, int line)
1174{ 1174{
1175 return 0; 1175 return 0;
1176} 1176}
1177 1177
1178int check_collection (packet, lease, collection) 1178int check_collection (packet, lease, collection)
1179 struct packet *packet; 1179 struct packet *packet;
1180 struct lease *lease; 1180 struct lease *lease;
1181 struct collection *collection; 1181 struct collection *collection;
1182{ 1182{
1183 return 0; 1183 return 0;
1184} 1184}
1185 1185
1186void classify (packet, class) 1186void classify (packet, class)
1187 struct packet *packet; 1187 struct packet *packet;
1188 struct class *class; 1188 struct class *class;
1189{ 1189{
1190} 1190}
1191 1191
1192void unbill_class (lease) 1192void unbill_class (lease)
1193 struct lease *lease; 1193 struct lease *lease;
1194{ 1194{
1195} 1195}
1196 1196
1197int find_subnet (struct subnet **sp, 1197int find_subnet (struct subnet **sp,
1198 struct iaddr addr, const char *file, int line) 1198 struct iaddr addr, const char *file, int line)
1199{ 1199{
1200 return 0; 1200 return 0;
1201} 1201}
1202 1202
1203/* Individual States: 1203/* Individual States:
1204 * 1204 *
1205 * Each routine is called from the dhclient_state_machine() in one of 1205 * Each routine is called from the dhclient_state_machine() in one of
1206 * these conditions: 1206 * these conditions:
1207 * -> entering INIT state 1207 * -> entering INIT state
1208 * -> recvpacket_flag == 0: timeout in this state 1208 * -> recvpacket_flag == 0: timeout in this state
1209 * -> otherwise: received a packet in this state 1209 * -> otherwise: received a packet in this state
1210 * 1210 *
1211 * Return conditions as handled by dhclient_state_machine(): 1211 * Return conditions as handled by dhclient_state_machine():
1212 * Returns 1, sendpacket_flag = 1: send packet, reset timer. 1212 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
1213 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). 1213 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
1214 * Returns 0: finish the nap which was interrupted for no good reason. 1214 * Returns 0: finish the nap which was interrupted for no good reason.
1215 * 1215 *
1216 * Several per-interface variables are used to keep track of the process: 1216 * Several per-interface variables are used to keep track of the process:
1217 * active_lease: the lease that is being used on the interface 1217 * active_lease: the lease that is being used on the interface
1218 * (null pointer if not configured yet). 1218 * (null pointer if not configured yet).
1219 * offered_leases: leases corresponding to DHCPOFFER messages that have 1219 * offered_leases: leases corresponding to DHCPOFFER messages that have
1220 * been sent to us by DHCP servers. 1220 * been sent to us by DHCP servers.
1221 * acked_leases: leases corresponding to DHCPACK messages that have been 1221 * acked_leases: leases corresponding to DHCPACK messages that have been
1222 * sent to us by DHCP servers. 1222 * sent to us by DHCP servers.
1223 * sendpacket: DHCP packet we're trying to send. 1223 * sendpacket: DHCP packet we're trying to send.
1224 * destination: IP address to send sendpacket to 1224 * destination: IP address to send sendpacket to
1225 * In addition, there are several relevant per-lease variables. 1225 * In addition, there are several relevant per-lease variables.
1226 * T1_expiry, T2_expiry, lease_expiry: lease milestones 1226 * T1_expiry, T2_expiry, lease_expiry: lease milestones
1227 * In the active lease, these control the process of renewing the lease; 1227 * In the active lease, these control the process of renewing the lease;
1228 * In leases on the acked_leases list, this simply determines when we 1228 * In leases on the acked_leases list, this simply determines when we
1229 * can no longer legitimately use the lease. 1229 * can no longer legitimately use the lease.
1230 */ 1230 */
1231 1231
1232#include <sys/cdefs.h> 1232#include <sys/cdefs.h>
1233__RCSID("$NetBSD: dhclient.c,v 1.3 2020/08/03 21:10:56 christos Exp $"); 1233__RCSID("$NetBSD: dhclient.c,v 1.4 2021/05/26 22:52:31 christos Exp $");
1234 1234
1235void state_reboot (cpp) 1235void state_reboot (cpp)
1236 void *cpp; 1236 void *cpp;
1237{ 1237{
1238 struct client_state *client = cpp; 1238 struct client_state *client = cpp;
1239 1239
1240#if defined(DHCPv6) && defined(DHCP4o6) 1240#if defined(DHCPv6) && defined(DHCP4o6)
1241 if (dhcpv4_over_dhcpv6 && (dhcp4o6_state <= 0)) { 1241 if (dhcpv4_over_dhcpv6 && (dhcp4o6_state <= 0)) {
1242 if (dhcp4o6_state < 0) 1242 if (dhcp4o6_state < 0)
1243 dhcp4o6_poll(NULL); 1243 dhcp4o6_poll(NULL);
1244 client->pending = P_REBOOT; 1244 client->pending = P_REBOOT;
1245 return; 1245 return;
1246 } 1246 }
1247#endif 1247#endif
1248 1248
1249 client->pending= P_NONE; 1249 client->pending= P_NONE;
1250 1250
1251 /* If we don't remember an active lease, go straight to INIT. */ 1251 /* If we don't remember an active lease, go straight to INIT. */
1252 if (!client -> active || 1252 if (!client -> active ||
1253 client -> active -> is_bootp || 1253 client -> active -> is_bootp ||
1254 client -> active -> expiry <= cur_time) { 1254 client -> active -> expiry <= cur_time) {
1255 state_init (client); 1255 state_init (client);
1256 return; 1256 return;
1257 } 1257 }
1258 1258
1259 /* We are in the rebooting state. */ 1259 /* We are in the rebooting state. */
1260 client -> state = S_REBOOTING; 1260 client -> state = S_REBOOTING;
1261 1261
1262 /* 1262 /*
1263 * make_request doesn't initialize xid because it normally comes 1263 * make_request doesn't initialize xid because it normally comes
1264 * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, 1264 * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
1265 * so pick an xid now. 1265 * so pick an xid now.
1266 */ 1266 */
1267 client -> xid = random (); 1267 client -> xid = random ();
1268 1268
1269 /* 1269 /*
1270 * Make a DHCPREQUEST packet, and set 1270 * Make a DHCPREQUEST packet, and set
1271 * appropriate per-interface flags. 1271 * appropriate per-interface flags.
1272 */ 1272 */
1273 make_request (client, client -> active); 1273 make_request (client, client -> active);
1274 client -> destination = iaddr_broadcast; 1274 client -> destination = iaddr_broadcast;
1275 client -> first_sending = cur_time; 1275 client -> first_sending = cur_time;
1276 client -> interval = client -> config -> initial_interval; 1276 client -> interval = client -> config -> initial_interval;
1277 1277
1278 /* Zap the medium list... */ 1278 /* Zap the medium list... */
1279 client -> medium = NULL; 1279 client -> medium = NULL;
1280 1280
1281 /* Send out the first DHCPREQUEST packet. */ 1281 /* Send out the first DHCPREQUEST packet. */
1282 send_request (client); 1282 send_request (client);
1283} 1283}
1284 1284
1285/* Called when a lease has completely expired and we've been unable to 1285/* Called when a lease has completely expired and we've been unable to
1286 renew it. */ 1286 renew it. */
1287 1287
1288void state_init (cpp) 1288void state_init (cpp)
1289 void *cpp; 1289 void *cpp;
1290{ 1290{
1291 struct client_state *client = cpp; 1291 struct client_state *client = cpp;
1292 1292
1293 ASSERT_STATE(state, S_INIT); 1293 ASSERT_STATE(state, S_INIT);
1294 1294
1295 /* Make a DHCPDISCOVER packet, and set appropriate per-interface 1295 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
1296 flags. */ 1296 flags. */
1297 make_discover (client, client -> active); 1297 make_discover (client, client -> active);
1298 client -> xid = client -> packet.xid; 1298 client -> xid = client -> packet.xid;
1299 client -> destination = iaddr_broadcast; 1299 client -> destination = iaddr_broadcast;
1300 client -> state = S_SELECTING; 1300 client -> state = S_SELECTING;
1301 client -> first_sending = cur_time; 1301 client -> first_sending = cur_time;
1302 client -> interval = client -> config -> initial_interval; 1302 client -> interval = client -> config -> initial_interval;
1303 1303
1304 /* Add an immediate timeout to cause the first DHCPDISCOVER packet 1304 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
1305 to go out. */ 1305 to go out. */
1306 send_discover (client); 1306 send_discover (client);
1307} 1307}
1308 1308
1309/* 1309/*
1310 * state_selecting is called when one or more DHCPOFFER packets have been 1310 * state_selecting is called when one or more DHCPOFFER packets have been
1311 * received and a configurable period of time has passed. 1311 * received and a configurable period of time has passed.
1312 */ 1312 */
1313 1313
1314void state_selecting (cpp) 1314void state_selecting (cpp)
1315 void *cpp; 1315 void *cpp;
1316{ 1316{
1317 struct client_state *client = cpp; 1317 struct client_state *client = cpp;
1318 struct client_lease *lp, *next, *picked; 1318 struct client_lease *lp, *next, *picked;
1319 1319
1320 1320
1321 ASSERT_STATE(state, S_SELECTING); 1321 ASSERT_STATE(state, S_SELECTING);
1322 1322
1323 /* 1323 /*
1324 * Cancel state_selecting and send_discover timeouts, since either 1324 * Cancel state_selecting and send_discover timeouts, since either
1325 * one could have got us here. 1325 * one could have got us here.
1326 */ 1326 */
1327 cancel_timeout (state_selecting, client); 1327 cancel_timeout (state_selecting, client);
1328 cancel_timeout (send_discover, client); 1328 cancel_timeout (send_discover, client);
1329 1329
1330 /* 1330 /*
1331 * We have received one or more DHCPOFFER packets. Currently, 1331 * We have received one or more DHCPOFFER packets. Currently,
1332 * the only criterion by which we judge leases is whether or 1332 * the only criterion by which we judge leases is whether or
1333 * not we get a response when we arp for them. 1333 * not we get a response when we arp for them.
1334 */ 1334 */
1335 picked = NULL; 1335 picked = NULL;
1336 for (lp = client -> offered_leases; lp; lp = next) { 1336 for (lp = client -> offered_leases; lp; lp = next) {
1337 next = lp -> next; 1337 next = lp -> next;
1338 1338
1339 /* 1339 /*
1340 * Check to see if we got an ARPREPLY for the address 1340 * Check to see if we got an ARPREPLY for the address
1341 * in this particular lease. 1341 * in this particular lease.
1342 */ 1342 */
1343 if (!picked) { 1343 if (!picked) {
1344 picked = lp; 1344 picked = lp;
1345 picked -> next = NULL; 1345 picked -> next = NULL;
1346 } else { 1346 } else {
1347 destroy_client_lease (lp); 1347 destroy_client_lease (lp);
1348 } 1348 }
1349 } 1349 }
1350 client -> offered_leases = NULL; 1350 client -> offered_leases = NULL;
1351 1351
1352 /* 1352 /*
1353 * If we just tossed all the leases we were offered, go back 1353 * If we just tossed all the leases we were offered, go back
1354 * to square one. 1354 * to square one.
1355 */ 1355 */
1356 if (!picked) { 1356 if (!picked) {
1357 client -> state = S_INIT; 1357 client -> state = S_INIT;
1358 state_init (client); 1358 state_init (client);
1359 return; 1359 return;
1360 } 1360 }
1361 1361
1362 /* If it was a BOOTREPLY, we can just take the address right now. */ 1362 /* If it was a BOOTREPLY, we can just take the address right now. */
1363 if (picked -> is_bootp) { 1363 if (picked -> is_bootp) {
1364 client -> new = picked; 1364 client -> new = picked;
1365 1365
1366 /* Make up some lease expiry times 1366 /* Make up some lease expiry times
1367 XXX these should be configurable. */ 1367 XXX these should be configurable. */
1368 client -> new -> expiry = cur_time + 12000; 1368 client -> new -> expiry = cur_time + 12000;
1369 client -> new -> renewal += cur_time + 8000; 1369 client -> new -> renewal += cur_time + 8000;
1370 client -> new -> rebind += cur_time + 10000; 1370 client -> new -> rebind += cur_time + 10000;
1371 1371
1372 client -> state = S_REQUESTING; 1372 client -> state = S_REQUESTING;
1373 1373
1374 /* Bind to the address we received. */ 1374 /* Bind to the address we received. */
1375 bind_lease (client); 1375 bind_lease (client);
1376 return; 1376 return;
1377 } 1377 }
1378 1378
1379 /* Go to the REQUESTING state. */ 1379 /* Go to the REQUESTING state. */
1380 client -> destination = iaddr_broadcast; 1380 client -> destination = iaddr_broadcast;
1381 client -> state = S_REQUESTING; 1381 client -> state = S_REQUESTING;
1382 client -> first_sending = cur_time; 1382 client -> first_sending = cur_time;
1383 client -> interval = client -> config -> initial_interval; 1383 client -> interval = client -> config -> initial_interval;
1384 1384
1385 /* Make a DHCPREQUEST packet from the lease we picked. */ 1385 /* Make a DHCPREQUEST packet from the lease we picked. */
1386 make_request (client, picked); 1386 make_request (client, picked);
1387 client -> xid = client -> packet.xid; 1387 client -> xid = client -> packet.xid;
1388 1388
1389 /* Toss the lease we picked - we'll get it back in a DHCPACK. */ 1389 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
1390 destroy_client_lease (picked); 1390 destroy_client_lease (picked);
1391 1391
1392 /* Add an immediate timeout to send the first DHCPREQUEST packet. */ 1392 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
1393 send_request (client); 1393 send_request (client);
1394} 1394}
1395 1395
1396static isc_boolean_t 1396static isc_boolean_t
1397compare_hw_address(const char *name, struct packet *packet) { 1397compare_hw_address(const char *name, struct packet *packet) {
1398 if (packet->interface->hw_address.hlen - 1 != packet->raw->hlen || 1398 if (packet->interface->hw_address.hlen - 1 != packet->raw->hlen ||
1399 memcmp(&packet->interface->hw_address.hbuf[1], 1399 memcmp(&packet->interface->hw_address.hbuf[1],
1400 packet->raw->chaddr, packet->raw->hlen)) { 1400 packet->raw->chaddr, packet->raw->hlen)) {
1401 unsigned char *c = packet->raw ->chaddr; 1401 unsigned char *c = packet->raw ->chaddr;
1402 log_error ("%s raw = %d %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",  1402 log_error ("%s raw = %d %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
1403 name, packet->raw->hlen, 1403 name, packet->raw->hlen,
1404 c[0], c[1], c[2], c[3], c[4], c[5]); 1404 c[0], c[1], c[2], c[3], c[4], c[5]);
1405 c = &packet -> interface -> hw_address.hbuf [1]; 1405 c = &packet -> interface -> hw_address.hbuf [1];
1406 log_error ("%s cooked = %d %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",  1406 log_error ("%s cooked = %d %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
1407 name, packet->interface->hw_address.hlen - 1, 1407 name, packet->interface->hw_address.hlen - 1,
1408 c[0], c[1], c[2], c[3], c[4], c[5]); 1408 c[0], c[1], c[2], c[3], c[4], c[5]);
1409 log_error ("%s in wrong transaction (%s ignored).", name, 1409 log_error ("%s in wrong transaction (%s ignored).", name,
1410 hw_mismatch_drop ? "packet" : "error"); 1410 hw_mismatch_drop ? "packet" : "error");
1411 return hw_mismatch_drop; 1411 return hw_mismatch_drop;
1412 } 1412 }
1413 return ISC_FALSE; 1413 return ISC_FALSE;
1414} 1414}
1415 1415
1416/* state_requesting is called when we receive a DHCPACK message after 1416/* state_requesting is called when we receive a DHCPACK message after
1417 having sent out one or more DHCPREQUEST packets. */ 1417 having sent out one or more DHCPREQUEST packets. */
1418 1418
1419void dhcpack (packet) 1419void dhcpack (packet)
1420 struct packet *packet; 1420 struct packet *packet;
1421{ 1421{
1422 struct interface_info *ip = packet -> interface; 1422 struct interface_info *ip = packet -> interface;
1423 struct client_state *client; 1423 struct client_state *client;
1424 struct client_lease *lease; 1424 struct client_lease *lease;
1425 struct option_cache *oc; 1425 struct option_cache *oc;
1426 struct data_string ds; 1426 struct data_string ds;
1427 1427
1428 /* If we're not receptive to an offer right now, or if the offer 1428 /* If we're not receptive to an offer right now, or if the offer
1429 has an unrecognizable transaction id, then just drop it. */ 1429 has an unrecognizable transaction id, then just drop it. */
1430 for (client = ip -> client; client; client = client -> next) { 1430 for (client = ip -> client; client; client = client -> next) {
1431 if (client -> xid == packet -> raw -> xid) 1431 if (client -> xid == packet -> raw -> xid)
1432 break; 1432 break;
1433 } 1433 }
1434 if (!client || compare_hw_address("DHCPACK", packet) == ISC_TRUE) 1434 if (!client || compare_hw_address("DHCPACK", packet) == ISC_TRUE)
1435 return; 1435 return;
1436 1436
1437 if (client -> state != S_REBOOTING && 1437 if (client -> state != S_REBOOTING &&
1438 client -> state != S_REQUESTING && 1438 client -> state != S_REQUESTING &&
1439 client -> state != S_RENEWING && 1439 client -> state != S_RENEWING &&
1440 client -> state != S_REBINDING) { 1440 client -> state != S_REBINDING) {
1441#if defined (DEBUG) 1441#if defined (DEBUG)
1442 log_debug ("DHCPACK in wrong state."); 1442 log_debug ("DHCPACK in wrong state.");
1443#endif 1443#endif
1444 return; 1444 return;
1445 } 1445 }
1446 1446
1447 log_info ("DHCPACK of %s from %s", 1447 log_info ("DHCPACK of %s from %s",
1448 inet_ntoa(packet->raw->yiaddr), 1448 inet_ntoa(packet->raw->yiaddr),
1449 piaddr (packet->client_addr)); 1449 piaddr (packet->client_addr));
1450 1450
1451 lease = packet_to_lease (packet, client); 1451 lease = packet_to_lease (packet, client);
1452 if (!lease) { 1452 if (!lease) {
1453 log_info ("packet_to_lease failed."); 1453 log_info ("packet_to_lease failed.");
1454 return; 1454 return;
1455 } 1455 }
1456 1456
1457 client -> new = lease; 1457 client -> new = lease;
1458 1458
1459 /* Stop resending DHCPREQUEST. */ 1459 /* Stop resending DHCPREQUEST. */
1460 cancel_timeout (send_request, client); 1460 cancel_timeout (send_request, client);
1461 1461
1462 /* Figure out the lease time. */ 1462 /* Figure out the lease time. */
1463 oc = lookup_option (&dhcp_universe, client -> new -> options, 1463 oc = lookup_option (&dhcp_universe, client -> new -> options,
1464 DHO_DHCP_LEASE_TIME); 1464 DHO_DHCP_LEASE_TIME);
1465 memset (&ds, 0, sizeof ds); 1465 memset (&ds, 0, sizeof ds);
1466 if (oc && 1466 if (oc &&
1467 evaluate_option_cache (&ds, packet, (struct lease *)0, client, 1467 evaluate_option_cache (&ds, packet, (struct lease *)0, client,
1468 packet -> options, client -> new -> options, 1468 packet -> options, client -> new -> options,
1469 &global_scope, oc, MDL)) { 1469 &global_scope, oc, MDL)) {
1470 if (ds.len > 3) 1470 if (ds.len > 3)
1471 client -> new -> expiry = getULong (ds.data); 1471 client -> new -> expiry = getULong (ds.data);
1472 else 1472 else
1473 client -> new -> expiry = 0; 1473 client -> new -> expiry = 0;
1474 data_string_forget (&ds, MDL); 1474 data_string_forget (&ds, MDL);
1475 } else 1475 } else
1476 client -> new -> expiry = 0; 1476 client -> new -> expiry = 0;
1477 1477
1478 if (client->new->expiry == 0) { 1478 if (client->new->expiry == 0) {
1479 struct timeval tv; 1479 struct timeval tv;
1480 1480
1481 log_error ("no expiry time on offered lease."); 1481 log_error ("no expiry time on offered lease.");
1482 1482
1483 /* Quench this (broken) server. Return to INIT to reselect. */ 1483 /* Quench this (broken) server. Return to INIT to reselect. */
1484 add_reject(packet); 1484 add_reject(packet);
1485 1485
1486 /* 1/2 second delay to restart at INIT. */ 1486 /* 1/2 second delay to restart at INIT. */
1487 tv.tv_sec = cur_tv.tv_sec; 1487 tv.tv_sec = cur_tv.tv_sec;
1488 tv.tv_usec = cur_tv.tv_usec + 500000; 1488 tv.tv_usec = cur_tv.tv_usec + 500000;
1489 1489
1490 if (tv.tv_usec >= 1000000) { 1490 if (tv.tv_usec >= 1000000) {
1491 tv.tv_sec++; 1491 tv.tv_sec++;
1492 tv.tv_usec -= 1000000; 1492 tv.tv_usec -= 1000000;
1493 } 1493 }
1494 1494
1495 add_timeout(&tv, state_init, client, 0, 0); 1495 add_timeout(&tv, state_init, client, 0, 0);
1496 return; 1496 return;
1497 } 1497 }
1498 1498
1499 /* 1499 /*
1500 * A number that looks negative here is really just very large, 1500 * A number that looks negative here is really just very large,
1501 * because the lease expiry offset is unsigned. 1501 * because the lease expiry offset is unsigned.
1502 */ 1502 */
1503 if (client->new->expiry < 0) 1503 if (client->new->expiry < 0)
1504 client->new->expiry = TIME_MAX; 1504 client->new->expiry = TIME_MAX;
1505 1505
1506 /* Take the server-provided renewal time if there is one. */ 1506 /* Take the server-provided renewal time if there is one. */
1507 oc = lookup_option (&dhcp_universe, client -> new -> options, 1507 oc = lookup_option (&dhcp_universe, client -> new -> options,
1508 DHO_DHCP_RENEWAL_TIME); 1508 DHO_DHCP_RENEWAL_TIME);
1509 if (oc && 1509 if (oc &&
1510 evaluate_option_cache (&ds, packet, (struct lease *)0, client, 1510 evaluate_option_cache (&ds, packet, (struct lease *)0, client,
1511 packet -> options, client -> new -> options, 1511 packet -> options, client -> new -> options,
1512 &global_scope, oc, MDL)) { 1512 &global_scope, oc, MDL)) {
1513 if (ds.len > 3) 1513 if (ds.len > 3)
1514 client -> new -> renewal = getULong (ds.data); 1514 client -> new -> renewal = getULong (ds.data);
1515 else 1515 else
1516 client -> new -> renewal = 0; 1516 client -> new -> renewal = 0;
1517 data_string_forget (&ds, MDL); 1517 data_string_forget (&ds, MDL);
1518 } else 1518 } else
1519 client -> new -> renewal = 0; 1519 client -> new -> renewal = 0;
1520 1520
1521 /* If it wasn't specified by the server, calculate it. */ 1521 /* If it wasn't specified by the server, calculate it. */
1522 if (!client -> new -> renewal) 1522 if (!client -> new -> renewal)
1523 client -> new -> renewal = client -> new -> expiry / 2 + 1; 1523 client -> new -> renewal = client -> new -> expiry / 2 + 1;
1524 1524
1525 if (client -> new -> renewal <= 0) 1525 if (client -> new -> renewal <= 0)
1526 client -> new -> renewal = TIME_MAX; 1526 client -> new -> renewal = TIME_MAX;
1527 1527
1528 /* Now introduce some randomness to the renewal time: */ 1528 /* Now introduce some randomness to the renewal time: */
1529 if (client->new->renewal <= ((TIME_MAX / 3) - 3)) 1529 if (client->new->renewal <= ((TIME_MAX / 3) - 3))
1530 client->new->renewal = (((client->new->renewal * 3) + 3) / 4) + 1530 client->new->renewal = (((client->new->renewal * 3) + 3) / 4) +
1531 (((random() % client->new->renewal) + 3) / 4); 1531 (((random() % client->new->renewal) + 3) / 4);
1532 1532
1533 /* Same deal with the rebind time. */ 1533 /* Same deal with the rebind time. */
1534 oc = lookup_option (&dhcp_universe, client -> new -> options, 1534 oc = lookup_option (&dhcp_universe, client -> new -> options,
1535 DHO_DHCP_REBINDING_TIME); 1535 DHO_DHCP_REBINDING_TIME);
1536 if (oc && 1536 if (oc &&
1537 evaluate_option_cache (&ds, packet, (struct lease *)0, client, 1537 evaluate_option_cache (&ds, packet, (struct lease *)0, client,
1538 packet -> options, client -> new -> options, 1538 packet -> options, client -> new -> options,
1539 &global_scope, oc, MDL)) { 1539 &global_scope, oc, MDL)) {
1540 if (ds.len > 3) 1540 if (ds.len > 3)
1541 client -> new -> rebind = getULong (ds.data); 1541 client -> new -> rebind = getULong (ds.data);
1542 else 1542 else
1543 client -> new -> rebind = 0; 1543 client -> new -> rebind = 0;
1544 data_string_forget (&ds, MDL); 1544 data_string_forget (&ds, MDL);
1545 } else 1545 } else
1546 client -> new -> rebind = 0; 1546 client -> new -> rebind = 0;
1547 1547
1548 if (client -> new -> rebind <= 0) { 1548 if (client -> new -> rebind <= 0) {
1549 if (client -> new -> expiry <= TIME_MAX / 7) 1549 if (client -> new -> expiry <= TIME_MAX / 7)
1550 client -> new -> rebind = 1550 client -> new -> rebind =
1551 client -> new -> expiry * 7 / 8; 1551 client -> new -> expiry * 7 / 8;
1552 else 1552 else
1553 client -> new -> rebind = 1553 client -> new -> rebind =
1554 client -> new -> expiry / 8 * 7; 1554 client -> new -> expiry / 8 * 7;
1555 } 1555 }
1556 1556
1557 /* Make sure our randomness didn't run the renewal time past the 1557 /* Make sure our randomness didn't run the renewal time past the
1558 rebind time. */ 1558 rebind time. */
1559 if (client -> new -> renewal > client -> new -> rebind) { 1559 if (client -> new -> renewal > client -> new -> rebind) {
1560 if (client -> new -> rebind <= TIME_MAX / 3) 1560 if (client -> new -> rebind <= TIME_MAX / 3)
1561 client -> new -> renewal = 1561 client -> new -> renewal =
1562 client -> new -> rebind * 3 / 4; 1562 client -> new -> rebind * 3 / 4;
1563 else 1563 else
1564 client -> new -> renewal = 1564 client -> new -> renewal =
1565 client -> new -> rebind / 4 * 3; 1565 client -> new -> rebind / 4 * 3;
1566 } 1566 }
1567 1567
1568 client -> new -> expiry += cur_time; 1568 client -> new -> expiry += cur_time;
1569 /* Lease lengths can never be negative. */ 1569 /* Lease lengths can never be negative. */
1570 if (client -> new -> expiry < cur_time) 1570 if (client -> new -> expiry < cur_time)
1571 client -> new -> expiry = TIME_MAX; 1571 client -> new -> expiry = TIME_MAX;
1572 client -> new -> renewal += cur_time; 1572 client -> new -> renewal += cur_time;
1573 if (client -> new -> renewal < cur_time) 1573 if (client -> new -> renewal < cur_time)
1574 client -> new -> renewal = TIME_MAX; 1574 client -> new -> renewal = TIME_MAX;
1575 client -> new -> rebind += cur_time; 1575 client -> new -> rebind += cur_time;
1576 if (client -> new -> rebind < cur_time) 1576 if (client -> new -> rebind < cur_time)
1577 client -> new -> rebind = TIME_MAX; 1577 client -> new -> rebind = TIME_MAX;
1578 1578
1579 bind_lease (client); 1579 bind_lease (client);
1580} 1580}
1581 1581
1582void bind_lease (client) 1582void bind_lease (client)
1583 struct client_state *client; 1583 struct client_state *client;
1584{ 1584{
1585 struct timeval tv; 1585 struct timeval tv;
1586 1586
1587 /* Remember the medium. */ 1587 /* Remember the medium. */
1588 client->new->medium = client->medium; 1588 client->new->medium = client->medium;
1589 1589
1590 /* Run the client script with the new parameters. */ 1590 /* Run the client script with the new parameters. */
1591 script_init(client, (client->state == S_REQUESTING ? "BOUND" : 1591 script_init(client, (client->state == S_REQUESTING ? "BOUND" :
1592 (client->state == S_RENEWING ? "RENEW" : 1592 (client->state == S_RENEWING ? "RENEW" :
1593 (client->state == S_REBOOTING ? "REBOOT" : 1593 (client->state == S_REBOOTING ? "REBOOT" :
1594 "REBIND"))), 1594 "REBIND"))),
1595 client->new->medium); 1595 client->new->medium);
1596 if (client->active && client->state != S_REBOOTING) 1596 if (client->active && client->state != S_REBOOTING)
1597 script_write_params(client, "old_", client->active); 1597 script_write_params(client, "old_", client->active);
1598 script_write_params(client, "new_", client->new); 1598 script_write_params(client, "new_", client->new);
1599 script_write_requested(client); 1599 script_write_requested(client);
1600 if (client->alias) 1600 if (client->alias)
1601 script_write_params(client, "alias_", client->alias); 1601 script_write_params(client, "alias_", client->alias);
1602 1602
1603 /* If the BOUND/RENEW code detects another machine using the 1603 /* If the BOUND/RENEW code detects another machine using the
1604 offered address, it exits nonzero. We need to send a 1604 offered address, it exits nonzero. We need to send a
1605 DHCPDECLINE and toss the lease. */ 1605 DHCPDECLINE and toss the lease. */
1606 if (script_go(client)) { 1606 if (script_go(client)) {
1607 make_decline(client, client->new); 1607 make_decline(client, client->new);
1608 send_decline(client); 1608 send_decline(client);
1609 destroy_client_lease(client->new); 1609 destroy_client_lease(client->new);
1610 client->new = NULL; 1610 client->new = NULL;
1611 if (onetry) { 1611 if (onetry) {
1612 if (!quiet) { 1612 if (!quiet) {
1613 log_info("Unable to obtain a lease on first " 1613 log_info("Unable to obtain a lease on first "
1614 "try (declined). Exiting."); 1614 "try (declined). Exiting.");
1615 } 1615 }
1616 1616
1617#if defined (CALL_SCRIPT_ON_ONETRY_FAIL) 1617#if defined (CALL_SCRIPT_ON_ONETRY_FAIL)
1618 /* Let's call a script and we're done */ 1618 /* Let's call a script and we're done */
1619 script_init(client, "FAIL", (struct string_list *)0); 1619 script_init(client, "FAIL", (struct string_list *)0);
1620 script_go(client); 1620 script_go(client);
1621#endif 1621#endif
1622 finish(2); 1622 finish(2);
1623 } else { 1623 } else {
1624 struct timeval tv; 1624 struct timeval tv;
1625 tv.tv_sec = cur_tv.tv_sec + decline_wait_time; 1625 tv.tv_sec = cur_tv.tv_sec + decline_wait_time;
1626 tv.tv_usec = cur_tv.tv_usec; 1626 tv.tv_usec = cur_tv.tv_usec;
1627 add_timeout(&tv, state_init, client, 0, 0); 1627 add_timeout(&tv, state_init, client, 0, 0);
1628 return; 1628 return;
1629 } 1629 }
1630 } 1630 }
1631 1631
1632 /* Write out the new lease if it has been long enough. */ 1632 /* Write out the new lease if it has been long enough. */
1633 if (!client->last_write || 1633 if (!client->last_write ||
1634 (cur_time - client->last_write) >= MIN_LEASE_WRITE) 1634 (cur_time - client->last_write) >= MIN_LEASE_WRITE)
1635 write_client_lease(client, client->new, 0, 1); 1635 write_client_lease(client, client->new, 0, 1);
1636 1636
1637 /* Replace the old active lease with the new one. */ 1637 /* Replace the old active lease with the new one. */
1638 if (client->active) { 1638 if (client->active) {
1639 if (client->active->is_static) { 1639 if (client->active->is_static) {
1640 // We need to preserve the fallback lease in case 1640 // We need to preserve the fallback lease in case
1641 // we lose DHCP service again. 1641 // we lose DHCP service again.
1642 add_to_tail(&client->leases, client->active); 1642 add_to_tail(&client->leases, client->active);
1643 } else { 1643 } else {
1644 destroy_client_lease(client->active); 1644 destroy_client_lease(client->active);
1645 } 1645 }
1646 } 1646 }
1647 1647
1648 client->active = client->new; 1648 client->active = client->new;
1649 client->new = NULL; 1649 client->new = NULL;
1650 1650
1651 /* Set up a timeout to start the renewal process. */ 1651 /* Set up a timeout to start the renewal process. */
1652 tv.tv_sec = client->active->renewal; 1652 tv.tv_sec = client->active->renewal;
1653 tv.tv_usec = ((client->active->renewal - cur_tv.tv_sec) > 1) ? 1653 tv.tv_usec = ((client->active->renewal - cur_tv.tv_sec) > 1) ?
1654 random() % 1000000 : cur_tv.tv_usec; 1654 random() % 1000000 : cur_tv.tv_usec;
1655 add_timeout(&tv, state_bound, client, 0, 0); 1655 add_timeout(&tv, state_bound, client, 0, 0);
1656 1656
1657 log_info("bound to %s -- renewal in %ld seconds.", 1657 log_info("bound to %s -- renewal in %ld seconds.",
1658 piaddr(client->active->address), 1658 piaddr(client->active->address),
1659 (long)(client->active->renewal - cur_time)); 1659 (long)(client->active->renewal - cur_time));
1660 client->state = S_BOUND; 1660 client->state = S_BOUND;
1661 reinitialize_interfaces(); 1661 reinitialize_interfaces();
1662 detach(); 1662 detach();
1663#if defined (NSUPDATE) 1663#if defined (NSUPDATE)
1664 if (client->config->do_forward_update) 1664 if (client->config->do_forward_update)
1665 dhclient_schedule_updates(client, &client->active->address, 1); 1665 dhclient_schedule_updates(client, &client->active->address, 1);
1666#endif /* defined NSUPDATE */ 1666#endif /* defined NSUPDATE */
1667 1667
1668} 1668}
1669 1669
1670/* state_bound is called when we've successfully bound to a particular 1670/* state_bound is called when we've successfully bound to a particular
1671 lease, but the renewal time on that lease has expired. We are 1671 lease, but the renewal time on that lease has expired. We are
1672 expected to unicast a DHCPREQUEST to the server that gave us our 1672 expected to unicast a DHCPREQUEST to the server that gave us our
1673 original lease. */ 1673 original lease. */
1674 1674
1675void state_bound (cpp) 1675void state_bound (cpp)
1676 void *cpp; 1676 void *cpp;
1677{ 1677{
1678 struct client_state *client = cpp; 1678 struct client_state *client = cpp;
1679 struct option_cache *oc; 1679 struct option_cache *oc;
1680 struct data_string ds; 1680 struct data_string ds;
1681 1681
1682 ASSERT_STATE(state, S_BOUND); 1682 ASSERT_STATE(state, S_BOUND);
1683 1683
1684 /* T1 has expired. */ 1684 /* T1 has expired. */
1685 make_request (client, client -> active); 1685 make_request (client, client -> active);
1686 client -> xid = client -> packet.xid; 1686 client -> xid = client -> packet.xid;
1687 1687
1688 memset (&ds, 0, sizeof ds); 1688 memset (&ds, 0, sizeof ds);
1689 oc = lookup_option (&dhcp_universe, client -> active -> options, 1689 oc = lookup_option (&dhcp_universe, client -> active -> options,
1690 DHO_DHCP_SERVER_IDENTIFIER); 1690 DHO_DHCP_SERVER_IDENTIFIER);
1691 if (oc && 1691 if (oc &&
1692 evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, 1692 evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
1693 client, (struct option_state *)0, 1693 client, (struct option_state *)0,
1694 client -> active -> options, 1694 client -> active -> options,
1695 &global_scope, oc, MDL)) { 1695 &global_scope, oc, MDL)) {
1696 if (ds.len > 3) { 1696 if (ds.len > 3) {
1697 memcpy (client -> destination.iabuf, ds.data, 4); 1697 memcpy (client -> destination.iabuf, ds.data, 4);
1698 client -> destination.len = 4; 1698 client -> destination.len = 4;
1699 } else 1699 } else
1700 client -> destination = iaddr_broadcast; 1700 client -> destination = iaddr_broadcast;
1701 1701
1702 data_string_forget (&ds, MDL); 1702 data_string_forget (&ds, MDL);
1703 } else 1703 } else
1704 client -> destination = iaddr_broadcast; 1704 client -> destination = iaddr_broadcast;
1705 1705
1706 client -> first_sending = cur_time; 1706 client -> first_sending = cur_time;
1707 client -> interval = client -> config -> initial_interval; 1707 client -> interval = client -> config -> initial_interval;
1708 client -> state = S_RENEWING; 1708 client -> state = S_RENEWING;
1709 1709
1710 /* Send the first packet immediately. */ 1710 /* Send the first packet immediately. */
1711 send_request (client); 1711 send_request (client);
1712} 1712}
1713 1713
1714/* state_stop is called when we've been told to shut down. We unconfigure 1714/* state_stop is called when we've been told to shut down. We unconfigure
1715 the interfaces, and then stop operating until told otherwise. */ 1715 the interfaces, and then stop operating until told otherwise. */
1716 1716
1717void state_stop (cpp) 1717void state_stop (cpp)
1718 void *cpp; 1718 void *cpp;
1719{ 1719{
1720 struct client_state *client = cpp; 1720 struct client_state *client = cpp;
1721 1721
1722 client->pending = P_NONE; 1722 client->pending = P_NONE;
1723 1723
1724 /* Cancel all timeouts. */ 1724 /* Cancel all timeouts. */
1725 cancel_timeout(state_selecting, client); 1725 cancel_timeout(state_selecting, client);
1726 cancel_timeout(send_discover, client); 1726 cancel_timeout(send_discover, client);
1727 cancel_timeout(send_request, client); 1727 cancel_timeout(send_request, client);
1728 cancel_timeout(state_bound, client); 1728 cancel_timeout(state_bound, client);
1729 1729
1730 /* If we have an address, unconfigure it. */ 1730 /* If we have an address, unconfigure it. */
1731 if (client->active) { 1731 if (client->active) {
1732 script_init(client, "STOP", client->active->medium); 1732 script_init(client, "STOP", client->active->medium);
1733 script_write_params(client, "old_", client->active); 1733 script_write_params(client, "old_", client->active);
1734 script_write_requested(client); 1734 script_write_requested(client);
1735 if (client->alias) 1735 if (client->alias)
1736 script_write_params(client, "alias_", client->alias); 1736 script_write_params(client, "alias_", client->alias);
1737 script_go(client); 1737 script_go(client);
1738 } 1738 }
1739} 1739}
1740 1740
1741int commit_leases () 1741int commit_leases ()
1742{ 1742{
1743 return 0; 1743 return 0;
1744} 1744}
1745 1745
1746int write_lease (lease) 1746int write_lease (lease)
1747 struct lease *lease; 1747 struct lease *lease;
1748{ 1748{
1749 return 0; 1749 return 0;
1750} 1750}
1751 1751
1752int write_host (host) 1752int write_host (host)
1753 struct host_decl *host; 1753 struct host_decl *host;
1754{ 1754{
1755 return 0; 1755 return 0;
1756} 1756}
1757 1757
1758void db_startup (testp) 1758void db_startup (testp)
1759 int testp; 1759 int testp;
1760{ 1760{
1761} 1761}
1762 1762
1763void bootp (packet) 1763void bootp (packet)
1764 struct packet *packet; 1764 struct packet *packet;
1765{ 1765{
1766 struct iaddrmatchlist *ap; 1766 struct iaddrmatchlist *ap;
1767 char addrbuf[4*16]; 1767 char addrbuf[4*16];
1768 char maskbuf[4*16]; 1768 char maskbuf[4*16];
1769 1769
1770 if (packet -> raw -> op != BOOTREPLY) 1770 if (packet -> raw -> op != BOOTREPLY)
1771 return; 1771 return;
1772 1772
1773 /* If there's a reject list, make sure this packet's sender isn't 1773 /* If there's a reject list, make sure this packet's sender isn't
1774 on it. */ 1774 on it. */
1775 for (ap = packet -> interface -> client -> config -> reject_list; 1775 for (ap = packet -> interface -> client -> config -> reject_list;
1776 ap; ap = ap -> next) { 1776 ap; ap = ap -> next) {
1777 if (addr_match(&packet->client_addr, &ap->match)) { 1777 if (addr_match(&packet->client_addr, &ap->match)) {
1778 1778
1779 /* piaddr() returns its result in a static 1779 /* piaddr() returns its result in a static
1780 buffer sized 4*16 (see common/inet.c). */ 1780 buffer sized 4*16 (see common/inet.c). */
1781 1781
1782 strcpy(addrbuf, piaddr(ap->match.addr)); 1782 strcpy(addrbuf, piaddr(ap->match.addr));
1783 strcpy(maskbuf, piaddr(ap->match.mask)); 1783 strcpy(maskbuf, piaddr(ap->match.mask));
1784 1784
1785 log_info("BOOTREPLY from %s rejected by rule %s " 1785 log_info("BOOTREPLY from %s rejected by rule %s "
1786 "mask %s.", piaddr(packet->client_addr), 1786 "mask %s.", piaddr(packet->client_addr),
1787 addrbuf, maskbuf); 1787 addrbuf, maskbuf);
1788 return; 1788 return;
1789 } 1789 }
1790 } 1790 }
1791 1791
1792 dhcpoffer (packet); 1792 dhcpoffer (packet);
1793 1793
1794} 1794}
1795 1795
1796void dhcp (packet) 1796void dhcp (packet)
1797 struct packet *packet; 1797 struct packet *packet;
1798{ 1798{
1799 struct iaddrmatchlist *ap; 1799 struct iaddrmatchlist *ap;
1800 void (*handler) (struct packet *); 1800 void (*handler) (struct packet *);
1801 const char *type; 1801 const char *type;
1802 char addrbuf[4*16]; 1802 char addrbuf[4*16];
1803 char maskbuf[4*16]; 1803 char maskbuf[4*16];
1804 1804
1805 switch (packet -> packet_type) { 1805 switch (packet -> packet_type) {
1806 case DHCPOFFER: 1806 case DHCPOFFER:
1807 handler = dhcpoffer; 1807 handler = dhcpoffer;
1808 type = "DHCPOFFER"; 1808 type = "DHCPOFFER";
1809 break; 1809 break;
1810 1810
1811 case DHCPNAK: 1811 case DHCPNAK:
1812 handler = dhcpnak; 1812 handler = dhcpnak;
1813 type = "DHCPNACK"; 1813 type = "DHCPNACK";
1814 break; 1814 break;
1815 1815
1816 case DHCPACK: 1816 case DHCPACK:
1817 handler = dhcpack; 1817 handler = dhcpack;
1818 type = "DHCPACK"; 1818 type = "DHCPACK";
1819 break; 1819 break;
1820 1820
1821 default: 1821 default:
1822 return; 1822 return;
1823 } 1823 }
1824 1824
1825 /* If there's a reject list, make sure this packet's sender isn't 1825 /* If there's a reject list, make sure this packet's sender isn't
1826 on it. */ 1826 on it. */
1827 for (ap = packet -> interface -> client -> config -> reject_list; 1827 for (ap = packet -> interface -> client -> config -> reject_list;
1828 ap; ap = ap -> next) { 1828 ap; ap = ap -> next) {
1829 if (addr_match(&packet->client_addr, &ap->match)) { 1829 if (addr_match(&packet->client_addr, &ap->match)) {
1830 1830
1831 /* piaddr() returns its result in a static 1831 /* piaddr() returns its result in a static
1832 buffer sized 4*16 (see common/inet.c). */ 1832 buffer sized 4*16 (see common/inet.c). */
1833 1833
1834 strcpy(addrbuf, piaddr(ap->match.addr)); 1834 strcpy(addrbuf, piaddr(ap->match.addr));
1835 strcpy(maskbuf, piaddr(ap->match.mask)); 1835 strcpy(maskbuf, piaddr(ap->match.mask));
1836 1836
1837 log_info("%s from %s rejected by rule %s mask %s.", 1837 log_info("%s from %s rejected by rule %s mask %s.",
1838 type, piaddr(packet->client_addr), 1838 type, piaddr(packet->client_addr),
1839 addrbuf, maskbuf); 1839 addrbuf, maskbuf);
1840 return; 1840 return;
1841 } 1841 }
1842 } 1842 }
1843 (*handler) (packet); 1843 (*handler) (packet);
1844} 1844}
1845 1845
1846#ifdef DHCPv6 1846#ifdef DHCPv6
1847void 1847void
1848dhcpv6(struct packet *packet) { 1848dhcpv6(struct packet *packet) {
1849 struct iaddrmatchlist *ap; 1849 struct iaddrmatchlist *ap;
1850 struct client_state *client; 1850 struct client_state *client;
1851 char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; 1851 char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
1852 1852
1853 /* Silently drop bogus messages. */ 1853 /* Silently drop bogus messages. */
1854 if (packet->dhcpv6_msg_type >= dhcpv6_type_name_max) 1854 if (packet->dhcpv6_msg_type >= dhcpv6_type_name_max)
1855 return; 1855 return;
1856 1856
1857 /* Discard, with log, packets from quenched sources. */ 1857 /* Discard, with log, packets from quenched sources. */
1858 for (ap = packet->interface->client->config->reject_list ; 1858 for (ap = packet->interface->client->config->reject_list ;
1859 ap ; ap = ap->next) { 1859 ap ; ap = ap->next) {
1860 if (addr_match(&packet->client_addr, &ap->match)) { 1860 if (addr_match(&packet->client_addr, &ap->match)) {
1861 strcpy(addrbuf, piaddr(packet->client_addr)); 1861 strcpy(addrbuf, piaddr(packet->client_addr));
1862 log_info("%s from %s rejected by rule %s", 1862 log_info("%s from %s rejected by rule %s",
1863 dhcpv6_type_names[packet->dhcpv6_msg_type], 1863 dhcpv6_type_names[packet->dhcpv6_msg_type],
1864 addrbuf, 1864 addrbuf,
1865 piaddrmask(&ap->match.addr, &ap->match.mask)); 1865 piaddrmask(&ap->match.addr, &ap->match.mask));
1866 return; 1866 return;
1867 } 1867 }
1868 } 1868 }
1869 1869
1870 /* Screen out nonsensical messages. */ 1870 /* Screen out nonsensical messages. */
1871 switch(packet->dhcpv6_msg_type) { 1871 switch(packet->dhcpv6_msg_type) {
1872#ifdef DHCP4o6 1872#ifdef DHCP4o6
1873 case DHCPV6_DHCPV4_RESPONSE: 1873 case DHCPV6_DHCPV4_RESPONSE:
1874 if (dhcpv4_over_dhcpv6) { 1874 if (dhcpv4_over_dhcpv6) {
1875 log_info("RCV: %s message on %s from %s.", 1875 log_info("RCV: %s message on %s from %s.",
1876 dhcpv6_type_names[packet->dhcpv6_msg_type], 1876 dhcpv6_type_names[packet->dhcpv6_msg_type],
1877 packet->interface->name, 1877 packet->interface->name,
1878 piaddr(packet->client_addr)); 1878 piaddr(packet->client_addr));
1879 forw_dhcpv4_response(packet); 1879 forw_dhcpv4_response(packet);
1880 } 1880 }
1881 return; 1881 return;
1882#endif 1882#endif
1883 case DHCPV6_ADVERTISE: 1883 case DHCPV6_ADVERTISE:
1884 case DHCPV6_RECONFIGURE: 1884 case DHCPV6_RECONFIGURE:
1885 if (stateless) 1885 if (stateless)
1886 return; 1886 return;
1887 /* Falls through */ 1887 /* Falls through */
1888 case DHCPV6_REPLY: 1888 case DHCPV6_REPLY:
1889 log_info("RCV: %s message on %s from %s.", 1889 log_info("RCV: %s message on %s from %s.",
1890 dhcpv6_type_names[packet->dhcpv6_msg_type], 1890 dhcpv6_type_names[packet->dhcpv6_msg_type],
1891 packet->interface->name, piaddr(packet->client_addr)); 1891 packet->interface->name, piaddr(packet->client_addr));
1892 break; 1892 break;
1893 1893
1894 default: 1894 default:
1895 return; 1895 return;
1896 } 1896 }
1897 1897
1898 /* Find a client state that matches the incoming XID. */ 1898 /* Find a client state that matches the incoming XID. */
1899 for (client = packet->interface->client ; client ; 1899 for (client = packet->interface->client ; client ;
1900 client = client->next) { 1900 client = client->next) {
1901 if (memcmp(&client->dhcpv6_transaction_id, 1901 if (memcmp(&client->dhcpv6_transaction_id,
1902 packet->dhcpv6_transaction_id, 3) == 0) { 1902 packet->dhcpv6_transaction_id, 3) == 0) {
1903 client->v6_handler(packet, client); 1903 client->v6_handler(packet, client);
1904 return; 1904 return;
1905 } 1905 }
1906 } 1906 }
1907 1907
1908 /* XXX: temporary log for debugging */ 1908 /* XXX: temporary log for debugging */
1909 log_info("Packet received, but nothing done with it."); 1909 log_info("Packet received, but nothing done with it.");
1910} 1910}
1911 1911
1912#ifdef DHCP4o6 1912#ifdef DHCP4o6
1913/* 1913/*
1914 * \brief Forward a DHCPv4-response to the DHCPv4 client. 1914 * \brief Forward a DHCPv4-response to the DHCPv4 client.
1915 * (DHCPv6 client function) 1915 * (DHCPv6 client function)
1916 * 1916 *
1917 * The DHCPv6 client receives a DHCPv4-response which is forwarded 1917 * The DHCPv6 client receives a DHCPv4-response which is forwarded
1918 * to the DHCPv4 client. 1918 * to the DHCPv4 client.
1919 * Format: address:16 + DHCPv4 message content 1919 * Format: address:16 + DHCPv4 message content
1920 * (we have no state to keep the address so it is transported in 1920 * (we have no state to keep the address so it is transported in
1921 * DHCPv6 <-> DHCPv6 inter-process messages) 1921 * DHCPv6 <-> DHCPv6 inter-process messages)
1922 * 1922 *
1923 * \param packet the DHCPv4-response packet 1923 * \param packet the DHCPv4-response packet
1924 */ 1924 */
1925static void forw_dhcpv4_response(struct packet *packet) 1925static void forw_dhcpv4_response(struct packet *packet)
1926{ 1926{
1927 struct option_cache *oc; 1927 struct option_cache *oc;
1928 struct data_string enc_opt_data; 1928 struct data_string enc_opt_data;
1929 struct data_string ds; 1929 struct data_string ds;
1930 int cc; 1930 int cc;
1931 1931
1932 /* 1932 /*
1933 * Discard if relay is not ready. 1933 * Discard if relay is not ready.
1934 */ 1934 */
1935 if (dhcp4o6_state == -1) { 1935 if (dhcp4o6_state == -1) {
1936 log_info("forw_dhcpv4_response: not ready."); 1936 log_info("forw_dhcpv4_response: not ready.");
1937 return; 1937 return;
1938 } 1938 }
1939 1939
1940 if (packet->client_addr.len != 16) { 1940 if (packet->client_addr.len != 16) {
1941 log_error("forw_dhcpv4_response: bad address"); 1941 log_error("forw_dhcpv4_response: bad address");
1942 return; 1942 return;
1943 } 1943 }
1944 1944
1945 /* 1945 /*
1946 * Get our encapsulated DHCPv4 message. 1946 * Get our encapsulated DHCPv4 message.
1947 */ 1947 */
1948 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_DHCPV4_MSG); 1948 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_DHCPV4_MSG);
1949 if (oc == NULL) { 1949 if (oc == NULL) {
1950 log_info("DHCPv4-response from %s missing " 1950 log_info("DHCPv4-response from %s missing "
1951 "DHCPv4 Message option.", 1951 "DHCPv4 Message option.",
1952 piaddr(packet->client_addr)); 1952 piaddr(packet->client_addr));
1953 return; 1953 return;
1954 } 1954 }
1955 1955
1956 memset(&enc_opt_data, 0, sizeof(enc_opt_data)); 1956 memset(&enc_opt_data, 0, sizeof(enc_opt_data));
1957 if (!evaluate_option_cache(&enc_opt_data, NULL, NULL, NULL, 1957 if (!evaluate_option_cache(&enc_opt_data, NULL, NULL, NULL,
1958 NULL, NULL, &global_scope, oc, MDL)) { 1958 NULL, NULL, &global_scope, oc, MDL)) {
1959 log_error("forw_dhcpv4_response: error evaluating " 1959 log_error("forw_dhcpv4_response: error evaluating "
1960 "DHCPv4 message."); 1960 "DHCPv4 message.");
1961 data_string_forget(&enc_opt_data, MDL); 1961 data_string_forget(&enc_opt_data, MDL);
1962 return; 1962 return;
1963 } 1963 }
1964 1964
1965 if (enc_opt_data.len < DHCP_FIXED_NON_UDP) { 1965 if (enc_opt_data.len < DHCP_FIXED_NON_UDP) {
1966 log_error("forw_dhcpv4_response: " 1966 log_error("forw_dhcpv4_response: "
1967 "no memory for encapsulated packet."); 1967 "no memory for encapsulated packet.");
1968 data_string_forget(&enc_opt_data, MDL); 1968 data_string_forget(&enc_opt_data, MDL);
1969 return; 1969 return;
1970 } 1970 }
1971 1971
1972 /* 1972 /*
1973 * Append address. 1973 * Append address.
1974 */ 1974 */
1975 memset(&ds, 0, sizeof(ds)); 1975 memset(&ds, 0, sizeof(ds));
1976 if (!buffer_allocate(&ds.buffer, enc_opt_data.len + 16, MDL)) { 1976 if (!buffer_allocate(&ds.buffer, enc_opt_data.len + 16, MDL)) {
1977 log_error("forw_dhcpv4_response: no memory buffer."); 1977 log_error("forw_dhcpv4_response: no memory buffer.");
1978 data_string_forget(&enc_opt_data, MDL); 1978 data_string_forget(&enc_opt_data, MDL);
1979 return; 1979 return;
1980 } 1980 }
1981 ds.data = ds.buffer->data; 1981 ds.data = ds.buffer->data;
1982 ds.len = enc_opt_data.len + 16; 1982 ds.len = enc_opt_data.len + 16;
1983 memcpy(ds.buffer->data, enc_opt_data.data, enc_opt_data.len); 1983 memcpy(ds.buffer->data, enc_opt_data.data, enc_opt_data.len);
1984 memcpy(ds.buffer->data + enc_opt_data.len, 1984 memcpy(ds.buffer->data + enc_opt_data.len,
1985 packet->client_addr.iabuf, 16); 1985 packet->client_addr.iabuf, 16);
1986 data_string_forget(&enc_opt_data, MDL); 1986 data_string_forget(&enc_opt_data, MDL);
1987 1987
1988 /* 1988 /*
1989 * Forward them. 1989 * Forward them.
1990 */ 1990 */
1991 cc = send(dhcp4o6_fd, ds.data, ds.len, 0); 1991 cc = send(dhcp4o6_fd, ds.data, ds.len, 0);
1992 if (cc < 0) 1992 if (cc < 0)
1993 log_error("forw_dhcpv4_response: send(): %m"); 1993 log_error("forw_dhcpv4_response: send(): %m");
1994 1994
1995 data_string_forget(&ds, MDL); 1995 data_string_forget(&ds, MDL);
1996} 1996}
1997 1997
1998/* 1998/*
1999 * \brief Receive a DHCPv4-response from the DHCPv6 client. 1999 * \brief Receive a DHCPv4-response from the DHCPv6 client.
2000 * (DHCPv4 client function) 2000 * (DHCPv4 client function)
2001 * 2001 *
2002 * The DHCPv4 client receives a DHCPv4-response forwarded 2002 * The DHCPv4 client receives a DHCPv4-response forwarded
2003 * by the DHCPv6 client (using \ref forw_dhcpv4_response()) 2003 * by the DHCPv6 client (using \ref forw_dhcpv4_response())
2004 * 2004 *
2005 * \param raw the DHCPv4-response raw packet 2005 * \param raw the DHCPv4-response raw packet
2006 */ 2006 */
2007static void recv_dhcpv4_response(struct data_string *raw) 2007static void recv_dhcpv4_response(struct data_string *raw)
2008{ 2008{
2009 struct packet *packet; 2009 struct packet *packet;
2010 struct iaddr from; 2010 struct iaddr from;
2011 2011
2012 if (interfaces == NULL) { 2012 if (interfaces == NULL) {
2013 log_error("recv_dhcpv4_response: no interfaces."); 2013 log_error("recv_dhcpv4_response: no interfaces.");
2014 return; 2014 return;
2015 } 2015 }
2016 2016
2017 from.len = 16; 2017 from.len = 16;
2018 memcpy(from.iabuf, raw->data + (raw->len - 16), 16); 2018 memcpy(from.iabuf, raw->data + (raw->len - 16), 16);
2019 2019
2020 /* 2020 /*
2021 * Build a packet structure. 2021 * Build a packet structure.
2022 */ 2022 */
2023 packet = NULL; 2023 packet = NULL;
2024 if (!packet_allocate(&packet, MDL)) { 2024 if (!packet_allocate(&packet, MDL)) {
2025 log_error("recv_dhcpv4_response: no memory for packet."); 2025 log_error("recv_dhcpv4_response: no memory for packet.");
2026 return; 2026 return;
2027 } 2027 }
2028 2028
2029 packet->raw = (struct dhcp_packet *) raw->data; 2029 packet->raw = (struct dhcp_packet *) raw->data;
2030 packet->packet_length = raw->len - 16; 2030 packet->packet_length = raw->len - 16;
2031 packet->client_port = remote_port; 2031 packet->client_port = remote_port;
2032 packet->client_addr = from; 2032 packet->client_addr = from;
2033 interface_reference(&packet->interface, interfaces, MDL); 2033 interface_reference(&packet->interface, interfaces, MDL);
2034 2034
2035 /* Allocate packet->options now so it is non-null for all packets */ 2035 /* Allocate packet->options now so it is non-null for all packets */
2036 if (!option_state_allocate (&packet->options, MDL)) { 2036 if (!option_state_allocate (&packet->options, MDL)) {
2037 log_error("recv_dhcpv4_response: no memory for options."); 2037 log_error("recv_dhcpv4_response: no memory for options.");
2038 packet_dereference (&packet, MDL); 2038 packet_dereference (&packet, MDL);
2039 return; 2039 return;
2040 } 2040 }
2041 2041
2042 /* If there's an option buffer, try to parse it. */ 2042 /* If there's an option buffer, try to parse it. */
2043 if (packet->packet_length >= DHCP_FIXED_NON_UDP + 4) { 2043 if (packet->packet_length >= DHCP_FIXED_NON_UDP + 4) {
2044 struct option_cache *op; 2044 struct option_cache *op;
2045 if (!parse_options(packet)) { 2045 if (!parse_options(packet)) {
2046 if (packet->options) 2046 if (packet->options)
2047 option_state_dereference 2047 option_state_dereference
2048 (&packet->options, MDL); 2048 (&packet->options, MDL);
2049 packet_dereference (&packet, MDL); 2049 packet_dereference (&packet, MDL);
2050 return; 2050 return;
2051 } 2051 }
2052 2052
2053 if (packet->options_valid && 2053 if (packet->options_valid &&
2054 (op = lookup_option(&dhcp_universe, 2054 (op = lookup_option(&dhcp_universe,
2055 packet->options, 2055 packet->options,
2056 DHO_DHCP_MESSAGE_TYPE))) { 2056 DHO_DHCP_MESSAGE_TYPE))) {
2057 struct data_string dp; 2057 struct data_string dp;
2058 memset(&dp, 0, sizeof dp); 2058 memset(&dp, 0, sizeof dp);
2059 evaluate_option_cache(&dp, packet, NULL, NULL, 2059 evaluate_option_cache(&dp, packet, NULL, NULL,
2060 packet->options, NULL, 2060 packet->options, NULL,
2061 NULL, op, MDL); 2061 NULL, op, MDL);
2062 if (dp.len > 0) 2062 if (dp.len > 0)
2063 packet->packet_type = dp.data[0]; 2063 packet->packet_type = dp.data[0];
2064 else 2064 else
2065 packet->packet_type = 0; 2065 packet->packet_type = 0;
2066 data_string_forget(&dp, MDL); 2066 data_string_forget(&dp, MDL);
2067 } 2067 }
2068 } 2068 }
2069 2069
2070 if (validate_packet(packet) != 0) { 2070 if (validate_packet(packet) != 0) {
2071 if (packet->packet_type) 2071 if (packet->packet_type)
2072 dhcp(packet); 2072 dhcp(packet);
2073 else 2073 else
2074 bootp(packet); 2074 bootp(packet);
2075 } 2075 }
2076 2076
2077 /* If the caller kept the packet, they'll have upped the refcnt. */ 2077 /* If the caller kept the packet, they'll have upped the refcnt. */
2078 packet_dereference(&packet, MDL); 2078 packet_dereference(&packet, MDL);
2079} 2079}
2080#endif /* DHCP4o6 */ 2080#endif /* DHCP4o6 */
2081#endif /* DHCPv6 */ 2081#endif /* DHCPv6 */
2082 2082
2083void dhcpoffer (packet) 2083void dhcpoffer (packet)
2084 struct packet *packet; 2084 struct packet *packet;
2085{ 2085{
2086 struct interface_info *ip = packet -> interface; 2086 struct interface_info *ip = packet -> interface;
2087 struct client_state *client; 2087 struct client_state *client;
2088 struct client_lease *lease, *lp; 2088 struct client_lease *lease, *lp;
2089 struct option **req; 2089 struct option **req;
2090 int i; 2090 int i;
2091 int stop_selecting; 2091 int stop_selecting;
2092 const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY"; 2092 const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
2093 char obuf [1024]; 2093 char obuf [1024];
2094 struct timeval tv; 2094 struct timeval tv;
2095 2095
2096#ifdef DEBUG_PACKET 2096#ifdef DEBUG_PACKET
2097 dump_packet (packet); 2097 dump_packet (packet);
2098#endif 2098#endif
2099 2099
2100 /* Find a client state that matches the xid... */ 2100 /* Find a client state that matches the xid... */
2101 for (client = ip -> client; client; client = client -> next) 2101 for (client = ip -> client; client; client = client -> next)
2102 if (client -> xid == packet -> raw -> xid) 2102 if (client -> xid == packet -> raw -> xid)
2103 break; 2103 break;
2104 2104
2105 /* If we're not receptive to an offer right now, or if the offer 2105 /* If we're not receptive to an offer right now, or if the offer
2106 has an unrecognizable transaction id, then just drop it. */ 2106 has an unrecognizable transaction id, then just drop it. */
2107 if (!client || client -> state != S_SELECTING || 2107 if (!client || client -> state != S_SELECTING ||
2108 compare_hw_address(name, packet) == ISC_TRUE) 2108 compare_hw_address(name, packet) == ISC_TRUE)
2109 return; 2109 return;
2110 2110
2111 sprintf (obuf, "%s of %s from %s", name, 2111 sprintf (obuf, "%s of %s from %s", name,
2112 inet_ntoa(packet->raw->yiaddr), 2112 inet_ntoa(packet->raw->yiaddr),
2113 piaddr(packet->client_addr)); 2113 piaddr(packet->client_addr));
2114 2114
2115 /* If this lease doesn't supply the minimum required DHCPv4 parameters, 2115 /* If this lease doesn't supply the minimum required DHCPv4 parameters,
2116 * ignore it. 2116 * ignore it.
2117 */ 2117 */
2118 req = client->config->required_options; 2118 req = client->config->required_options;
2119 if (req != NULL) { 2119 if (req != NULL) {
2120 for (i = 0 ; req[i] != NULL ; i++) { 2120 for (i = 0 ; req[i] != NULL ; i++) {
2121 if ((req[i]->universe == &dhcp_universe) && 2121 if ((req[i]->universe == &dhcp_universe) &&
2122 !lookup_option(&dhcp_universe, packet->options, 2122 !lookup_option(&dhcp_universe, packet->options,
2123 req[i]->code)) { 2123 req[i]->code)) {
2124 struct option *option = NULL; 2124 struct option *option = NULL;
2125 unsigned code = req[i]->code; 2125 unsigned code = req[i]->code;
2126 2126
2127 option_code_hash_lookup(&option, 2127 option_code_hash_lookup(&option,
2128 dhcp_universe.code_hash, 2128 dhcp_universe.code_hash,
2129 &code, 0, MDL); 2129 &code, 0, MDL);
2130 2130
2131 if (option) 2131 if (option)
2132 log_info("%s: no %s option.", obuf, 2132 log_info("%s: no %s option.", obuf,
2133 option->name); 2133 option->name);
2134 else 2134 else
2135 log_info("%s: no unknown-%u option.", 2135 log_info("%s: no unknown-%u option.",
2136 obuf, code); 2136 obuf, code);
2137 2137
2138 option_dereference(&option, MDL); 2138 option_dereference(&option, MDL);
2139 2139
2140 return; 2140 return;
2141 } 2141 }
2142 } 2142 }
2143 } 2143 }
2144 2144
2145 /* If we've already seen this lease, don't record it again. */ 2145 /* If we've already seen this lease, don't record it again. */
2146 for (lease = client -> offered_leases; lease; lease = lease -> next) { 2146 for (lease = client -> offered_leases; lease; lease = lease -> next) {
2147 if (lease -> address.len == sizeof packet -> raw -> yiaddr && 2147 if (lease -> address.len == sizeof packet -> raw -> yiaddr &&
2148 !memcmp (lease -> address.iabuf, 2148 !memcmp (lease -> address.iabuf,
2149 &packet -> raw -> yiaddr, lease -> address.len)) { 2149 &packet -> raw -> yiaddr, lease -> address.len)) {
2150 log_debug ("%s: already seen.", obuf); 2150 log_debug ("%s: already seen.", obuf);
2151 return; 2151 return;
2152 } 2152 }
2153 } 2153 }
2154 2154
2155 lease = packet_to_lease (packet, client); 2155 lease = packet_to_lease (packet, client);
2156 if (!lease) { 2156 if (!lease) {
2157 log_info ("%s: packet_to_lease failed.", obuf); 2157 log_info ("%s: packet_to_lease failed.", obuf);
2158 return; 2158 return;
2159 } 2159 }
2160 2160
2161 /* log it now, so it emits before the request goes out */ 2161 /* log it now, so it emits before the request goes out */
2162 log_info("%s", obuf); 2162 log_info("%s", obuf);
2163 2163
2164 /* If this lease was acquired through a BOOTREPLY, record that 2164 /* If this lease was acquired through a BOOTREPLY, record that
2165 fact. */ 2165 fact. */
2166 if (!packet -> options_valid || !packet -> packet_type) 2166 if (!packet -> options_valid || !packet -> packet_type)
2167 lease -> is_bootp = 1; 2167 lease -> is_bootp = 1;
2168 2168
2169 /* Record the medium under which this lease was offered. */ 2169 /* Record the medium under which this lease was offered. */
2170 lease -> medium = client -> medium; 2170 lease -> medium = client -> medium;
2171 2171
2172 /* Figure out when we're supposed to stop selecting. */ 2172 /* Figure out when we're supposed to stop selecting. */
2173 stop_selecting = (client -> first_sending + 2173 stop_selecting = (client -> first_sending +
2174 client -> config -> select_interval); 2174 client -> config -> select_interval);
2175 2175
2176 /* If this is the lease we asked for, put it at the head of the 2176 /* If this is the lease we asked for, put it at the head of the
2177 list, and don't mess with the arp request timeout. */ 2177 list, and don't mess with the arp request timeout. */
2178 if (lease -> address.len == client -> requested_address.len && 2178 if (lease -> address.len == client -> requested_address.len &&
2179 !memcmp (lease -> address.iabuf, 2179 !memcmp (lease -> address.iabuf,
2180 client -> requested_address.iabuf, 2180 client -> requested_address.iabuf,
2181 client -> requested_address.len)) { 2181 client -> requested_address.len)) {
2182 lease -> next = client -> offered_leases; 2182 lease -> next = client -> offered_leases;
2183 client -> offered_leases = lease; 2183 client -> offered_leases = lease;
2184 } else { 2184 } else {
2185 /* Put the lease at the end of the list. */ 2185 /* Put the lease at the end of the list. */
2186 lease -> next = (struct client_lease *)0; 2186 lease -> next = (struct client_lease *)0;
2187 if (!client -> offered_leases) 2187 if (!client -> offered_leases)
2188 client -> offered_leases = lease; 2188 client -> offered_leases = lease;
2189 else { 2189 else {
2190 for (lp = client -> offered_leases; lp -> next; 2190 for (lp = client -> offered_leases; lp -> next;
2191 lp = lp -> next) 2191 lp = lp -> next)
2192 ; 2192 ;
2193 lp -> next = lease; 2193 lp -> next = lease;
2194 } 2194 }
2195 } 2195 }
2196 2196
2197 /* If the selecting interval has expired, go immediately to 2197 /* If the selecting interval has expired, go immediately to
2198 state_selecting(). Otherwise, time out into 2198 state_selecting(). Otherwise, time out into
2199 state_selecting at the select interval. */ 2199 state_selecting at the select interval. */
2200 if (stop_selecting <= cur_tv.tv_sec) 2200 if (stop_selecting <= cur_tv.tv_sec)
2201 state_selecting (client); 2201 state_selecting (client);
2202 else { 2202 else {
2203 tv.tv_sec = stop_selecting; 2203 tv.tv_sec = stop_selecting;
2204 tv.tv_usec = cur_tv.tv_usec; 2204 tv.tv_usec = cur_tv.tv_usec;
2205 add_timeout(&tv, state_selecting, client, 0, 0); 2205 add_timeout(&tv, state_selecting, client, 0, 0);
2206 cancel_timeout(send_discover, client); 2206 cancel_timeout(send_discover, client);
2207 } 2207 }
2208} 2208}
2209 2209
2210/* Allocate a client_lease structure and initialize it from the parameters 2210/* Allocate a client_lease structure and initialize it from the parameters
2211 in the specified packet. */ 2211 in the specified packet. */
2212 2212
2213struct client_lease *packet_to_lease (packet, client) 2213struct client_lease *packet_to_lease (packet, client)
2214 struct packet *packet; 2214 struct packet *packet;
2215 struct client_state *client; 2215 struct client_state *client;
2216{ 2216{
2217 struct client_lease *lease; 2217 struct client_lease *lease;
2218 unsigned i; 2218 unsigned i;
2219 struct option_cache *oc; 2219 struct option_cache *oc;
2220 struct option *option = NULL; 2220 struct option *option = NULL;
2221 struct data_string data; 2221 struct data_string data;
2222 2222
2223 lease = (struct client_lease *)new_client_lease (MDL); 2223 lease = (struct client_lease *)new_client_lease (MDL);
2224 2224
2225 if (!lease) { 2225 if (!lease) {
2226 log_error("packet_to_lease: no memory to record lease.\n"); 2226 log_error("packet_to_lease: no memory to record lease.\n");
2227 return NULL; 2227 return NULL;
2228 } 2228 }
2229 2229
2230 memset(lease, 0, sizeof(*lease)); 2230 memset(lease, 0, sizeof(*lease));
2231 2231
2232 /* Copy the lease options. */ 2232 /* Copy the lease options. */

cvs diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/common/parse.c (switch to unified diff)

--- src/external/mpl/dhcp/dist/common/parse.c 2020/08/03 21:10:56 1.3
+++ src/external/mpl/dhcp/dist/common/parse.c 2021/05/26 22:52:31 1.4
@@ -1,1031 +1,1031 @@ @@ -1,1031 +1,1031 @@
1/* $NetBSD: parse.c,v 1.3 2020/08/03 21:10:56 christos Exp $ */ 1/* $NetBSD: parse.c,v 1.4 2021/05/26 22:52:31 christos Exp $ */
2 2
3/* parse.c 3/* parse.c
4 4
5 Common parser code for dhcpd and dhclient. */ 5 Common parser code for dhcpd and dhclient. */
6 6
7/* 7/*
8 * Copyright (c) 2004-2019 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004-2021 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1995-2003 by Internet Software Consortium 9 * Copyright (c) 1995-2003 by Internet Software Consortium
10 * 10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public 11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this 12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 * 14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * 22 *
23 * Internet Systems Consortium, Inc. 23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street 24 * 950 Charter Street
25 * Redwood City, CA 94063 25 * Redwood City, CA 94063
26 * <info@isc.org> 26 * <info@isc.org>
27 * https://www.isc.org/ 27 * https://www.isc.org/
28 * 28 *
29 */ 29 */
30 30
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32__RCSID("$NetBSD: parse.c,v 1.3 2020/08/03 21:10:56 christos Exp $"); 32__RCSID("$NetBSD: parse.c,v 1.4 2021/05/26 22:52:31 christos Exp $");
33 33
34#include "dhcpd.h" 34#include "dhcpd.h"
35#include <isc/util.h> 35#include <isc/util.h>
36#include <syslog.h> 36#include <syslog.h>
37 37
38struct collection default_collection = { NULL, "default", NULL }; 38struct collection default_collection = { NULL, "default", NULL };
39struct collection *collections = &default_collection; 39struct collection *collections = &default_collection;
40 40
41/* Enumerations can be specified in option formats, and are used for 41/* Enumerations can be specified in option formats, and are used for
42 parsing, so we define the routines that manage them here. */ 42 parsing, so we define the routines that manage them here. */
43 43
44struct enumeration *enumerations; 44struct enumeration *enumerations;
45 45
46void add_enumeration (struct enumeration *enumeration) 46void add_enumeration (struct enumeration *enumeration)
47{ 47{
48 enumeration -> next = enumerations; 48 enumeration -> next = enumerations;
49 enumerations = enumeration; 49 enumerations = enumeration;
50} 50}
51 51
52struct enumeration *find_enumeration (const char *name, int length) 52struct enumeration *find_enumeration (const char *name, int length)
53{ 53{
54 struct enumeration *e; 54 struct enumeration *e;
55 55
56 for (e = enumerations; e; e = e -> next) 56 for (e = enumerations; e; e = e -> next)
57 if (strlen (e -> name) == length && 57 if (strlen (e -> name) == length &&
58 !memcmp (e -> name, name, (unsigned)length)) 58 !memcmp (e -> name, name, (unsigned)length))
59 return e; 59 return e;
60 return (struct enumeration *)0; 60 return (struct enumeration *)0;
61} 61}
62 62
63struct enumeration_value *find_enumeration_value (const char *name, 63struct enumeration_value *find_enumeration_value (const char *name,
64 int length, 64 int length,
65 unsigned *widthp, 65 unsigned *widthp,
66 const char *value) 66 const char *value)
67{ 67{
68 struct enumeration *e; 68 struct enumeration *e;
69 int i; 69 int i;
70 70
71 e = find_enumeration (name, length); 71 e = find_enumeration (name, length);
72 if (e) { 72 if (e) {
73 if (widthp != NULL) 73 if (widthp != NULL)
74 *widthp = e->width; 74 *widthp = e->width;
75 for (i = 0; e -> values [i].name; i++) { 75 for (i = 0; e -> values [i].name; i++) {
76 if (!strcmp (value, e -> values [i].name)) 76 if (!strcmp (value, e -> values [i].name))
77 return &e -> values [i]; 77 return &e -> values [i];
78 } 78 }
79 } 79 }
80 return (struct enumeration_value *)0; 80 return (struct enumeration_value *)0;
81} 81}
82 82
83/* Skip to the semicolon ending the current statement. If we encounter 83/* Skip to the semicolon ending the current statement. If we encounter
84 braces, the matching closing brace terminates the statement. 84 braces, the matching closing brace terminates the statement.
85*/ 85*/
86void skip_to_semi (cfile) 86void skip_to_semi (cfile)
87 struct parse *cfile; 87 struct parse *cfile;
88{ 88{
89 skip_to_rbrace(cfile, 0); 89 skip_to_rbrace(cfile, 0);
90} 90}
91 91
92/* Skips everything from the current point upto (and including) the given 92/* Skips everything from the current point upto (and including) the given
93 number of right braces. If we encounter a semicolon but haven't seen a 93 number of right braces. If we encounter a semicolon but haven't seen a
94 left brace, consume it and return. 94 left brace, consume it and return.
95 This lets us skip over: 95 This lets us skip over:
96 96
97 statement; 97 statement;
98 statement foo bar { } 98 statement foo bar { }
99 statement foo bar { statement { } } 99 statement foo bar { statement { } }
100 statement} 100 statement}
101  101
102 ...et cetera. */ 102 ...et cetera. */
103void skip_to_rbrace (cfile, brace_count) 103void skip_to_rbrace (cfile, brace_count)
104 struct parse *cfile; 104 struct parse *cfile;
105 int brace_count; 105 int brace_count;
106{ 106{
107 enum dhcp_token token; 107 enum dhcp_token token;
108 const char *val; 108 const char *val;
109 109
110#if defined (DEBUG_TOKENS) 110#if defined (DEBUG_TOKENS)
111 log_error("skip_to_rbrace: %d\n", brace_count); 111 log_error("skip_to_rbrace: %d\n", brace_count);
112#endif 112#endif
113 do { 113 do {
114 token = peek_token(&val, NULL, cfile); 114 token = peek_token(&val, NULL, cfile);
115 if (token == RBRACE) { 115 if (token == RBRACE) {
116 if (brace_count > 0) { 116 if (brace_count > 0) {
117 --brace_count; 117 --brace_count;
118 } 118 }
119 119
120 if (brace_count == 0) { 120 if (brace_count == 0) {
121 /* Eat the brace and return. */ 121 /* Eat the brace and return. */
122 skip_token(&val, NULL, cfile); 122 skip_token(&val, NULL, cfile);
123 return; 123 return;
124 } 124 }
125 } else if (token == LBRACE) { 125 } else if (token == LBRACE) {
126 brace_count++; 126 brace_count++;
127 } else if (token == SEMI && (brace_count == 0)) { 127 } else if (token == SEMI && (brace_count == 0)) {
128 /* Eat the semicolon and return. */ 128 /* Eat the semicolon and return. */
129 skip_token(&val, NULL, cfile); 129 skip_token(&val, NULL, cfile);
130 return; 130 return;
131 } else if (token == EOL) { 131 } else if (token == EOL) {
132 /* EOL only happens when parsing /etc/resolv.conf, 132 /* EOL only happens when parsing /etc/resolv.conf,
133 and we treat it like a semicolon because the 133 and we treat it like a semicolon because the
134 resolv.conf file is line-oriented. */ 134 resolv.conf file is line-oriented. */
135 skip_token(&val, NULL, cfile); 135 skip_token(&val, NULL, cfile);
136 return; 136 return;
137 } 137 }
138 138
139 /* Eat the current token */ 139 /* Eat the current token */
140 token = next_token(&val, NULL, cfile); 140 token = next_token(&val, NULL, cfile);
141 } while (token != END_OF_FILE); 141 } while (token != END_OF_FILE);
142} 142}
143 143
144int parse_semi (cfile) 144int parse_semi (cfile)
145 struct parse *cfile; 145 struct parse *cfile;
146{ 146{
147 enum dhcp_token token; 147 enum dhcp_token token;
148 const char *val; 148 const char *val;
149 149
150 token = next_token (&val, (unsigned *)0, cfile); 150 token = next_token (&val, (unsigned *)0, cfile);
151 if (token != SEMI) { 151 if (token != SEMI) {
152 parse_warn (cfile, "semicolon expected."); 152 parse_warn (cfile, "semicolon expected.");
153 skip_to_semi (cfile); 153 skip_to_semi (cfile);
154 return 0; 154 return 0;
155 } 155 }
156 return 1; 156 return 1;
157} 157}
158 158
159/* string-parameter :== STRING SEMI */ 159/* string-parameter :== STRING SEMI */
160 160
161int parse_string (cfile, sptr, lptr) 161int parse_string (cfile, sptr, lptr)
162 struct parse *cfile; 162 struct parse *cfile;
163 char **sptr; 163 char **sptr;
164 unsigned *lptr; 164 unsigned *lptr;
165{ 165{
166 const char *val; 166 const char *val;
167 enum dhcp_token token; 167 enum dhcp_token token;
168 char *s; 168 char *s;
169 unsigned len; 169 unsigned len;
170 170
171 token = next_token (&val, &len, cfile); 171 token = next_token (&val, &len, cfile);
172 if (token != STRING) { 172 if (token != STRING) {
173 parse_warn (cfile, "expecting a string"); 173 parse_warn (cfile, "expecting a string");
174 skip_to_semi (cfile); 174 skip_to_semi (cfile);
175 return 0; 175 return 0;
176 } 176 }
177 s = (char *)dmalloc (len + 1, MDL); 177 s = (char *)dmalloc (len + 1, MDL);
178 if (!s) 178 if (!s)
179 log_fatal ("no memory for string %s.", val); 179 log_fatal ("no memory for string %s.", val);
180 memcpy (s, val, len + 1); 180 memcpy (s, val, len + 1);
181 181
182 if (!parse_semi (cfile)) { 182 if (!parse_semi (cfile)) {
183 dfree (s, MDL); 183 dfree (s, MDL);
184 return 0; 184 return 0;
185 } 185 }
186 if (sptr) 186 if (sptr)
187 *sptr = s; 187 *sptr = s;
188 else 188 else
189 dfree (s, MDL); 189 dfree (s, MDL);
190 if (lptr) 190 if (lptr)
191 *lptr = len; 191 *lptr = len;
192 return 1; 192 return 1;
193} 193}
194 194
195/* 195/*
196 * hostname :== IDENTIFIER 196 * hostname :== IDENTIFIER
197 * | IDENTIFIER DOT 197 * | IDENTIFIER DOT
198 * | hostname DOT IDENTIFIER 198 * | hostname DOT IDENTIFIER
199 */ 199 */
200 200
201char *parse_host_name (cfile) 201char *parse_host_name (cfile)
202 struct parse *cfile; 202 struct parse *cfile;
203{ 203{
204 const char *val; 204 const char *val;
205 enum dhcp_token token; 205 enum dhcp_token token;
206 unsigned len = 0; 206 unsigned len = 0;
207 char *s; 207 char *s;
208 char *t; 208 char *t;
209 pair c = (pair)0; 209 pair c = (pair)0;
210 int ltid = 0; 210 int ltid = 0;
211  211
212 /* Read a dotted hostname... */ 212 /* Read a dotted hostname... */
213 do { 213 do {
214 /* Read a token, which should be an identifier. */ 214 /* Read a token, which should be an identifier. */
215 token = peek_token (&val, (unsigned *)0, cfile); 215 token = peek_token (&val, (unsigned *)0, cfile);
216 if (!is_identifier (token) && token != NUMBER) 216 if (!is_identifier (token) && token != NUMBER)
217 break; 217 break;
218 skip_token(&val, (unsigned *)0, cfile); 218 skip_token(&val, (unsigned *)0, cfile);
219 219
220 /* Store this identifier... */ 220 /* Store this identifier... */
221 if (!(s = (char *)dmalloc (strlen (val) + 1, MDL))) 221 if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
222 log_fatal ("can't allocate temp space for hostname."); 222 log_fatal ("can't allocate temp space for hostname.");
223 strcpy (s, val); 223 strcpy (s, val);
224 c = cons ((caddr_t)s, c); 224 c = cons ((caddr_t)s, c);
225 len += strlen (s) + 1; 225 len += strlen (s) + 1;
226 /* Look for a dot; if it's there, keep going, otherwise 226 /* Look for a dot; if it's there, keep going, otherwise
227 we're done. */ 227 we're done. */
228 token = peek_token (&val, (unsigned *)0, cfile); 228 token = peek_token (&val, (unsigned *)0, cfile);
229 if (token == DOT) { 229 if (token == DOT) {
230 token = next_token (&val, (unsigned *)0, cfile); 230 token = next_token (&val, (unsigned *)0, cfile);
231 ltid = 1; 231 ltid = 1;
232 } else 232 } else
233 ltid = 0; 233 ltid = 0;
234 } while (token == DOT); 234 } while (token == DOT);
235 235
236 /* Should be at least one token. */ 236 /* Should be at least one token. */
237 if (!len) 237 if (!len)
238 return (char *)0; 238 return (char *)0;
239 239
240 /* Assemble the hostname together into a string. */ 240 /* Assemble the hostname together into a string. */
241 if (!(s = (char *)dmalloc (len + ltid, MDL))) 241 if (!(s = (char *)dmalloc (len + ltid, MDL)))
242 log_fatal ("can't allocate space for hostname."); 242 log_fatal ("can't allocate space for hostname.");
243 t = s + len + ltid; 243 t = s + len + ltid;
244 *--t = 0; 244 *--t = 0;
245 if (ltid) 245 if (ltid)
246 *--t = '.'; 246 *--t = '.';
247 while (c) { 247 while (c) {
248 pair cdr = c -> cdr; 248 pair cdr = c -> cdr;
249 unsigned l = strlen ((char *)(c -> car)); 249 unsigned l = strlen ((char *)(c -> car));
250 t -= l; 250 t -= l;
251 memcpy (t, (char *)(c -> car), l); 251 memcpy (t, (char *)(c -> car), l);
252 /* Free up temp space. */ 252 /* Free up temp space. */
253 dfree (c -> car, MDL); 253 dfree (c -> car, MDL);
254 dfree (c, MDL); 254 dfree (c, MDL);
255 c = cdr; 255 c = cdr;
256 if (t != s) 256 if (t != s)
257 *--t = '.'; 257 *--t = '.';
258 } 258 }
259 return s; 259 return s;
260} 260}
261 261
262/* ip-addr-or-hostname :== ip-address | hostname 262/* ip-addr-or-hostname :== ip-address | hostname
263 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER 263 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
264  264
265 Parse an ip address or a hostname. If uniform is zero, put in 265 Parse an ip address or a hostname. If uniform is zero, put in
266 an expr_substring node to limit hostnames that evaluate to more 266 an expr_substring node to limit hostnames that evaluate to more
267 than one IP address. 267 than one IP address.
268 268
269 Note that RFC1123 permits hostnames to consist of all digits, 269 Note that RFC1123 permits hostnames to consist of all digits,
270 making it difficult to quickly disambiguate them from ip addresses. 270 making it difficult to quickly disambiguate them from ip addresses.
271*/ 271*/
272 272
273int parse_ip_addr_or_hostname (expr, cfile, uniform) 273int parse_ip_addr_or_hostname (expr, cfile, uniform)
274 struct expression **expr; 274 struct expression **expr;
275 struct parse *cfile; 275 struct parse *cfile;
276 int uniform; 276 int uniform;
277{ 277{
278 const char *val; 278 const char *val;
279 enum dhcp_token token; 279 enum dhcp_token token;
280 unsigned char addr [4]; 280 unsigned char addr [4];
281 unsigned len = sizeof addr; 281 unsigned len = sizeof addr;
282 char *name; 282 char *name;
283 struct expression *x = (struct expression *)0; 283 struct expression *x = (struct expression *)0;
284 int ipaddr = 0; 284 int ipaddr = 0;
285 285
286 token = peek_token (&val, (unsigned *)0, cfile); 286 token = peek_token (&val, (unsigned *)0, cfile);
287 287
288 if (token == NUMBER) { 288 if (token == NUMBER) {
289 /* 289 /*
290 * a hostname may be numeric, but domain names must 290 * a hostname may be numeric, but domain names must
291 * start with a letter, so we can disambiguate by 291 * start with a letter, so we can disambiguate by
292 * looking ahead a few tokens. we save the parse 292 * looking ahead a few tokens. we save the parse
293 * context first, and restore it after we know what 293 * context first, and restore it after we know what
294 * we're dealing with. 294 * we're dealing with.
295 */ 295 */
296 save_parse_state(cfile); 296 save_parse_state(cfile);
297 skip_token(NULL, NULL, cfile); 297 skip_token(NULL, NULL, cfile);
298 if (next_token(NULL, NULL, cfile) == DOT && 298 if (next_token(NULL, NULL, cfile) == DOT &&
299 next_token(NULL, NULL, cfile) == NUMBER) 299 next_token(NULL, NULL, cfile) == NUMBER)
300 ipaddr = 1; 300 ipaddr = 1;
301 restore_parse_state(cfile); 301 restore_parse_state(cfile);
302 302
303 if (ipaddr && 303 if (ipaddr &&
304 parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) 304 parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
305 return make_const_data (expr, addr, len, 0, 1, MDL); 305 return make_const_data (expr, addr, len, 0, 1, MDL);
306 306
307 } 307 }
308 308
309 if (is_identifier (token) || token == NUMBER) { 309 if (is_identifier (token) || token == NUMBER) {
310 name = parse_host_name (cfile); 310 name = parse_host_name (cfile);
311 if (!name) 311 if (!name)
312 return 0; 312 return 0;
313 if (!make_host_lookup (expr, name)) { 313 if (!make_host_lookup (expr, name)) {
314 dfree(name, MDL); 314 dfree(name, MDL);
315 return 0; 315 return 0;
316 } 316 }
317 dfree(name, MDL); 317 dfree(name, MDL);
318 if (!uniform) { 318 if (!uniform) {
319 if (!make_limit (&x, *expr, 4)) 319 if (!make_limit (&x, *expr, 4))
320 return 0; 320 return 0;
321 expression_dereference (expr, MDL); 321 expression_dereference (expr, MDL);
322 *expr = x; 322 *expr = x;
323 } 323 }
324 } else { 324 } else {
325 if (token != RBRACE && token != LBRACE) 325 if (token != RBRACE && token != LBRACE)
326 token = next_token (&val, (unsigned *)0, cfile); 326 token = next_token (&val, (unsigned *)0, cfile);
327 parse_warn (cfile, "%s (%d): expecting IP address or hostname", 327 parse_warn (cfile, "%s (%d): expecting IP address or hostname",
328 val, token); 328 val, token);
329 if (token != SEMI) 329 if (token != SEMI)
330 skip_to_semi (cfile); 330 skip_to_semi (cfile);
331 return 0; 331 return 0;
332 } 332 }
333 333
334 return 1; 334 return 1;
335}  335}
336  336
337/* 337/*
338 * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER 338 * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
339 */ 339 */
340 340
341int parse_ip_addr (cfile, addr) 341int parse_ip_addr (cfile, addr)
342 struct parse *cfile; 342 struct parse *cfile;
343 struct iaddr *addr; 343 struct iaddr *addr;
344{ 344{
345 addr -> len = 4; 345 addr -> len = 4;
346 if (parse_numeric_aggregate (cfile, addr -> iabuf, 346 if (parse_numeric_aggregate (cfile, addr -> iabuf,
347 &addr -> len, DOT, 10, 8)) 347 &addr -> len, DOT, 10, 8))
348 return 1; 348 return 1;
349 return 0; 349 return 0;
350}  350}
351 351
352/* 352/*
353 * Return true if every character in the string is hexadecimal. 353 * Return true if every character in the string is hexadecimal.
354 */ 354 */
355static int 355static int
356is_hex_string(const char *s) { 356is_hex_string(const char *s) {
357 while (*s != '\0') { 357 while (*s != '\0') {
358 if (!isxdigit((int)*s)) { 358 if (!isxdigit((int)*s)) {
359 return 0; 359 return 0;
360 } 360 }
361 s++; 361 s++;
362 } 362 }
363 return 1; 363 return 1;
364} 364}
365 365
366/* 366/*
367 * ip-address6 :== (complicated set of rules) 367 * ip-address6 :== (complicated set of rules)
368 * 368 *
369 * See section 2.2 of RFC 1884 for details. 369 * See section 2.2 of RFC 1884 for details.
370 * 370 *
371 * We are lazy for this. We pull numbers, names, colons, and dots  371 * We are lazy for this. We pull numbers, names, colons, and dots
372 * together and then throw the resulting string at the inet_pton() 372 * together and then throw the resulting string at the inet_pton()
373 * function. 373 * function.
374 */ 374 */
375 375
376int 376int
377parse_ip6_addr(struct parse *cfile, struct iaddr *addr) { 377parse_ip6_addr(struct parse *cfile, struct iaddr *addr) {
378 enum dhcp_token token; 378 enum dhcp_token token;
379 const char *val; 379 const char *val;
380 int val_len; 380 int val_len;
381 381
382 char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 382 char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
383 int v6_len; 383 int v6_len;
384 384
385 /* 385 /*
386 * First token is non-raw. This way we eat any whitespace before  386 * First token is non-raw. This way we eat any whitespace before
387 * our IPv6 address begins, like one would expect. 387 * our IPv6 address begins, like one would expect.
388 */ 388 */
389 token = peek_token(&val, NULL, cfile); 389 token = peek_token(&val, NULL, cfile);
390 390
391 /* 391 /*
392 * Gather symbols. 392 * Gather symbols.
393 */ 393 */
394 v6_len = 0; 394 v6_len = 0;
395 for (;;) { 395 for (;;) {
396 if ((((token == NAME) || (token == NUMBER_OR_NAME)) && 396 if ((((token == NAME) || (token == NUMBER_OR_NAME)) &&
397 is_hex_string(val)) || 397 is_hex_string(val)) ||
398 (token == NUMBER) || 398 (token == NUMBER) ||
399 (token == TOKEN_ADD) || 399 (token == TOKEN_ADD) ||
400 (token == DOT) || 400 (token == DOT) ||
401 (token == COLON)) { 401 (token == COLON)) {
402 402
403 next_raw_token(&val, NULL, cfile); 403 next_raw_token(&val, NULL, cfile);
404 val_len = strlen(val); 404 val_len = strlen(val);
405 if ((v6_len + val_len) >= sizeof(v6)) { 405 if ((v6_len + val_len) >= sizeof(v6)) {
406 parse_warn(cfile, "Invalid IPv6 address."); 406 parse_warn(cfile, "Invalid IPv6 address.");
407 skip_to_semi(cfile); 407 skip_to_semi(cfile);
408 return 0; 408 return 0;
409 } 409 }
410 memcpy(v6+v6_len, val, val_len); 410 memcpy(v6+v6_len, val, val_len);
411 v6_len += val_len; 411 v6_len += val_len;
412 412
413 } else { 413 } else {
414 break; 414 break;
415 } 415 }
416 token = peek_raw_token(&val, NULL, cfile); 416 token = peek_raw_token(&val, NULL, cfile);
417 } 417 }
418 v6[v6_len] = '\0'; 418 v6[v6_len] = '\0';
419 419
420 /* 420 /*
421 * Use inet_pton() for actual work. 421 * Use inet_pton() for actual work.
422 */ 422 */
423 if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) { 423 if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) {
424 parse_warn(cfile, "Invalid IPv6 address."); 424 parse_warn(cfile, "Invalid IPv6 address.");
425 skip_to_semi(cfile); 425 skip_to_semi(cfile);
426 return 0; 426 return 0;
427 } 427 }
428 addr->len = 16; 428 addr->len = 16;
429 return 1; 429 return 1;
430} 430}
431 431
432/* 432/*
433 * Same as parse_ip6_addr() above, but returns the value in the  433 * Same as parse_ip6_addr() above, but returns the value in the
434 * expression rather than in an address structure. 434 * expression rather than in an address structure.
435 */ 435 */
436int 436int
437parse_ip6_addr_expr(struct expression **expr,  437parse_ip6_addr_expr(struct expression **expr,
438 struct parse *cfile) { 438 struct parse *cfile) {
439 struct iaddr addr; 439 struct iaddr addr;
440 440
441 if (!parse_ip6_addr(cfile, &addr)) { 441 if (!parse_ip6_addr(cfile, &addr)) {
442 return 0; 442 return 0;
443 } 443 }
444 return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL); 444 return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL);
445} 445}
446 446
447/* 447/*
448 * ip6-prefix :== ip6-address "/" NUMBER 448 * ip6-prefix :== ip6-address "/" NUMBER
449 */ 449 */
450int 450int
451parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) { 451parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) {
452 enum dhcp_token token; 452 enum dhcp_token token;
453 const char *val; 453 const char *val;
454 int n; 454 int n;
455 455
456 if (!parse_ip6_addr(cfile, addr)) { 456 if (!parse_ip6_addr(cfile, addr)) {
457 return 0; 457 return 0;
458 } 458 }
459 token = next_token(&val, NULL, cfile); 459 token = next_token(&val, NULL, cfile);
460 if (token != SLASH) { 460 if (token != SLASH) {
461 parse_warn(cfile, "Slash expected."); 461 parse_warn(cfile, "Slash expected.");
462 if (token != SEMI) 462 if (token != SEMI)
463 skip_to_semi(cfile); 463 skip_to_semi(cfile);
464 return 0; 464 return 0;
465 } 465 }
466 token = next_token(&val, NULL, cfile); 466 token = next_token(&val, NULL, cfile);
467 if (token != NUMBER) { 467 if (token != NUMBER) {
468 parse_warn(cfile, "Number expected."); 468 parse_warn(cfile, "Number expected.");
469 if (token != SEMI) 469 if (token != SEMI)
470 skip_to_semi(cfile); 470 skip_to_semi(cfile);
471 return 0; 471 return 0;
472 } 472 }
473 n = atoi(val); 473 n = atoi(val);
474 if ((n < 0) || (n > 128)) { 474 if ((n < 0) || (n > 128)) {
475 parse_warn(cfile, "Invalid IPv6 prefix length."); 475 parse_warn(cfile, "Invalid IPv6 prefix length.");
476 skip_to_semi(cfile); 476 skip_to_semi(cfile);
477 return 0; 477 return 0;
478 } 478 }
479 if (!is_cidr_mask_valid(addr, n)) { 479 if (!is_cidr_mask_valid(addr, n)) {
480 parse_warn(cfile, "network mask too short."); 480 parse_warn(cfile, "network mask too short.");
481 skip_to_semi(cfile); 481 skip_to_semi(cfile);
482 return 0; 482 return 0;
483 } 483 }
484 *plen = n; 484 *plen = n;
485 return 1; 485 return 1;
486} 486}
487 487
488/* 488/*
489 * ip-address-with-subnet :== ip-address | 489 * ip-address-with-subnet :== ip-address |
490 * ip-address "/" NUMBER 490 * ip-address "/" NUMBER
491 */ 491 */
492 492
493int 493int
494parse_ip_addr_with_subnet(cfile, match) 494parse_ip_addr_with_subnet(cfile, match)
495 struct parse *cfile; 495 struct parse *cfile;
496 struct iaddrmatch *match; 496 struct iaddrmatch *match;
497{ 497{
498 const char *val, *orig; 498 const char *val, *orig;
499 enum dhcp_token token; 499 enum dhcp_token token;
500 int prefixlen; 500 int prefixlen;
501 int fflen; 501 int fflen;
502 unsigned char newval, warnmask=0; 502 unsigned char newval, warnmask=0;
503 503
504 if (parse_ip_addr(cfile, &match->addr)) { 504 if (parse_ip_addr(cfile, &match->addr)) {
505 /* default to host mask */ 505 /* default to host mask */
506 prefixlen = match->addr.len * 8; 506 prefixlen = match->addr.len * 8;
507 507
508 token = peek_token(&val, NULL, cfile); 508 token = peek_token(&val, NULL, cfile);
509 509
510 if (token == SLASH) { 510 if (token == SLASH) {
511 skip_token(&val, NULL, cfile); 511 skip_token(&val, NULL, cfile);
512 token = next_token(&val, NULL, cfile); 512 token = next_token(&val, NULL, cfile);
513 513
514 if (token != NUMBER) { 514 if (token != NUMBER) {
515 parse_warn(cfile, "Invalid CIDR prefix length:" 515 parse_warn(cfile, "Invalid CIDR prefix length:"
516 " expecting a number."); 516 " expecting a number.");
517 return 0; 517 return 0;
518 } 518 }
519 519
520 prefixlen = atoi(val); 520 prefixlen = atoi(val);
521 521
522 if (prefixlen < 0 || 522 if (prefixlen < 0 ||
523 prefixlen > (match->addr.len * 8)) { 523 prefixlen > (match->addr.len * 8)) {
524 parse_warn(cfile, "subnet prefix is out of " 524 parse_warn(cfile, "subnet prefix is out of "
525 "range [0..%d].", 525 "range [0..%d].",
526 match->addr.len * 8); 526 match->addr.len * 8);
527 return 0; 527 return 0;
528 } 528 }
529 } 529 }
530 530
531 /* construct a suitable mask field */ 531 /* construct a suitable mask field */
532 532
533 /* copy length */ 533 /* copy length */
534 match->mask.len = match->addr.len; 534 match->mask.len = match->addr.len;
535 535
536 /* count of 0xff bytes in mask */ 536 /* count of 0xff bytes in mask */
537 fflen = prefixlen / 8; 537 fflen = prefixlen / 8;
538 538
539 /* set leading mask */ 539 /* set leading mask */
540 memset(match->mask.iabuf, 0xff, fflen); 540 memset(match->mask.iabuf, 0xff, fflen);
541 541
542 /* set zeroes */ 542 /* set zeroes */
543 if (fflen < match->mask.len) { 543 if (fflen < match->mask.len) {
544 match->mask.iabuf[fflen] = 544 match->mask.iabuf[fflen] =
545 "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8]; 545 "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8];
546 546
547 memset(match->mask.iabuf+fflen+1, 0x00,  547 memset(match->mask.iabuf+fflen+1, 0x00,
548 match->mask.len - fflen - 1); 548 match->mask.len - fflen - 1);
549 549
550 /* AND-out insignificant bits from supplied netmask. */ 550 /* AND-out insignificant bits from supplied netmask. */
551 orig = piaddr(match->addr); 551 orig = piaddr(match->addr);
552 do { 552 do {
553 newval = match->addr.iabuf[fflen] & 553 newval = match->addr.iabuf[fflen] &
554 match->mask.iabuf[fflen]; 554 match->mask.iabuf[fflen];
555 555
556 if (newval != match->addr.iabuf[fflen]) { 556 if (newval != match->addr.iabuf[fflen]) {
557 warnmask = 1; 557 warnmask = 1;
558 match->addr.iabuf[fflen] = newval; 558 match->addr.iabuf[fflen] = newval;
559 } 559 }
560 } while (++fflen < match->mask.len); 560 } while (++fflen < match->mask.len);
561 561
562 if (warnmask) { 562 if (warnmask) {
563 log_error("Warning: Extraneous bits removed " 563 log_error("Warning: Extraneous bits removed "
564 "in address component of %s/%d.", 564 "in address component of %s/%d.",
565 orig, prefixlen); 565 orig, prefixlen);
566 log_error("New value: %s/%d.", 566 log_error("New value: %s/%d.",
567 piaddr(match->addr), prefixlen); 567 piaddr(match->addr), prefixlen);
568 } 568 }
569 } 569 }
570 570
571 return 1; 571 return 1;
572 } 572 }
573 573
574 parse_warn(cfile, 574 parse_warn(cfile,
575 "expecting ip-address or ip-address/prefixlen"); 575 "expecting ip-address or ip-address/prefixlen");
576 576
577 return 0; /* let caller pick up pieces */  577 return 0; /* let caller pick up pieces */
578} 578}
579 579
580/* 580/*
581 * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI 581 * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI
582 * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI | INFINIBAND 582 * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI | INFINIBAND
583 * Note that INFINIBAND may not be useful for some items, such as classification 583 * Note that INFINIBAND may not be useful for some items, such as classification
584 * as the hardware address won't always be available. 584 * as the hardware address won't always be available.
585 */ 585 */
586 586
587void parse_hardware_param (cfile, hardware) 587void parse_hardware_param (cfile, hardware)
588 struct parse *cfile; 588 struct parse *cfile;
589 struct hardware *hardware; 589 struct hardware *hardware;
590{ 590{
591 const char *val; 591 const char *val;
592 enum dhcp_token token; 592 enum dhcp_token token;
593 unsigned hlen; 593 unsigned hlen;
594 unsigned char *t; 594 unsigned char *t;
595 595
596 token = next_token(&val, NULL, cfile); 596 token = next_token(&val, NULL, cfile);
597 switch (token) { 597 switch (token) {
598 case ETHERNET: 598 case ETHERNET:
599 hardware->hbuf[0] = HTYPE_ETHER; 599 hardware->hbuf[0] = HTYPE_ETHER;
600 break; 600 break;
601 case TOKEN_RING: 601 case TOKEN_RING:
602 hardware->hbuf[0] = HTYPE_IEEE802; 602 hardware->hbuf[0] = HTYPE_IEEE802;
603 break; 603 break;
604 case TOKEN_FDDI: 604 case TOKEN_FDDI:
605 hardware->hbuf[0] = HTYPE_FDDI; 605 hardware->hbuf[0] = HTYPE_FDDI;
606 break; 606 break;
607 case TOKEN_INFINIBAND: 607 case TOKEN_INFINIBAND:
608 hardware->hbuf[0] = HTYPE_INFINIBAND; 608 hardware->hbuf[0] = HTYPE_INFINIBAND;
609 break; 609 break;
610 default: 610 default:
611 if (!strncmp(val, "unknown-", 8)) { 611 if (!strncmp(val, "unknown-", 8)) {
612 hardware->hbuf[0] = atoi(&val[8]); 612 hardware->hbuf[0] = atoi(&val[8]);
613 } else { 613 } else {
614 parse_warn(cfile, 614 parse_warn(cfile,
615 "expecting a network hardware type"); 615 "expecting a network hardware type");
616 skip_to_semi(cfile); 616 skip_to_semi(cfile);
617 617
618 return; 618 return;
619 } 619 }
620 } 620 }
621 621
622 /* Parse the hardware address information. Technically, 622 /* Parse the hardware address information. Technically,
623 it would make a lot of sense to restrict the length of the 623 it would make a lot of sense to restrict the length of the
624 data we'll accept here to the length of a particular hardware 624 data we'll accept here to the length of a particular hardware
625 address type. Unfortunately, there are some broken clients 625 address type. Unfortunately, there are some broken clients
626 out there that put bogus data in the chaddr buffer, and we accept 626 out there that put bogus data in the chaddr buffer, and we accept
627 that data in the lease file rather than simply failing on such 627 that data in the lease file rather than simply failing on such
628 clients. Yuck. */ 628 clients. Yuck. */
629 hlen = 0; 629 hlen = 0;
630 token = peek_token(&val, NULL, cfile); 630 token = peek_token(&val, NULL, cfile);
631 if (token == SEMI) { 631 if (token == SEMI) {
632 hardware->hlen = 1; 632 hardware->hlen = 1;
633 goto out; 633 goto out;
634 } 634 }
635 t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8); 635 t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
636 if (t == NULL) { 636 if (t == NULL) {
637 hardware->hlen = 1; 637 hardware->hlen = 1;
638 return; 638 return;
639 } 639 }
640 if (hlen + 1 > sizeof(hardware->hbuf)) { 640 if (hlen + 1 > sizeof(hardware->hbuf)) {
641 dfree(t, MDL); 641 dfree(t, MDL);
642 parse_warn(cfile, "hardware address too long"); 642 parse_warn(cfile, "hardware address too long");
643 } else { 643 } else {
644 hardware->hlen = hlen + 1; 644 hardware->hlen = hlen + 1;
645 memcpy((unsigned char *)&hardware->hbuf[1], t, hlen); 645 memcpy((unsigned char *)&hardware->hbuf[1], t, hlen);
646 if (hlen + 1 < sizeof(hardware->hbuf)) 646 if (hlen + 1 < sizeof(hardware->hbuf))
647 memset(&hardware->hbuf[hlen + 1], 0, 647 memset(&hardware->hbuf[hlen + 1], 0,
648 (sizeof(hardware->hbuf)) - hlen - 1); 648 (sizeof(hardware->hbuf)) - hlen - 1);
649 dfree(t, MDL); 649 dfree(t, MDL);
650 } 650 }
651  651
652 out: 652 out:
653 token = next_token(&val, NULL, cfile); 653 token = next_token(&val, NULL, cfile);
654 if (token != SEMI) { 654 if (token != SEMI) {
655 parse_warn(cfile, "expecting semicolon."); 655 parse_warn(cfile, "expecting semicolon.");
656 skip_to_semi(cfile); 656 skip_to_semi(cfile);
657 } 657 }
658} 658}
659 659
660/* lease-time :== NUMBER SEMI */ 660/* lease-time :== NUMBER SEMI */
661 661
662void parse_lease_time (cfile, timep) 662void parse_lease_time (cfile, timep)
663 struct parse *cfile; 663 struct parse *cfile;
664 TIME *timep; 664 TIME *timep;
665{ 665{
666 const char *val; 666 const char *val;
667 enum dhcp_token token; 667 enum dhcp_token token;
668 u_int32_t num; 668 u_int32_t num;
669 669
670 token = next_token (&val, (unsigned *)0, cfile); 670 token = next_token (&val, (unsigned *)0, cfile);
671 if (token != NUMBER) { 671 if (token != NUMBER) {
672 parse_warn (cfile, "Expecting numeric lease time"); 672 parse_warn (cfile, "Expecting numeric lease time");
673 skip_to_semi (cfile); 673 skip_to_semi (cfile);
674 return; 674 return;
675 } 675 }
676 convert_num(cfile, (unsigned char *)&num, val, 10, 32); 676 convert_num(cfile, (unsigned char *)&num, val, 10, 32);
677 /* Unswap the number - convert_num returns stuff in NBO. */ 677 /* Unswap the number - convert_num returns stuff in NBO. */
678 *timep = ntohl(num); 678 *timep = ntohl(num);
679 679
680 parse_semi (cfile); 680 parse_semi (cfile);
681} 681}
682 682
683/* No BNF for numeric aggregates - that's defined by the caller. What 683/* No BNF for numeric aggregates - that's defined by the caller. What
684 this function does is to parse a sequence of numbers separated by 684 this function does is to parse a sequence of numbers separated by
685 the token specified in separator. If max is zero, any number of 685 the token specified in separator. If max is zero, any number of
686 numbers will be parsed; otherwise, exactly max numbers are 686 numbers will be parsed; otherwise, exactly max numbers are
687 expected. Base and size tell us how to internalize the numbers 687 expected. Base and size tell us how to internalize the numbers
688 once they've been tokenized. 688 once they've been tokenized.
689 689
690 buf - A pointer to space to return the parsed value, if it is null 690 buf - A pointer to space to return the parsed value, if it is null
691 then the function will allocate space for the return. 691 then the function will allocate space for the return.
692 692
693 max - The maximum number of items to store. If zero there is no 693 max - The maximum number of items to store. If zero there is no
694 maximum. When buf is null and the function needs to allocate space 694 maximum. When buf is null and the function needs to allocate space
695 it will do an allocation of max size at the beginning if max is non 695 it will do an allocation of max size at the beginning if max is non
696 zero. If max is zero then the allocation will be done later, after 696 zero. If max is zero then the allocation will be done later, after
697 the function has determined the size necessary for the incoming 697 the function has determined the size necessary for the incoming
698 string. 698 string.
699 699
700 returns NULL on errors or a pointer to the value string on success. 700 returns NULL on errors or a pointer to the value string on success.
701 The pointer will either be buf if it was non-NULL or newly allocated 701 The pointer will either be buf if it was non-NULL or newly allocated
702 space if buf was NULL 702 space if buf was NULL
703 */ 703 */
704 704
705 705
706unsigned char *parse_numeric_aggregate (cfile, buf, 706unsigned char *parse_numeric_aggregate (cfile, buf,
707 max, separator, base, size) 707 max, separator, base, size)
708 struct parse *cfile; 708 struct parse *cfile;
709 unsigned char *buf; 709 unsigned char *buf;
710 unsigned *max; 710 unsigned *max;
711 int separator; 711 int separator;
712 int base; 712 int base;
713 unsigned size; 713 unsigned size;
714{ 714{
715 const char *val; 715 const char *val;
716 enum dhcp_token token; 716 enum dhcp_token token;
717 unsigned char *bufp = buf, *s, *t; 717 unsigned char *bufp = buf, *s, *t;
718 unsigned count = 0; 718 unsigned count = 0;
719 pair c = (pair)0; 719 pair c = (pair)0;
720 720
721 if (!bufp && *max) { 721 if (!bufp && *max) {
722 bufp = (unsigned char *)dmalloc (*max * size / 8, MDL); 722 bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
723 if (!bufp) 723 if (!bufp)
724 log_fatal ("no space for numeric aggregate"); 724 log_fatal ("no space for numeric aggregate");
725 } 725 }
726 s = bufp; 726 s = bufp;
727 727
728 do { 728 do {
729 if (count) { 729 if (count) {
730 token = peek_token (&val, (unsigned *)0, cfile); 730 token = peek_token (&val, (unsigned *)0, cfile);
731 if (token != separator) { 731 if (token != separator) {
732 if (!*max) 732 if (!*max)
733 break; 733 break;
734 if (token != RBRACE && token != LBRACE) 734 if (token != RBRACE && token != LBRACE)
735 token = next_token (&val, 735 token = next_token (&val,
736 (unsigned *)0, 736 (unsigned *)0,
737 cfile); 737 cfile);
738 parse_warn (cfile, "too few numbers."); 738 parse_warn (cfile, "too few numbers.");
739 if (token != SEMI) 739 if (token != SEMI)
740 skip_to_semi (cfile); 740 skip_to_semi (cfile);
741 /* free bufp if it was allocated */ 741 /* free bufp if it was allocated */
742 if ((bufp != NULL) && (bufp != buf)) 742 if ((bufp != NULL) && (bufp != buf))
743 dfree(bufp, MDL); 743 dfree(bufp, MDL);
744 return (unsigned char *)0; 744 return (unsigned char *)0;
745 } 745 }
746 skip_token(&val, (unsigned *)0, cfile); 746 skip_token(&val, (unsigned *)0, cfile);
747 } 747 }
748 token = next_token (&val, (unsigned *)0, cfile); 748 token = next_token (&val, (unsigned *)0, cfile);
749 749
750 if (token == END_OF_FILE) { 750 if (token == END_OF_FILE) {
751 parse_warn (cfile, "unexpected end of file"); 751 parse_warn (cfile, "unexpected end of file");
752 break; 752 break;
753 } 753 }
754 754
755 /* Allow NUMBER_OR_NAME if base is 16. */ 755 /* Allow NUMBER_OR_NAME if base is 16. */
756 if (token != NUMBER && 756 if (token != NUMBER &&
757 (base != 16 || token != NUMBER_OR_NAME)) { 757 (base != 16 || token != NUMBER_OR_NAME)) {
758 parse_warn (cfile, "expecting numeric value."); 758 parse_warn (cfile, "expecting numeric value.");
759 skip_to_semi (cfile); 759 skip_to_semi (cfile);
760 /* free bufp if it was allocated */ 760 /* free bufp if it was allocated */
761 if ((bufp != NULL) && (bufp != buf)) 761 if ((bufp != NULL) && (bufp != buf))
762 dfree(bufp, MDL); 762 dfree(bufp, MDL);
763 /* free any linked numbers we may have allocated */ 763 /* free any linked numbers we may have allocated */
764 while (c) { 764 while (c) {
765 pair cdr = c->cdr; 765 pair cdr = c->cdr;
766 dfree(c->car, MDL); 766 dfree(c->car, MDL);
767 dfree(c, MDL); 767 dfree(c, MDL);
768 c = cdr; 768 c = cdr;
769 } 769 }
770 return (NULL); 770 return (NULL);
771 } 771 }
772 /* If we can, convert the number now; otherwise, build 772 /* If we can, convert the number now; otherwise, build
773 a linked list of all the numbers. */ 773 a linked list of all the numbers. */
774 if (s) { 774 if (s) {
775 convert_num (cfile, s, val, base, size); 775 convert_num (cfile, s, val, base, size);
776 s += size / 8; 776 s += size / 8;
777 } else { 777 } else {
778 t = (unsigned char *)dmalloc (strlen (val) + 1, MDL); 778 t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
779 if (!t) 779 if (!t)
780 log_fatal ("no temp space for number."); 780 log_fatal ("no temp space for number.");
781 strcpy ((char *)t, val); 781 strcpy ((char *)t, val);
782 c = cons ((caddr_t)t, c); 782 c = cons ((caddr_t)t, c);
783 } 783 }
784 } while (++count != *max); 784 } while (++count != *max);
785 785
786 /* If we had to cons up a list, convert it now. */ 786 /* If we had to cons up a list, convert it now. */
787 if (c) { 787 if (c) {
788 /* 788 /*
789 * No need to cleanup bufp, to get here we didn't allocate 789 * No need to cleanup bufp, to get here we didn't allocate
790 * bufp above 790 * bufp above
791 */ 791 */
792 bufp = (unsigned char *)dmalloc (count * size / 8, MDL); 792 bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
793 if (!bufp) 793 if (!bufp)
794 log_fatal ("no space for numeric aggregate."); 794 log_fatal ("no space for numeric aggregate.");
795 s = bufp + count - size / 8; 795 s = bufp + count - size / 8;
796 *max = count; 796 *max = count;
797 } 797 }
798 while (c) { 798 while (c) {
799 pair cdr = c -> cdr; 799 pair cdr = c -> cdr;
800 convert_num (cfile, s, (char *)(c -> car), base, size); 800 convert_num (cfile, s, (char *)(c -> car), base, size);
801 s -= size / 8; 801 s -= size / 8;
802 /* Free up temp space. */ 802 /* Free up temp space. */
803 dfree (c -> car, MDL); 803 dfree (c -> car, MDL);
804 dfree (c, MDL); 804 dfree (c, MDL);
805 c = cdr; 805 c = cdr;
806 } 806 }
807 return bufp; 807 return bufp;
808} 808}
809 809
810void convert_num (cfile, buf, str, base, size) 810void convert_num (cfile, buf, str, base, size)
811 struct parse *cfile; 811 struct parse *cfile;
812 unsigned char *buf; 812 unsigned char *buf;
813 const char *str; 813 const char *str;
814 int base; 814 int base;
815 unsigned size; 815 unsigned size;
816{ 816{
817 const unsigned char *ptr = (const unsigned char *)str; 817 const unsigned char *ptr = (const unsigned char *)str;
818 int negative = 0; 818 int negative = 0;
819 u_int32_t val = 0; 819 u_int32_t val = 0;
820 int tval; 820 int tval;
821 int max; 821 int max;
822 822
823 if (*ptr == '-') { 823 if (*ptr == '-') {
824 negative = 1; 824 negative = 1;
825 ++ptr; 825 ++ptr;
826 } 826 }
827 827
828 /* If base wasn't specified, figure it out from the data. */ 828 /* If base wasn't specified, figure it out from the data. */
829 if (!base) { 829 if (!base) {
830 if (ptr [0] == '0') { 830 if (ptr [0] == '0') {
831 if (ptr [1] == 'x') { 831 if (ptr [1] == 'x') {
832 base = 16; 832 base = 16;
833 ptr += 2; 833 ptr += 2;
834 } else if (isascii (ptr [1]) && isdigit (ptr [1])) { 834 } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
835 base = 8; 835 base = 8;
836 ptr += 1; 836 ptr += 1;
837 } else { 837 } else {
838 base = 10; 838 base = 10;
839 } 839 }
840 } else { 840 } else {
841 base = 10; 841 base = 10;
842 } 842 }
843 } 843 }
844 844
845 do { 845 do {
846 tval = *ptr++; 846 tval = *ptr++;
847 /* XXX assumes ASCII... */ 847 /* XXX assumes ASCII... */
848 if (tval >= 'a') 848 if (tval >= 'a')
849 tval = tval - 'a' + 10; 849 tval = tval - 'a' + 10;
850 else if (tval >= 'A') 850 else if (tval >= 'A')
851 tval = tval - 'A' + 10; 851 tval = tval - 'A' + 10;
852 else if (tval >= '0') 852 else if (tval >= '0')
853 tval -= '0'; 853 tval -= '0';
854 else { 854 else {
855 parse_warn (cfile, "Bogus number: %s.", str); 855 parse_warn (cfile, "Bogus number: %s.", str);
856 break; 856 break;
857 } 857 }
858 if (tval >= base) { 858 if (tval >= base) {
859 parse_warn (cfile, 859 parse_warn (cfile,
860 "Bogus number %s: digit %d not in base %d", 860 "Bogus number %s: digit %d not in base %d",
861 str, tval, base); 861 str, tval, base);
862 break; 862 break;
863 } 863 }
864 val = val * base + tval; 864 val = val * base + tval;
865 } while (*ptr); 865 } while (*ptr);
866 866
867 if (negative) 867 if (negative)
868 max = (1 << (size - 1)); 868 max = (1 << (size - 1));
869 else 869 else
870 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); 870 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
871 if (val > max) { 871 if (val > max) {
872 switch (base) { 872 switch (base) {
873 case 8: 873 case 8:
874 parse_warn (cfile, 874 parse_warn (cfile,
875 "%s%lo exceeds max (%d) for precision.", 875 "%s%lo exceeds max (%d) for precision.",
876 negative ? "-" : "", 876 negative ? "-" : "",
877 (unsigned long)val, max); 877 (unsigned long)val, max);
878 break; 878 break;
879 case 16: 879 case 16:
880 parse_warn (cfile, 880 parse_warn (cfile,
881 "%s%lx exceeds max (%d) for precision.", 881 "%s%lx exceeds max (%d) for precision.",
882 negative ? "-" : "", 882 negative ? "-" : "",
883 (unsigned long)val, max); 883 (unsigned long)val, max);
884 break; 884 break;
885 default: 885 default:
886 parse_warn (cfile, 886 parse_warn (cfile,
887 "%s%lu exceeds max (%d) for precision.", 887 "%s%lu exceeds max (%d) for precision.",
888 negative ? "-" : "", 888 negative ? "-" : "",
889 (unsigned long)val, max); 889 (unsigned long)val, max);
890 break; 890 break;
891 } 891 }
892 } 892 }
893 893
894 if (negative) { 894 if (negative) {
895 switch (size) { 895 switch (size) {
896 case 8: 896 case 8:
897 *buf = -(unsigned long)val; 897 *buf = -(unsigned long)val;
898 break; 898 break;
899 case 16: 899 case 16:
900 putShort (buf, -(long)val); 900 putShort (buf, -(long)val);
901 break; 901 break;
902 case 32: 902 case 32:
903 putLong (buf, -(long)val); 903 putLong (buf, -(long)val);
904 break; 904 break;
905 default: 905 default:
906 parse_warn (cfile, 906 parse_warn (cfile,
907 "Unexpected integer size: %d\n", size); 907 "Unexpected integer size: %d\n", size);
908 break; 908 break;
909 } 909 }
910 } else { 910 } else {
911 switch (size) { 911 switch (size) {
912 case 8: 912 case 8:
913 *buf = (u_int8_t)val; 913 *buf = (u_int8_t)val;
914 break; 914 break;
915 case 16: 915 case 16:
916 putUShort (buf, (u_int16_t)val); 916 putUShort (buf, (u_int16_t)val);
917 break; 917 break;
918 case 32: 918 case 32:
919 putULong (buf, val); 919 putULong (buf, val);
920 break; 920 break;
921 default: 921 default:
922 parse_warn (cfile, 922 parse_warn (cfile,
923 "Unexpected integer size: %d\n", size); 923 "Unexpected integer size: %d\n", size);
924 break; 924 break;
925 } 925 }
926 } 926 }
927} 927}
928 928
929/* 929/*
930 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER  930 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
931 * NUMBER COLON NUMBER COLON NUMBER | 931 * NUMBER COLON NUMBER COLON NUMBER |
932 * NUMBER NUMBER SLASH NUMBER SLASH NUMBER  932 * NUMBER NUMBER SLASH NUMBER SLASH NUMBER
933 * NUMBER COLON NUMBER COLON NUMBER NUMBER | 933 * NUMBER COLON NUMBER COLON NUMBER NUMBER |
934 * EPOCH NUMBER | 934 * EPOCH NUMBER |
935 * NEVER 935 * NEVER
936 * 936 *
937 * Dates are stored in UTC or with a timezone offset; first number is day 937 * Dates are stored in UTC or with a timezone offset; first number is day
938 * of week; next is year/month/day; next is hours:minutes:seconds on a 938 * of week; next is year/month/day; next is hours:minutes:seconds on a
939 * 24-hour clock, followed by the timezone offset in seconds, which is 939 * 24-hour clock, followed by the timezone offset in seconds, which is
940 * optional. 940 * optional.
941 */ 941 */
942 942
943/* 943/*
944 * just parse the date 944 * just parse the date
945 * any trailing semi must be consumed by the caller of this routine 945 * any trailing semi must be consumed by the caller of this routine
946 */ 946 */
947TIME  947TIME
948parse_date_core(cfile) 948parse_date_core(cfile)
949 struct parse *cfile; 949 struct parse *cfile;
950{ 950{
951 int guess; 951 int guess;
952 int tzoff, year, mon, mday, hour, min, sec; 952 int tzoff, year, mon, mday, hour, min, sec;
953 const char *val; 953 const char *val;
954 enum dhcp_token token; 954 enum dhcp_token token;
955 static int months[11] = { 31, 59, 90, 120, 151, 181, 955 static int months[11] = { 31, 59, 90, 120, 151, 181,
956 212, 243, 273, 304, 334 }; 956 212, 243, 273, 304, 334 };
957 957
958 /* "never", "epoch" or day of week */ 958 /* "never", "epoch" or day of week */
959 token = peek_token(&val, NULL, cfile); 959 token = peek_token(&val, NULL, cfile);
960 if (token == NEVER) { 960 if (token == NEVER) {
961 skip_token(&val, NULL, cfile); /* consume NEVER */ 961 skip_token(&val, NULL, cfile); /* consume NEVER */
962 return(MAX_TIME); 962 return(MAX_TIME);
963 } 963 }
964 964
965 /* This indicates 'local' time format. */ 965 /* This indicates 'local' time format. */
966 if (token == EPOCH) { 966 if (token == EPOCH) {
967 skip_token(&val, NULL, cfile); /* consume EPOCH */ 967 skip_token(&val, NULL, cfile); /* consume EPOCH */
968 token = peek_token(&val, NULL, cfile); 968 token = peek_token(&val, NULL, cfile);
969 969
970 if (token != NUMBER) { 970 if (token != NUMBER) {
971 if (token != SEMI) 971 if (token != SEMI)
972 skip_token(&val, NULL, cfile); 972 skip_token(&val, NULL, cfile);
973 parse_warn(cfile, "Seconds since epoch expected."); 973 parse_warn(cfile, "Seconds since epoch expected.");
974 return((TIME)0); 974 return((TIME)0);
975 } 975 }
976 976
977 skip_token(&val, NULL, cfile); /* consume number */ 977 skip_token(&val, NULL, cfile); /* consume number */
978 guess = atoi(val); 978 guess = atoi(val);
979 979
980 return((TIME)guess); 980 return((TIME)guess);
981 } 981 }
982 982
983 if (token != NUMBER) { 983 if (token != NUMBER) {
984 if (token != SEMI) 984 if (token != SEMI)
985 skip_token(&val, NULL, cfile); 985 skip_token(&val, NULL, cfile);
986 parse_warn(cfile, "numeric day of week expected."); 986 parse_warn(cfile, "numeric day of week expected.");
987 return((TIME)0); 987 return((TIME)0);
988 } 988 }
989 skip_token(&val, NULL, cfile); /* consume day of week */ 989 skip_token(&val, NULL, cfile); /* consume day of week */
990 /* we are not using this for anything */ 990 /* we are not using this for anything */
991 991
992 /* Year... */ 992 /* Year... */
993 token = peek_token(&val, NULL, cfile); 993 token = peek_token(&val, NULL, cfile);
994 if (token != NUMBER) { 994 if (token != NUMBER) {
995 if (token != SEMI) 995 if (token != SEMI)
996 skip_token(&val, NULL, cfile); 996 skip_token(&val, NULL, cfile);
997 parse_warn(cfile, "numeric year expected."); 997 parse_warn(cfile, "numeric year expected.");
998 return((TIME)0); 998 return((TIME)0);
999 } 999 }
1000 skip_token(&val, NULL, cfile); /* consume year */ 1000 skip_token(&val, NULL, cfile); /* consume year */
1001 1001
1002 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until 1002 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
1003 somebody invents a time machine, I think we can safely disregard 1003 somebody invents a time machine, I think we can safely disregard
1004 it. This actually works around a stupid Y2K bug that was present 1004 it. This actually works around a stupid Y2K bug that was present
1005 in a very early beta release of dhcpd. */ 1005 in a very early beta release of dhcpd. */
1006 year = atoi(val); 1006 year = atoi(val);
1007 if (year > 1900) 1007 if (year > 1900)
1008 year -= 1900; 1008 year -= 1900;
1009 1009
1010 /* Slash separating year from month... */ 1010 /* Slash separating year from month... */
1011 token = peek_token(&val, NULL, cfile); 1011 token = peek_token(&val, NULL, cfile);
1012 if (token != SLASH) { 1012 if (token != SLASH) {
1013 if (token != SEMI) 1013 if (token != SEMI)
1014 skip_token(&val, NULL, cfile); 1014 skip_token(&val, NULL, cfile);
1015 parse_warn(cfile, 1015 parse_warn(cfile,
1016 "expected slash separating year from month."); 1016 "expected slash separating year from month.");
1017 return((TIME)0); 1017 return((TIME)0);
1018 } 1018 }
1019 skip_token(&val, NULL, cfile); /* consume SLASH */ 1019 skip_token(&val, NULL, cfile); /* consume SLASH */
1020 1020
1021 /* Month... */ 1021 /* Month... */
1022 token = peek_token(&val, NULL, cfile); 1022 token = peek_token(&val, NULL, cfile);
1023 if (token != NUMBER) { 1023 if (token != NUMBER) {
1024 if (token != SEMI) 1024 if (token != SEMI)
1025 skip_token(&val, NULL, cfile); 1025 skip_token(&val, NULL, cfile);
1026 parse_warn(cfile, "numeric month expected."); 1026 parse_warn(cfile, "numeric month expected.");
1027 return((TIME)0); 1027 return((TIME)0);
1028 } 1028 }
1029 skip_token(&val, NULL, cfile); /* consume month */  1029 skip_token(&val, NULL, cfile); /* consume month */
1030 mon = atoi(val) - 1; 1030 mon = atoi(val) - 1;
1031 1031
@@ -4565,1208 +4565,1209 @@ int parse_expression (expr, cfile, lose, @@ -4565,1208 +4565,1209 @@ int parse_expression (expr, cfile, lose,
4565 context = expression_context (rhs); 4565 context = expression_context (rhs);
4566 break; 4566 break;
4567 4567
4568 case OR: 4568 case OR:
4569 next_op = expr_or; 4569 next_op = expr_or;
4570 context = expression_context (rhs); 4570 context = expression_context (rhs);
4571 break; 4571 break;
4572 4572
4573 case PLUS: 4573 case PLUS:
4574 next_op = expr_add; 4574 next_op = expr_add;
4575 context = expression_context (rhs); 4575 context = expression_context (rhs);
4576 break; 4576 break;
4577 4577
4578 case MINUS: 4578 case MINUS:
4579 next_op = expr_subtract; 4579 next_op = expr_subtract;
4580 context = expression_context (rhs); 4580 context = expression_context (rhs);
4581 break; 4581 break;
4582 4582
4583 case SLASH: 4583 case SLASH:
4584 next_op = expr_divide; 4584 next_op = expr_divide;
4585 context = expression_context (rhs); 4585 context = expression_context (rhs);
4586 break; 4586 break;
4587 4587
4588 case ASTERISK: 4588 case ASTERISK:
4589 next_op = expr_multiply; 4589 next_op = expr_multiply;
4590 context = expression_context (rhs); 4590 context = expression_context (rhs);
4591 break; 4591 break;
4592 4592
4593 case PERCENT: 4593 case PERCENT:
4594 next_op = expr_remainder; 4594 next_op = expr_remainder;
4595 context = expression_context (rhs); 4595 context = expression_context (rhs);
4596 break; 4596 break;
4597 4597
4598 case AMPERSAND: 4598 case AMPERSAND:
4599 next_op = expr_binary_and; 4599 next_op = expr_binary_and;
4600 context = expression_context (rhs); 4600 context = expression_context (rhs);
4601 break; 4601 break;
4602 4602
4603 case PIPE: 4603 case PIPE:
4604 next_op = expr_binary_or; 4604 next_op = expr_binary_or;
4605 context = expression_context (rhs); 4605 context = expression_context (rhs);
4606 break; 4606 break;
4607 4607
4608 case CARET: 4608 case CARET:
4609 next_op = expr_binary_xor; 4609 next_op = expr_binary_xor;
4610 context = expression_context (rhs); 4610 context = expression_context (rhs);
4611 break; 4611 break;
4612 4612
4613 default: 4613 default:
4614 next_op = expr_none; 4614 next_op = expr_none;
4615 } 4615 }
4616 4616
4617 /* If we have no lhs yet, we just parsed it. */ 4617 /* If we have no lhs yet, we just parsed it. */
4618 if (!lhs) { 4618 if (!lhs) {
4619 /* If there was no operator following what we just parsed, 4619 /* If there was no operator following what we just parsed,
4620 then we're done - return it. */ 4620 then we're done - return it. */
4621 if (next_op == expr_none) { 4621 if (next_op == expr_none) {
4622 *expr = rhs; 4622 *expr = rhs;
4623 return 1; 4623 return 1;
4624 } 4624 }
4625 lhs = rhs; 4625 lhs = rhs;
4626 rhs = (struct expression *)0; 4626 rhs = (struct expression *)0;
4627 binop = next_op; 4627 binop = next_op;
4628 skip_token(&val, (unsigned *)0, cfile); 4628 skip_token(&val, (unsigned *)0, cfile);
4629 goto new_rhs; 4629 goto new_rhs;
4630 } 4630 }
4631 4631
4632 /* If the next binary operator is of greater precedence than the 4632 /* If the next binary operator is of greater precedence than the
4633 * current operator, then rhs we have parsed so far is actually 4633 * current operator, then rhs we have parsed so far is actually
4634 * the lhs of the next operator. To get this value, we have to 4634 * the lhs of the next operator. To get this value, we have to
4635 * recurse. 4635 * recurse.
4636 */ 4636 */
4637 if (binop != expr_none && next_op != expr_none && 4637 if (binop != expr_none && next_op != expr_none &&
4638 op_precedence (binop, next_op) < 0) { 4638 op_precedence (binop, next_op) < 0) {
4639 4639
4640 /* Eat the subexpression operator token, which we pass to 4640 /* Eat the subexpression operator token, which we pass to
4641 * parse_expression...we only peek()'d earlier. 4641 * parse_expression...we only peek()'d earlier.
4642 */ 4642 */
4643 skip_token(&val, (unsigned *)0, cfile); 4643 skip_token(&val, (unsigned *)0, cfile);
4644 4644
4645 /* Continue parsing of the right hand side with that token. */ 4645 /* Continue parsing of the right hand side with that token. */
4646 tmp = rhs; 4646 tmp = rhs;
4647 rhs = (struct expression *)0; 4647 rhs = (struct expression *)0;
4648 if (!parse_expression (&rhs, cfile, lose, op_context (next_op), 4648 if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
4649 &tmp, next_op)) { 4649 &tmp, next_op)) {
4650 if (!*lose) { 4650 if (!*lose) {
4651 parse_warn (cfile, 4651 parse_warn (cfile,
4652 "expecting a subexpression"); 4652 "expecting a subexpression");
4653 *lose = 1; 4653 *lose = 1;
4654 } 4654 }
4655 return 0; 4655 return 0;
4656 } 4656 }
4657 next_op = expr_none; 4657 next_op = expr_none;
4658 } 4658 }
4659 4659
4660 if (binop != expr_none) { 4660 if (binop != expr_none) {
4661 rhs_context = expression_context(rhs); 4661 rhs_context = expression_context(rhs);
4662 lhs_context = expression_context(lhs); 4662 lhs_context = expression_context(lhs);
4663 4663
4664 if ((rhs_context != context_any) && (lhs_context != context_any) && 4664 if ((rhs_context != context_any) && (lhs_context != context_any) &&
4665 (rhs_context != lhs_context)) { 4665 (rhs_context != lhs_context)) {
4666 parse_warn (cfile, "illegal expression relating different types"); 4666 parse_warn (cfile, "illegal expression relating different types");
4667 skip_to_semi (cfile); 4667 skip_to_semi (cfile);
4668 expression_dereference (&rhs, MDL); 4668 expression_dereference (&rhs, MDL);
4669 expression_dereference (&lhs, MDL); 4669 expression_dereference (&lhs, MDL);
4670 *lose = 1; 4670 *lose = 1;
4671 return 0; 4671 return 0;
4672 } 4672 }
4673 4673
4674 switch(binop) { 4674 switch(binop) {
4675 case expr_not_equal: 4675 case expr_not_equal:
4676 case expr_equal: 4676 case expr_equal:
4677 if ((rhs_context != context_data_or_numeric) && 4677 if ((rhs_context != context_data_or_numeric) &&
4678 (rhs_context != context_data) && 4678 (rhs_context != context_data) &&
4679 (rhs_context != context_numeric) && 4679 (rhs_context != context_numeric) &&
4680 (rhs_context != context_any)) { 4680 (rhs_context != context_any)) {
4681 parse_warn (cfile, "expecting data/numeric expression"); 4681 parse_warn (cfile, "expecting data/numeric expression");
4682 skip_to_semi (cfile); 4682 skip_to_semi (cfile);
4683 expression_dereference (&rhs, MDL); 4683 expression_dereference (&rhs, MDL);
4684 *lose = 1; 4684 *lose = 1;
4685 return 0; 4685 return 0;
4686 } 4686 }
4687 break; 4687 break;
4688 4688
4689 case expr_regex_match: 4689 case expr_regex_match:
4690#ifdef HAVE_REGEX_H 4690#ifdef HAVE_REGEX_H
4691 if (expression_context(rhs) != context_data) { 4691 if (expression_context(rhs) != context_data) {
4692 parse_warn(cfile, "expecting data expression"); 4692 parse_warn(cfile, "expecting data expression");
4693 skip_to_semi(cfile); 4693 skip_to_semi(cfile);
4694 expression_dereference(&rhs, MDL); 4694 expression_dereference(&rhs, MDL);
4695 *lose = 1; 4695 *lose = 1;
4696 return 0; 4696 return 0;
4697 } 4697 }
4698#else 4698#else
4699 /* It should not be possible to attempt to parse the right 4699 /* It should not be possible to attempt to parse the right
4700 * hand side of an operator there is no support for. 4700 * hand side of an operator there is no support for.
4701 */ 4701 */
4702 log_fatal("Impossible condition at %s:%d.", MDL); 4702 log_fatal("Impossible condition at %s:%d.", MDL);
4703#endif 4703#endif
4704 break; 4704 break;
4705 4705
4706 case expr_and: 4706 case expr_and:
4707 case expr_or: 4707 case expr_or:
4708 if ((rhs_context != context_boolean) && 4708 if ((rhs_context != context_boolean) &&
4709 (rhs_context != context_any)) { 4709 (rhs_context != context_any)) {
4710 parse_warn (cfile, "expecting boolean expressions"); 4710 parse_warn (cfile, "expecting boolean expressions");
4711 skip_to_semi (cfile); 4711 skip_to_semi (cfile);
4712 expression_dereference (&rhs, MDL); 4712 expression_dereference (&rhs, MDL);
4713 *lose = 1; 4713 *lose = 1;
4714 return 0; 4714 return 0;
4715 } 4715 }
4716 break; 4716 break;
4717 4717
4718 case expr_add: 4718 case expr_add:
4719 case expr_subtract: 4719 case expr_subtract:
4720 case expr_divide: 4720 case expr_divide:
4721 case expr_multiply: 4721 case expr_multiply:
4722 case expr_remainder: 4722 case expr_remainder:
4723 case expr_binary_and: 4723 case expr_binary_and:
4724 case expr_binary_or: 4724 case expr_binary_or:
4725 case expr_binary_xor: 4725 case expr_binary_xor:
4726 if ((rhs_context != context_numeric) && 4726 if ((rhs_context != context_numeric) &&
4727 (rhs_context != context_any)) { 4727 (rhs_context != context_any)) {
4728 parse_warn (cfile, "expecting numeric expressions"); 4728 parse_warn (cfile, "expecting numeric expressions");
4729 skip_to_semi (cfile); 4729 skip_to_semi (cfile);
4730 expression_dereference (&rhs, MDL); 4730 expression_dereference (&rhs, MDL);
4731 *lose = 1; 4731 *lose = 1;
4732 return 0; 4732 return 0;
4733 } 4733 }
4734 break; 4734 break;
4735 4735
4736 default: 4736 default:
4737 break; 4737 break;
4738 } 4738 }
4739 } 4739 }
4740 4740
4741 /* Now, if we didn't find a binary operator, we're done parsing 4741 /* Now, if we didn't find a binary operator, we're done parsing
4742 this subexpression, so combine it with the preceding binary 4742 this subexpression, so combine it with the preceding binary
4743 operator and return the result. */ 4743 operator and return the result. */
4744 if (next_op == expr_none) { 4744 if (next_op == expr_none) {
4745 if (!expression_allocate (expr, MDL)) 4745 if (!expression_allocate (expr, MDL))
4746 log_fatal ("Can't allocate expression!"); 4746 log_fatal ("Can't allocate expression!");
4747 4747
4748 (*expr) -> op = binop; 4748 (*expr) -> op = binop;
4749 /* All the binary operators' data union members 4749 /* All the binary operators' data union members
4750 are the same, so we'll cheat and use the member 4750 are the same, so we'll cheat and use the member
4751 for the equals operator. */ 4751 for the equals operator. */
4752 (*expr) -> data.equal [0] = lhs; 4752 (*expr) -> data.equal [0] = lhs;
4753 (*expr) -> data.equal [1] = rhs; 4753 (*expr) -> data.equal [1] = rhs;
4754 return 1; 4754 return 1;
4755 } 4755 }
4756 4756
4757 /* Eat the operator token - we now know it was a binary operator... */ 4757 /* Eat the operator token - we now know it was a binary operator... */
4758 skip_token(&val, (unsigned *)0, cfile); 4758 skip_token(&val, (unsigned *)0, cfile);
4759 4759
4760 /* Now combine the LHS and the RHS using binop. */ 4760 /* Now combine the LHS and the RHS using binop. */
4761 tmp = (struct expression *)0; 4761 tmp = (struct expression *)0;
4762 if (!expression_allocate (&tmp, MDL)) 4762 if (!expression_allocate (&tmp, MDL))
4763 log_fatal ("No memory for equal precedence combination."); 4763 log_fatal ("No memory for equal precedence combination.");
4764  4764
4765 /* Store the LHS and RHS. */ 4765 /* Store the LHS and RHS. */
4766 tmp -> data.equal [0] = lhs; 4766 tmp -> data.equal [0] = lhs;
4767 tmp -> data.equal [1] = rhs; 4767 tmp -> data.equal [1] = rhs;
4768 tmp -> op = binop; 4768 tmp -> op = binop;
4769  4769
4770 lhs = tmp; 4770 lhs = tmp;
4771 tmp = (struct expression *)0; 4771 tmp = (struct expression *)0;
4772 rhs = (struct expression *)0; 4772 rhs = (struct expression *)0;
4773 4773
4774 binop = next_op; 4774 binop = next_op;
4775 goto new_rhs; 4775 goto new_rhs;
4776}  4776}
4777 4777
4778 4778
4779int parse_option_data (expr, cfile, lookups, option) 4779int parse_option_data (expr, cfile, lookups, option)
4780struct expression **expr; 4780struct expression **expr;
4781struct parse *cfile; 4781struct parse *cfile;
4782int lookups; 4782int lookups;
4783struct option *option; 4783struct option *option;
4784{ 4784{
4785 const char *val; 4785 const char *val;
4786 const char *fmt = NULL; 4786 const char *fmt = NULL;
4787 struct expression *tmp; 4787 struct expression *tmp;
4788 enum dhcp_token token; 4788 enum dhcp_token token;
4789 4789
4790 do { 4790 do {
4791 /* 4791 /*
4792 * Set a flag if this is an array of a simple type (i.e., 4792 * Set a flag if this is an array of a simple type (i.e.,
4793 * not an array of pairs of IP addresses, or something like 4793 * not an array of pairs of IP addresses, or something like
4794 * that. 4794 * that.
4795 */ 4795 */
4796 int uniform = 0; 4796 int uniform = 0;
4797 4797
4798 and_again: 4798 and_again:
4799 /* Set fmt to start of format for 'A' and one char back 4799 /* Set fmt to start of format for 'A' and one char back
4800 * for 'a'. 4800 * for 'a'.
4801 */ 4801 */
4802 if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a')) 4802 if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a'))
4803 fmt -= 1; 4803 fmt -= 1;
4804 else if ((fmt == NULL) || (*fmt == 'A')) 4804 else if ((fmt == NULL) || (*fmt == 'A'))
4805 fmt = option->format; 4805 fmt = option->format;
4806 4806
4807 /* 'a' means always uniform */ 4807 /* 'a' means always uniform */
4808 if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a'))  4808 if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a'))
4809 uniform = 1; 4809 uniform = 1;
4810 4810
4811 do { 4811 do {
4812 if ((*fmt == 'A') || (*fmt == 'a')) 4812 if ((*fmt == 'A') || (*fmt == 'a'))
4813 break; 4813 break;
4814 if (*fmt == 'o') { 4814 if (*fmt == 'o') {
4815 /* consume the optional flag */ 4815 /* consume the optional flag */
4816 fmt++; 4816 fmt++;
4817 continue; 4817 continue;
4818 } 4818 }
4819 4819
4820 if (fmt[1] == 'o') { 4820 if (fmt[1] == 'o') {
4821 /* 4821 /*
4822 * A value for the current format is 4822 * A value for the current format is
4823 * optional - check to see if the next 4823 * optional - check to see if the next
4824 * token is a semi-colon if so we don't 4824 * token is a semi-colon if so we don't
4825 * need to parse it and doing so would 4825 * need to parse it and doing so would
4826 * consume the semi-colon which our 4826 * consume the semi-colon which our
4827 * caller is expecting to parse 4827 * caller is expecting to parse
4828 */ 4828 */
4829 token = peek_token(&val, (unsigned *)0, 4829 token = peek_token(&val, (unsigned *)0,
4830 cfile); 4830 cfile);
4831 if (token == SEMI) { 4831 if (token == SEMI) {
4832 fmt++; 4832 fmt++;
4833 continue; 4833 continue;
4834 } 4834 }
4835 } 4835 }
4836 4836
4837 tmp = *expr; 4837 tmp = *expr;
4838 *expr = NULL; 4838 *expr = NULL;
4839 4839
4840 if (!parse_option_token(expr, cfile, &fmt, tmp, 4840 if (!parse_option_token(expr, cfile, &fmt, tmp,
4841 uniform, lookups)) { 4841 uniform, lookups)) {
4842 if (fmt [1] != 'o') { 4842 if (fmt [1] != 'o') {
4843 if (tmp) 4843 if (tmp)
4844 expression_dereference (&tmp, 4844 expression_dereference (&tmp,
4845 MDL); 4845 MDL);
4846 return 0; 4846 return 0;
4847 } 4847 }
4848 *expr = tmp; 4848 *expr = tmp;
4849 tmp = NULL; 4849 tmp = NULL;
4850 } 4850 }
4851 if (tmp) 4851 if (tmp)
4852 expression_dereference (&tmp, MDL); 4852 expression_dereference (&tmp, MDL);
4853 4853
4854 fmt++; 4854 fmt++;
4855 } while (*fmt != '\0'); 4855 } while (*fmt != '\0');
4856 4856
4857 if ((*fmt == 'A') || (*fmt == 'a')) { 4857 if ((*fmt == 'A') || (*fmt == 'a')) {
4858 token = peek_token (&val, (unsigned *)0, cfile); 4858 token = peek_token (&val, (unsigned *)0, cfile);
4859 /* Comma means: continue with next element in array */ 4859 /* Comma means: continue with next element in array */
4860 if (token == COMMA) { 4860 if (token == COMMA) {
4861 skip_token(&val, (unsigned *)0, cfile); 4861 skip_token(&val, (unsigned *)0, cfile);
4862 continue; 4862 continue;
4863 } 4863 }
4864 /* no comma: end of array. 4864 /* no comma: end of array.
4865 'A' or end of string means: leave the loop */ 4865 'A' or end of string means: leave the loop */
4866 if ((*fmt == 'A') || (fmt[1] == '\0')) 4866 if ((*fmt == 'A') || (fmt[1] == '\0'))
4867 break; 4867 break;
4868 /* 'a' means: go on with next char */ 4868 /* 'a' means: go on with next char */
4869 if (*fmt == 'a') { 4869 if (*fmt == 'a') {
4870 fmt++; 4870 fmt++;
4871 goto and_again; 4871 goto and_again;
4872 } 4872 }
4873 } 4873 }
4874 } while ((*fmt == 'A') || (*fmt == 'a')); 4874 } while ((*fmt == 'A') || (*fmt == 'a'));
4875 4875
4876 return 1; 4876 return 1;
4877} 4877}
4878 4878
4879/* option-statement :== identifier DOT identifier <syntax> SEMI 4879/* option-statement :== identifier DOT identifier <syntax> SEMI
4880 | identifier <syntax> SEMI 4880 | identifier <syntax> SEMI
4881 4881
4882 Option syntax is handled specially through format strings, so it 4882 Option syntax is handled specially through format strings, so it
4883 would be painful to come up with BNF for it. However, it always 4883 would be painful to come up with BNF for it. However, it always
4884 starts as above and ends in a SEMI. */ 4884 starts as above and ends in a SEMI. */
4885 4885
4886int parse_option_statement (result, cfile, lookups, option, op) 4886int parse_option_statement (result, cfile, lookups, option, op)
4887 struct executable_statement **result; 4887 struct executable_statement **result;
4888 struct parse *cfile; 4888 struct parse *cfile;
4889 int lookups; 4889 int lookups;
4890 struct option *option; 4890 struct option *option;
4891 enum statement_op op; 4891 enum statement_op op;
4892{ 4892{
4893 const char *val; 4893 const char *val;
4894 enum dhcp_token token; 4894 enum dhcp_token token;
4895 struct expression *expr = (struct expression *)0; 4895 struct expression *expr = (struct expression *)0;
4896 int lose; 4896 int lose;
4897 4897
4898 token = peek_token (&val, (unsigned *)0, cfile); 4898 token = peek_token (&val, (unsigned *)0, cfile);
4899 if ((token == SEMI) && (option->format[0] != 'Z')) { 4899 if ((token == SEMI) && (option->format[0] != 'Z')) {
4900 /* Eat the semicolon... */ 4900 /* Eat the semicolon... */
4901 /* 4901 /*
4902 * XXXSK: I'm not sure why we should ever get here, but we  4902 * XXXSK: I'm not sure why we should ever get here, but we
4903 * do during our startup. This confuses things if 4903 * do during our startup. This confuses things if
4904 * we are parsing a zero-length option, so don't 4904 * we are parsing a zero-length option, so don't
4905 * eat the semicolon token in that case. 4905 * eat the semicolon token in that case.
4906 */ 4906 */
4907 skip_token(&val, (unsigned *)0, cfile); 4907 skip_token(&val, (unsigned *)0, cfile);
4908 } else if (token == EQUAL) { 4908 } else if (token == EQUAL) {
4909 /* Eat the equals sign. */ 4909 /* Eat the equals sign. */
4910 skip_token(&val, (unsigned *)0, cfile); 4910 skip_token(&val, (unsigned *)0, cfile);
4911 4911
4912 /* Parse a data expression and use its value for the data. */ 4912 /* Parse a data expression and use its value for the data. */
4913 if (!parse_data_expression (&expr, cfile, &lose)) { 4913 if (!parse_data_expression (&expr, cfile, &lose)) {
4914 /* In this context, we must have an executable 4914 /* In this context, we must have an executable
4915 statement, so if we found something else, it's 4915 statement, so if we found something else, it's
4916 still an error. */ 4916 still an error. */
4917 if (!lose) { 4917 if (!lose) {
4918 parse_warn (cfile, 4918 parse_warn (cfile,
4919 "expecting a data expression."); 4919 "expecting a data expression.");
4920 skip_to_semi (cfile); 4920 skip_to_semi (cfile);
4921 } 4921 }
4922 return 0; 4922 return 0;
4923 } 4923 }
4924 } else { 4924 } else {
4925 if (! parse_option_data(&expr, cfile, lookups, option)) 4925 if (! parse_option_data(&expr, cfile, lookups, option))
4926 return 0; 4926 return 0;
4927 } 4927 }
4928 4928
4929 if (!parse_semi (cfile)) 4929 if (!parse_semi (cfile))
4930 return 0; 4930 return 0;
4931 if (!executable_statement_allocate (result, MDL)) 4931 if (!executable_statement_allocate (result, MDL))
4932 log_fatal ("no memory for option statement."); 4932 log_fatal ("no memory for option statement.");
4933 4933
4934 (*result)->op = op; 4934 (*result)->op = op;
4935 if (expr && !option_cache (&(*result)->data.option, 4935 if (expr && !option_cache (&(*result)->data.option,
4936 NULL, expr, option, MDL)) 4936 NULL, expr, option, MDL))
4937 log_fatal ("no memory for option cache"); 4937 log_fatal ("no memory for option cache");
4938 4938
4939 if (expr) 4939 if (expr)
4940 expression_dereference (&expr, MDL); 4940 expression_dereference (&expr, MDL);
4941 4941
4942 return 1; 4942 return 1;
4943} 4943}
4944 4944
4945int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) 4945int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
4946 struct expression **rv; 4946 struct expression **rv;
4947 struct parse *cfile; 4947 struct parse *cfile;
4948 const char **fmt; 4948 const char **fmt;
4949 struct expression *expr; 4949 struct expression *expr;
4950 int uniform; 4950 int uniform;
4951 int lookups; 4951 int lookups;
4952{ 4952{
4953 const char *val; 4953 const char *val;
4954 enum dhcp_token token; 4954 enum dhcp_token token;
4955 struct expression *t = (struct expression *)0; 4955 struct expression *t = (struct expression *)0;
4956 unsigned char buf [4]; 4956 unsigned char buf [4];
4957 unsigned len; 4957 unsigned len;
4958 struct iaddr addr; 4958 struct iaddr addr;
4959 int compress; 4959 int compress;
4960 isc_boolean_t freeval = ISC_FALSE; 4960 isc_boolean_t freeval = ISC_FALSE;
4961 const char *f, *g; 4961 const char *f, *g;
4962 struct enumeration_value *e; 4962 struct enumeration_value *e;
4963 4963
4964 switch (**fmt) { 4964 switch (**fmt) {
4965 case 'U': 4965 case 'U':
4966 token = next_token (&val, &len, cfile); 4966 token = next_token (&val, &len, cfile);
4967 if (!is_identifier (token)) { 4967 if (!is_identifier (token)) {
4968 if ((*fmt) [1] != 'o') { 4968 if ((*fmt) [1] != 'o') {
4969 parse_warn (cfile, "expecting identifier."); 4969 parse_warn (cfile, "expecting identifier.");
4970 if (token != SEMI) 4970 if (token != SEMI)
4971 skip_to_semi (cfile); 4971 skip_to_semi (cfile);
4972 } 4972 }
4973 return 0; 4973 return 0;
4974 } 4974 }
4975 if (!make_const_data (&t, (const unsigned char *)val, 4975 if (!make_const_data (&t, (const unsigned char *)val,
4976 len, 1, 1, MDL)) 4976 len, 1, 1, MDL))
4977 log_fatal ("No memory for %s", val); 4977 log_fatal ("No memory for %s", val);
4978 break; 4978 break;
4979 4979
4980 case 'E': 4980 case 'E':
4981 g = strchr (*fmt, '.'); 4981 g = strchr (*fmt, '.');
4982 if (!g) { 4982 if (!g) {
4983 parse_warn (cfile, 4983 parse_warn (cfile,
4984 "malformed encapsulation format (bug!)"); 4984 "malformed encapsulation format (bug!)");
4985 skip_to_semi (cfile); 4985 skip_to_semi (cfile);
4986 return 0; 4986 return 0;
4987 } 4987 }
4988 *fmt = g; 4988 *fmt = g;
4989 /* FALL THROUGH */ 4989 /* FALL THROUGH */
4990 /* to get string value for the option */ 4990 /* to get string value for the option */
4991 case 'X': 4991 case 'X':
4992 token = peek_token (&val, (unsigned *)0, cfile); 4992 token = peek_token (&val, (unsigned *)0, cfile);
4993 if (token == NUMBER_OR_NAME || token == NUMBER) { 4993 if (token == NUMBER_OR_NAME || token == NUMBER) {
4994 if (!expression_allocate (&t, MDL)) 4994 if (!expression_allocate (&t, MDL))
4995 return 0; 4995 return 0;
4996 if (!parse_cshl (&t -> data.const_data, cfile)) { 4996 if (!parse_cshl (&t -> data.const_data, cfile)) {
4997 expression_dereference (&t, MDL); 4997 expression_dereference (&t, MDL);
4998 return 0; 4998 return 0;
4999 } 4999 }
5000 t -> op = expr_const_data; 5000 t -> op = expr_const_data;
5001 } else { 5001 } else {
5002 token = next_token (&val, &len, cfile); 5002 token = next_token (&val, &len, cfile);
5003 5003
5004 if(token == STRING) { 5004 if(token == STRING) {
5005 if (!make_const_data (&t, 5005 if (!make_const_data (&t,
5006 (const unsigned char *)val, 5006 (const unsigned char *)val,
5007 len, 1, 1, MDL)) 5007 len, 1, 1, MDL))
5008 log_fatal ("No memory for \"%s\"", val); 5008 log_fatal ("No memory for \"%s\"", val);
5009 } else { 5009 } else {
5010 if ((*fmt) [1] != 'o') { 5010 if ((*fmt) [1] != 'o') {
5011 parse_warn (cfile, "expecting string " 5011 parse_warn (cfile, "expecting string "
5012 "or hexadecimal data."); 5012 "or hexadecimal data.");
5013 skip_to_semi (cfile); 5013 skip_to_semi (cfile);
5014 } 5014 }
5015 return 0; 5015 return 0;
5016 } 5016 }
5017 } 5017 }
5018 break; 5018 break;
5019 5019
5020 case 'D': /* Domain list... */ 5020 case 'D': /* Domain list... */
5021 if ((*fmt)[1] == 'c') { 5021 if ((*fmt)[1] == 'c') {
5022 compress = 1; 5022 compress = 1;
5023 /* Skip the compress-flag atom. */ 5023 /* Skip the compress-flag atom. */
5024 (*fmt)++; 5024 (*fmt)++;
5025 } else 5025 } else
5026 compress = 0; 5026 compress = 0;
5027 5027
5028 t = parse_domain_list(cfile, compress); 5028 t = parse_domain_list(cfile, compress);
5029 5029
5030 if (!t) { 5030 if (!t) {
5031 if ((*fmt)[1] != 'o') 5031 if ((*fmt)[1] != 'o')
5032 skip_to_semi(cfile); 5032 skip_to_semi(cfile);
5033 return 0; 5033 return 0;
5034 } 5034 }
5035 5035
5036 break; 5036 break;
5037 5037
5038 case 'd': /* Domain name... */ 5038 case 'd': /* Domain name... */
5039 t = parse_domain_name(cfile); 5039 t = parse_domain_name(cfile);
5040 if (!t) { 5040 if (!t) {
5041 parse_warn(cfile, "not a valid domain name."); 5041 parse_warn(cfile, "not a valid domain name.");
5042 skip_to_semi(cfile); 5042 skip_to_semi(cfile);
5043 return 0; 5043 return 0;
5044 } 5044 }
5045 break; 5045 break;
5046 5046
5047 case 't': /* Text string... */ 5047 case 't': /* Text string... */
5048 token = next_token (&val, &len, cfile); 5048 token = next_token (&val, &len, cfile);
5049 if (token != STRING && !is_identifier (token)) { 5049 if (token != STRING && !is_identifier (token)) {
5050 if ((*fmt) [1] != 'o') { 5050 if ((*fmt) [1] != 'o') {
5051 parse_warn (cfile, "expecting string."); 5051 parse_warn (cfile, "expecting string.");
5052 if (token != SEMI) 5052 if (token != SEMI)
5053 skip_to_semi (cfile); 5053 skip_to_semi (cfile);
5054 } 5054 }
5055 return 0; 5055 return 0;
5056 } 5056 }
5057 if (!make_const_data (&t, (const unsigned char *)val, 5057 if (!make_const_data (&t, (const unsigned char *)val,
5058 len, 1, 1, MDL)) 5058 len, 1, 1, MDL))
5059 log_fatal ("No memory for concatenation"); 5059 log_fatal ("No memory for concatenation");
5060 if (freeval == ISC_TRUE) { 5060 if (freeval == ISC_TRUE) {
5061 dfree((char *)val, MDL); 5061 dfree((char *)val, MDL);
5062 freeval = ISC_FALSE; 5062 freeval = ISC_FALSE;
5063 POST(freeval); 5063 POST(freeval);
5064 } 5064 }
5065 break; 5065 break;
5066 5066
5067 case 'k': /* key name */  5067 case 'k': /* key name */
5068 token = peek_token (&val, &len, cfile); 5068 token = peek_token (&val, &len, cfile);
5069 if (token == STRING) { 5069 if (token == STRING) {
5070 token = next_token (&val, &len, cfile); 5070 token = next_token (&val, &len, cfile);
5071 } else { 5071 } else {
5072 val = parse_host_name(cfile); 5072 val = parse_host_name(cfile);
5073 if (!val) { 5073 if (!val) {
5074 parse_warn(cfile, "not a valid key name."); 5074 parse_warn(cfile, "not a valid key name.");
5075 skip_to_semi(cfile); 5075 skip_to_semi(cfile);
5076 return 0; 5076 return 0;
5077 } 5077 }
5078 freeval = ISC_TRUE; 5078 freeval = ISC_TRUE;
5079 } 5079 }
5080 5080
5081 if (!make_const_data (&t, (const unsigned char *)val, 5081 if (!make_const_data (&t, (const unsigned char *)val,
5082 strlen(val), 1, 1, MDL)) { 5082 strlen(val), 1, 1, MDL)) {
5083 log_fatal ("No memory key name"); 5083 log_fatal ("No memory key name");
5084 } 5084 }
5085 5085
5086 if (freeval == ISC_TRUE) { 5086 if (freeval == ISC_TRUE) {
5087 dfree((char *)val, MDL); 5087 dfree((char *)val, MDL);
5088 freeval = ISC_FALSE; 5088 freeval = ISC_FALSE;
5089 } 5089 }
5090 5090
5091 break; 5091 break;
5092 5092
5093 case 'N': 5093 case 'N':
5094 f = (*fmt) + 1; 5094 f = (*fmt) + 1;
5095 g = strchr (*fmt, '.'); 5095 g = strchr (*fmt, '.');
5096 if (!g) { 5096 if (!g) {
5097 parse_warn (cfile, "malformed %s (bug!)", 5097 parse_warn (cfile, "malformed %s (bug!)",
5098 "enumeration format"); 5098 "enumeration format");
5099 foo: 5099 foo:
5100 skip_to_semi (cfile); 5100 skip_to_semi (cfile);
5101 return 0; 5101 return 0;
5102 } 5102 }
5103 *fmt = g; 5103 *fmt = g;
5104 token = next_token (&val, (unsigned *)0, cfile); 5104 token = next_token (&val, (unsigned *)0, cfile);
5105 if (!is_identifier (token)) { 5105 if (!is_identifier (token)) {
5106 parse_warn (cfile, 5106 parse_warn (cfile,
5107 "identifier expected"); 5107 "identifier expected");
5108 goto foo; 5108 goto foo;
5109 } 5109 }
5110 e = find_enumeration_value (f, (*fmt) - f, &len, val); 5110 e = find_enumeration_value (f, (*fmt) - f, &len, val);
5111 if (!e) { 5111 if (!e) {
5112 parse_warn (cfile, "unknown value"); 5112 parse_warn (cfile, "unknown value");
5113 goto foo; 5113 goto foo;
5114 } 5114 }
5115 if (!make_const_data (&t, &e -> value, len, 0, 1, MDL)) 5115 if (!make_const_data (&t, &e -> value, len, 0, 1, MDL))
5116 return 0; 5116 return 0;
5117 break; 5117 break;
5118 5118
5119 case 'I': /* IP address or hostname. */ 5119 case 'I': /* IP address or hostname. */
5120 if (lookups) { 5120 if (lookups) {
5121 if (!parse_ip_addr_or_hostname (&t, cfile, uniform)) 5121 if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
5122 return 0; 5122 return 0;
5123 } else { 5123 } else {
5124 if (!parse_ip_addr (cfile, &addr)) 5124 if (!parse_ip_addr (cfile, &addr))
5125 return 0; 5125 return 0;
5126 if (!make_const_data (&t, addr.iabuf, addr.len, 5126 if (!make_const_data (&t, addr.iabuf, addr.len,
5127 0, 1, MDL)) 5127 0, 1, MDL))
5128 return 0; 5128 return 0;
5129 } 5129 }
5130 break; 5130 break;
5131 5131
5132 case '6': /* IPv6 address. */ 5132 case '6': /* IPv6 address. */
5133 if (!parse_ip6_addr(cfile, &addr)) { 5133 if (!parse_ip6_addr(cfile, &addr)) {
5134 return 0; 5134 return 0;
5135 } 5135 }
5136 if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) { 5136 if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) {
5137 return 0; 5137 return 0;
5138 } 5138 }
5139 break; 5139 break;
5140  5140
5141 case 'T': /* Lease interval. */ 5141 case 'T': /* Lease interval. */
5142 token = next_token (&val, (unsigned *)0, cfile); 5142 token = next_token (&val, (unsigned *)0, cfile);
5143 if (token != INFINITE) 5143 if (token != INFINITE)
5144 goto check_number; 5144 goto check_number;
5145 putLong (buf, -1); 5145 putLong (buf, -1);
5146 if (!make_const_data (&t, buf, 4, 0, 1, MDL)) 5146 if (!make_const_data (&t, buf, 4, 0, 1, MDL))
5147 return 0; 5147 return 0;
5148 break; 5148 break;
5149 5149
5150 case 'L': /* Unsigned 32-bit integer... */ 5150 case 'L': /* Unsigned 32-bit integer... */
5151 case 'l': /* Signed 32-bit integer... */ 5151 case 'l': /* Signed 32-bit integer... */
5152 token = next_token (&val, (unsigned *)0, cfile); 5152 token = next_token (&val, (unsigned *)0, cfile);
5153 check_number: 5153 check_number:
5154 if ((token != NUMBER) && (token != NUMBER_OR_NAME)) { 5154 if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
5155 need_number: 5155 need_number:
5156 if ((*fmt) [1] != 'o') { 5156 if ((*fmt) [1] != 'o') {
5157 parse_warn (cfile, "expecting number."); 5157 parse_warn (cfile, "expecting number.");
5158 if (token != SEMI) 5158 if (token != SEMI)
5159 skip_to_semi (cfile); 5159 skip_to_semi (cfile);
5160 } 5160 }
5161 return 0; 5161 return 0;
5162 } 5162 }
5163 convert_num (cfile, buf, val, 0, 32); 5163 convert_num (cfile, buf, val, 0, 32);
5164 if (!make_const_data (&t, buf, 4, 0, 1, MDL)) 5164 if (!make_const_data (&t, buf, 4, 0, 1, MDL))
5165 return 0; 5165 return 0;
5166 break; 5166 break;
5167 5167
5168 case 's': /* Signed 16-bit integer. */ 5168 case 's': /* Signed 16-bit integer. */
5169 case 'S': /* Unsigned 16-bit integer. */ 5169 case 'S': /* Unsigned 16-bit integer. */
5170 token = next_token (&val, (unsigned *)0, cfile); 5170 token = next_token (&val, (unsigned *)0, cfile);
5171 if ((token != NUMBER) && (token != NUMBER_OR_NAME)) 5171 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
5172 goto need_number; 5172 goto need_number;
5173 convert_num (cfile, buf, val, 0, 16); 5173 convert_num (cfile, buf, val, 0, 16);
5174 if (!make_const_data (&t, buf, 2, 0, 1, MDL)) 5174 if (!make_const_data (&t, buf, 2, 0, 1, MDL))
5175 return 0; 5175 return 0;
5176 break; 5176 break;
5177 5177
5178 case 'b': /* Signed 8-bit integer. */ 5178 case 'b': /* Signed 8-bit integer. */
5179 case 'B': /* Unsigned 8-bit integer. */ 5179 case 'B': /* Unsigned 8-bit integer. */
5180 token = next_token (&val, (unsigned *)0, cfile); 5180 token = next_token (&val, (unsigned *)0, cfile);
5181 if ((token != NUMBER) && (token != NUMBER_OR_NAME)) 5181 if ((token != NUMBER) && (token != NUMBER_OR_NAME))
5182 goto need_number; 5182 goto need_number;
5183 convert_num (cfile, buf, val, 0, 8); 5183 convert_num (cfile, buf, val, 0, 8);
5184 if (!make_const_data (&t, buf, 1, 0, 1, MDL)) 5184 if (!make_const_data (&t, buf, 1, 0, 1, MDL))
5185 return 0; 5185 return 0;
5186 break; 5186 break;
5187 5187
5188 case 'f': /* Boolean flag. */ 5188 case 'f': /* Boolean flag. */
5189 token = next_token (&val, (unsigned *)0, cfile); 5189 token = next_token (&val, (unsigned *)0, cfile);
5190 if (!is_identifier (token)) { 5190 if (!is_identifier (token)) {
5191 if ((*fmt) [1] != 'o') 5191 if ((*fmt) [1] != 'o')
5192 parse_warn (cfile, "expecting identifier."); 5192 parse_warn (cfile, "expecting identifier.");
5193 bad_flag: 5193 bad_flag:
5194 if ((*fmt) [1] != 'o') { 5194 if ((*fmt) [1] != 'o') {
5195 if (token != SEMI) 5195 if (token != SEMI)
5196 skip_to_semi (cfile); 5196 skip_to_semi (cfile);
5197 } 5197 }
5198 return 0; 5198 return 0;
5199 } 5199 }
5200 if (!strcasecmp (val, "true") 5200 if (!strcasecmp (val, "true")
5201 || !strcasecmp (val, "on")) 5201 || !strcasecmp (val, "on"))
5202 buf [0] = 1; 5202 buf [0] = 1;
5203 else if (!strcasecmp (val, "false") 5203 else if (!strcasecmp (val, "false")
5204 || !strcasecmp (val, "off")) 5204 || !strcasecmp (val, "off"))
5205 buf [0] = 0; 5205 buf [0] = 0;
5206 else if (!strcasecmp (val, "ignore")) 5206 else if (!strcasecmp (val, "ignore"))
5207 buf [0] = 2; 5207 buf [0] = 2;
5208 else { 5208 else {
5209 if ((*fmt) [1] != 'o') 5209 if ((*fmt) [1] != 'o')
5210 parse_warn (cfile, "expecting boolean."); 5210 parse_warn (cfile, "expecting boolean.");
5211 goto bad_flag; 5211 goto bad_flag;
5212 } 5212 }
5213 if (!make_const_data (&t, buf, 1, 0, 1, MDL)) 5213 if (!make_const_data (&t, buf, 1, 0, 1, MDL))
5214 return 0; 5214 return 0;
5215 break; 5215 break;
5216 5216
5217 case 'Z': /* Zero-length option. */ 5217 case 'Z': /* Zero-length option. */
5218 token = peek_token (&val, (unsigned *)0, cfile); 5218 token = peek_token (&val, (unsigned *)0, cfile);
5219 if (token != SEMI) { 5219 if (token != SEMI) {
5220 parse_warn(cfile, "semicolon expected."); 5220 parse_warn(cfile, "semicolon expected.");
5221 skip_to_semi(cfile); 5221 skip_to_semi(cfile);
5222 } 5222 }
5223 buf[0] = '\0'; 5223 buf[0] = '\0';
5224 if (!make_const_data(&t, /* expression */ 5224 if (!make_const_data(&t, /* expression */
5225 buf, /* buffer */  5225 buf, /* buffer */
5226 0, /* length */  5226 0, /* length */
5227 0, /* terminated */  5227 0, /* terminated */
5228 1, /* allocate */  5228 1, /* allocate */
5229 MDL))  5229 MDL))
5230 return 0; 5230 return 0;
5231 break; 5231 break;
5232 5232
5233 default: 5233 default:
5234 parse_warn (cfile, "Bad format '%c' in parse_option_token.", 5234 parse_warn (cfile, "Bad format '%c' in parse_option_token.",
5235 **fmt); 5235 **fmt);
5236 skip_to_semi (cfile); 5236 skip_to_semi (cfile);
5237 return 0; 5237 return 0;
5238 } 5238 }
5239 if (expr) { 5239 if (expr) {
5240 if (!make_concat (rv, expr, t)) 5240 if (!make_concat (rv, expr, t))
5241 return 0; 5241 return 0;
5242 } else 5242 } else
5243 expression_reference (rv, t, MDL); 5243 expression_reference (rv, t, MDL);
5244 expression_dereference (&t, MDL); 5244 expression_dereference (&t, MDL);
5245 return 1; 5245 return 1;
5246} 5246}
5247 5247
5248int parse_option_decl (oc, cfile) 5248int parse_option_decl (oc, cfile)
5249 struct option_cache **oc; 5249 struct option_cache **oc;
5250 struct parse *cfile; 5250 struct parse *cfile;
5251{ 5251{
5252 const char *val; 5252 const char *val;
5253 int token; 5253 int token;
5254 u_int8_t buf [4]; 5254 u_int8_t buf [4];
5255 u_int8_t hunkbuf [1024]; 5255 u_int8_t hunkbuf [1024];
5256 unsigned hunkix = 0; 5256 unsigned hunkix = 0;
5257 const char *fmt, *f; 5257 const char *fmt, *f;
5258 struct option *option=NULL; 5258 struct option *option=NULL;
5259 struct iaddr ip_addr; 5259 struct iaddr ip_addr;
5260 u_int8_t *dp; 5260 u_int8_t *dp;
5261 const u_int8_t *cdp; 5261 const u_int8_t *cdp;
5262 unsigned len; 5262 unsigned len;
5263 int nul_term = 0; 5263 int nul_term = 0;
5264 struct buffer *bp; 5264 struct buffer *bp;
5265 int known = 0; 5265 int known = 0;
5266 int compress; 5266 int compress;
5267 struct expression *express = NULL; 5267 struct expression *express = NULL;
5268 struct enumeration_value *e; 5268 struct enumeration_value *e;
5269 isc_result_t status; 5269 isc_result_t status;
5270 5270
5271 status = parse_option_name (cfile, 0, &known, &option); 5271 status = parse_option_name (cfile, 0, &known, &option);
5272 if (status != ISC_R_SUCCESS || option == NULL) 5272 if (status != ISC_R_SUCCESS || option == NULL)
5273 return 0; 5273 return 0;
5274 5274
5275 fmt = option->format; 5275 fmt = option->format;
5276 5276
5277 /* Parse the option data... */ 5277 /* Parse the option data... */
5278 do { 5278 do {
5279 for (; *fmt; fmt++) { 5279 for (; *fmt; fmt++) {
5280 if (*fmt == 'A') { 5280 if (*fmt == 'A') {
5281 /* 'A' is an array of records, start at 5281 /* 'A' is an array of records, start at
5282 * the beginning 5282 * the beginning
5283 */ 5283 */
5284 fmt = option->format; 5284 fmt = option->format;
5285 break; 5285 break;
5286 } 5286 }
5287 5287
5288 if (*fmt == 'a') { 5288 if (*fmt == 'a') {
5289 /* 'a' is an array of the last field, 5289 /* 'a' is an array of the last field,
5290 * back up one format character 5290 * back up one format character
5291 */ 5291 */
5292 fmt--; 5292 fmt--;
5293 break; 5293 break;
5294 } 5294 }
5295 if (*fmt == 'o' && fmt != option -> format) 5295 if (*fmt == 'o' && fmt != option -> format)
5296 continue; 5296 continue;
5297 switch (*fmt) { 5297 switch (*fmt) {
5298 case 'E': 5298 case 'E':
5299 fmt = strchr (fmt, '.'); 5299 fmt = strchr (fmt, '.');
5300 if (!fmt) { 5300 if (!fmt) {
5301 parse_warn (cfile, 5301 parse_warn (cfile,
5302 "malformed %s (bug!)", 5302 "malformed %s (bug!)",
5303 "encapsulation format"); 5303 "encapsulation format");
5304 goto parse_exit; 5304 goto parse_exit;
5305 } 5305 }
5306 /* FALL THROUGH */ 5306 /* FALL THROUGH */
5307 /* to get string value for the option */ 5307 /* to get string value for the option */
5308 case 'X': 5308 case 'X':
5309 len = parse_X (cfile, &hunkbuf [hunkix], 5309 len = parse_X (cfile, &hunkbuf [hunkix],
5310 sizeof hunkbuf - hunkix); 5310 sizeof hunkbuf - hunkix);
5311 hunkix += len; 5311 hunkix += len;
5312 break; 5312 break;
5313  5313
5314 case 't': /* Text string... */ 5314 case 't': /* Text string... */
5315 token = peek_token (&val, 5315 token = peek_token (&val,
5316 &len, cfile); 5316 &len, cfile);
5317 if (token == SEMI && fmt[1] == 'o') { 5317 if (token == SEMI && fmt[1] == 'o') {
5318 fmt++; 5318 fmt++;
5319 break; 5319 break;
5320 } 5320 }
5321 token = next_token (&val, 5321 token = next_token (&val,
5322 &len, cfile); 5322 &len, cfile);
5323 if (token != STRING) { 5323 if (token != STRING) {
5324 parse_warn (cfile, 5324 parse_warn (cfile,
5325 "expecting string."); 5325 "expecting string.");
5326 goto parse_exit; 5326 goto parse_exit;
5327 } 5327 }
5328 if (hunkix + len + 1 > sizeof hunkbuf) { 5328 if (hunkix + len + 1 > sizeof hunkbuf) {
5329 parse_warn (cfile, 5329 parse_warn (cfile,
5330 "option data buffer %s", 5330 "option data buffer %s",
5331 "overflow"); 5331 "overflow");
5332 goto parse_exit; 5332 goto parse_exit;
5333 } 5333 }
5334 memcpy (&hunkbuf [hunkix], val, len + 1); 5334 memcpy (&hunkbuf [hunkix], val, len + 1);
5335 nul_term = 1; 5335 nul_term = 1;
5336 hunkix += len; 5336 hunkix += len;
5337 break; 5337 break;
5338 5338
5339 case 'D': 5339 case 'D':
5340 if (fmt[1] == 'c') { 5340 if (fmt[1] == 'c') {
5341 compress = 1; 5341 compress = 1;
5342 fmt++; 5342 fmt++;
5343 } else 5343 } else
5344 compress = 0; 5344 compress = 0;
5345 5345
5346 express = parse_domain_list(cfile, compress); 5346 express = parse_domain_list(cfile, compress);
5347 5347
5348 if (express == NULL) 5348 if (express == NULL)
5349 goto exit; 5349 goto exit;
5350 5350
5351 if (express->op != expr_const_data) { 5351 if (express->op != expr_const_data) {
5352 parse_warn(cfile, "unexpected " 5352 parse_warn(cfile, "unexpected "
5353 "expression"); 5353 "expression");
5354 goto parse_exit; 5354 goto parse_exit;
5355 } 5355 }
5356 5356
5357 len = express->data.const_data.len; 5357 len = express->data.const_data.len;
5358 cdp = express->data.const_data.data; 5358 cdp = express->data.const_data.data;
5359 5359
5360 if ((hunkix + len) > sizeof(hunkbuf)) { 5360 if ((hunkix + len) > sizeof(hunkbuf)) {
5361 parse_warn(cfile, "option data buffer " 5361 parse_warn(cfile, "option data buffer "
5362 "overflow"); 5362 "overflow");
5363 goto parse_exit; 5363 goto parse_exit;
5364 } 5364 }
5365 memcpy(&hunkbuf[hunkix], cdp, len); 5365 memcpy(&hunkbuf[hunkix], cdp, len);
5366 hunkix += len; 5366 hunkix += len;
5367 5367
5368 expression_dereference(&express, MDL); 5368 expression_dereference(&express, MDL);
5369 break; 5369 break;
5370 5370
5371 case 'N': 5371 case 'N':
5372 f = fmt + 1; 5372 f = fmt + 1;
5373 fmt = strchr (fmt, '.'); 5373 fmt = strchr (fmt, '.');
5374 if (!fmt) { 5374 if (!fmt) {
5375 parse_warn (cfile, 5375 parse_warn (cfile,
5376 "malformed %s (bug!)", 5376 "malformed %s (bug!)",
5377 "enumeration format"); 5377 "enumeration format");
5378 goto parse_exit; 5378 goto parse_exit;
5379 } 5379 }
5380 token = next_token (&val, 5380 token = next_token (&val,
5381 (unsigned *)0, cfile); 5381 (unsigned *)0, cfile);
5382 if (!is_identifier (token)) { 5382 if (!is_identifier (token)) {
5383 parse_warn (cfile, 5383 parse_warn (cfile,
5384 "identifier expected"); 5384 "identifier expected");
5385 goto parse_exit; 5385 goto parse_exit;
5386 } 5386 }
5387 e = find_enumeration_value (f, fmt - f, 5387 e = find_enumeration_value (f, fmt - f,
5388 &len, val); 5388 &len, val);
5389 if (!e) { 5389 if (!e) {
5390 parse_warn (cfile, 5390 parse_warn (cfile,
5391 "unknown value"); 5391 "unknown value");
5392 goto parse_exit; 5392 goto parse_exit;
5393 } 5393 }
5394 dp = &e -> value; 5394 dp = &e -> value;
5395 goto alloc; 5395 goto alloc;
5396 5396
5397 case '6': 5397 case '6':
5398 if (!parse_ip6_addr(cfile, &ip_addr)) 5398 if (!parse_ip6_addr(cfile, &ip_addr))
5399 goto exit; 5399 goto exit;
5400 len = ip_addr.len; 5400 len = ip_addr.len;
5401 dp = ip_addr.iabuf; 5401 dp = ip_addr.iabuf;
5402 goto alloc; 5402 goto alloc;
5403 5403
5404 case 'I': /* IP address. */ 5404 case 'I': /* IP address. */
5405 if (!parse_ip_addr (cfile, &ip_addr)) 5405 if (!parse_ip_addr (cfile, &ip_addr))
5406 goto exit; 5406 goto exit;
5407 len = ip_addr.len; 5407 len = ip_addr.len;
5408 dp = ip_addr.iabuf; 5408 dp = ip_addr.iabuf;
5409 5409
5410 alloc: 5410 alloc:
5411 if (hunkix + len > sizeof hunkbuf) { 5411 if (hunkix + len > sizeof hunkbuf) {
5412 parse_warn (cfile, 5412 parse_warn (cfile,
5413 "option data buffer %s", 5413 "option data buffer %s",
5414 "overflow"); 5414 "overflow");
5415 goto parse_exit; 5415 goto parse_exit;
5416 } 5416 }
5417 memcpy (&hunkbuf [hunkix], dp, len); 5417 memcpy (&hunkbuf [hunkix], dp, len);
5418 hunkix += len; 5418 hunkix += len;
5419 break; 5419 break;
5420 5420
5421 case 'L': /* Unsigned 32-bit integer... */ 5421 case 'L': /* Unsigned 32-bit integer... */
5422 case 'l': /* Signed 32-bit integer... */ 5422 case 'l': /* Signed 32-bit integer... */
5423 token = next_token (&val, 5423 token = next_token (&val,
5424 (unsigned *)0, cfile); 5424 (unsigned *)0, cfile);
5425 if ((token != NUMBER) && 5425 if ((token != NUMBER) &&
5426 (token != NUMBER_OR_NAME)) { 5426 (token != NUMBER_OR_NAME)) {
5427 need_number: 5427 need_number:
5428 parse_warn (cfile, 5428 parse_warn (cfile,
5429 "expecting number."); 5429 "expecting number.");
5430 if (token != SEMI) 5430 if (token != SEMI)
5431 goto parse_exit; 5431 goto parse_exit;
5432 else 5432 else
5433 goto exit; 5433 goto exit;
5434 } 5434 }
5435 convert_num (cfile, buf, val, 0, 32); 5435 convert_num (cfile, buf, val, 0, 32);
5436 len = 4; 5436 len = 4;
5437 dp = buf; 5437 dp = buf;
5438 goto alloc; 5438 goto alloc;
5439 5439
5440 case 's': /* Signed 16-bit integer. */ 5440 case 's': /* Signed 16-bit integer. */
5441 case 'S': /* Unsigned 16-bit integer. */ 5441 case 'S': /* Unsigned 16-bit integer. */
5442 token = next_token (&val, 5442 token = next_token (&val,
5443 (unsigned *)0, cfile); 5443 (unsigned *)0, cfile);
5444 if ((token != NUMBER) && 5444 if ((token != NUMBER) &&
5445 (token != NUMBER_OR_NAME)) 5445 (token != NUMBER_OR_NAME))
5446 goto need_number; 5446 goto need_number;
5447 convert_num (cfile, buf, val, 0, 16); 5447 convert_num (cfile, buf, val, 0, 16);
5448 len = 2; 5448 len = 2;
5449 dp = buf; 5449 dp = buf;
5450 goto alloc; 5450 goto alloc;
5451 5451
5452 case 'b': /* Signed 8-bit integer. */ 5452 case 'b': /* Signed 8-bit integer. */
5453 case 'B': /* Unsigned 8-bit integer. */ 5453 case 'B': /* Unsigned 8-bit integer. */
5454 token = next_token (&val, 5454 token = next_token (&val,
5455 (unsigned *)0, cfile); 5455 (unsigned *)0, cfile);
5456 if ((token != NUMBER) && 5456 if ((token != NUMBER) &&
5457 (token != NUMBER_OR_NAME)) 5457 (token != NUMBER_OR_NAME))
5458 goto need_number; 5458 goto need_number;
5459 convert_num (cfile, buf, val, 0, 8); 5459 convert_num (cfile, buf, val, 0, 8);
5460 len = 1; 5460 len = 1;
5461 dp = buf; 5461 dp = buf;
5462 goto alloc; 5462 goto alloc;
5463 5463
5464 case 'f': /* Boolean flag. */ 5464 case 'f': /* Boolean flag. */
5465 token = next_token (&val, 5465 token = next_token (&val,
5466 (unsigned *)0, cfile); 5466 (unsigned *)0, cfile);
5467 if (!is_identifier (token)) { 5467 if (!is_identifier (token)) {
5468 parse_warn (cfile, 5468 parse_warn (cfile,
5469 "expecting identifier."); 5469 "expecting identifier.");
5470 bad_flag: 5470 bad_flag:
5471 if (token != SEMI) 5471 if (token != SEMI)
5472 goto parse_exit; 5472 goto parse_exit;
5473 else 5473 else
5474 goto exit; 5474 goto exit;
5475 } 5475 }
5476 if (!strcasecmp (val, "true") 5476 if (!strcasecmp (val, "true")
5477 || !strcasecmp (val, "on")) 5477 || !strcasecmp (val, "on"))
5478 buf [0] = 1; 5478 buf [0] = 1;
5479 else if (!strcasecmp (val, "false") 5479 else if (!strcasecmp (val, "false")
5480 || !strcasecmp (val, "off")) 5480 || !strcasecmp (val, "off"))
5481 buf [0] = 0; 5481 buf [0] = 0;
5482 else { 5482 else {
5483 parse_warn (cfile, 5483 parse_warn (cfile,
5484 "expecting boolean."); 5484 "expecting boolean.");
5485 goto bad_flag; 5485 goto bad_flag;
5486 } 5486 }
5487 len = 1; 5487 len = 1;
5488 dp = buf; 5488 dp = buf;
5489 goto alloc; 5489 goto alloc;
5490 5490
5491 case 'Z': /* Zero-length option */ 5491 case 'Z': /* Zero-length option */
5492 token = peek_token(&val, (unsigned *)0, cfile); 5492 token = peek_token(&val, (unsigned *)0, cfile);
5493 if (token != SEMI) { 5493 if (token != SEMI) {
5494 parse_warn(cfile, 5494 parse_warn(cfile,
5495 "semicolon expected."); 5495 "semicolon expected.");
5496 goto parse_exit; 5496 goto parse_exit;
5497 } 5497 }
5498 len = 0; 5498 len = 0;
5499 buf[0] = '\0'; 5499 buf[0] = '\0';
5500 break; 5500 break;
5501 5501
5502 default: 5502 default:
5503 log_error ("parse_option_param: Bad format %c", 5503 log_error ("parse_option_param: Bad format %c",
5504 *fmt); 5504 *fmt);
5505 goto parse_exit; 5505 goto parse_exit;
5506 } 5506 }
5507 } 5507 }
5508 token = next_token (&val, (unsigned *)0, cfile); 5508 token = next_token (&val, (unsigned *)0, cfile);
5509 } while (*fmt && token == COMMA); 5509 } while (*fmt && token == COMMA);
5510 5510
5511 if (token != SEMI) { 5511 if (token != SEMI) {
5512 parse_warn (cfile, "semicolon expected."); 5512 parse_warn (cfile, "semicolon expected.");
5513 goto parse_exit; 5513 goto parse_exit;
5514 } 5514 }
5515 5515
5516 bp = (struct buffer *)0; 5516 bp = (struct buffer *)0;
5517 if (!buffer_allocate (&bp, hunkix + nul_term, MDL)) 5517 if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
5518 log_fatal ("no memory to store option declaration."); 5518 log_fatal ("no memory to store option declaration.");
5519 memcpy (bp -> data, hunkbuf, hunkix + nul_term); 5519 memcpy (bp -> data, hunkbuf, hunkix + nul_term);
5520  5520
5521 if (!option_cache_allocate (oc, MDL)) 5521 if (!option_cache_allocate (oc, MDL))
5522 log_fatal ("out of memory allocating option cache."); 5522 log_fatal ("out of memory allocating option cache.");
5523 5523
5524 (*oc) -> data.buffer = bp; 5524 (*oc) -> data.buffer = bp;
5525 (*oc) -> data.data = &bp -> data [0]; 5525 (*oc) -> data.data = &bp -> data [0];
5526 (*oc) -> data.terminated = nul_term; 5526 (*oc) -> data.terminated = nul_term;
5527 (*oc) -> data.len = hunkix; 5527 (*oc) -> data.len = hunkix;
5528 option_reference(&(*oc)->option, option, MDL); 5528 option_reference(&(*oc)->option, option, MDL);
5529 option_dereference(&option, MDL); 5529 option_dereference(&option, MDL);
5530 return 1; 5530 return 1;
5531 5531
5532parse_exit: 5532parse_exit:
5533 if (express != NULL) 5533 if (express != NULL)
5534 expression_dereference(&express, MDL); 5534 expression_dereference(&express, MDL);
5535 skip_to_semi (cfile); 5535 skip_to_semi (cfile);
5536exit: 5536exit:
5537 option_dereference(&option, MDL); 5537 option_dereference(&option, MDL);
5538 5538
5539 return 0; 5539 return 0;
5540} 5540}
5541 5541
5542/* Consider merging parse_cshl into this. */ 5542/* Consider merging parse_cshl into this. */
5543 5543
5544int parse_X (cfile, buf, max) 5544int parse_X (cfile, buf, max)
5545 struct parse *cfile; 5545 struct parse *cfile;
5546 u_int8_t *buf; 5546 u_int8_t *buf;
5547 unsigned max; 5547 unsigned max;
5548{ 5548{
5549 int token; 5549 int token;
5550 const char *val; 5550 const char *val;
5551 unsigned len; 5551 unsigned len;
5552 5552
5553 token = peek_token (&val, (unsigned *)0, cfile); 5553 token = peek_token (&val, (unsigned *)0, cfile);
5554 if (token == NUMBER_OR_NAME || token == NUMBER) { 5554 if (token == NUMBER_OR_NAME || token == NUMBER) {
5555 len = 0; 5555 len = 0;
5556 do { 5556 do {
5557 token = next_token (&val, (unsigned *)0, cfile); 5557 token = next_token (&val, (unsigned *)0, cfile);
5558 if (token != NUMBER && token != NUMBER_OR_NAME) { 5558 if (token != NUMBER && token != NUMBER_OR_NAME) {
5559 parse_warn (cfile, 5559 parse_warn (cfile,
5560 "expecting hexadecimal constant."); 5560 "expecting hexadecimal constant.");
5561 skip_to_semi (cfile); 5561 skip_to_semi (cfile);
5562 return 0; 5562 return 0;
5563 } 5563 }
5564 convert_num (cfile, &buf [len], val, 16, 8); 5564 if (len >= max) {
5565 if (len++ > max) { 
5566 parse_warn (cfile, 5565 parse_warn (cfile,
5567 "hexadecimal constant too long."); 5566 "hexadecimal constant too long.");
5568 skip_to_semi (cfile); 5567 skip_to_semi (cfile);
5569 return 0; 5568 return 0;
5570 } 5569 }
 5570 convert_num (cfile, &buf [len], val, 16, 8);
 5571 len++;
5571 token = peek_token (&val, (unsigned *)0, cfile); 5572 token = peek_token (&val, (unsigned *)0, cfile);
5572 if (token == COLON) 5573 if (token == COLON)
5573 token = next_token (&val, 5574 token = next_token (&val,
5574 (unsigned *)0, cfile); 5575 (unsigned *)0, cfile);
5575 } while (token == COLON); 5576 } while (token == COLON);
5576 val = (char *)buf; 5577 val = (char *)buf;
5577 } else if (token == STRING) { 5578 } else if (token == STRING) {
5578 skip_token(&val, &len, cfile); 5579 skip_token(&val, &len, cfile);
5579 if (len + 1 > max) { 5580 if (len + 1 > max) {
5580 parse_warn (cfile, "string constant too long."); 5581 parse_warn (cfile, "string constant too long.");
5581 skip_to_semi (cfile); 5582 skip_to_semi (cfile);
5582 return 0; 5583 return 0;
5583 } 5584 }
5584 memcpy (buf, val, len + 1); 5585 memcpy (buf, val, len + 1);
5585 } else { 5586 } else {
5586 parse_warn (cfile, "expecting string or hexadecimal data"); 5587 parse_warn (cfile, "expecting string or hexadecimal data");
5587 skip_to_semi (cfile); 5588 skip_to_semi (cfile);
5588 return 0; 5589 return 0;
5589 } 5590 }
5590 return len; 5591 return len;
5591} 5592}
5592 5593
5593int parse_warn (struct parse *cfile, const char *fmt, ...) 5594int parse_warn (struct parse *cfile, const char *fmt, ...)
5594{ 5595{
5595 va_list list; 5596 va_list list;
5596 char lexbuf [256]; 5597 char lexbuf [256];
5597 char mbuf [1024]; /* errorwarn.c CVT_BUF_MAX + 1 */ 5598 char mbuf [1024]; /* errorwarn.c CVT_BUF_MAX + 1 */
5598 char fbuf [2048]; 5599 char fbuf [2048];
5599 char final[4096]; 5600 char final[4096];
5600 unsigned i, lix; 5601 unsigned i, lix;
5601 5602
5602 /* Replace %m in fmt with errno error text */ 5603 /* Replace %m in fmt with errno error text */
5603 do_percentm (mbuf, sizeof(mbuf), fmt); 5604 do_percentm (mbuf, sizeof(mbuf), fmt);
5604 5605
5605 /* %Audit% This is log output. %2004.06.17,Safe% 5606 /* %Audit% This is log output. %2004.06.17,Safe%
5606 * If we truncate we hope the user can get a hint from the log. 5607 * If we truncate we hope the user can get a hint from the log.
5607 */ 5608 */
5608 5609
5609 /* Prepend the file and line number */ 5610 /* Prepend the file and line number */
5610 snprintf (fbuf, sizeof fbuf, "%s line %d: %s", 5611 snprintf (fbuf, sizeof fbuf, "%s line %d: %s",
5611 cfile -> tlname, cfile -> lexline, mbuf); 5612 cfile -> tlname, cfile -> lexline, mbuf);
5612 5613
5613 /* Now add the var args to the format for the final log message. */ 5614 /* Now add the var args to the format for the final log message. */
5614 va_start (list, fmt); 5615 va_start (list, fmt);
5615 vsnprintf (final, sizeof final, fbuf, list); 5616 vsnprintf (final, sizeof final, fbuf, list);
5616 va_end (list); 5617 va_end (list);
5617 5618
5618 lix = 0; 5619 lix = 0;
5619 for (i = 0; 5620 for (i = 0;
5620 cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) { 5621 cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) {
5621 if (lix < (sizeof lexbuf) - 1) 5622 if (lix < (sizeof lexbuf) - 1)
5622 lexbuf [lix++] = ' '; 5623 lexbuf [lix++] = ' ';
5623 if (cfile -> token_line [i] == '\t') { 5624 if (cfile -> token_line [i] == '\t') {
5624 for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++) 5625 for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
5625 lexbuf [lix] = ' '; 5626 lexbuf [lix] = ' ';
5626 } 5627 }
5627 } 5628 }
5628 lexbuf [lix] = 0; 5629 lexbuf [lix] = 0;
5629 5630
5630#ifndef DEBUG 5631#ifndef DEBUG
5631 syslog (LOG_ERR, "%s", final); 5632 syslog (LOG_ERR, "%s", final);
5632 syslog (LOG_ERR, "%s", cfile -> token_line); 5633 syslog (LOG_ERR, "%s", cfile -> token_line);
5633 if (cfile -> lexchar < 81) 5634 if (cfile -> lexchar < 81)
5634 syslog (LOG_ERR, "%s^", lexbuf); 5635 syslog (LOG_ERR, "%s^", lexbuf);
5635#endif 5636#endif
5636 5637
5637 if (log_perror) { 5638 if (log_perror) {
5638 IGNORE_RET (write (STDERR_FILENO, final, strlen (final))); 5639 IGNORE_RET (write (STDERR_FILENO, final, strlen (final)));
5639 IGNORE_RET (write (STDERR_FILENO, "\n", 1)); 5640 IGNORE_RET (write (STDERR_FILENO, "\n", 1));
5640 IGNORE_RET (write (STDERR_FILENO, cfile -> token_line, 5641 IGNORE_RET (write (STDERR_FILENO, cfile -> token_line,
5641 strlen (cfile -> token_line))); 5642 strlen (cfile -> token_line)));
5642 IGNORE_RET (write (STDERR_FILENO, "\n", 1)); 5643 IGNORE_RET (write (STDERR_FILENO, "\n", 1));
5643 if (cfile -> lexchar < 81) 5644 if (cfile -> lexchar < 81)
5644 IGNORE_RET (write (STDERR_FILENO, lexbuf, lix)); 5645 IGNORE_RET (write (STDERR_FILENO, lexbuf, lix));
5645 IGNORE_RET (write (STDERR_FILENO, "^\n", 2)); 5646 IGNORE_RET (write (STDERR_FILENO, "^\n", 2));
5646 } 5647 }
5647 5648
5648 cfile -> warnings_occurred = 1; 5649 cfile -> warnings_occurred = 1;
5649 5650
5650 return 0; 5651 return 0;
5651} 5652}
5652 5653
5653struct expression * 5654struct expression *
5654parse_domain_list(struct parse *cfile, int compress) 5655parse_domain_list(struct parse *cfile, int compress)
5655{ 5656{
5656 const char *val; 5657 const char *val;
5657 enum dhcp_token token = SEMI; 5658 enum dhcp_token token = SEMI;
5658 struct expression *t = NULL; 5659 struct expression *t = NULL;
5659 unsigned len, clen = 0; 5660 unsigned len, clen = 0;
5660 int result; 5661 int result;
5661 unsigned char compbuf[256 * NS_MAXCDNAME]; 5662 unsigned char compbuf[256 * NS_MAXCDNAME];
5662 const unsigned char *dnptrs[256], **lastdnptr; 5663 const unsigned char *dnptrs[256], **lastdnptr;
5663 5664
5664 memset(compbuf, 0, sizeof(compbuf)); 5665 memset(compbuf, 0, sizeof(compbuf));
5665 memset(dnptrs, 0, sizeof(dnptrs)); 5666 memset(dnptrs, 0, sizeof(dnptrs));
5666 dnptrs[0] = compbuf; 5667 dnptrs[0] = compbuf;
5667 lastdnptr = &dnptrs[255]; 5668 lastdnptr = &dnptrs[255];
5668 5669
5669 do { 5670 do {
5670 /* Consume the COMMA token if peeked. */ 5671 /* Consume the COMMA token if peeked. */
5671 if (token == COMMA) 5672 if (token == COMMA)
5672 skip_token(&val, NULL, cfile); 5673 skip_token(&val, NULL, cfile);
5673 5674
5674 /* Get next (or first) value. */ 5675 /* Get next (or first) value. */
5675 token = next_token(&val, &len, cfile); 5676 token = next_token(&val, &len, cfile);
5676 5677
5677 if (token != STRING) { 5678 if (token != STRING) {
5678 parse_warn(cfile, "Expecting a domain string."); 5679 parse_warn(cfile, "Expecting a domain string.");
5679 return NULL; 5680 return NULL;
5680 } 5681 }
5681 5682
5682 /* If compression pointers are enabled, compress. If not, 5683 /* If compression pointers are enabled, compress. If not,
5683 * just pack the names in series into the buffer. 5684 * just pack the names in series into the buffer.
5684 */ 5685 */
5685 if (compress) { 5686 if (compress) {
5686 result = MRns_name_compress(val, compbuf + clen, 5687 result = MRns_name_compress(val, compbuf + clen,
5687 sizeof(compbuf) - clen, 5688 sizeof(compbuf) - clen,
5688 dnptrs, lastdnptr); 5689 dnptrs, lastdnptr);
5689 5690
5690 if (result < 0) { 5691 if (result < 0) {
5691 parse_warn(cfile, "Error compressing domain " 5692 parse_warn(cfile, "Error compressing domain "
5692 "list: %m"); 5693 "list: %m");
5693 return NULL; 5694 return NULL;
5694 } 5695 }
5695 5696
5696 clen += result; 5697 clen += result;
5697 } else { 5698 } else {
5698 result = MRns_name_pton(val, compbuf + clen, 5699 result = MRns_name_pton(val, compbuf + clen,
5699 sizeof(compbuf) - clen); 5700 sizeof(compbuf) - clen);
5700 5701
5701 /* result == 1 means the input was fully qualified. 5702 /* result == 1 means the input was fully qualified.
5702 * result == 0 means the input wasn't. 5703 * result == 0 means the input wasn't.
5703 * result == -1 means bad things. 5704 * result == -1 means bad things.
5704 */ 5705 */
5705 if (result < 0) { 5706 if (result < 0) {
5706 parse_warn(cfile, "Error assembling domain " 5707 parse_warn(cfile, "Error assembling domain "
5707 "list: %m"); 5708 "list: %m");
5708 return NULL; 5709 return NULL;
5709 } 5710 }
5710 5711
5711 /* 5712 /*
5712 * We need to figure out how many bytes to increment 5713 * We need to figure out how many bytes to increment
5713 * our buffer pointer since pton doesn't tell us. 5714 * our buffer pointer since pton doesn't tell us.
5714 */ 5715 */
5715 while (compbuf[clen] != 0) 5716 while (compbuf[clen] != 0)
5716 clen += compbuf[clen] + 1; 5717 clen += compbuf[clen] + 1;
5717 5718
5718 /* Count the last label (0). */ 5719 /* Count the last label (0). */
5719 clen++; 5720 clen++;
5720 } 5721 }
5721 5722
5722 if (clen > sizeof(compbuf)) 5723 if (clen > sizeof(compbuf))
5723 log_fatal("Impossible error at %s:%d", MDL); 5724 log_fatal("Impossible error at %s:%d", MDL);
5724 5725
5725 token = peek_token(&val, NULL, cfile); 5726 token = peek_token(&val, NULL, cfile);
5726 } while (token == COMMA); 5727 } while (token == COMMA);
5727 5728
5728 if (!make_const_data(&t, compbuf, clen, 1, 1, MDL)) 5729 if (!make_const_data(&t, compbuf, clen, 1, 1, MDL))
5729 log_fatal("No memory for domain list object."); 5730 log_fatal("No memory for domain list object.");
5730 5731
5731 return t; 5732 return t;
5732} 5733}
5733 5734
5734struct expression * 5735struct expression *
5735parse_domain_name(struct parse *cfile) 5736parse_domain_name(struct parse *cfile)
5736{ 5737{
5737 const char *val; 5738 const char *val;
5738 struct expression *t = NULL; 5739 struct expression *t = NULL;
5739 unsigned len; 5740 unsigned len;
5740 int result; 5741 int result;
5741 unsigned char buf[NS_MAXCDNAME]; 5742 unsigned char buf[NS_MAXCDNAME];
5742 5743
5743 val = parse_host_name(cfile); 5744 val = parse_host_name(cfile);
5744 if (!val) { 5745 if (!val) {
5745 return NULL; 5746 return NULL;
5746 } 5747 }
5747 result = MRns_name_pton(val, buf, sizeof(buf)); 5748 result = MRns_name_pton(val, buf, sizeof(buf));
5748 /* No longer need val */ 5749 /* No longer need val */
5749 dfree((char *)val, MDL); 5750 dfree((char *)val, MDL);
5750 5751
5751 /* result == 1 means the input was fully qualified. 5752 /* result == 1 means the input was fully qualified.
5752 * result == 0 means the input wasn't. 5753 * result == 0 means the input wasn't.
5753 * result == -1 means bad things. 5754 * result == -1 means bad things.
5754 */ 5755 */
5755 if (result < 0) { 5756 if (result < 0) {
5756 parse_warn(cfile, "Error assembling domain name: %m"); 5757 parse_warn(cfile, "Error assembling domain name: %m");
5757 return NULL; 5758 return NULL;
5758 } 5759 }
5759 5760
5760 /* Compute the used length */ 5761 /* Compute the used length */
5761 len = 0; 5762 len = 0;
5762 while (buf[len] != 0) { 5763 while (buf[len] != 0) {
5763 len += buf[len] + 1; 5764 len += buf[len] + 1;
5764 } 5765 }
5765 /* Count the last label (0). */ 5766 /* Count the last label (0). */
5766 len++; 5767 len++;
5767 5768
5768 if (!make_const_data(&t, buf, len, 1, 1, MDL)) 5769 if (!make_const_data(&t, buf, len, 1, 1, MDL))
5769 log_fatal("No memory for domain name object."); 5770 log_fatal("No memory for domain name object.");
5770 5771
5771 return t; 5772 return t;
5772} 5773}

cvs diff -r1.2 -r1.3 src/external/mpl/dhcp/dist/common/tests/option_unittest.c (switch to unified diff)

--- src/external/mpl/dhcp/dist/common/tests/option_unittest.c 2018/04/07 22:37:29 1.2
+++ src/external/mpl/dhcp/dist/common/tests/option_unittest.c 2021/05/26 22:52:31 1.3
@@ -1,144 +1,228 @@ @@ -1,144 +1,228 @@
1/* $NetBSD: option_unittest.c,v 1.2 2018/04/07 22:37:29 christos Exp $ */ 1/* $NetBSD: option_unittest.c,v 1.3 2021/05/26 22:52:31 christos Exp $ */
2 2
3/* 3/*
4 * Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") 4 * Copyright (C) 2018-2021 Internet Systems Consortium, Inc. ("ISC")
5 * 5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public 6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * 9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE. 16 * PERFORMANCE OF THIS SOFTWARE.
17 */ 17 */
18 18
19#include <config.h> 19#include <config.h>
20#include <atf-c.h> 20#include <atf-c.h>
21#include "dhcpd.h" 21#include "dhcpd.h"
22 22
23ATF_TC(option_refcnt); 23ATF_TC(option_refcnt);
24 24
25ATF_TC_HEAD(option_refcnt, tc) 25ATF_TC_HEAD(option_refcnt, tc)
26{ 26{
27 atf_tc_set_md_var(tc, "descr", 27 atf_tc_set_md_var(tc, "descr",
28 "Verify option reference count does not overflow."); 28 "Verify option reference count does not overflow.");
29} 29}
30 30
31/* This test does a simple check to see if option reference count is 31/* This test does a simple check to see if option reference count is
32 * decremented even an error path exiting parse_option_buffer() 32 * decremented even an error path exiting parse_option_buffer()
33 */ 33 */
34ATF_TC_BODY(option_refcnt, tc) 34ATF_TC_BODY(option_refcnt, tc)
35{ 35{
36 struct option_state *options; 36 struct option_state *options;
37 struct option *option; 37 struct option *option;
38 unsigned code; 38 unsigned code;
39 int refcnt; 39 int refcnt;
40 unsigned char buffer[3] = { 15, 255, 0 }; 40 unsigned char buffer[3] = { 15, 255, 0 };
41 41
42 initialize_common_option_spaces(); 42 initialize_common_option_spaces();
43 43
44 options = NULL; 44 options = NULL;
45 if (!option_state_allocate(&options, MDL)) { 45 if (!option_state_allocate(&options, MDL)) {
46 atf_tc_fail("can't allocate option state"); 46 atf_tc_fail("can't allocate option state");
47 } 47 }
48 48
49 option = NULL; 49 option = NULL;
50 code = 15; /* domain-name */ 50 code = 15; /* domain-name */
51 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, 51 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
52 &code, 0, MDL)) { 52 &code, 0, MDL)) {
53 atf_tc_fail("can't find option 15"); 53 atf_tc_fail("can't find option 15");
54 } 54 }
55 if (option == NULL) { 55 if (option == NULL) {
56 atf_tc_fail("option is NULL"); 56 atf_tc_fail("option is NULL");
57 } 57 }
58 refcnt = option->refcnt; 58 refcnt = option->refcnt;
59 59
60 buffer[0] = 15; 60 buffer[0] = 15;
61 buffer[1] = 255; /* invalid */ 61 buffer[1] = 255; /* invalid */
62 buffer[2] = 0; 62 buffer[2] = 0;
63 63
64 if (parse_option_buffer(options, buffer, 3, &dhcp_universe)) { 64 if (parse_option_buffer(options, buffer, 3, &dhcp_universe)) {
65 atf_tc_fail("parse_option_buffer is expected to fail"); 65 atf_tc_fail("parse_option_buffer is expected to fail");
66 } 66 }
67 67
68 if (refcnt != option->refcnt) { 68 if (refcnt != option->refcnt) {
69 atf_tc_fail("refcnt changed from %d to %d", refcnt, option->refcnt); 69 atf_tc_fail("refcnt changed from %d to %d", refcnt, option->refcnt);
70 } 70 }
71} 71}
72 72
73ATF_TC(pretty_print_option); 73ATF_TC(pretty_print_option);
74 74
75ATF_TC_HEAD(pretty_print_option, tc) 75ATF_TC_HEAD(pretty_print_option, tc)
76{ 76{
77 atf_tc_set_md_var(tc, "descr", 77 atf_tc_set_md_var(tc, "descr",
78 "Verify pretty_print_option does not overrun its buffer."); 78 "Verify pretty_print_option does not overrun its buffer.");
79} 79}
80 80
81 81
82/* 82/*
83 * This test verifies that pretty_print_option() will not overrun its 83 * This test verifies that pretty_print_option() will not overrun its
84 * internal, static buffer when given large 'x/X' format options. 84 * internal, static buffer when given large 'x/X' format options.
85 * 85 *
86 */ 86 */
87ATF_TC_BODY(pretty_print_option, tc) 87ATF_TC_BODY(pretty_print_option, tc)
88{ 88{
89 struct option *option; 89 struct option *option;
90 unsigned code; 90 unsigned code;
91 unsigned char bad_data[32*1024]; 91 unsigned char bad_data[32*1024];
92 unsigned char good_data[] = { 1,2,3,4,5,6 }; 92 unsigned char good_data[] = { 1,2,3,4,5,6 };
93 int emit_commas = 1; 93 int emit_commas = 1;
94 int emit_quotes = 1; 94 int emit_quotes = 1;
95 const char *output_buf; 95 const char *output_buf;
96 96
97 /* Initialize whole thing to non-printable chars */ 97 /* Initialize whole thing to non-printable chars */
98 memset(bad_data, 0x1f, sizeof(bad_data)); 98 memset(bad_data, 0x1f, sizeof(bad_data));
99 99
100 initialize_common_option_spaces(); 100 initialize_common_option_spaces();
101 101
102 /* We'll use dhcp_client_identitifer because it happens to be format X */ 102 /* We'll use dhcp_client_identitifer because it happens to be format X */
103 code = 61; 103 code = 61;
104 option = NULL; 104 option = NULL;
105 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, 105 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
106 &code, 0, MDL)) { 106 &code, 0, MDL)) {
107 atf_tc_fail("can't find option %d", code); 107 atf_tc_fail("can't find option %d", code);
108 } 108 }
109 109
110 if (option == NULL) { 110 if (option == NULL) {
111 atf_tc_fail("option is NULL"); 111 atf_tc_fail("option is NULL");
112 } 112 }
113 113
114 /* First we will try a good value we know should fit. */ 114 /* First we will try a good value we know should fit. */
115 output_buf = pretty_print_option (option, good_data, sizeof(good_data), 115 output_buf = pretty_print_option (option, good_data, sizeof(good_data),
116 emit_commas, emit_quotes); 116 emit_commas, emit_quotes);
117 117
118 /* Make sure we get what we expect */ 118 /* Make sure we get what we expect */
119 if (!output_buf || strcmp(output_buf, "1:2:3:4:5:6")) { 119 if (!output_buf || strcmp(output_buf, "1:2:3:4:5:6")) {
120 atf_tc_fail("pretty_print_option did not return \"<error>\""); 120 atf_tc_fail("pretty_print_option did not return \"<error>\"");
121 } 121 }
122 122
123 123
124 /* Now we'll try a data value that's too large */ 124 /* Now we'll try a data value that's too large */
125 output_buf = pretty_print_option (option, bad_data, sizeof(bad_data), 125 output_buf = pretty_print_option (option, bad_data, sizeof(bad_data),
126 emit_commas, emit_quotes); 126 emit_commas, emit_quotes);
127 127
128 /* Make sure we safely get an error */ 128 /* Make sure we safely get an error */
129 if (!output_buf || strcmp(output_buf, "<error>")) { 129 if (!output_buf || strcmp(output_buf, "<error>")) {
130 atf_tc_fail("pretty_print_option did not return \"<error>\""); 130 atf_tc_fail("pretty_print_option did not return \"<error>\"");
131 } 131 }
132} 132}
133 133
 134ATF_TC(parse_X);
 135
 136ATF_TC_HEAD(parse_X, tc)
 137{
 138 atf_tc_set_md_var(tc, "descr",
 139 "Verify parse_X survices option too big.");
 140}
 141
 142/* Initializes a parse struct from an input buffer of data. */
 143static void init_parse(struct parse *cfile, char* name, char *input) {
 144 memset(cfile, 0, sizeof(struct parse));
 145 cfile->tlname = name;
 146 cfile->lpos = cfile->line = 1;
 147 cfile->cur_line = cfile->line1;
 148 cfile->prev_line = cfile->line2;
 149 cfile->token_line = cfile->cur_line;
 150 cfile->cur_line[0] = cfile->prev_line[0] = 0;
 151 cfile->file = -1;
 152 cfile->eol_token = 0;
 153
 154 cfile->inbuf = input;
 155 cfile->buflen = strlen(input);
 156 cfile->bufsiz = 0;
 157}
 158
 159/*
 160 * This test verifies that parse_X does not overwrite the output
 161 * buffer when given input data that exceeds the output buffer
 162 * capacity.
 163*/
 164ATF_TC_BODY(parse_X, tc)
 165{
 166 struct parse cfile;
 167 u_int8_t output[10];
 168 unsigned len;
 169
 170 /* Input hex literal */
 171 char *input = "01:02:03:04:05:06:07:08";
 172 unsigned expected_len = 8;
 173
 174 /* Normal output plus two filler bytes */
 175 u_int8_t expected_plus_two[] = {
 176 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xff, 0xff
 177 };
 178
 179 /* Safe output when option is too long */
 180 unsigned short_buf_len = 4;
 181 u_int8_t expected_too_long[] = {
 182 0x01, 0x02, 0x03, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 183 };
 184
 185 /* First we'll run one that works normally */
 186 memset(output, 0xff, sizeof(output));
 187 init_parse(&cfile, "hex_fits", input);
 188
 189 len = parse_X(&cfile, output, expected_len);
 190
 191 // Len should match the expected len.
 192 if (len != expected_len) {
 193 atf_tc_fail("parse_X failed, output len: %d", len);
 194 }
 195
 196 // We should not have written anything past the end of the buffer.
 197 if (memcmp(output, expected_plus_two, sizeof(output))) {
 198 atf_tc_fail("parse_X failed, output does not match expected");
 199 }
 200
 201 // Now we'll try it with a buffer that's too small.
 202 init_parse(&cfile, "hex_too_long", input);
 203 memset(output, 0xff, sizeof(output));
 204
 205 len = parse_X(&cfile, output, short_buf_len);
 206
 207 // On errors, len should be zero.
 208 if (len != 0) {
 209 atf_tc_fail("parse_X failed, we should have had an error");
 210 }
 211
 212 // We should not have written anything past the end of the buffer.
 213 if (memcmp(output, expected_too_long, sizeof(output))) {
 214 atf_tc_fail("parse_X overwrote buffer!");
 215 }
 216}
134 217
135/* This macro defines main() method that will call specified 218/* This macro defines main() method that will call specified
136 test cases. tp and simple_test_case names can be whatever you want 219 test cases. tp and simple_test_case names can be whatever you want
137 as long as it is a valid variable identifier. */ 220 as long as it is a valid variable identifier. */
138ATF_TP_ADD_TCS(tp) 221ATF_TP_ADD_TCS(tp)
139{ 222{
140 ATF_TP_ADD_TC(tp, option_refcnt); 223 ATF_TP_ADD_TC(tp, option_refcnt);
141 ATF_TP_ADD_TC(tp, pretty_print_option); 224 ATF_TP_ADD_TC(tp, pretty_print_option);
 225 ATF_TP_ADD_TC(tp, parse_X);
142 226
143 return (atf_no_error()); 227 return (atf_no_error());
144} 228}

cvs diff -r1.4 -r1.5 src/external/mpl/dhcp/dist/relay/dhcrelay.c (switch to unified diff)

--- src/external/mpl/dhcp/dist/relay/dhcrelay.c 2021/05/21 21:07:37 1.4
+++ src/external/mpl/dhcp/dist/relay/dhcrelay.c 2021/05/26 22:52:32 1.5
@@ -1,2183 +1,2182 @@ @@ -1,2183 +1,2182 @@
1/* $NetBSD: dhcrelay.c,v 1.4 2021/05/21 21:07:37 christos Exp $ */ 1/* $NetBSD: dhcrelay.c,v 1.5 2021/05/26 22:52:32 christos Exp $ */
2 2
3/* dhcrelay.c 3/* dhcrelay.c
4 4
5 DHCP/BOOTP Relay Agent. */ 5 DHCP/BOOTP Relay Agent. */
6 6
7/* 7/*
8 * Copyright(c) 2004-2020 by Internet Systems Consortium, Inc.("ISC") 8 * Copyright(c) 2004-2021 by Internet Systems Consortium, Inc.("ISC")
9 * Copyright(c) 1997-2003 by Internet Software Consortium 9 * Copyright(c) 1997-2003 by Internet Software Consortium
10 * 10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public 11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this 12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 * 14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * 22 *
23 * Internet Systems Consortium, Inc. 23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street 24 * 950 Charter Street
25 * Redwood City, CA 94063 25 * Redwood City, CA 94063
26 * <info@isc.org> 26 * <info@isc.org>
27 * https://www.isc.org/ 27 * https://www.isc.org/
28 * 28 *
29 */ 29 */
30 30
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32__RCSID("$NetBSD: dhcrelay.c,v 1.4 2021/05/21 21:07:37 christos Exp $"); 32__RCSID("$NetBSD: dhcrelay.c,v 1.5 2021/05/26 22:52:32 christos Exp $");
33 33
34#include "dhcpd.h" 34#include "dhcpd.h"
35#include <syslog.h> 35#include <syslog.h>
36#include <signal.h> 36#include <signal.h>
37#include <sys/time.h> 37#include <sys/time.h>
38#include <isc/file.h> 38#include <isc/file.h>
39 39
40TIME default_lease_time = 43200; /* 12 hours... */ 40TIME default_lease_time = 43200; /* 12 hours... */
41TIME max_lease_time = 86400; /* 24 hours... */ 41TIME max_lease_time = 86400; /* 24 hours... */
42struct tree_cache *global_options[256]; 42struct tree_cache *global_options[256];
43 43
44struct option *requested_opts[2]; 44struct option *requested_opts[2];
45 45
46/* Needed to prevent linking against conflex.c. */ 46/* Needed to prevent linking against conflex.c. */
47int lexline; 47int lexline;
48int lexchar; 48int lexchar;
49char *token_line; 49char *token_line;
50char *tlname; 50char *tlname;
51 51
52const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID; 52const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID;
53isc_boolean_t no_dhcrelay_pid = ISC_FALSE; 53isc_boolean_t no_dhcrelay_pid = ISC_FALSE;
54/* False (default) => we write and use a pid file */ 54/* False (default) => we write and use a pid file */
55isc_boolean_t no_pid_file = ISC_FALSE; 55isc_boolean_t no_pid_file = ISC_FALSE;
56 56
57int bogus_agent_drops = 0; /* Packets dropped because agent option 57int bogus_agent_drops = 0; /* Packets dropped because agent option
58 field was specified and we're not relaying 58 field was specified and we're not relaying
59 packets that already have an agent option 59 packets that already have an agent option
60 specified. */ 60 specified. */
61int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a 61int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a
62 client, but with a bogus giaddr. */ 62 client, but with a bogus giaddr. */
63int client_packets_relayed = 0; /* Packets relayed from client to server. */ 63int client_packets_relayed = 0; /* Packets relayed from client to server. */
64int server_packet_errors = 0; /* Errors sending packets to servers. */ 64int server_packet_errors = 0; /* Errors sending packets to servers. */
65int server_packets_relayed = 0; /* Packets relayed from server to client. */ 65int server_packets_relayed = 0; /* Packets relayed from server to client. */
66int client_packet_errors = 0; /* Errors sending packets to clients. */ 66int client_packet_errors = 0; /* Errors sending packets to clients. */
67 67
68int add_agent_options = 0; /* If nonzero, add relay agent options. */ 68int add_agent_options = 0; /* If nonzero, add relay agent options. */
69int add_rfc3527_suboption = 0; /* If nonzero, add RFC3527 link selection sub-option. */ 69int add_rfc3527_suboption = 0; /* If nonzero, add RFC3527 link selection sub-option. */
70 70
71int agent_option_errors = 0; /* Number of packets forwarded without 71int agent_option_errors = 0; /* Number of packets forwarded without
72 agent options because there was no room. */ 72 agent options because there was no room. */
73int drop_agent_mismatches = 0; /* If nonzero, drop server replies that 73int drop_agent_mismatches = 0; /* If nonzero, drop server replies that
74 don't have matching circuit-id's. */ 74 don't have matching circuit-id's. */
75int corrupt_agent_options = 0; /* Number of packets dropped because 75int corrupt_agent_options = 0; /* Number of packets dropped because
76 relay agent information option was bad. */ 76 relay agent information option was bad. */
77int missing_agent_option = 0; /* Number of packets dropped because no 77int missing_agent_option = 0; /* Number of packets dropped because no
78 RAI option matching our ID was found. */ 78 RAI option matching our ID was found. */
79int bad_circuit_id = 0; /* Circuit ID option in matching RAI option 79int bad_circuit_id = 0; /* Circuit ID option in matching RAI option
80 did not match any known circuit ID. */ 80 did not match any known circuit ID. */
81int missing_circuit_id = 0; /* Circuit ID option in matching RAI option 81int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
82 was missing. */ 82 was missing. */
83int max_hop_count = 10; /* Maximum hop count */ 83int max_hop_count = 10; /* Maximum hop count */
84 84
85int no_daemon = 0; 85int no_daemon = 0;
86int dfd[2] = { -1, -1 }; 86int dfd[2] = { -1, -1 };
87 87
88#ifdef DHCPv6 88#ifdef DHCPv6
89 /* Force use of DHCPv6 interface-id option. */ 89 /* Force use of DHCPv6 interface-id option. */
90isc_boolean_t use_if_id = ISC_FALSE; 90isc_boolean_t use_if_id = ISC_FALSE;
91#endif 91#endif
92 92
93 /* Maximum size of a packet with agent options added. */ 93 /* Maximum size of a packet with agent options added. */
94int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN; 94int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
95 95
96 /* What to do about packets we're asked to relay that 96 /* What to do about packets we're asked to relay that
97 already have a relay option: */ 97 already have a relay option: */
98enum { forward_and_append, /* Forward and append our own relay option. */ 98enum { forward_and_append, /* Forward and append our own relay option. */
99 forward_and_replace, /* Forward, but replace theirs with ours. */ 99 forward_and_replace, /* Forward, but replace theirs with ours. */
100 forward_untouched, /* Forward without changes. */ 100 forward_untouched, /* Forward without changes. */
101 discard } agent_relay_mode = forward_and_replace; 101 discard } agent_relay_mode = forward_and_replace;
102 102
103u_int16_t local_port = 0; 103u_int16_t local_port = 0;
104u_int16_t remote_port = 0; 104u_int16_t remote_port = 0;
105 105
106/* Relay agent server list. */ 106/* Relay agent server list. */
107struct server_list { 107struct server_list {
108 struct server_list *next; 108 struct server_list *next;
109 struct sockaddr_in to; 109 struct sockaddr_in to;
110} *servers; 110} *servers;
111 111
112struct interface_info *uplink = NULL; 112struct interface_info *uplink = NULL;
113 113
114#ifdef DHCPv6 114#ifdef DHCPv6
115struct stream_list { 115struct stream_list {
116 struct stream_list *next; 116 struct stream_list *next;
117 struct interface_info *ifp; 117 struct interface_info *ifp;
118 struct sockaddr_in6 link; 118 struct sockaddr_in6 link;
119 int id; 119 int id;
120} *downstreams, *upstreams; 120} *downstreams, *upstreams;
121 121
122#ifndef UNIT_TEST 122#ifndef UNIT_TEST
123static struct stream_list *parse_downstream(char *); 123static struct stream_list *parse_downstream(char *);
124static struct stream_list *parse_upstream(char *); 124static struct stream_list *parse_upstream(char *);
125static void setup_streams(void); 125static void setup_streams(void);
126#endif /* UNIT_TEST */ 126#endif /* UNIT_TEST */
127 127
128/* 128/*
129 * A pointer to a subscriber id to add to the message we forward. 129 * A pointer to a subscriber id to add to the message we forward.
130 * This is primarily for testing purposes as we only have one id 130 * This is primarily for testing purposes as we only have one id
131 * for the entire relay and don't determine one per client which 131 * for the entire relay and don't determine one per client which
132 * would be more useful. 132 * would be more useful.
133 */ 133 */
134char *dhcrelay_sub_id = NULL; 134char *dhcrelay_sub_id = NULL;
135#endif 135#endif
136 136
137libdhcp_callbacks_t dhcrelay_callbacks = { 137libdhcp_callbacks_t dhcrelay_callbacks = {
138 &local_port, 138 &local_port,
139 &remote_port, 139 &remote_port,
140 classify, 140 classify,
141 check_collection, 141 check_collection,
142 dhcp, 142 dhcp,
143#ifdef DHCPv6 143#ifdef DHCPv6
144 dhcpv6, 144 dhcpv6,
145#endif /* DHCPv6 */ 145#endif /* DHCPv6 */
146 bootp, 146 bootp,
147 find_class, 147 find_class,
148 parse_allow_deny, 148 parse_allow_deny,
149 dhcp_set_control_state, 149 dhcp_set_control_state,
150}; 150};
151 151
152#ifndef UNIT_TEST 152#ifndef UNIT_TEST
153static void do_relay4(struct interface_info *, struct dhcp_packet *, 153static void do_relay4(struct interface_info *, struct dhcp_packet *,
154 unsigned int, unsigned int, struct iaddr, 154 unsigned int, unsigned int, struct iaddr,
155 struct hardware *); 155 struct hardware *);
156#endif /* UNIT_TEST */ 156#endif /* UNIT_TEST */
157 157
158extern int add_relay_agent_options(struct interface_info *, 158extern int add_relay_agent_options(struct interface_info *,
159 struct dhcp_packet *, unsigned, 159 struct dhcp_packet *, unsigned,
160 struct in_addr); 160 struct in_addr);
161extern int find_interface_by_agent_option(struct dhcp_packet *, 161extern int find_interface_by_agent_option(struct dhcp_packet *,
162 struct interface_info **, u_int8_t *, int); 162 struct interface_info **, u_int8_t *, int);
163 163
164extern int strip_relay_agent_options(struct interface_info *, 164extern int strip_relay_agent_options(struct interface_info *,
165 struct interface_info **, 165 struct interface_info **,
166 struct dhcp_packet *, unsigned); 166 struct dhcp_packet *, unsigned);
167 167
168#ifndef UNIT_TEST 168#ifndef UNIT_TEST
169static void request_v4_interface(const char* name, int flags); 169static void request_v4_interface(const char* name, int flags);
170 170
171static const char copyright[] = 171static const char copyright[] =
172"Copyright 2004-2020 Internet Systems Consortium."; 172"Copyright 2004-2021 Internet Systems Consortium.";
173static const char arr[] = "All rights reserved."; 173static const char arr[] = "All rights reserved.";
174static const char message[] = 174static const char message[] =
175"Internet Systems Consortium DHCP Relay Agent"; 175"Internet Systems Consortium DHCP Relay Agent";
176static const char url[] = 176static const char url[] =
177"For info, please visit https://www.isc.org/software/dhcp/"; 177"For info, please visit https://www.isc.org/software/dhcp/";
178 178
179char *progname; 179char *progname;
180 180
181#ifdef DHCPv6 181#ifdef DHCPv6
182#ifdef RELAY_PORT 182#ifdef RELAY_PORT
183#define DHCRELAY_USAGE \ 183#define DHCRELAY_USAGE \
184"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \ 184"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \
185" [-A <length>] [-c <hops>]\n" \ 185" [-A <length>] [-c <hops>]\n" \
186" [-p <port> | -rp <relay-port>]\n" \ 186" [-p <port> | -rp <relay-port>]\n" \
187" [-pf <pid-file>] [--no-pid]\n"\ 187" [-pf <pid-file>] [--no-pid]\n"\
188" [-m append|replace|forward|discard]\n" \ 188" [-m append|replace|forward|discard]\n" \
189" [-i interface0 [ ... -i interfaceN]\n" \ 189" [-i interface0 [ ... -i interfaceN]\n" \
190" [-iu interface0 [ ... -iu interfaceN]\n" \ 190" [-iu interface0 [ ... -iu interfaceN]\n" \
191" [-id interface0 [ ... -id interfaceN]\n" \ 191" [-id interface0 [ ... -id interfaceN]\n" \
192" [-U interface]\n" \ 192" [-U interface]\n" \
193" server0 [ ... serverN]\n\n" \ 193" server0 [ ... serverN]\n\n" \
194" %s -6 [-d] [-q] [-I] [-c <hops>]\n" \ 194" %s -6 [-d] [-q] [-I] [-c <hops>]\n" \
195" [-p <port> | -rp <relay-port>]\n" \ 195" [-p <port> | -rp <relay-port>]\n" \
196" [-pf <pid-file>] [--no-pid]\n" \ 196" [-pf <pid-file>] [--no-pid]\n" \
197" [-s <subscriber-id>]\n" \ 197" [-s <subscriber-id>]\n" \
198" -l lower0 [ ... -l lowerN]\n" \ 198" -l lower0 [ ... -l lowerN]\n" \
199" -u upper0 [ ... -u upperN]\n" \ 199" -u upper0 [ ... -u upperN]\n" \
200" lower (client link): [address%%]interface[#index]\n" \ 200" lower (client link): [address%%]interface[#index]\n" \
201" upper (server link): [address%%]interface\n\n" \ 201" upper (server link): [address%%]interface\n\n" \
202" %s {--version|--help|-h}" 202" %s {--version|--help|-h}"
203#else 203#else
204#define DHCRELAY_USAGE \ 204#define DHCRELAY_USAGE \
205"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \ 205"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \
206" [-A <length>] [-c <hops>] [-p <port>]\n" \ 206" [-A <length>] [-c <hops>] [-p <port>]\n" \
207" [-pf <pid-file>] [--no-pid]\n"\ 207" [-pf <pid-file>] [--no-pid]\n"\
208" [-m append|replace|forward|discard]\n" \ 208" [-m append|replace|forward|discard]\n" \
209" [-i interface0 [ ... -i interfaceN]\n" \ 209" [-i interface0 [ ... -i interfaceN]\n" \
210" [-iu interface0 [ ... -iu interfaceN]\n" \ 210" [-iu interface0 [ ... -iu interfaceN]\n" \
211" [-id interface0 [ ... -id interfaceN]\n" \ 211" [-id interface0 [ ... -id interfaceN]\n" \
212" [-U interface]\n" \ 212" [-U interface]\n" \
213" server0 [ ... serverN]\n\n" \ 213" server0 [ ... serverN]\n\n" \
214" %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \ 214" %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
215" [-pf <pid-file>] [--no-pid]\n" \ 215" [-pf <pid-file>] [--no-pid]\n" \
216" [-s <subscriber-id>]\n" \ 216" [-s <subscriber-id>]\n" \
217" -l lower0 [ ... -l lowerN]\n" \ 217" -l lower0 [ ... -l lowerN]\n" \
218" -u upper0 [ ... -u upperN]\n" \ 218" -u upper0 [ ... -u upperN]\n" \
219" lower (client link): [address%%]interface[#index]\n" \ 219" lower (client link): [address%%]interface[#index]\n" \
220" upper (server link): [address%%]interface\n\n" \ 220" upper (server link): [address%%]interface\n\n" \
221" %s {--version|--help|-h}" 221" %s {--version|--help|-h}"
222#endif 222#endif
223#else /* !DHCPv6 */ 223#else /* !DHCPv6 */
224#ifdef RELAY_PORT 224#ifdef RELAY_PORT
225#define DHCRELAY_USAGE \ 225#define DHCRELAY_USAGE \
226"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>]\n" \ 226"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>]\n" \
227" [-p <port> | -rp <relay-port>]\n" \ 227" [-p <port> | -rp <relay-port>]\n" \
228" [-pf <pid-file>] [--no-pid]\n" \ 228" [-pf <pid-file>] [--no-pid]\n" \
229" [-m append|replace|forward|discard]\n" \ 229" [-m append|replace|forward|discard]\n" \
230" [-i interface0 [ ... -i interfaceN]\n" \ 230" [-i interface0 [ ... -i interfaceN]\n" \
231" [-iu interface0 [ ... -iu interfaceN]\n" \ 231" [-iu interface0 [ ... -iu interfaceN]\n" \
232" [-id interface0 [ ... -id interfaceN]\n" \ 232" [-id interface0 [ ... -id interfaceN]\n" \
233" [-U interface]\n" \ 233" [-U interface]\n" \
234" server0 [ ... serverN]\n\n" \ 234" server0 [ ... serverN]\n\n" \
235" %s {--version|--help|-h}" 235" %s {--version|--help|-h}"
236#else 236#else
237#define DHCRELAY_USAGE \ 237#define DHCRELAY_USAGE \
238"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \ 238"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
239" [-pf <pid-file>] [--no-pid]\n" \ 239" [-pf <pid-file>] [--no-pid]\n" \
240" [-m append|replace|forward|discard]\n" \ 240" [-m append|replace|forward|discard]\n" \
241" [-i interface0 [ ... -i interfaceN]\n" \ 241" [-i interface0 [ ... -i interfaceN]\n" \
242" [-iu interface0 [ ... -iu interfaceN]\n" \ 242" [-iu interface0 [ ... -iu interfaceN]\n" \
243" [-id interface0 [ ... -id interfaceN]\n" \ 243" [-id interface0 [ ... -id interfaceN]\n" \
244" [-U interface]\n" \ 244" [-U interface]\n" \
245" server0 [ ... serverN]\n\n" \ 245" server0 [ ... serverN]\n\n" \
246" %s {--version|--help|-h}" 246" %s {--version|--help|-h}"
247#endif 247#endif
248#endif 248#endif
249 249
250/*! 250/*!
251 * 251 *
252 * \brief Print the generic usage message 252 * \brief Print the generic usage message
253 * 253 *
254 * If the user has provided an incorrect command line print out 254 * If the user has provided an incorrect command line print out
255 * the description of the command line. The arguments provide 255 * the description of the command line. The arguments provide
256 * a way for the caller to request more specific information about 256 * a way for the caller to request more specific information about
257 * the error be printed as well. Mostly this will be that some 257 * the error be printed as well. Mostly this will be that some
258 * comamnd doesn't include its argument. 258 * comamnd doesn't include its argument.
259 * 259 *
260 * \param sfmt - The basic string and format for the specific error 260 * \param sfmt - The basic string and format for the specific error
261 * \param sarg - Generally the offending argument from the comamnd line. 261 * \param sarg - Generally the offending argument from the comamnd line.
262 * 262 *
263 * \return Nothing 263 * \return Nothing
264 */ 264 */
265 265
266#include <sys/cdefs.h> 266#include <sys/cdefs.h>
267__RCSID("$NetBSD: dhcrelay.c,v 1.4 2021/05/21 21:07:37 christos Exp $"); 267__RCSID("$NetBSD: dhcrelay.c,v 1.5 2021/05/26 22:52:32 christos Exp $");
268static const char use_noarg[] = "No argument for command: %s"; 268static const char use_noarg[] = "No argument for command: %s";
269#ifdef RELAY_PORT 269#ifdef RELAY_PORT
270static const char use_port_defined[] = "Port already set, %s inappropriate"; 270static const char use_port_defined[] = "Port already set, %s inappropriate";
271#if !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE) 271#if !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE)
272static const char bpf_sock_support[] = "Only LPF and BPF are supported: %s"; 272static const char bpf_sock_support[] = "Only LPF and BPF are supported: %s";
273#endif 273#endif
274#endif 274#endif
275#ifdef DHCPv6 275#ifdef DHCPv6
276static const char use_badproto[] = "Protocol already set, %s inappropriate"; 276static const char use_badproto[] = "Protocol already set, %s inappropriate";
277static const char use_v4command[] = "Command not used for DHCPv6: %s"; 277static const char use_v4command[] = "Command not used for DHCPv6: %s";
278static const char use_v6command[] = "Command not used for DHCPv4: %s"; 278static const char use_v6command[] = "Command not used for DHCPv4: %s";
279#endif 279#endif
280 280
281static void 281static void
282usage(const char *sfmt, const char *sarg) { 282usage(const char *sfmt, const char *sarg) {
283 log_info("%s %s", message, PACKAGE_VERSION); 283 log_info("%s %s", message, PACKAGE_VERSION);
284 log_info(copyright); 284 log_info(copyright);
285 log_info(arr); 285 log_info(arr);
286 log_info(url); 286 log_info(url);
287 287
288 /* If desired print out the specific error message */ 288 /* If desired print out the specific error message */
289#ifdef PRINT_SPECIFIC_CL_ERRORS 289#ifdef PRINT_SPECIFIC_CL_ERRORS
290 if (sfmt != NULL) 290 if (sfmt != NULL)
291 log_error(sfmt, sarg); 291 log_error(sfmt, sarg);
292#endif 292#endif
293 293
294 log_fatal(DHCRELAY_USAGE, 294 log_fatal(DHCRELAY_USAGE,
295#ifdef DHCPv6 295#ifdef DHCPv6
296 isc_file_basename(progname), 296 isc_file_basename(progname),
297#endif 297#endif
298 isc_file_basename(progname), 298 isc_file_basename(progname),
299 isc_file_basename(progname)); 299 isc_file_basename(progname));
300} 300}
301 301
302int 302int
303main(int argc, char **argv) { 303main(int argc, char **argv) {
304 isc_result_t status; 304 isc_result_t status;
305 struct servent *ent; 305 struct servent *ent;
306 struct server_list *sp = NULL; 306 struct server_list *sp = NULL;
307 char *service_local = NULL, *service_remote = NULL; 307 char *service_local = NULL, *service_remote = NULL;
308 u_int16_t port_local = 0, port_remote = 0; 308 u_int16_t port_local = 0, port_remote = 0;
309 int quiet = 0; 309 int quiet = 0;
310 int fd; 310 int fd;
311 int i; 311 int i;
312#ifdef RELAY_PORT 312#ifdef RELAY_PORT
313 int port_defined = 0; 313 int port_defined = 0;
314#endif 314#endif
315#ifdef DHCPv6 315#ifdef DHCPv6
316 struct stream_list *sl = NULL; 316 struct stream_list *sl = NULL;
317 int local_family_set = 0; 317 int local_family_set = 0;
318#endif 318#endif
319 319
320 libdhcp_callbacks_register(&dhcrelay_callbacks); 320 libdhcp_callbacks_register(&dhcrelay_callbacks);
321 321
322#ifdef OLD_LOG_NAME 322#ifdef OLD_LOG_NAME
323 progname = "dhcrelay"; 323 progname = "dhcrelay";
324#else 324#else
325 progname = argv[0]; 325 progname = argv[0];
326#endif 326#endif
327 327
328 /* Make sure that file descriptors 0(stdin), 1,(stdout), and 328 /* Make sure that file descriptors 0(stdin), 1,(stdout), and
329 2(stderr) are open. To do this, we assume that when we 329 2(stderr) are open. To do this, we assume that when we
330 open a file the lowest available file descriptor is used. */ 330 open a file the lowest available file descriptor is used. */
331 fd = open("/dev/null", O_RDWR); 331 fd = open("/dev/null", O_RDWR);
332 if (fd == 0) 332 if (fd == 0)
333 fd = open("/dev/null", O_RDWR); 333 fd = open("/dev/null", O_RDWR);
334 if (fd == 1) 334 if (fd == 1)
335 fd = open("/dev/null", O_RDWR); 335 fd = open("/dev/null", O_RDWR);
336 if (fd == 2) 336 if (fd == 2)
337 log_perror = 0; /* No sense logging to /dev/null. */ 337 log_perror = 0; /* No sense logging to /dev/null. */
338 else if (fd != -1) 338 else if (fd != -1)
339 close(fd); 339 close(fd);
340 340
341 openlog(isc_file_basename(progname), DHCP_LOG_OPTIONS, LOG_DAEMON); 341 openlog(isc_file_basename(progname), DHCP_LOG_OPTIONS, LOG_DAEMON);
342 342
343#if !defined(DEBUG) 343#if !defined(DEBUG)
344 setlogmask(LOG_UPTO(LOG_INFO)); 344 setlogmask(LOG_UPTO(LOG_INFO));
345#endif 345#endif
346 346
347 /* Parse arguments changing no_daemon */ 347 /* Parse arguments changing no_daemon */
348 for (i = 1; i < argc; i++) { 348 for (i = 1; i < argc; i++) {
349 if (!strcmp(argv[i], "-d")) { 349 if (!strcmp(argv[i], "-d")) {
350 no_daemon = 1; 350 no_daemon = 1;
351 } else if (!strcmp(argv[i], "--version")) { 351 } else if (!strcmp(argv[i], "--version")) {
352 log_info("isc-dhcrelay-%s", PACKAGE_VERSION); 352 log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
353 exit(0); 353 exit(0);
354 } else if (!strcmp(argv[i], "--help") || 354 } else if (!strcmp(argv[i], "--help") ||
355 !strcmp(argv[i], "-h")) { 355 !strcmp(argv[i], "-h")) {
356 log_info(DHCRELAY_USAGE, 356 log_info(DHCRELAY_USAGE,
357#ifdef DHCPv6 357#ifdef DHCPv6
358 isc_file_basename(progname), 358 isc_file_basename(progname),
359#endif 359#endif
360 isc_file_basename(progname), 360 isc_file_basename(progname),
361 isc_file_basename(progname)); 361 isc_file_basename(progname));
362 exit(0); 362 exit(0);
363 } 363 }
364 } 364 }
365 /* When not forbidden prepare to become a daemon */ 365 /* When not forbidden prepare to become a daemon */
366 if (!no_daemon) { 366 if (!no_daemon) {
367 int pid; 367 int pid;
368 368
369 if (pipe(dfd) == -1) 369 if (pipe(dfd) == -1)
370 log_fatal("Can't get pipe: %m"); 370 log_fatal("Can't get pipe: %m");
371 if ((pid = fork ()) < 0) 371 if ((pid = fork ()) < 0)
372 log_fatal("Can't fork daemon: %m"); 372 log_fatal("Can't fork daemon: %m");
373 if (pid != 0) { 373 if (pid != 0) {
374 /* Parent: wait for the child to start */ 374 /* Parent: wait for the child to start */
375 int n; 375 int n;
376 376
377 (void) close(dfd[1]); 377 (void) close(dfd[1]);
378 do { 378 do {
379 char buf; 379 char buf;
380 380
381 n = read(dfd[0], &buf, 1); 381 n = read(dfd[0], &buf, 1);
382 if (n == 1) 382 if (n == 1)
383 _exit(0); 383 _exit(0);
384 } while (n == -1 && errno == EINTR); 384 } while (n == -1 && errno == EINTR);
385 _exit(1); 385 _exit(1);
386 } 386 }
387 /* Child */ 387 /* Child */
388 (void) close(dfd[0]); 388 (void) close(dfd[0]);
389 } 389 }
390 390
391 391
392 /* Set up the isc and dns library managers */ 392 /* Set up the isc and dns library managers */
393 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL); 393 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL);
394 if (status != ISC_R_SUCCESS) 394 if (status != ISC_R_SUCCESS)
395 log_fatal("Can't initialize context: %s", 395 log_fatal("Can't initialize context: %s",
396 isc_result_totext(status)); 396 isc_result_totext(status));
397 397
398 /* Set up the OMAPI. */ 398 /* Set up the OMAPI. */
399 status = omapi_init(); 399 status = omapi_init();
400 if (status != ISC_R_SUCCESS) 400 if (status != ISC_R_SUCCESS)
401 log_fatal("Can't initialize OMAPI: %s", 401 log_fatal("Can't initialize OMAPI: %s",
402 isc_result_totext(status)); 402 isc_result_totext(status));
403 403
404 /* Set up the OMAPI wrappers for the interface object. */ 404 /* Set up the OMAPI wrappers for the interface object. */
405 interface_setup(); 405 interface_setup();
406 406
407 for (i = 1; i < argc; i++) { 407 for (i = 1; i < argc; i++) {
408 if (!strcmp(argv[i], "-4")) { 408 if (!strcmp(argv[i], "-4")) {
409#ifdef DHCPv6 409#ifdef DHCPv6
410 if (local_family_set && (local_family == AF_INET6)) { 410 if (local_family_set && (local_family == AF_INET6)) {
411 usage(use_badproto, "-4"); 411 usage(use_badproto, "-4");
412 } 412 }
413 local_family_set = 1; 413 local_family_set = 1;
414 local_family = AF_INET; 414 local_family = AF_INET;
415 } else if (!strcmp(argv[i], "-6")) { 415 } else if (!strcmp(argv[i], "-6")) {
416 if (local_family_set && (local_family == AF_INET)) { 416 if (local_family_set && (local_family == AF_INET)) {
417 usage(use_badproto, "-6"); 417 usage(use_badproto, "-6");
418 } 418 }
419 local_family_set = 1; 419 local_family_set = 1;
420 local_family = AF_INET6; 420 local_family = AF_INET6;
421#endif 421#endif
422 } else if (!strcmp(argv[i], "-d")) { 422 } else if (!strcmp(argv[i], "-d")) {
423 /* no_daemon = 1; */ 423 /* no_daemon = 1; */
424 } else if (!strcmp(argv[i], "-q")) { 424 } else if (!strcmp(argv[i], "-q")) {
425 quiet = 1; 425 quiet = 1;
426 quiet_interface_discovery = 1; 426 quiet_interface_discovery = 1;
427 } else if (!strcmp(argv[i], "-p")) { 427 } else if (!strcmp(argv[i], "-p")) {
428 if (++i == argc) 428 if (++i == argc)
429 usage(use_noarg, argv[i-1]); 429 usage(use_noarg, argv[i-1]);
430#ifdef RELAY_PORT 430#ifdef RELAY_PORT
431 if (port_defined) 431 if (port_defined)
432 usage(use_port_defined, argv[i-1]); 432 usage(use_port_defined, argv[i-1]);
433 port_defined = 1; 433 port_defined = 1;
434#endif 434#endif
435 local_port = validate_port(argv[i]); 435 local_port = validate_port(argv[i]);
436 log_debug("binding to user-specified port %d", 436 log_debug("binding to user-specified port %d",
437 ntohs(local_port)); 437 ntohs(local_port));
438#ifdef RELAY_PORT 438#ifdef RELAY_PORT
439 } else if (!strcmp(argv[i], "-rp")) { 439 } else if (!strcmp(argv[i], "-rp")) {
440 if (++i == argc) 440 if (++i == argc)
441 usage(use_noarg, argv[i-1]); 441 usage(use_noarg, argv[i-1]);
442 if (port_defined) 442 if (port_defined)
443 usage(use_port_defined, argv[i-1]); 443 usage(use_port_defined, argv[i-1]);
444 port_defined = 1; 444 port_defined = 1;
445 relay_port = validate_port(argv[i]); 445 relay_port = validate_port(argv[i]);
446 log_debug("binding to user-specified relay port %d", 446 log_debug("binding to user-specified relay port %d",
447 ntohs(relay_port)); 447 ntohs(relay_port));
448 add_agent_options = 1; 448 add_agent_options = 1;
449#endif 449#endif
450 } else if (!strcmp(argv[i], "-c")) { 450 } else if (!strcmp(argv[i], "-c")) {
451 int hcount; 451 int hcount;
452 if (++i == argc) 452 if (++i == argc)
453 usage(use_noarg, argv[i-1]); 453 usage(use_noarg, argv[i-1]);
454 hcount = atoi(argv[i]); 454 hcount = atoi(argv[i]);
455 if (hcount <= 255) 455 if (hcount <= 255)
456 max_hop_count= hcount; 456 max_hop_count= hcount;
457 else 457 else
458 usage("Bad hop count to -c: %s", argv[i]); 458 usage("Bad hop count to -c: %s", argv[i]);
459 } else if (!strcmp(argv[i], "-i")) { 459 } else if (!strcmp(argv[i], "-i")) {
460#ifdef DHCPv6 460#ifdef DHCPv6
461 if (local_family_set && (local_family == AF_INET6)) { 461 if (local_family_set && (local_family == AF_INET6)) {
462 usage(use_v4command, argv[i]); 462 usage(use_v4command, argv[i]);
463 } 463 }
464 local_family_set = 1; 464 local_family_set = 1;
465 local_family = AF_INET; 465 local_family = AF_INET;
466#endif 466#endif
467 if (++i == argc) { 467 if (++i == argc) {
468 usage(use_noarg, argv[i-1]); 468 usage(use_noarg, argv[i-1]);
469 } 469 }
470 470
471 request_v4_interface(argv[i], INTERFACE_STREAMS); 471 request_v4_interface(argv[i], INTERFACE_STREAMS);
472 } else if (!strcmp(argv[i], "-iu")) { 472 } else if (!strcmp(argv[i], "-iu")) {
473#ifdef DHCPv6 473#ifdef DHCPv6
474 if (local_family_set && (local_family == AF_INET6)) { 474 if (local_family_set && (local_family == AF_INET6)) {
475 usage(use_v4command, argv[i]); 475 usage(use_v4command, argv[i]);
476 } 476 }
477 local_family_set = 1; 477 local_family_set = 1;
478 local_family = AF_INET; 478 local_family = AF_INET;
479#endif 479#endif
480 if (++i == argc) { 480 if (++i == argc) {
481 usage(use_noarg, argv[i-1]); 481 usage(use_noarg, argv[i-1]);
482 } 482 }
483 483
484 request_v4_interface(argv[i], INTERFACE_UPSTREAM); 484 request_v4_interface(argv[i], INTERFACE_UPSTREAM);
485 } else if (!strcmp(argv[i], "-id")) { 485 } else if (!strcmp(argv[i], "-id")) {
486#ifdef DHCPv6 486#ifdef DHCPv6
487 if (local_family_set && (local_family == AF_INET6)) { 487 if (local_family_set && (local_family == AF_INET6)) {
488 usage(use_v4command, argv[i]); 488 usage(use_v4command, argv[i]);
489 } 489 }
490 local_family_set = 1; 490 local_family_set = 1;
491 local_family = AF_INET; 491 local_family = AF_INET;
492#endif 492#endif
493 if (++i == argc) { 493 if (++i == argc) {
494 usage(use_noarg, argv[i-1]); 494 usage(use_noarg, argv[i-1]);
495 } 495 }
496 496
497 request_v4_interface(argv[i], INTERFACE_DOWNSTREAM); 497 request_v4_interface(argv[i], INTERFACE_DOWNSTREAM);
498 } else if (!strcmp(argv[i], "-a")) { 498 } else if (!strcmp(argv[i], "-a")) {
499#ifdef DHCPv6 499#ifdef DHCPv6
500 if (local_family_set && (local_family == AF_INET6)) { 500 if (local_family_set && (local_family == AF_INET6)) {
501 usage(use_v4command, argv[i]); 501 usage(use_v4command, argv[i]);
502 } 502 }
503 local_family_set = 1; 503 local_family_set = 1;
504 local_family = AF_INET; 504 local_family = AF_INET;
505#endif 505#endif
506 add_agent_options = 1; 506 add_agent_options = 1;
507 } else if (!strcmp(argv[i], "-A")) { 507 } else if (!strcmp(argv[i], "-A")) {
508#ifdef DHCPv6 508#ifdef DHCPv6
509 if (local_family_set && (local_family == AF_INET6)) { 509 if (local_family_set && (local_family == AF_INET6)) {
510 usage(use_v4command, argv[i]); 510 usage(use_v4command, argv[i]);
511 } 511 }
512 local_family_set = 1; 512 local_family_set = 1;
513 local_family = AF_INET; 513 local_family = AF_INET;
514#endif 514#endif
515 if (++i == argc) 515 if (++i == argc)
516 usage(use_noarg, argv[i-1]); 516 usage(use_noarg, argv[i-1]);
517 517
518 dhcp_max_agent_option_packet_length = atoi(argv[i]); 518 dhcp_max_agent_option_packet_length = atoi(argv[i]);
519 519
520 if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX) 520 if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX)
521 log_fatal("%s: packet length exceeds " 521 log_fatal("%s: packet length exceeds "
522 "longest possible MTU\n", 522 "longest possible MTU\n",
523 argv[i]); 523 argv[i]);
524 } else if (!strcmp(argv[i], "-m")) { 524 } else if (!strcmp(argv[i], "-m")) {
525#ifdef DHCPv6 525#ifdef DHCPv6
526 if (local_family_set && (local_family == AF_INET6)) { 526 if (local_family_set && (local_family == AF_INET6)) {
527 usage(use_v4command, argv[i]); 527 usage(use_v4command, argv[i]);
528 } 528 }
529 local_family_set = 1; 529 local_family_set = 1;
530 local_family = AF_INET; 530 local_family = AF_INET;
531#endif 531#endif
532 if (++i == argc) 532 if (++i == argc)
533 usage(use_noarg, argv[i-1]); 533 usage(use_noarg, argv[i-1]);
534 if (!strcasecmp(argv[i], "append")) { 534 if (!strcasecmp(argv[i], "append")) {
535 agent_relay_mode = forward_and_append; 535 agent_relay_mode = forward_and_append;
536 } else if (!strcasecmp(argv[i], "replace")) { 536 } else if (!strcasecmp(argv[i], "replace")) {
537 agent_relay_mode = forward_and_replace; 537 agent_relay_mode = forward_and_replace;
538 } else if (!strcasecmp(argv[i], "forward")) { 538 } else if (!strcasecmp(argv[i], "forward")) {
539 agent_relay_mode = forward_untouched; 539 agent_relay_mode = forward_untouched;
540 } else if (!strcasecmp(argv[i], "discard")) { 540 } else if (!strcasecmp(argv[i], "discard")) {
541 agent_relay_mode = discard; 541 agent_relay_mode = discard;
542 } else 542 } else
543 usage("Unknown argument to -m: %s", argv[i]); 543 usage("Unknown argument to -m: %s", argv[i]);
544 } else if (!strcmp(argv [i], "-U")) { 544 } else if (!strcmp(argv [i], "-U")) {
545 if (++i == argc) 545 if (++i == argc)
546 usage(use_noarg, argv[i-1]); 546 usage(use_noarg, argv[i-1]);
547 547
548 if (uplink) { 548 if (uplink) {
549 usage("more than one uplink (-U) specified: %s" 549 usage("more than one uplink (-U) specified: %s"
550 ,argv[i]); 550 ,argv[i]);
551 } 551 }
552 552
553 /* Allocate the uplink interface */ 553 /* Allocate the uplink interface */
554 status = interface_allocate(&uplink, MDL); 554 status = interface_allocate(&uplink, MDL);
555 if (status != ISC_R_SUCCESS) { 555 if (status != ISC_R_SUCCESS) {
556 log_fatal("%s: uplink interface_allocate: %s", 556 log_fatal("%s: uplink interface_allocate: %s",
557 argv[i], isc_result_totext(status)); 557 argv[i], isc_result_totext(status));
558 } 558 }
559 559
560 if (strlen(argv[i]) >= sizeof(uplink->name)) { 560 if (strlen(argv[i]) >= sizeof(uplink->name)) {
561 log_fatal("%s: uplink name too long," 561 log_fatal("%s: uplink name too long,"
562 " it cannot exceed: %ld characters", 562 " it cannot exceed: %ld characters",
563 argv[i], (long)(sizeof(uplink->name) - 1)); 563 argv[i], (long)(sizeof(uplink->name) - 1));
564 } 564 }
565 565
566 uplink->name[sizeof(uplink->name) - 1] = 0x00; 566 uplink->name[sizeof(uplink->name) - 1] = 0x00;
567 strncpy(uplink->name, argv[i], 567 strncpy(uplink->name, argv[i],
568 sizeof(uplink->name) - 1); 568 sizeof(uplink->name) - 1);
569 interface_snorf(uplink, (INTERFACE_REQUESTED | 569 interface_snorf(uplink, (INTERFACE_REQUESTED |
570 INTERFACE_STREAMS)); 570 INTERFACE_STREAMS));
571 571
572 /* Turn on -a, in case they don't do so explicitly */ 572 /* Turn on -a, in case they don't do so explicitly */
573 add_agent_options = 1; 573 add_agent_options = 1;
574 add_rfc3527_suboption = 1; 574 add_rfc3527_suboption = 1;
575 } else if (!strcmp(argv[i], "-D")) { 575 } else if (!strcmp(argv[i], "-D")) {
576#ifdef DHCPv6 576#ifdef DHCPv6
577 if (local_family_set && (local_family == AF_INET6)) { 577 if (local_family_set && (local_family == AF_INET6)) {
578 usage(use_v4command, argv[i]); 578 usage(use_v4command, argv[i]);
579 } 579 }
580 local_family_set = 1; 580 local_family_set = 1;
581 local_family = AF_INET; 581 local_family = AF_INET;
582#endif 582#endif
583 drop_agent_mismatches = 1; 583 drop_agent_mismatches = 1;
584#ifdef DHCPv6 584#ifdef DHCPv6
585 } else if (!strcmp(argv[i], "-I")) { 585 } else if (!strcmp(argv[i], "-I")) {
586 if (local_family_set && (local_family == AF_INET)) { 586 if (local_family_set && (local_family == AF_INET)) {
587 usage(use_v6command, argv[i]); 587 usage(use_v6command, argv[i]);
588 } 588 }
589 local_family_set = 1; 589 local_family_set = 1;
590 local_family = AF_INET6; 590 local_family = AF_INET6;
591 use_if_id = ISC_TRUE; 591 use_if_id = ISC_TRUE;
592 } else if (!strcmp(argv[i], "-l")) { 592 } else if (!strcmp(argv[i], "-l")) {
593 if (local_family_set && (local_family == AF_INET)) { 593 if (local_family_set && (local_family == AF_INET)) {
594 usage(use_v6command, argv[i]); 594 usage(use_v6command, argv[i]);
595 } 595 }
596 local_family_set = 1; 596 local_family_set = 1;
597 local_family = AF_INET6; 597 local_family = AF_INET6;
598 if (downstreams != NULL) 598 if (downstreams != NULL)
599 use_if_id = ISC_TRUE; 599 use_if_id = ISC_TRUE;
600 if (++i == argc) 600 if (++i == argc)
601 usage(use_noarg, argv[i-1]); 601 usage(use_noarg, argv[i-1]);
602 sl = parse_downstream(argv[i]); 602 sl = parse_downstream(argv[i]);
603 sl->next = downstreams; 603 sl->next = downstreams;
604 downstreams = sl; 604 downstreams = sl;
605 } else if (!strcmp(argv[i], "-u")) { 605 } else if (!strcmp(argv[i], "-u")) {
606 if (local_family_set && (local_family == AF_INET)) { 606 if (local_family_set && (local_family == AF_INET)) {
607 usage(use_v6command, argv[i]); 607 usage(use_v6command, argv[i]);
608 } 608 }
609 local_family_set = 1; 609 local_family_set = 1;
610 local_family = AF_INET6; 610 local_family = AF_INET6;
611 if (++i == argc) 611 if (++i == argc)
612 usage(use_noarg, argv[i-1]); 612 usage(use_noarg, argv[i-1]);
613 sl = parse_upstream(argv[i]); 613 sl = parse_upstream(argv[i]);
614 sl->next = upstreams; 614 sl->next = upstreams;
615 upstreams = sl; 615 upstreams = sl;
616 } else if (!strcmp(argv[i], "-s")) { 616 } else if (!strcmp(argv[i], "-s")) {
617 if (local_family_set && (local_family == AF_INET)) { 617 if (local_family_set && (local_family == AF_INET)) {
618 usage(use_v6command, argv[i]); 618 usage(use_v6command, argv[i]);
619 } 619 }
620 local_family_set = 1; 620 local_family_set = 1;
621 local_family = AF_INET6; 621 local_family = AF_INET6;
622 if (++i == argc) 622 if (++i == argc)
623 usage(use_noarg, argv[i-1]); 623 usage(use_noarg, argv[i-1]);
624 dhcrelay_sub_id = argv[i]; 624 dhcrelay_sub_id = argv[i];
625#endif 625#endif
626 } else if (!strcmp(argv[i], "-pf")) { 626 } else if (!strcmp(argv[i], "-pf")) {
627 if (++i == argc) 627 if (++i == argc)
628 usage(use_noarg, argv[i-1]); 628 usage(use_noarg, argv[i-1]);
629 path_dhcrelay_pid = argv[i]; 629 path_dhcrelay_pid = argv[i];
630 no_dhcrelay_pid = ISC_TRUE; 630 no_dhcrelay_pid = ISC_TRUE;
631 } else if (!strcmp(argv[i], "--no-pid")) { 631 } else if (!strcmp(argv[i], "--no-pid")) {
632 no_pid_file = ISC_TRUE; 632 no_pid_file = ISC_TRUE;
633 } else if (argv[i][0] == '-') { 633 } else if (argv[i][0] == '-') {
634 usage("Unknown command: %s", argv[i]); 634 usage("Unknown command: %s", argv[i]);
635 } else { 635 } else {
636 struct hostent *he; 636 struct hostent *he;
637 struct in_addr ia, *iap = NULL; 637 struct in_addr ia, *iap = NULL;
638 638
639#ifdef DHCPv6 639#ifdef DHCPv6
640 if (local_family_set && (local_family == AF_INET6)) { 640 if (local_family_set && (local_family == AF_INET6)) {
641 usage(use_v4command, argv[i]); 641 usage(use_v4command, argv[i]);
642 } 642 }
643 local_family_set = 1; 643 local_family_set = 1;
644 local_family = AF_INET; 644 local_family = AF_INET;
645#endif 645#endif
646 if (inet_aton(argv[i], &ia)) { 646 if (inet_aton(argv[i], &ia)) {
647 iap = &ia; 647 iap = &ia;
648 } else { 648 } else {
649 he = gethostbyname(argv[i]); 649 he = gethostbyname(argv[i]);
650 if (!he) { 650 if (!he) {
651 log_error("%s: host unknown", argv[i]); 651 log_error("%s: host unknown", argv[i]);
652 } else { 652 } else {
653 iap = ((struct in_addr *) 653 iap = ((struct in_addr *)
654 he->h_addr_list[0]); 654 he->h_addr_list[0]);
655 } 655 }
656 } 656 }
657 657
658 if (iap) { 658 if (iap) {
659 sp = ((struct server_list *) 659 sp = ((struct server_list *)
660 dmalloc(sizeof *sp, MDL)); 660 dmalloc(sizeof *sp, MDL));
661 if (!sp) 661 if (!sp)
662 log_fatal("no memory for server.\n"); 662 log_fatal("no memory for server.\n");
663 sp->next = servers; 663 sp->next = servers;
664 servers = sp; 664 servers = sp;
665 memcpy(&sp->to.sin_addr, iap, sizeof *iap); 665 memcpy(&sp->to.sin_addr, iap, sizeof *iap);
666 } 666 }
667 } 667 }
668 } 668 }
669 669
670#if defined(RELAY_PORT) && \ 670#if defined(RELAY_PORT) && \
671 !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE) 671 !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE)
672 if (relay_port && (local_family == AF_INET)) 672 if (relay_port && (local_family == AF_INET))
673 usage(bpf_sock_support, "-rp"); 673 usage(bpf_sock_support, "-rp");
674#endif 674#endif
675 675
676 /* 676 /*
677 * If the user didn't specify a pid file directly 677 * If the user didn't specify a pid file directly
678 * find one from environment variables or defaults 678 * find one from environment variables or defaults
679 */ 679 */
680 if (no_dhcrelay_pid == ISC_FALSE) { 680 if (no_dhcrelay_pid == ISC_FALSE) {
681 if (local_family == AF_INET) { 681 if (local_family == AF_INET) {
682 path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID"); 682 path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID");
683 if (path_dhcrelay_pid == NULL) 683 if (path_dhcrelay_pid == NULL)
684 path_dhcrelay_pid = _PATH_DHCRELAY_PID; 684 path_dhcrelay_pid = _PATH_DHCRELAY_PID;
685 } 685 }
686#ifdef DHCPv6 686#ifdef DHCPv6
687 else { 687 else {
688 path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID"); 688 path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID");
689 if (path_dhcrelay_pid == NULL) 689 if (path_dhcrelay_pid == NULL)
690 path_dhcrelay_pid = _PATH_DHCRELAY6_PID; 690 path_dhcrelay_pid = _PATH_DHCRELAY6_PID;
691 } 691 }
692#endif 692#endif
693 } 693 }
694 694
695 if (!quiet) { 695 if (!quiet) {
696 log_info("%s %s", message, PACKAGE_VERSION); 696 log_info("%s %s", message, PACKAGE_VERSION);
697 log_info(copyright); 697 log_info(copyright);
698 log_info(arr); 698 log_info(arr);
699 log_info(url); 699 log_info(url);
700 } else 700 } else
701 log_perror = 0; 701 log_perror = 0;
702 702
703 /* Set default port */ 703 /* Set default port */
704 if (local_family == AF_INET) { 704 if (local_family == AF_INET) {
705 service_local = "bootps"; 705 service_local = "bootps";
706 service_remote = "bootpc"; 706 service_remote = "bootpc";
707 port_local = htons(67); 707 port_local = htons(67);
708 port_remote = htons(68); 708 port_remote = htons(68);
709 } 709 }
710#ifdef DHCPv6 710#ifdef DHCPv6
711 else { 711 else {
712 service_local = "dhcpv6-server"; 712 service_local = "dhcpv6-server";
713 service_remote = "dhcpv6-client"; 713 service_remote = "dhcpv6-client";
714 port_local = htons(547); 714 port_local = htons(547);
715 port_remote = htons(546); 715 port_remote = htons(546);
716 } 716 }
717#endif 717#endif
718 718
719 if (!local_port) { 719 if (!local_port) {
720 ent = getservbyname(service_local, "udp"); 720 ent = getservbyname(service_local, "udp");
721 if (ent) 721 if (ent)
722 local_port = ent->s_port; 722 local_port = ent->s_port;
723 else 723 else
724 local_port = port_local; 724 local_port = port_local;
725 725
726 ent = getservbyname(service_remote, "udp"); 726 ent = getservbyname(service_remote, "udp");
727 if (ent) 727 if (ent)
728 remote_port = ent->s_port; 728 remote_port = ent->s_port;
729 else 729 else
730 remote_port = port_remote; 730 remote_port = port_remote;
731 731
732 endservent(); 732 endservent();
733 } 733 }
734 734
735 if (local_family == AF_INET) { 735 if (local_family == AF_INET) {
736 /* We need at least one server */ 736 /* We need at least one server */
737 if (servers == NULL) { 737 if (servers == NULL) {
738 log_fatal("No servers specified."); 738 log_fatal("No servers specified.");
739 } 739 }
740 740
741 741
742 /* Set up the server sockaddrs. */ 742 /* Set up the server sockaddrs. */
743 for (sp = servers; sp; sp = sp->next) { 743 for (sp = servers; sp; sp = sp->next) {
744 sp->to.sin_port = local_port; 744 sp->to.sin_port = local_port;
745 sp->to.sin_family = AF_INET; 745 sp->to.sin_family = AF_INET;
746#ifdef HAVE_SA_LEN 746#ifdef HAVE_SA_LEN
747 sp->to.sin_len = sizeof sp->to; 747 sp->to.sin_len = sizeof sp->to;
748#endif 748#endif
749 } 749 }
750 } 750 }
751#ifdef DHCPv6 751#ifdef DHCPv6
752 else { 752 else {
753 unsigned code; 753 unsigned code;
754 754
755 /* We need at least one upstream and one downstream interface */ 755 /* We need at least one upstream and one downstream interface */
756 if (upstreams == NULL || downstreams == NULL) { 756 if (upstreams == NULL || downstreams == NULL) {
757 log_info("Must specify at least one lower " 757 log_info("Must specify at least one lower "
758 "and one upper interface.\n"); 758 "and one upper interface.\n");
759 usage(NULL, NULL); 759 usage(NULL, NULL);
760 } 760 }
761 761
762 /* Set up the initial dhcp option universe. */ 762 /* Set up the initial dhcp option universe. */
763 initialize_common_option_spaces(); 763 initialize_common_option_spaces();
764 764
765 /* Check requested options. */ 765 /* Check requested options. */
766 code = D6O_RELAY_MSG; 766 code = D6O_RELAY_MSG;
767 if (!option_code_hash_lookup(&requested_opts[0], 767 if (!option_code_hash_lookup(&requested_opts[0],
768 dhcpv6_universe.code_hash, 768 dhcpv6_universe.code_hash,
769 &code, 0, MDL)) 769 &code, 0, MDL))
770 log_fatal("Unable to find the RELAY_MSG " 770 log_fatal("Unable to find the RELAY_MSG "
771 "option definition."); 771 "option definition.");
772 code = D6O_INTERFACE_ID; 772 code = D6O_INTERFACE_ID;
773 if (!option_code_hash_lookup(&requested_opts[1], 773 if (!option_code_hash_lookup(&requested_opts[1],
774 dhcpv6_universe.code_hash, 774 dhcpv6_universe.code_hash,
775 &code, 0, MDL)) 775 &code, 0, MDL))
776 log_fatal("Unable to find the INTERFACE_ID " 776 log_fatal("Unable to find the INTERFACE_ID "
777 "option definition."); 777 "option definition.");
778 } 778 }
779#endif 779#endif
780 780
781 /* Become a daemon... */ 781 /* Become a daemon... */
782 if (!no_daemon) { 782 if (!no_daemon) {
783 char buf = 0; 783 char buf = 0;
784 FILE *pf; 784 FILE *pf;
785 int pfdesc; 785 int pfdesc;
786 786
787 log_perror = 0; 787 log_perror = 0;
788 788
789 /* Signal parent we started successfully. */ 789 /* Signal parent we started successfully. */
790 if (dfd[0] != -1 && dfd[1] != -1) { 790 if (dfd[0] != -1 && dfd[1] != -1) {
791 if (write(dfd[1], &buf, 1) != 1) 791 if (write(dfd[1], &buf, 1) != 1)
792 log_fatal("write to parent: %m"); 792 log_fatal("write to parent: %m");
793 (void) close(dfd[1]); 793 (void) close(dfd[1]);
794 dfd[0] = dfd[1] = -1; 794 dfd[0] = dfd[1] = -1;
795 } 795 }
796 796
797 /* Create the pid file. */ 797 /* Create the pid file. */
798 if (no_pid_file == ISC_FALSE) { 798 if (no_pid_file == ISC_FALSE) {
799 pfdesc = open(path_dhcrelay_pid, 799 pfdesc = open(path_dhcrelay_pid,
800 O_CREAT | O_TRUNC | O_WRONLY, 0644); 800 O_CREAT | O_TRUNC | O_WRONLY, 0644);
801 801
802 if (pfdesc < 0) { 802 if (pfdesc < 0) {
803 log_error("Can't create %s: %m", 803 log_error("Can't create %s: %m",
804 path_dhcrelay_pid); 804 path_dhcrelay_pid);
805 } else { 805 } else {
806 pf = fdopen(pfdesc, "w"); 806 pf = fdopen(pfdesc, "w");
807 if (!pf) 807 if (!pf)
808 log_error("Can't fdopen %s: %m", 808 log_error("Can't fdopen %s: %m",
809 path_dhcrelay_pid); 809 path_dhcrelay_pid);
810 else { 810 else {
811 fprintf(pf, "%ld\n",(long)getpid()); 811 fprintf(pf, "%ld\n",(long)getpid());
812 fclose(pf); 812 fclose(pf);
813 } 813 }
814 } 814 }
815 } 815 }
816 816
817 (void) close(0); 817 (void) close(0);
818 (void) close(1); 818 (void) close(1);
819 (void) close(2); 819 (void) close(2);
820 (void) setsid(); 820 (void) setsid();
821 821
822 IGNORE_RET (chdir("/")); 822 IGNORE_RET (chdir("/"));
823 } 823 }
824 824
825 /* Set up the isc and dns library managers */ 825 /* Set up the isc and dns library managers */
826 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB, 826 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
827 NULL, NULL); 827 NULL, NULL);
828 if (status != ISC_R_SUCCESS) 828 if (status != ISC_R_SUCCESS)
829 log_fatal("Can't initialize context: %s", 829 log_fatal("Can't initialize context: %s",
830 isc_result_totext(status)); 830 isc_result_totext(status));
831 831
832 /* Get the current time... */ 832 /* Get the current time... */
833 gettimeofday(&cur_tv, NULL); 833 gettimeofday(&cur_tv, NULL);
834 834
835 /* Discover all the network interfaces. */ 835 /* Discover all the network interfaces. */
836 discover_interfaces(DISCOVER_RELAY); 836 discover_interfaces(DISCOVER_RELAY);
837 837
838#ifdef DHCPv6 838#ifdef DHCPv6
839 if (local_family == AF_INET6) 839 if (local_family == AF_INET6)
840 setup_streams(); 840 setup_streams();
841#endif 841#endif
842 842
843 /* Set up the packet handler... */ 843 /* Set up the packet handler... */
844 if (local_family == AF_INET) 844 if (local_family == AF_INET)
845 bootp_packet_handler = do_relay4; 845 bootp_packet_handler = do_relay4;
846#ifdef DHCPv6 846#ifdef DHCPv6
847 else 847 else
848 dhcpv6_packet_handler = do_packet6; 848 dhcpv6_packet_handler = do_packet6;
849#endif 849#endif
850 850
851#if defined(ENABLE_GENTLE_SHUTDOWN) 851#if defined(ENABLE_GENTLE_SHUTDOWN)
852 /* no signal handlers until we deal with the side effects */ 852 /* no signal handlers until we deal with the side effects */
853 /* install signal handlers */ 853 /* install signal handlers */
854 signal(SIGINT, dhcp_signal_handler); /* control-c */ 854 signal(SIGINT, dhcp_signal_handler); /* control-c */
855 signal(SIGTERM, dhcp_signal_handler); /* kill */ 855 signal(SIGTERM, dhcp_signal_handler); /* kill */
856#endif 856#endif
857 857
858 /* Start dispatching packets and timeouts... */ 858 /* Start dispatching packets and timeouts... */
859 dispatch(); 859 dispatch();
860 860
861 /* In fact dispatch() never returns. */ 861 /* In fact dispatch() never returns. */
862 return (0); 862 return (0);
863} 863}
864 864
865static void 865static void
866do_relay4(struct interface_info *ip, struct dhcp_packet *packet, 866do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
867 unsigned int length, unsigned int from_port, struct iaddr from, 867 unsigned int length, unsigned int from_port, struct iaddr from,
868 struct hardware *hfrom) { 868 struct hardware *hfrom) {
869 struct server_list *sp; 869 struct server_list *sp;
870 struct sockaddr_in to; 870 struct sockaddr_in to;
871 struct interface_info *out; 871 struct interface_info *out;
872 struct hardware hto, *htop; 872 struct hardware hto, *htop;
873 873
874 if (packet->hlen > sizeof packet->chaddr) { 874 if (packet->hlen > sizeof packet->chaddr) {
875 log_info("Discarding packet with invalid hlen, received on " 875 log_info("Discarding packet with invalid hlen, received on "
876 "%s interface.", ip->name); 876 "%s interface.", ip->name);
877 return; 877 return;
878 } 878 }
879 if (ip->address_count < 1 || ip->addresses == NULL) { 879 if (ip->address_count < 1 || ip->addresses == NULL) {
880 log_info("Discarding packet received on %s interface that " 880 log_info("Discarding packet received on %s interface that "
881 "has no IPv4 address assigned.", ip->name); 881 "has no IPv4 address assigned.", ip->name);
882 return; 882 return;
883 } 883 }
884 884
885 /* Find the interface that corresponds to the giaddr 885 /* Find the interface that corresponds to the giaddr
886 in the packet. */ 886 in the packet. */
887 if (packet->giaddr.s_addr) { 887 if (packet->giaddr.s_addr) {
888 for (out = interfaces; out; out = out->next) { 888 for (out = interfaces; out; out = out->next) {
889 int i; 889 int i;
890 890
891 for (i = 0 ; i < out->address_count ; i++ ) { 891 for (i = 0 ; i < out->address_count ; i++ ) {
892 if (out->addresses[i].s_addr == 892 if (out->addresses[i].s_addr ==
893 packet->giaddr.s_addr) { 893 packet->giaddr.s_addr) {
894 i = -1; 894 i = -1;
895 break; 895 break;
896 } 896 }
897 } 897 }
898 898
899 if (i == -1) 899 if (i == -1)
900 break; 900 break;
901 } 901 }
902 } else { 902 } else {
903 out = NULL; 903 out = NULL;
904 } 904 }
905 905
906 /* If it's a bootreply, forward it to the client. */ 906 /* If it's a bootreply, forward it to the client. */
907 if (packet->op == BOOTREPLY) { 907 if (packet->op == BOOTREPLY) {
908 if (!(ip->flags & INTERFACE_UPSTREAM)) { 908 if (!(ip->flags & INTERFACE_UPSTREAM)) {
909 log_debug("Dropping reply received on %s", ip->name); 909 log_debug("Dropping reply received on %s", ip->name);
910 return; 910 return;
911 } 911 }
912 912
913 if (!(packet->flags & htons(BOOTP_BROADCAST)) && 913 if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
914 can_unicast_without_arp(out)) { 914 can_unicast_without_arp(out)) {
915 to.sin_addr = packet->yiaddr; 915 to.sin_addr = packet->yiaddr;
916 to.sin_port = remote_port; 916 to.sin_port = remote_port;
917 917
918 /* and hardware address is not broadcast */ 918 /* and hardware address is not broadcast */
919 htop = &hto; 919 htop = &hto;
920 } else { 920 } else {
921 to.sin_addr.s_addr = htonl(INADDR_BROADCAST); 921 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
922 to.sin_port = remote_port; 922 to.sin_port = remote_port;
923 923
924 /* hardware address is broadcast */ 924 /* hardware address is broadcast */
925 htop = NULL; 925 htop = NULL;
926 } 926 }
927 to.sin_family = AF_INET; 927 to.sin_family = AF_INET;
928#ifdef HAVE_SA_LEN 928#ifdef HAVE_SA_LEN
929 to.sin_len = sizeof to; 929 to.sin_len = sizeof to;
930#endif 930#endif
931 931
932 memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen); 932 memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen);
933 hto.hbuf[0] = packet->htype; 933 hto.hbuf[0] = packet->htype;
934 hto.hlen = packet->hlen + 1; 934 hto.hlen = packet->hlen + 1;
935 935
936 /* Wipe out the agent relay options and, if possible, figure 936 /* Wipe out the agent relay options and, if possible, figure
937 out which interface to use based on the contents of the 937 out which interface to use based on the contents of the
938 option that we put on the request to which the server is 938 option that we put on the request to which the server is
939 replying. */ 939 replying. */
940 if (!(length = 940 if (!(length =
941 strip_relay_agent_options(ip, &out, packet, length))) 941 strip_relay_agent_options(ip, &out, packet, length)))
942 return; 942 return;
943 943
944 if (!out) { 944 if (!out) {
945 log_error("Packet to bogus giaddr %s.\n", 945 log_error("Packet to bogus giaddr %s.\n",
946 inet_ntoa(packet->giaddr)); 946 inet_ntoa(packet->giaddr));
947 ++bogus_giaddr_drops; 947 ++bogus_giaddr_drops;
948 return; 948 return;
949 } 949 }
950 950
951 if (send_packet(out, NULL, packet, length, out->addresses[0], 951 if (send_packet(out, NULL, packet, length, out->addresses[0],
952 &to, htop) < 0) { 952 &to, htop) < 0) {
953 ++server_packet_errors; 953 ++server_packet_errors;
954 } else { 954 } else {
955 log_debug("Forwarded BOOTREPLY for %s to %s", 955 log_debug("Forwarded BOOTREPLY for %s to %s",
956 print_hw_addr(packet->htype, packet->hlen, 956 print_hw_addr(packet->htype, packet->hlen,
957 packet->chaddr), 957 packet->chaddr),
958 inet_ntoa(to.sin_addr)); 958 inet_ntoa(to.sin_addr));
959 959
960 ++server_packets_relayed; 960 ++server_packets_relayed;
961 } 961 }
962 return; 962 return;
963 } 963 }
964 964
965 /* If giaddr matches one of our addresses, ignore the packet - 965 /* If giaddr matches one of our addresses, ignore the packet -
966 we just sent it. */ 966 we just sent it. */
967 if (out) 967 if (out)
968 return; 968 return;
969 969
970 if (!(ip->flags & INTERFACE_DOWNSTREAM)) { 970 if (!(ip->flags & INTERFACE_DOWNSTREAM)) {
971 log_debug("Dropping request received on %s", ip->name); 971 log_debug("Dropping request received on %s", ip->name);
972 return; 972 return;
973 } 973 }
974 974
975 /* Add relay agent options if indicated. If something goes wrong, 975 /* Add relay agent options if indicated. If something goes wrong,
976 * drop the packet. Note this may set packet->giaddr if RFC3527 976 * drop the packet. Note this may set packet->giaddr if RFC3527
977 * is enabled. */ 977 * is enabled. */
978 if (!(length = add_relay_agent_options(ip, packet, length, 978 if (!(length = add_relay_agent_options(ip, packet, length,
979 ip->addresses[0]))) 979 ip->addresses[0])))
980 return; 980 return;
981 981
982 /* If giaddr is not already set, Set it so the server can 982 /* If giaddr is not already set, Set it so the server can
983 figure out what net it's from and so that we can later 983 figure out what net it's from and so that we can later
984 forward the response to the correct net. If it's already 984 forward the response to the correct net. If it's already
985 set, the response will be sent directly to the relay agent 985 set, the response will be sent directly to the relay agent
986 that set giaddr, so we won't see it. */ 986 that set giaddr, so we won't see it. */
987 if (!packet->giaddr.s_addr) 987 if (!packet->giaddr.s_addr)
988 packet->giaddr = ip->addresses[0]; 988 packet->giaddr = ip->addresses[0];
989 if (packet->hops < max_hop_count) 989 if (packet->hops < max_hop_count)
990 packet->hops = packet->hops + 1; 990 packet->hops = packet->hops + 1;
991 else 991 else
992 return; 992 return;
993 993
994 /* Otherwise, it's a BOOTREQUEST, so forward it to all the 994 /* Otherwise, it's a BOOTREQUEST, so forward it to all the
995 servers. */ 995 servers. */
996 for (sp = servers; sp; sp = sp->next) { 996 for (sp = servers; sp; sp = sp->next) {
997 if (send_packet((fallback_interface 997 if (send_packet((fallback_interface
998 ? fallback_interface : interfaces), 998 ? fallback_interface : interfaces),
999 NULL, packet, length, ip->addresses[0], 999 NULL, packet, length, ip->addresses[0],
1000 &sp->to, NULL) < 0) { 1000 &sp->to, NULL) < 0) {
1001 ++client_packet_errors; 1001 ++client_packet_errors;
1002 } else { 1002 } else {
1003 log_debug("Forwarded BOOTREQUEST for %s to %s", 1003 log_debug("Forwarded BOOTREQUEST for %s to %s",
1004 print_hw_addr(packet->htype, packet->hlen, 1004 print_hw_addr(packet->htype, packet->hlen,
1005 packet->chaddr), 1005 packet->chaddr),
1006 inet_ntoa(sp->to.sin_addr)); 1006 inet_ntoa(sp->to.sin_addr));
1007 ++client_packets_relayed; 1007 ++client_packets_relayed;
1008 } 1008 }
1009 } 1009 }
1010 1010
1011} 1011}
1012 1012
1013#endif /* UNIT_TEST */ 1013#endif /* UNIT_TEST */
1014 1014
1015/* Strip any Relay Agent Information options from the DHCP packet 1015/* Strip any Relay Agent Information options from the DHCP packet
1016 option buffer. If there is a circuit ID suboption, look up the 1016 option buffer. If there is a circuit ID suboption, look up the
1017 outgoing interface based upon it. */ 1017 outgoing interface based upon it. */
1018 1018
1019int 1019int
1020strip_relay_agent_options(struct interface_info *in, 1020strip_relay_agent_options(struct interface_info *in,
1021 struct interface_info **out, 1021 struct interface_info **out,
1022 struct dhcp_packet *packet, 1022 struct dhcp_packet *packet,
1023 unsigned length) { 1023 unsigned length) {
1024 int is_dhcp = 0; 1024 int is_dhcp = 0;
1025 u_int8_t *op, *nextop, *sp, *max; 1025 u_int8_t *op, *nextop, *sp, *max;
1026 int good_agent_option = 0; 1026 int good_agent_option = 0;
1027 int status; 1027 int status;
1028 1028
1029 /* If we're not adding agent options to packets, we're not taking 1029 /* If we're not adding agent options to packets, we're not taking
1030 them out either. */ 1030 them out either. */
1031 if (!add_agent_options) 1031 if (!add_agent_options)
1032 return (length); 1032 return (length);
1033 1033
1034 /* If there's no cookie, it's a bootp packet, so we should just 1034 /* If there's no cookie, it's a bootp packet, so we should just
1035 forward it unchanged. */ 1035 forward it unchanged. */
1036 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4)) 1036 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
1037 return (length); 1037 return (length);
1038 1038
1039 max = ((u_int8_t *)packet) + length; 1039 max = ((u_int8_t *)packet) + length;
1040 sp = op = &packet->options[4]; 1040 sp = op = &packet->options[4];
1041 1041
1042 while (op < max) { 1042 while (op < max) {
1043 switch(*op) { 1043 switch(*op) {
1044 /* Skip padding... */ 1044 /* Skip padding... */
1045 case DHO_PAD: 1045 case DHO_PAD:
1046 if (sp != op) 1046 if (sp != op)
1047 *sp = *op; 1047 *sp = *op;
1048 ++op; 1048 ++op;
1049 ++sp; 1049 ++sp;
1050 continue; 1050 continue;
1051 1051
1052 /* If we see a message type, it's a DHCP packet. */ 1052 /* If we see a message type, it's a DHCP packet. */
1053 case DHO_DHCP_MESSAGE_TYPE: 1053 case DHO_DHCP_MESSAGE_TYPE:
1054 is_dhcp = 1; 1054 is_dhcp = 1;
1055 goto skip; 1055 goto skip;
1056 break; 1056 break;
1057 1057
1058 /* Quit immediately if we hit an End option. */ 1058 /* Quit immediately if we hit an End option. */
1059 case DHO_END: 1059 case DHO_END:
1060 if (sp != op) 1060 if (sp != op)
1061 *sp++ = *op++; 1061 *sp++ = *op++;
1062 goto out; 1062 goto out;
1063 1063
1064 case DHO_DHCP_AGENT_OPTIONS: 1064 case DHO_DHCP_AGENT_OPTIONS:
1065 /* We shouldn't see a relay agent option in a 1065 /* We shouldn't see a relay agent option in a
1066 packet before we've seen the DHCP packet type, 1066 packet before we've seen the DHCP packet type,
1067 but if we do, we have to leave it alone. */ 1067 but if we do, we have to leave it alone. */
1068 if (!is_dhcp) 1068 if (!is_dhcp)
1069 goto skip; 1069 goto skip;
1070 1070
1071 /* Do not process an agent option if it exceeds the 1071 /* Do not process an agent option if it exceeds the
1072 * buffer. Fail this packet. 1072 * buffer. Fail this packet.
1073 */ 1073 */
1074 nextop = op + op[1] + 2; 1074 nextop = op + op[1] + 2;
1075 if (nextop > max) 1075 if (nextop > max)
1076 return (0); 1076 return (0);
1077 1077
1078 status = find_interface_by_agent_option(packet, 1078 status = find_interface_by_agent_option(packet,
1079 out, op + 2, 1079 out, op + 2,
1080 op[1]); 1080 op[1]);
1081 if (status == -1 && drop_agent_mismatches) 1081 if (status == -1 && drop_agent_mismatches)
1082 return (0); 1082 return (0);
1083 if (status) 1083 if (status)
1084 good_agent_option = 1; 1084 good_agent_option = 1;
1085 op = nextop; 1085 op = nextop;
1086 break; 1086 break;
1087 1087
1088 skip: 1088 skip:
1089 /* Skip over other options. */ 1089 /* Skip over other options. */
1090 default: 1090 default:
1091 /* Fail if processing this option will exceed the 1091 /* Fail if processing this option will exceed the
1092 * buffer(op[1] is malformed). 1092 * buffer(op[1] is malformed).
1093 */ 1093 */
1094 nextop = op + op[1] + 2; 1094 nextop = op + op[1] + 2;
1095 if (nextop > max) 1095 if (nextop > max)
1096 return (0); 1096 return (0);
1097 1097
1098 if (sp != op) { 1098 if (sp != op) {
1099 size_t mlen = op[1] + 2; 1099 size_t mlen = op[1] + 2;
1100 memmove(sp, op, mlen); 1100 memmove(sp, op, mlen);
1101 sp += mlen; 1101 sp += mlen;
1102 if (sp > max) { 1102 if (sp > max) {
1103 return (0); 1103 return (0);
1104 } 1104 }
1105 1105
1106 op = nextop; 1106 op = nextop;
1107 } else 1107 } else
1108 op = sp = nextop; 1108 op = sp = nextop;
1109 1109
1110 break; 1110 break;
1111 } 1111 }
1112 } 1112 }
1113 out: 1113 out:
1114 1114
1115 /* If it's not a DHCP packet, we're not supposed to touch it. */ 1115 /* If it's not a DHCP packet, we're not supposed to touch it. */
1116 if (!is_dhcp) 1116 if (!is_dhcp)
1117 return (length); 1117 return (length);
1118 1118
1119 /* If none of the agent options we found matched, or if we didn't 1119 /* If none of the agent options we found matched, or if we didn't
1120 find any agent options, count this packet as not having any 1120 find any agent options, count this packet as not having any
1121 matching agent options, and if we're relying on agent options 1121 matching agent options, and if we're relying on agent options
1122 to determine the outgoing interface, drop the packet. */ 1122 to determine the outgoing interface, drop the packet. */
1123 1123
1124 if (!good_agent_option) { 1124 if (!good_agent_option) {
1125 ++missing_agent_option; 1125 ++missing_agent_option;
1126 if (drop_agent_mismatches) 1126 if (drop_agent_mismatches)
1127 return (0); 1127 return (0);
1128 } 1128 }
1129 1129
1130 /* Adjust the length... */ 1130 /* Adjust the length... */
1131 if (sp != op) { 1131 if (sp != op) {
1132 length = sp -((u_int8_t *)packet); 1132 length = sp -((u_int8_t *)packet);
1133 1133
1134 /* Make sure the packet isn't short(this is unlikely, 1134 /* Make sure the packet isn't short(this is unlikely,
1135 but WTH) */ 1135 but WTH) */
1136 if (length < BOOTP_MIN_LEN) { 1136 if (length < BOOTP_MIN_LEN) {
1137 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length); 1137 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
1138 length = BOOTP_MIN_LEN; 1138 length = BOOTP_MIN_LEN;
1139 } 1139 }
1140 } 1140 }
1141 return (length); 1141 return (length);
1142} 1142}
1143 1143
1144 1144
1145/* Find an interface that matches the circuit ID specified in the 1145/* Find an interface that matches the circuit ID specified in the
1146 Relay Agent Information option. If one is found, store it through 1146 Relay Agent Information option. If one is found, store it through
1147 the pointer given; otherwise, leave the existing pointer alone. 1147 the pointer given; otherwise, leave the existing pointer alone.
1148 1148
1149 We actually deviate somewhat from the current specification here: 1149 We actually deviate somewhat from the current specification here:
1150 if the option buffer is corrupt, we suggest that the caller not 1150 if the option buffer is corrupt, we suggest that the caller not
1151 respond to this packet. If the circuit ID doesn't match any known 1151 respond to this packet. If the circuit ID doesn't match any known
1152 interface, we suggest that the caller to drop the packet. Only if 1152 interface, we suggest that the caller to drop the packet. Only if
1153 we find a circuit ID that matches an existing interface do we tell 1153 we find a circuit ID that matches an existing interface do we tell
1154 the caller to go ahead and process the packet. */ 1154 the caller to go ahead and process the packet. */
1155 1155
1156int 1156int
1157find_interface_by_agent_option(struct dhcp_packet *packet, 1157find_interface_by_agent_option(struct dhcp_packet *packet,
1158 struct interface_info **out, 1158 struct interface_info **out,
1159 u_int8_t *buf, int len) { 1159 u_int8_t *buf, int len) {
1160 int i = 0; 1160 int i = 0;
1161 u_int8_t *circuit_id = 0; 1161 u_int8_t *circuit_id = 0;
1162 unsigned circuit_id_len = 0; 1162 unsigned circuit_id_len = 0;
1163 struct interface_info *ip; 1163 struct interface_info *ip;
1164 1164
1165 while (i < len) { 1165 while (i < len) {
1166 /* If the next agent option overflows the end of the 1166 /* If the next agent option overflows the end of the
1167 packet, the agent option buffer is corrupt. */ 1167 packet, the agent option buffer is corrupt. */
1168 if (i + 1 == len || 1168 if (i + 1 == len ||
1169 i + buf[i + 1] + 2 > len) { 1169 i + buf[i + 1] + 2 > len) {
1170 ++corrupt_agent_options; 1170 ++corrupt_agent_options;
1171 return (-1); 1171 return (-1);
1172 } 1172 }
1173 switch(buf[i]) { 1173 switch(buf[i]) {
1174 /* Remember where the circuit ID is... */ 1174 /* Remember where the circuit ID is... */
1175 case RAI_CIRCUIT_ID: 1175 case RAI_CIRCUIT_ID:
1176 circuit_id = &buf[i + 2]; 1176 circuit_id = &buf[i + 2];
1177 circuit_id_len = buf[i + 1]; 1177 circuit_id_len = buf[i + 1];
1178 i += circuit_id_len + 2; 1178 i += circuit_id_len + 2;
1179 continue; 1179 continue;
1180 1180
1181 default: 1181 default:
1182 i += buf[i + 1] + 2; 1182 i += buf[i + 1] + 2;
1183 break; 1183 break;
1184 } 1184 }
1185 } 1185 }
1186 1186
1187 /* If there's no circuit ID, it's not really ours, tell the caller 1187 /* If there's no circuit ID, it's not really ours, tell the caller
1188 it's no good. */ 1188 it's no good. */
1189 if (!circuit_id) { 1189 if (!circuit_id) {
1190 ++missing_circuit_id; 1190 ++missing_circuit_id;
1191 return (-1); 1191 return (-1);
1192 } 1192 }
1193 1193
1194 /* Scan the interface list looking for an interface whose 1194 /* Scan the interface list looking for an interface whose
1195 name matches the one specified in circuit_id. */ 1195 name matches the one specified in circuit_id. */
1196 1196
1197 for (ip = interfaces; ip; ip = ip->next) { 1197 for (ip = interfaces; ip; ip = ip->next) {
1198 if (ip->circuit_id && 1198 if (ip->circuit_id &&
1199 ip->circuit_id_len == circuit_id_len && 1199 ip->circuit_id_len == circuit_id_len &&
1200 !memcmp(ip->circuit_id, circuit_id, circuit_id_len)) 1200 !memcmp(ip->circuit_id, circuit_id, circuit_id_len))
1201 break; 1201 break;
1202 } 1202 }
1203 1203
1204 /* If we got a match, use it. */ 1204 /* If we got a match, use it. */
1205 if (ip) { 1205 if (ip) {
1206 *out = ip; 1206 *out = ip;
1207 return (1); 1207 return (1);
1208 } 1208 }
1209 1209
1210 /* If we didn't get a match, the circuit ID was bogus. */ 1210 /* If we didn't get a match, the circuit ID was bogus. */
1211 ++bad_circuit_id; 1211 ++bad_circuit_id;
1212 return (-1); 1212 return (-1);
1213} 1213}
1214 1214
1215/* 1215/*
1216 * Examine a packet to see if it's a candidate to have a Relay 1216 * Examine a packet to see if it's a candidate to have a Relay
1217 * Agent Information option tacked onto its tail. If it is, tack 1217 * Agent Information option tacked onto its tail. If it is, tack
1218 * the option on. 1218 * the option on.
1219 */ 1219 */
1220int 1220int
1221add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet, 1221add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
1222 unsigned length, struct in_addr giaddr) { 1222 unsigned length, struct in_addr giaddr) {
1223 int is_dhcp = 0, mms; 1223 int is_dhcp = 0, mms;
1224 unsigned optlen; 1224 unsigned optlen;
1225 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL; 1225 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
1226 int adding_link_select; 1226 int adding_link_select;
1227 1227
1228 /* If we're not adding agent options to packets, we can skip 1228 /* If we're not adding agent options to packets, we can skip
1229 this. */ 1229 this. */
1230 if (!add_agent_options) 1230 if (!add_agent_options)
1231 return (length); 1231 return (length);
1232 1232
1233 /* If there's no cookie, it's a bootp packet, so we should just 1233 /* If there's no cookie, it's a bootp packet, so we should just
1234 forward it unchanged. */ 1234 forward it unchanged. */
1235 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4)) 1235 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
1236 return (length); 1236 return (length);
1237 1237
1238 max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length; 1238 max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length;
1239 1239
1240 /* Add link selection suboption if enabled and we're the first relay */ 1240 /* Add link selection suboption if enabled and we're the first relay */
1241 adding_link_select = (add_rfc3527_suboption 1241 adding_link_select = (add_rfc3527_suboption
1242 && (packet->giaddr.s_addr == 0)); 1242 && (packet->giaddr.s_addr == 0));
1243 1243
1244 /* Commence processing after the cookie. */ 1244 /* Commence processing after the cookie. */
1245 sp = op = &packet->options[4]; 1245 sp = op = &packet->options[4];
1246 1246
1247 while (op < max) { 1247 while (op < max) {
1248 switch(*op) { 1248 switch(*op) {
1249 /* Skip padding... */ 1249 /* Skip padding... */
1250 case DHO_PAD: 1250 case DHO_PAD:
1251 /* Remember the first pad byte so we can commandeer 1251 /* Remember the first pad byte so we can commandeer
1252 * padded space. 1252 * padded space.
1253 * 1253 *
1254 * XXX: Is this really a good idea? Sure, we can 1254 * XXX: Is this really a good idea? Sure, we can
1255 * seemingly reduce the packet while we're looking, 1255 * seemingly reduce the packet while we're looking,
1256 * but if the packet was signed by the client then 1256 * but if the packet was signed by the client then
1257 * this padding is part of the checksum(RFC3118), 1257 * this padding is part of the checksum(RFC3118),
1258 * and its nonpresence would break authentication. 1258 * and its nonpresence would break authentication.
1259 */ 1259 */
1260 if (end_pad == NULL) 1260 if (end_pad == NULL)
1261 end_pad = sp; 1261 end_pad = sp;
1262 1262
1263 if (sp != op) 1263 if (sp != op)
1264 *sp++ = *op++; 1264 *sp++ = *op++;
1265 else 1265 else
1266 sp = ++op; 1266 sp = ++op;
1267 1267
1268 continue; 1268 continue;
1269 1269
1270 /* If we see a message type, it's a DHCP packet. */ 1270 /* If we see a message type, it's a DHCP packet. */
1271 case DHO_DHCP_MESSAGE_TYPE: 1271 case DHO_DHCP_MESSAGE_TYPE:
1272 is_dhcp = 1; 1272 is_dhcp = 1;
1273 goto skip; 1273 goto skip;
1274 1274
1275 /* 1275 /*
1276 * If there's a maximum message size option, we 1276 * If there's a maximum message size option, we
1277 * should pay attention to it 1277 * should pay attention to it
1278 */ 1278 */
1279 case DHO_DHCP_MAX_MESSAGE_SIZE: 1279 case DHO_DHCP_MAX_MESSAGE_SIZE:
1280 mms = ntohs(*(op + 2)); 1280 mms = ntohs(*(op + 2));
1281 if (mms < dhcp_max_agent_option_packet_length && 1281 if (mms < dhcp_max_agent_option_packet_length &&
1282 mms >= DHCP_MTU_MIN) 1282 mms >= DHCP_MTU_MIN)
1283 max = ((u_int8_t *)packet) + mms; 1283 max = ((u_int8_t *)packet) + mms;
1284 goto skip; 1284 goto skip;
1285 1285
1286 /* Quit immediately if we hit an End option. */ 1286 /* Quit immediately if we hit an End option. */
1287 case DHO_END: 1287 case DHO_END:
1288 goto out; 1288 goto out;
1289 1289
1290 case DHO_DHCP_AGENT_OPTIONS: 1290 case DHO_DHCP_AGENT_OPTIONS:
1291 /* We shouldn't see a relay agent option in a 1291 /* We shouldn't see a relay agent option in a
1292 packet before we've seen the DHCP packet type, 1292 packet before we've seen the DHCP packet type,
1293 but if we do, we have to leave it alone. */ 1293 but if we do, we have to leave it alone. */
1294 if (!is_dhcp) 1294 if (!is_dhcp)
1295 goto skip; 1295 goto skip;
1296 1296
1297 end_pad = NULL; 1297 end_pad = NULL;
1298 1298
1299 /* There's already a Relay Agent Information option 1299 /* There's already a Relay Agent Information option
1300 in this packet. How embarrassing. Decide what 1300 in this packet. How embarrassing. Decide what
1301 to do based on the mode the user specified. */ 1301 to do based on the mode the user specified. */
1302 1302
1303 switch(agent_relay_mode) { 1303 switch(agent_relay_mode) {
1304 case forward_and_append: 1304 case forward_and_append:
1305 goto skip; 1305 goto skip;
1306 case forward_untouched: 1306 case forward_untouched:
1307 return (length); 1307 return (length);
1308 case discard: 1308 case discard:
1309 return (0); 1309 return (0);
1310 case forward_and_replace: 1310 case forward_and_replace:
1311 default: 1311 default:
1312 break; 1312 break;
1313 } 1313 }
1314 1314
1315 /* Skip over the agent option and start copying 1315 /* Skip over the agent option and start copying
1316 if we aren't copying already. */ 1316 if we aren't copying already. */
1317 op += op[1] + 2; 1317 op += op[1] + 2;
1318 break; 1318 break;
1319 1319
1320 skip: 1320 skip:
1321 /* Skip over other options. */ 1321 /* Skip over other options. */
1322 default: 1322 default:
1323 /* Fail if processing this option will exceed the 1323 /* Fail if processing this option will exceed the
1324 * buffer(op[1] is malformed). 1324 * buffer(op[1] is malformed).
1325 */ 1325 */
1326 nextop = op + op[1] + 2; 1326 nextop = op + op[1] + 2;
1327 if (nextop > max) 1327 if (nextop > max)
1328 return (0); 1328 return (0);
1329 1329
1330 end_pad = NULL; 1330 end_pad = NULL;
1331 1331
1332 if (sp != op) { 1332 if (sp != op) {
1333 size_t mlen = op[1] + 2; 1333 size_t mlen = op[1] + 2;
1334 memmove(sp, op, mlen); 1334 memmove(sp, op, mlen);
1335 sp += mlen; 1335 sp += mlen;
1336 if (sp > max) { 1336 if (sp > max) {
1337 return (0); 1337 return (0);
1338 } 1338 }
1339 1339
1340 op = nextop; 1340 op = nextop;
1341 } else 1341 } else
1342 op = sp = nextop; 1342 op = sp = nextop;
1343 1343
1344 break; 1344 break;
1345 } 1345 }
1346 } 1346 }
1347 out: 1347 out:
1348 1348
1349 /* If it's not a DHCP packet, we're not supposed to touch it. */ 1349 /* If it's not a DHCP packet, we're not supposed to touch it. */
1350 if (!is_dhcp) 1350 if (!is_dhcp)
1351 return (length); 1351 return (length);
1352 1352
1353 /* If the packet was padded out, we can store the agent option 1353 /* If the packet was padded out, we can store the agent option
1354 at the beginning of the padding. */ 1354 at the beginning of the padding. */
1355 1355
1356 if (end_pad != NULL) 1356 if (end_pad != NULL)
1357 sp = end_pad; 1357 sp = end_pad;
1358 1358
1359#if 0 1359#if 0
1360 /* Remember where the end of the packet was after parsing 1360 /* Remember where the end of the packet was after parsing
1361 it. */ 1361 it. */
1362 op = sp; 1362 op = sp;
1363#endif 1363#endif
1364 1364
1365 /* Sanity check. Had better not ever happen. */ 1365 /* Sanity check. Had better not ever happen. */
1366 if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1)) 1366 if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
1367 log_fatal("Circuit ID length %d out of range [1-255] on " 1367 log_fatal("Circuit ID length %d out of range [1-255] on "
1368 "%s\n", ip->circuit_id_len, ip->name); 1368 "%s\n", ip->circuit_id_len, ip->name);
1369 optlen = ip->circuit_id_len + 2; /* RAI_CIRCUIT_ID + len */ 1369 optlen = ip->circuit_id_len + 2; /* RAI_CIRCUIT_ID + len */
1370 1370
1371 if (ip->remote_id) { 1371 if (ip->remote_id) {
1372 if (ip->remote_id_len > 255 || ip->remote_id_len < 1) 1372 if (ip->remote_id_len > 255 || ip->remote_id_len < 1)
1373 log_fatal("Remote ID length %d out of range [1-255] " 1373 log_fatal("Remote ID length %d out of range [1-255] "
1374 "on %s\n", ip->remote_id_len, ip->name); 1374 "on %s\n", ip->remote_id_len, ip->name);
1375 optlen += ip->remote_id_len + 2; /* RAI_REMOTE_ID + len */ 1375 optlen += ip->remote_id_len + 2; /* RAI_REMOTE_ID + len */
1376 } 1376 }
1377 1377
1378 if (adding_link_select) { 1378 if (adding_link_select) {
1379 optlen += 6; 1379 optlen += 6;
1380 } 1380 }
1381 1381
1382#ifdef RELAY_PORT 1382#ifdef RELAY_PORT
1383 if (relay_port) { 1383 if (relay_port) {
1384 optlen += 2; 1384 optlen += 2;
1385 } 1385 }
1386#endif 1386#endif
1387 1387
1388 /* We do not support relay option fragmenting(multiple options to 1388 /* We do not support relay option fragmenting(multiple options to
1389 * support an option data exceeding 255 bytes). 1389 * support an option data exceeding 255 bytes).
1390 */ 1390 */
1391 if ((optlen < 3) ||(optlen > 255)) 1391 if ((optlen < 3) ||(optlen > 255))
1392 log_fatal("Total agent option length(%u) out of range " 1392 log_fatal("Total agent option length(%u) out of range "
1393 "[3 - 255] on %s\n", optlen, ip->name); 1393 "[3 - 255] on %s\n", optlen, ip->name);
1394 1394
1395 /* 1395 /*
1396 * Is there room for the option, its code+len, and DHO_END? 1396 * Is there room for the option, its code+len, and DHO_END?
1397 * If not, forward without adding the option. 1397 * If not, forward without adding the option.
1398 */ 1398 */
1399 if (max - sp >= optlen + 3) { 1399 if (max - sp >= optlen + 3) {
1400 log_debug("Adding %d-byte relay agent option", optlen + 3); 1400 log_debug("Adding %d-byte relay agent option", optlen + 3);
1401 1401
1402 /* Okay, cons up *our* Relay Agent Information option. */ 1402 /* Okay, cons up *our* Relay Agent Information option. */
1403 *sp++ = DHO_DHCP_AGENT_OPTIONS; 1403 *sp++ = DHO_DHCP_AGENT_OPTIONS;
1404 *sp++ = optlen; 1404 *sp++ = optlen;
1405 1405
1406 /* Copy in the circuit id... */ 1406 /* Copy in the circuit id... */
1407 *sp++ = RAI_CIRCUIT_ID; 1407 *sp++ = RAI_CIRCUIT_ID;
1408 *sp++ = ip->circuit_id_len; 1408 *sp++ = ip->circuit_id_len;
1409 memcpy(sp, ip->circuit_id, ip->circuit_id_len); 1409 memcpy(sp, ip->circuit_id, ip->circuit_id_len);
1410 sp += ip->circuit_id_len; 1410 sp += ip->circuit_id_len;
1411 1411
1412 /* Copy in remote ID... */ 1412 /* Copy in remote ID... */
1413 if (ip->remote_id) { 1413 if (ip->remote_id) {
1414 *sp++ = RAI_REMOTE_ID; 1414 *sp++ = RAI_REMOTE_ID;
1415 *sp++ = ip->remote_id_len; 1415 *sp++ = ip->remote_id_len;
1416 memcpy(sp, ip->remote_id, ip->remote_id_len); 1416 memcpy(sp, ip->remote_id, ip->remote_id_len);
1417 sp += ip->remote_id_len; 1417 sp += ip->remote_id_len;
1418 } 1418 }
1419 1419
1420 /* RFC3527: Use the inbound packet's interface address in 1420 /* RFC3527: Use the inbound packet's interface address in
1421 * the link selection suboption and set the outbound giaddr 1421 * the link selection suboption and set the outbound giaddr
1422 * to the uplink address. */ 1422 * to the uplink address. */
1423 if (adding_link_select) { 1423 if (adding_link_select) {
1424 *sp++ = RAI_LINK_SELECT; 1424 *sp++ = RAI_LINK_SELECT;
1425 *sp++ = 4u; 1425 *sp++ = 4u;
1426 memcpy(sp, &giaddr.s_addr, 4); 1426 memcpy(sp, &giaddr.s_addr, 4);
1427 sp += 4; 1427 sp += 4;
1428 packet->giaddr = uplink->addresses[0]; 1428 packet->giaddr = uplink->addresses[0];
1429 log_debug ("Adding link selection suboption" 1429 log_debug ("Adding link selection suboption"
1430 " with addr: %s", inet_ntoa(giaddr)); 1430 " with addr: %s", inet_ntoa(giaddr));
1431 } 1431 }
1432 1432
1433#ifdef RELAY_PORT 1433#ifdef RELAY_PORT
1434 /* draft-ietf-dhc-relay-port-10.txt section 5.1 */ 1434 /* draft-ietf-dhc-relay-port-10.txt section 5.1 */
1435 if (relay_port) { 1435 if (relay_port) {
1436 *sp++ = RAI_RELAY_PORT; 1436 *sp++ = RAI_RELAY_PORT;
1437 *sp++ = 0u; 1437 *sp++ = 0u;
1438 } 1438 }
1439#endif 1439#endif
1440 } else { 1440 } else {
1441 ++agent_option_errors; 1441 ++agent_option_errors;
1442 log_error("No room in packet (used %d of %d) " 1442 log_error("No room in packet (used %d of %d) "
1443 "for %d-byte relay agent option: omitted", 1443 "for %d-byte relay agent option: omitted",
1444 (int) (sp - ((u_int8_t *) packet)), 1444 (int) (sp - ((u_int8_t *) packet)),
1445 (int) (max - ((u_int8_t *) packet)), 1445 (int) (max - ((u_int8_t *) packet)),
1446 optlen + 3); 1446 optlen + 3);
1447 } 1447 }
1448 1448
1449 /* 1449 /*
1450 * Deposit an END option unless the packet is full (shouldn't 1450 * Deposit an END option unless the packet is full (shouldn't
1451 * be possible). 1451 * be possible).
1452 */ 1452 */
1453 if (sp < max) 1453 if (sp < max)
1454 *sp++ = DHO_END; 1454 *sp++ = DHO_END;
1455 1455
1456 /* Recalculate total packet length. */ 1456 /* Recalculate total packet length. */
1457 length = sp -((u_int8_t *)packet); 1457 length = sp -((u_int8_t *)packet);
1458 1458
1459 /* Make sure the packet isn't short(this is unlikely, but WTH) */ 1459 /* Make sure the packet isn't short(this is unlikely, but WTH) */
1460 if (length < BOOTP_MIN_LEN) { 1460 if (length < BOOTP_MIN_LEN) {
1461 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length); 1461 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
1462 return (BOOTP_MIN_LEN); 1462 return (BOOTP_MIN_LEN);
1463 } 1463 }
1464 1464
1465 return (length); 1465 return (length);
1466} 1466}
1467 1467
1468#ifdef DHCPv6 
1469#ifndef UNIT_TEST 1468#ifndef UNIT_TEST
 1469
 1470#ifdef DHCPv6
1470/* 1471/*
1471 * Parse a downstream argument: [address%]interface[#index]. 1472 * Parse a downstream argument: [address%]interface[#index].
1472 */ 1473 */
1473static struct stream_list * 1474static struct stream_list *
1474parse_downstream(char *arg) { 1475parse_downstream(char *arg) {
1475 struct stream_list *dp, *up; 1476 struct stream_list *dp, *up;
1476 struct interface_info *ifp = NULL; 1477 struct interface_info *ifp = NULL;
1477 char *ifname, *addr, *iid; 1478 char *ifname, *addr, *iid;
1478 isc_result_t status; 1479 isc_result_t status;
1479 1480
1480 if (!supports_multiple_interfaces(ifp) && 1481 if (!supports_multiple_interfaces(ifp) &&
1481 (downstreams != NULL)) 1482 (downstreams != NULL))
1482 log_fatal("No support for multiple interfaces."); 1483 log_fatal("No support for multiple interfaces.");
1483 1484
1484 /* Decode the argument. */ 1485 /* Decode the argument. */
1485 ifname = strchr(arg, '%'); 1486 ifname = strchr(arg, '%');
1486 if (ifname == NULL) { 1487 if (ifname == NULL) {
1487 ifname = arg; 1488 ifname = arg;
1488 addr = NULL; 1489 addr = NULL;
1489 } else { 1490 } else {
1490 *ifname++ = '\0'; 1491 *ifname++ = '\0';
1491 addr = arg; 1492 addr = arg;
1492 } 1493 }
1493 iid = strchr(ifname, '#'); 1494 iid = strchr(ifname, '#');
1494 if (iid != NULL) { 1495 if (iid != NULL) {
1495 *iid++ = '\0'; 1496 *iid++ = '\0';
1496 } 1497 }
1497 if (strlen(ifname) >= sizeof(ifp->name)) { 1498 if (strlen(ifname) >= sizeof(ifp->name)) {
1498 usage("Interface name '%s' too long", ifname); 1499 usage("Interface name '%s' too long", ifname);
1499 } 1500 }
1500 1501
1501 /* Don't declare twice. */ 1502 /* Don't declare twice. */
1502 for (dp = downstreams; dp; dp = dp->next) { 1503 for (dp = downstreams; dp; dp = dp->next) {
1503 if (strcmp(ifname, dp->ifp->name) == 0) 1504 if (strcmp(ifname, dp->ifp->name) == 0)
1504 log_fatal("Down interface '%s' declared twice.", 1505 log_fatal("Down interface '%s' declared twice.",
1505 ifname); 1506 ifname);
1506 } 1507 }
1507 1508
1508 /* Share with up side? */ 1509 /* Share with up side? */
1509 for (up = upstreams; up; up = up->next) { 1510 for (up = upstreams; up; up = up->next) {
1510 if (strcmp(ifname, up->ifp->name) == 0) { 1511 if (strcmp(ifname, up->ifp->name) == 0) {
1511 log_info("parse_downstream: Interface '%s' is " 1512 log_info("parse_downstream: Interface '%s' is "
1512 "both down and up.", ifname); 1513 "both down and up.", ifname);
1513 ifp = up->ifp; 1514 ifp = up->ifp;
1514 break; 1515 break;
1515 } 1516 }
1516 } 1517 }
1517 1518
1518 /* New interface. */ 1519 /* New interface. */
1519 if (ifp == NULL) { 1520 if (ifp == NULL) {
1520 status = interface_allocate(&ifp, MDL); 1521 status = interface_allocate(&ifp, MDL);
1521 if (status != ISC_R_SUCCESS) 1522 if (status != ISC_R_SUCCESS)
1522 log_fatal("%s: interface_allocate: %s", 1523 log_fatal("%s: interface_allocate: %s",
1523 arg, isc_result_totext(status)); 1524 arg, isc_result_totext(status));
1524 strcpy(ifp->name, ifname); 1525 strcpy(ifp->name, ifname);
1525 if (interfaces) { 1526 if (interfaces) {
1526 interface_reference(&ifp->next, interfaces, MDL); 1527 interface_reference(&ifp->next, interfaces, MDL);
1527 interface_dereference(&interfaces, MDL); 1528 interface_dereference(&interfaces, MDL);
1528 } 1529 }
1529 interface_reference(&interfaces, ifp, MDL); 1530 interface_reference(&interfaces, ifp, MDL);
1530 } 1531 }
1531 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM; 1532 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM;
1532 1533
1533 /* New downstream. */ 1534 /* New downstream. */
1534 dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL); 1535 dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL);
1535 if (!dp) 1536 if (!dp)
1536 log_fatal("No memory for downstream."); 1537 log_fatal("No memory for downstream.");
1537 dp->ifp = ifp; 1538 dp->ifp = ifp;
1538 if (iid != NULL) { 1539 if (iid != NULL) {
1539 dp->id = atoi(iid); 1540 dp->id = atoi(iid);
1540 } else { 1541 } else {
1541 dp->id = -1; 1542 dp->id = -1;
1542 } 1543 }
1543 /* !addr case handled by setup. */ 1544 /* !addr case handled by setup. */
1544 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0)) 1545 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
1545 log_fatal("Bad link address '%s'", addr); 1546 log_fatal("Bad link address '%s'", addr);
1546 1547
1547 return dp; 1548 return dp;
1548} 1549}
1549 1550
1550/* 1551/*
1551 * Parse an upstream argument: [address]%interface. 1552 * Parse an upstream argument: [address]%interface.
1552 */ 1553 */
1553static struct stream_list * 1554static struct stream_list *
1554parse_upstream(char *arg) { 1555parse_upstream(char *arg) {
1555 struct stream_list *up, *dp; 1556 struct stream_list *up, *dp;
1556 struct interface_info *ifp = NULL; 1557 struct interface_info *ifp = NULL;
1557 char *ifname, *addr; 1558 char *ifname, *addr;
1558 isc_result_t status; 1559 isc_result_t status;
1559 1560
1560 /* Decode the argument. */ 1561 /* Decode the argument. */
1561 ifname = strchr(arg, '%'); 1562 ifname = strchr(arg, '%');
1562 if (ifname == NULL) { 1563 if (ifname == NULL) {
1563 ifname = arg; 1564 ifname = arg;
1564 addr = All_DHCP_Servers; 1565 addr = All_DHCP_Servers;
1565 } else { 1566 } else {
1566 *ifname++ = '\0'; 1567 *ifname++ = '\0';
1567 addr = arg; 1568 addr = arg;
1568 } 1569 }
1569 if (strlen(ifname) >= sizeof(ifp->name)) { 1570 if (strlen(ifname) >= sizeof(ifp->name)) {
1570 log_fatal("Interface name '%s' too long", ifname); 1571 log_fatal("Interface name '%s' too long", ifname);
1571 } 1572 }
1572 1573
1573 /* Shared up interface? */ 1574 /* Shared up interface? */
1574 for (up = upstreams; up; up = up->next) { 1575 for (up = upstreams; up; up = up->next) {
1575 if (strcmp(ifname, up->ifp->name) == 0) { 1576 if (strcmp(ifname, up->ifp->name) == 0) {
1576 ifp = up->ifp; 1577 ifp = up->ifp;
1577 break; 1578 break;
1578 } 1579 }
1579 } 1580 }
1580 for (dp = downstreams; dp; dp = dp->next) { 1581 for (dp = downstreams; dp; dp = dp->next) {
1581 if (strcmp(ifname, dp->ifp->name) == 0) { 1582 if (strcmp(ifname, dp->ifp->name) == 0) {
1582 log_info("parse_upstream: Interface '%s' is " 1583 log_info("parse_upstream: Interface '%s' is "
1583 "both down and up.", ifname); 1584 "both down and up.", ifname);
1584 ifp = dp->ifp; 1585 ifp = dp->ifp;
1585 break; 1586 break;
1586 } 1587 }
1587 } 1588 }
1588 1589
1589 /* New interface. */ 1590 /* New interface. */
1590 if (ifp == NULL) { 1591 if (ifp == NULL) {
1591 status = interface_allocate(&ifp, MDL); 1592 status = interface_allocate(&ifp, MDL);
1592 if (status != ISC_R_SUCCESS) 1593 if (status != ISC_R_SUCCESS)
1593 log_fatal("%s: interface_allocate: %s", 1594 log_fatal("%s: interface_allocate: %s",
1594 arg, isc_result_totext(status)); 1595 arg, isc_result_totext(status));
1595 strcpy(ifp->name, ifname); 1596 strcpy(ifp->name, ifname);
1596 if (interfaces) { 1597 if (interfaces) {
1597 interface_reference(&ifp->next, interfaces, MDL); 1598 interface_reference(&ifp->next, interfaces, MDL);
1598 interface_dereference(&interfaces, MDL); 1599 interface_dereference(&interfaces, MDL);
1599 } 1600 }
1600 interface_reference(&interfaces, ifp, MDL); 1601 interface_reference(&interfaces, ifp, MDL);
1601 } 1602 }
1602 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM; 1603 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM;
1603 1604
1604 /* New upstream. */ 1605 /* New upstream. */
1605 up = (struct stream_list *) dmalloc(sizeof(*up), MDL); 1606 up = (struct stream_list *) dmalloc(sizeof(*up), MDL);
1606 if (up == NULL) 1607 if (up == NULL)
1607 log_fatal("No memory for upstream."); 1608 log_fatal("No memory for upstream.");
1608 1609
1609 up->ifp = ifp; 1610 up->ifp = ifp;
1610 1611
1611 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0) 1612 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
1612 log_fatal("Bad address %s", addr); 1613 log_fatal("Bad address %s", addr);
1613 1614
1614 return up; 1615 return up;
1615} 1616}
1616 1617
1617/* 1618/*
1618 * Setup downstream interfaces. 1619 * Setup downstream interfaces.
1619 */ 1620 */
1620static void 1621static void
1621setup_streams(void) { 1622setup_streams(void) {
1622 struct stream_list *dp, *up; 1623 struct stream_list *dp, *up;
1623 int i; 1624 int i;
1624 isc_boolean_t link_is_set; 1625 isc_boolean_t link_is_set;
1625 1626
1626 for (dp = downstreams; dp; dp = dp->next) { 1627 for (dp = downstreams; dp; dp = dp->next) {
1627 /* Check interface */ 1628 /* Check interface */
1628 if (dp->ifp->v6address_count == 0) 1629 if (dp->ifp->v6address_count == 0)
1629 log_fatal("Interface '%s' has no IPv6 addresses.", 1630 log_fatal("Interface '%s' has no IPv6 addresses.",
1630 dp->ifp->name); 1631 dp->ifp->name);
1631 1632
1632 /* Check/set link. */ 1633 /* Check/set link. */
1633 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr)) 1634 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
1634 link_is_set = ISC_FALSE; 1635 link_is_set = ISC_FALSE;
1635 else 1636 else
1636 link_is_set = ISC_TRUE; 1637 link_is_set = ISC_TRUE;
1637 for (i = 0; i < dp->ifp->v6address_count; i++) { 1638 for (i = 0; i < dp->ifp->v6address_count; i++) {
1638 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i])) 1639 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
1639 continue; 1640 continue;
1640 if (!link_is_set) 1641 if (!link_is_set)
1641 break; 1642 break;
1642 if (!memcmp(&dp->ifp->v6addresses[i], 1643 if (!memcmp(&dp->ifp->v6addresses[i],
1643 &dp->link.sin6_addr, 1644 &dp->link.sin6_addr,
1644 sizeof(dp->link.sin6_addr))) 1645 sizeof(dp->link.sin6_addr)))
1645 break; 1646 break;
1646 } 1647 }
1647 if (i == dp->ifp->v6address_count) 1648 if (i == dp->ifp->v6address_count)
1648 log_fatal("Interface %s does not have global IPv6 " 1649 log_fatal("Interface %s does not have global IPv6 "
1649 "address assigned.", dp->ifp->name); 1650 "address assigned.", dp->ifp->name);
1650 if (!link_is_set) 1651 if (!link_is_set)
1651 memcpy(&dp->link.sin6_addr, 1652 memcpy(&dp->link.sin6_addr,
1652 &dp->ifp->v6addresses[i], 1653 &dp->ifp->v6addresses[i],
1653 sizeof(dp->link.sin6_addr)); 1654 sizeof(dp->link.sin6_addr));
1654 1655
1655 /* Set interface-id. */ 1656 /* Set interface-id. */
1656 if (dp->id == -1) 1657 if (dp->id == -1)
1657 dp->id = dp->ifp->index; 1658 dp->id = dp->ifp->index;
1658 } 1659 }
1659 1660
1660 for (up = upstreams; up; up = up->next) { 1661 for (up = upstreams; up; up = up->next) {
1661 up->link.sin6_port = local_port; 1662 up->link.sin6_port = local_port;
1662 up->link.sin6_family = AF_INET6; 1663 up->link.sin6_family = AF_INET6;
1663#ifdef HAVE_SA_LEN 1664#ifdef HAVE_SA_LEN
1664 up->link.sin6_len = sizeof(up->link); 1665 up->link.sin6_len = sizeof(up->link);
1665#endif 1666#endif
1666 1667
1667 if (up->ifp->v6address_count == 0) 1668 if (up->ifp->v6address_count == 0)
1668 log_fatal("Interface '%s' has no IPv6 addresses.", 1669 log_fatal("Interface '%s' has no IPv6 addresses.",
1669 up->ifp->name); 1670 up->ifp->name);
1670 1671
1671 /* RFC 3315 Sec 20 - "If the relay agent relays messages to 1672 /* RFC 3315 Sec 20 - "If the relay agent relays messages to
1672 * the All_DHCP_Servers address or other multicast addresses, 1673 * the All_DHCP_Servers address or other multicast addresses,
1673 * it sets the Hop Limit field to 32." */ 1674 * it sets the Hop Limit field to 32." */
1674 if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) { 1675 if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) {
1675 set_multicast_hop_limit(up->ifp, HOP_COUNT_LIMIT); 1676 set_multicast_hop_limit(up->ifp, HOP_COUNT_LIMIT);
1676 } 1677 }
1677 } 1678 }
1678} 1679}
1679 1680
1680/* 1681/*
1681 * Add DHCPv6 agent options here. 1682 * Add DHCPv6 agent options here.
1682 */ 1683 */
1683static const int required_forw_opts[] = { 1684static const int required_forw_opts[] = {
1684 D6O_INTERFACE_ID, 1685 D6O_INTERFACE_ID,
1685 D6O_SUBSCRIBER_ID, 1686 D6O_SUBSCRIBER_ID,
1686#if defined(RELAY_PORT) 1687#if defined(RELAY_PORT)
1687 D6O_RELAY_SOURCE_PORT, 1688 D6O_RELAY_SOURCE_PORT,
1688#endif 1689#endif
1689 D6O_RELAY_MSG, 1690 D6O_RELAY_MSG,
1690 0 1691 0
1691}; 1692};
1692 1693
1693/* 1694/*
1694 * Process a packet upwards, i.e., from client to server. 1695 * Process a packet upwards, i.e., from client to server.
1695 */ 1696 */
1696static void 1697static void
1697process_up6(struct packet *packet, struct stream_list *dp) { 1698process_up6(struct packet *packet, struct stream_list *dp) {
1698 char forw_data[65535]; 1699 char forw_data[65535];
1699 unsigned cursor; 1700 unsigned cursor;
1700 struct dhcpv6_relay_packet *relay; 1701 struct dhcpv6_relay_packet *relay;
1701 struct option_state *opts; 1702 struct option_state *opts;
1702 struct stream_list *up; 1703 struct stream_list *up;
1703 u_int16_t relay_client_port = 0; 1704 u_int16_t relay_client_port = 0;
1704 1705
1705 /* Check if the message should be relayed to the server. */ 1706 /* Check if the message should be relayed to the server. */
1706 switch (packet->dhcpv6_msg_type) { 1707 switch (packet->dhcpv6_msg_type) {
1707 case DHCPV6_SOLICIT: 1708 case DHCPV6_SOLICIT:
1708 case DHCPV6_REQUEST: 1709 case DHCPV6_REQUEST:
1709 case DHCPV6_CONFIRM: 1710 case DHCPV6_CONFIRM:
1710 case DHCPV6_RENEW: 1711 case DHCPV6_RENEW:
1711 case DHCPV6_REBIND: 1712 case DHCPV6_REBIND:
1712 case DHCPV6_RELEASE: 1713 case DHCPV6_RELEASE:
1713 case DHCPV6_DECLINE: 1714 case DHCPV6_DECLINE:
1714 case DHCPV6_INFORMATION_REQUEST: 1715 case DHCPV6_INFORMATION_REQUEST:
1715 case DHCPV6_RELAY_FORW: 1716 case DHCPV6_RELAY_FORW:
1716 case DHCPV6_LEASEQUERY: 1717 case DHCPV6_LEASEQUERY:
1717 case DHCPV6_DHCPV4_QUERY: 1718 case DHCPV6_DHCPV4_QUERY:
1718 log_info("Relaying %s from %s port %d going up.", 1719 log_info("Relaying %s from %s port %d going up.",
1719 dhcpv6_type_names[packet->dhcpv6_msg_type], 1720 dhcpv6_type_names[packet->dhcpv6_msg_type],
1720 piaddr(packet->client_addr), 1721 piaddr(packet->client_addr),
1721 ntohs(packet->client_port)); 1722 ntohs(packet->client_port));
1722 break; 1723 break;
1723 1724
1724 case DHCPV6_ADVERTISE: 1725 case DHCPV6_ADVERTISE:
1725 case DHCPV6_REPLY: 1726 case DHCPV6_REPLY:
1726 case DHCPV6_RECONFIGURE: 1727 case DHCPV6_RECONFIGURE:
1727 case DHCPV6_RELAY_REPL: 1728 case DHCPV6_RELAY_REPL:
1728 case DHCPV6_LEASEQUERY_REPLY: 1729 case DHCPV6_LEASEQUERY_REPLY:
1729 case DHCPV6_DHCPV4_RESPONSE: 1730 case DHCPV6_DHCPV4_RESPONSE:
1730 log_info("Discarding %s from %s port %d going up.", 1731 log_info("Discarding %s from %s port %d going up.",
1731 dhcpv6_type_names[packet->dhcpv6_msg_type], 1732 dhcpv6_type_names[packet->dhcpv6_msg_type],
1732 piaddr(packet->client_addr), 1733 piaddr(packet->client_addr),
1733 ntohs(packet->client_port)); 1734 ntohs(packet->client_port));
1734 return; 1735 return;
1735 1736
1736 default: 1737 default:
1737 log_info("Unknown %d type from %s port %d going up.", 1738 log_info("Unknown %d type from %s port %d going up.",
1738 packet->dhcpv6_msg_type, 1739 packet->dhcpv6_msg_type,
1739 piaddr(packet->client_addr), 1740 piaddr(packet->client_addr),
1740 ntohs(packet->client_port)); 1741 ntohs(packet->client_port));
1741 return; 1742 return;
1742 } 1743 }
1743 1744
1744 /* Build the relay-forward header. */ 1745 /* Build the relay-forward header. */
1745 relay = (struct dhcpv6_relay_packet *) forw_data; 1746 relay = (struct dhcpv6_relay_packet *) forw_data;
1746 cursor = offsetof(struct dhcpv6_relay_packet, options); 1747 cursor = offsetof(struct dhcpv6_relay_packet, options);
1747 relay->msg_type = DHCPV6_RELAY_FORW; 1748 relay->msg_type = DHCPV6_RELAY_FORW;
1748 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) { 1749 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
1749 if (packet->dhcpv6_hop_count >= max_hop_count) { 1750 if (packet->dhcpv6_hop_count >= max_hop_count) {
1750 log_info("Hop count exceeded,"); 1751 log_info("Hop count exceeded,");
1751 return; 1752 return;
1752 } 1753 }
1753 relay->hop_count = packet->dhcpv6_hop_count + 1; 1754 relay->hop_count = packet->dhcpv6_hop_count + 1;
1754 if (dp) { 1755 if (dp) {
1755 memcpy(&relay->link_address, &dp->link.sin6_addr, 16); 1756 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1756 } else { 1757 } else {
1757 /* On smart relay add: && !global. */ 1758 /* On smart relay add: && !global. */
1758 if (!use_if_id && downstreams->next) { 1759 if (!use_if_id && downstreams->next) {
1759 log_info("Shan't get back the interface."); 1760 log_info("Shan't get back the interface.");
1760 return; 1761 return;
1761 } 1762 }
1762 memset(&relay->link_address, 0, 16); 1763 memset(&relay->link_address, 0, 16);
1763 } 1764 }
1764 1765
1765 if (packet->client_port != htons(547)) { 1766 if (packet->client_port != htons(547)) {
1766 relay_client_port = packet->client_port; 1767 relay_client_port = packet->client_port;
1767 } 1768 }
1768 } else { 1769 } else {
1769 relay->hop_count = 0; 1770 relay->hop_count = 0;
1770 if (!dp) 1771 if (!dp)
1771 return; 1772 return;
1772 memcpy(&relay->link_address, &dp->link.sin6_addr, 16); 1773 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1773 } 1774 }
1774 memcpy(&relay->peer_address, packet->client_addr.iabuf, 16); 1775 memcpy(&relay->peer_address, packet->client_addr.iabuf, 16);
1775 1776
1776 /* Get an option state. */ 1777 /* Get an option state. */
1777 opts = NULL; 1778 opts = NULL;
1778 if (!option_state_allocate(&opts, MDL)) { 1779 if (!option_state_allocate(&opts, MDL)) {
1779 log_fatal("No memory for upwards options."); 1780 log_fatal("No memory for upwards options.");
1780 } 1781 }
1781 1782
1782 /* Add an interface-id (if used). */ 1783 /* Add an interface-id (if used). */
1783 if (use_if_id) { 1784 if (use_if_id) {
1784 int if_id; 1785 int if_id;
1785 1786
1786 if (dp) { 1787 if (dp) {
1787 if_id = dp->id; 1788 if_id = dp->id;
1788 } else if (!downstreams->next) { 1789 } else if (!downstreams->next) {
1789 if_id = downstreams->id; 1790 if_id = downstreams->id;
1790 } else { 1791 } else {
1791 log_info("Don't know the interface."); 1792 log_info("Don't know the interface.");
1792 option_state_dereference(&opts, MDL); 1793 option_state_dereference(&opts, MDL);
1793 return; 1794 return;
1794 } 1795 }
1795 1796
1796 if (!save_option_buffer(&dhcpv6_universe, opts, 1797 if (!save_option_buffer(&dhcpv6_universe, opts,
1797 NULL, (unsigned char *) &if_id, 1798 NULL, (unsigned char *) &if_id,
1798 sizeof(int), 1799 sizeof(int),
1799 D6O_INTERFACE_ID, 0)) { 1800 D6O_INTERFACE_ID, 0)) {
1800 log_error("Can't save interface-id."); 1801 log_error("Can't save interface-id.");
1801 option_state_dereference(&opts, MDL); 1802 option_state_dereference(&opts, MDL);
1802 return; 1803 return;
1803 } 1804 }
1804 } 1805 }
1805 1806
1806 /* Add a subscriber-id if desired. */ 1807 /* Add a subscriber-id if desired. */
1807 /* This is for testing rather than general use */ 1808 /* This is for testing rather than general use */
1808 if (dhcrelay_sub_id != NULL) { 1809 if (dhcrelay_sub_id != NULL) {
1809 if (!save_option_buffer(&dhcpv6_universe, opts, NULL, 1810 if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
1810 (unsigned char *) dhcrelay_sub_id, 1811 (unsigned char *) dhcrelay_sub_id,
1811 strlen(dhcrelay_sub_id), 1812 strlen(dhcrelay_sub_id),
1812 D6O_SUBSCRIBER_ID, 0)) { 1813 D6O_SUBSCRIBER_ID, 0)) {
1813 log_error("Can't save subsriber-id."); 1814 log_error("Can't save subsriber-id.");
1814 option_state_dereference(&opts, MDL); 1815 option_state_dereference(&opts, MDL);
1815 return; 1816 return;
1816 } 1817 }
1817 } 1818 }
1818 1819
1819 1820
1820#if defined(RELAY_PORT) 1821#if defined(RELAY_PORT)
1821 /* 1822 /*
1822 * If we use a non-547 UDP source port or if we have received 1823 * If we use a non-547 UDP source port or if we have received
1823 * from a downstream relay agent uses a non-547 port, we need 1824 * from a downstream relay agent uses a non-547 port, we need
1824 * to include the RELAY-SOURCE-PORT option. The "Downstream 1825 * to include the RELAY-SOURCE-PORT option. The "Downstream
1825 * UDP Port" field value in the option allow us to send 1826 * UDP Port" field value in the option allow us to send
1826 * relay-reply message back to the downstream relay agent 1827 * relay-reply message back to the downstream relay agent
1827 * with the correct UDP source port. 1828 * with the correct UDP source port.
1828 */ 1829 */
1829 if (relay_port || relay_client_port) { 1830 if (relay_port || relay_client_port) {
1830 if (!save_option_buffer(&dhcpv6_universe, opts, NULL, 1831 if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
1831 (unsigned char *) &relay_client_port, 1832 (unsigned char *) &relay_client_port,
1832 sizeof(u_int16_t), 1833 sizeof(u_int16_t),
1833 D6O_RELAY_SOURCE_PORT, 0)) { 1834 D6O_RELAY_SOURCE_PORT, 0)) {
1834 log_error("Can't save relay-source-port."); 1835 log_error("Can't save relay-source-port.");
1835 option_state_dereference(&opts, MDL); 1836 option_state_dereference(&opts, MDL);
1836 return; 1837 return;
1837 } 1838 }
1838 } 1839 }
1839#else 1840#else
1840 /* Avoid unused but set warning, */ 1841 /* Avoid unused but set warning, */
1841 (void)(relay_client_port); 1842 (void)(relay_client_port);
1842#endif 1843#endif
1843 1844
1844 /* Add the relay-msg carrying the packet. */ 1845 /* Add the relay-msg carrying the packet. */
1845 if (!save_option_buffer(&dhcpv6_universe, opts, 1846 if (!save_option_buffer(&dhcpv6_universe, opts,
1846 NULL, (unsigned char *) packet->raw, 1847 NULL, (unsigned char *) packet->raw,
1847 packet->packet_length, 1848 packet->packet_length,
1848 D6O_RELAY_MSG, 0)) { 1849 D6O_RELAY_MSG, 0)) {
1849 log_error("Can't save relay-msg."); 1850 log_error("Can't save relay-msg.");
1850 option_state_dereference(&opts, MDL); 1851 option_state_dereference(&opts, MDL);
1851 return; 1852 return;
1852 } 1853 }
1853 1854
1854 /* Finish the relay-forward message. */ 1855 /* Finish the relay-forward message. */
1855 cursor += store_options6(forw_data + cursor, 1856 cursor += store_options6(forw_data + cursor,
1856 sizeof(forw_data) - cursor, 1857 sizeof(forw_data) - cursor,
1857 opts, packet, 1858 opts, packet,
1858 required_forw_opts, NULL); 1859 required_forw_opts, NULL);
1859 option_state_dereference(&opts, MDL); 1860 option_state_dereference(&opts, MDL);
1860 1861
1861 /* Send it to all upstreams. */ 1862 /* Send it to all upstreams. */
1862 for (up = upstreams; up; up = up->next) { 1863 for (up = upstreams; up; up = up->next) {
1863 send_packet6(up->ifp, (unsigned char *) forw_data, 1864 send_packet6(up->ifp, (unsigned char *) forw_data,
1864 (size_t) cursor, &up->link); 1865 (size_t) cursor, &up->link);
1865 } 1866 }
1866} 1867}
1867 1868
1868/* 1869/*
1869 * Process a packet downwards, i.e., from server to client. 1870 * Process a packet downwards, i.e., from server to client.
1870 */ 1871 */
1871static void 1872static void
1872process_down6(struct packet *packet) { 1873process_down6(struct packet *packet) {
1873 struct stream_list *dp; 1874 struct stream_list *dp;
1874 struct option_cache *oc; 1875 struct option_cache *oc;
1875 struct data_string relay_msg; 1876 struct data_string relay_msg;
1876 const struct dhcpv6_packet *msg; 1877 const struct dhcpv6_packet *msg;
1877 struct data_string if_id; 1878 struct data_string if_id;
1878#if defined(RELAY_PORT) 1879#if defined(RELAY_PORT)
1879 struct data_string down_port; 1880 struct data_string down_port;
1880#endif 1881#endif
1881 struct sockaddr_in6 to; 1882 struct sockaddr_in6 to;
1882 struct iaddr peer; 1883 struct iaddr peer;
1883 1884
1884 /* The packet must be a relay-reply message. */ 1885 /* The packet must be a relay-reply message. */
1885 if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) { 1886 if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) {
1886 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) 1887 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max)
1887 log_info("Discarding %s from %s port %d going down.", 1888 log_info("Discarding %s from %s port %d going down.",
1888 dhcpv6_type_names[packet->dhcpv6_msg_type], 1889 dhcpv6_type_names[packet->dhcpv6_msg_type],
1889 piaddr(packet->client_addr), 1890 piaddr(packet->client_addr),
1890 ntohs(packet->client_port)); 1891 ntohs(packet->client_port));
1891 else 1892 else
1892 log_info("Unknown %d type from %s port %d going down.", 1893 log_info("Unknown %d type from %s port %d going down.",
1893 packet->dhcpv6_msg_type, 1894 packet->dhcpv6_msg_type,
1894 piaddr(packet->client_addr), 1895 piaddr(packet->client_addr),
1895 ntohs(packet->client_port)); 1896 ntohs(packet->client_port));
1896 return; 1897 return;
1897 } 1898 }
1898 1899
1899 /* Inits. */ 1900 /* Inits. */
1900 memset(&relay_msg, 0, sizeof(relay_msg)); 1901 memset(&relay_msg, 0, sizeof(relay_msg));
1901 memset(&if_id, 0, sizeof(if_id)); 1902 memset(&if_id, 0, sizeof(if_id));
1902#if defined(RELAY_PORT) 1903#if defined(RELAY_PORT)
1903 memset(&down_port, 0, sizeof(down_port)); 1904 memset(&down_port, 0, sizeof(down_port));
1904#endif 1905#endif
1905 memset(&to, 0, sizeof(to)); 1906 memset(&to, 0, sizeof(to));
1906 to.sin6_family = AF_INET6; 1907 to.sin6_family = AF_INET6;
1907#ifdef HAVE_SA_LEN 1908#ifdef HAVE_SA_LEN
1908 to.sin6_len = sizeof(to); 1909 to.sin6_len = sizeof(to);
1909#endif 1910#endif
1910 to.sin6_port = remote_port; 1911 to.sin6_port = remote_port;
1911 peer.len = 16; 1912 peer.len = 16;
1912 1913
1913 /* Get the relay-msg option (carrying the message to relay). */ 1914 /* Get the relay-msg option (carrying the message to relay). */
1914 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG); 1915 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
1915 if (oc == NULL) { 1916 if (oc == NULL) {
1916 log_info("No relay-msg."); 1917 log_info("No relay-msg.");
1917 return; 1918 return;
1918 } 1919 }
1919 if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL, 1920 if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL,
1920 packet->options, NULL, 1921 packet->options, NULL,
1921 &global_scope, oc, MDL) || 1922 &global_scope, oc, MDL) ||
1922 (relay_msg.len < offsetof(struct dhcpv6_packet, options))) { 1923 (relay_msg.len < offsetof(struct dhcpv6_packet, options))) {
1923 log_error("Can't evaluate relay-msg."); 1924 log_error("Can't evaluate relay-msg.");
1924 goto cleanup; 1925 goto cleanup;
1925 } 1926 }
1926 msg = (const struct dhcpv6_packet *) relay_msg.data; 1927 msg = (const struct dhcpv6_packet *) relay_msg.data;
1927 1928
1928 /* Get the interface-id (if exists) and the downstream. */ 1929 /* Get the interface-id (if exists) and the downstream. */
1929 oc = lookup_option(&dhcpv6_universe, packet->options, 1930 oc = lookup_option(&dhcpv6_universe, packet->options,
1930 D6O_INTERFACE_ID); 1931 D6O_INTERFACE_ID);
1931 if (oc != NULL) { 1932 if (oc != NULL) {
1932 int if_index; 1933 int if_index;
1933 1934
1934 if (!evaluate_option_cache(&if_id, packet, NULL, NULL, 1935 if (!evaluate_option_cache(&if_id, packet, NULL, NULL,
1935 packet->options, NULL, 1936 packet->options, NULL,
1936 &global_scope, oc, MDL) || 1937 &global_scope, oc, MDL) ||
1937 (if_id.len != sizeof(int))) { 1938 (if_id.len != sizeof(int))) {
1938 log_info("Can't evaluate interface-id."); 1939 log_info("Can't evaluate interface-id.");
1939 goto cleanup; 1940 goto cleanup;
1940 } 1941 }
1941 memcpy(&if_index, if_id.data, sizeof(int)); 1942 memcpy(&if_index, if_id.data, sizeof(int));
1942 for (dp = downstreams; dp; dp = dp->next) { 1943 for (dp = downstreams; dp; dp = dp->next) {
1943 if (dp->id == if_index) 1944 if (dp->id == if_index)
1944 break; 1945 break;
1945 } 1946 }
1946 } else { 1947 } else {
1947 if (use_if_id) { 1948 if (use_if_id) {
1948 /* Require an interface-id. */ 1949 /* Require an interface-id. */
1949 log_info("No interface-id."); 1950 log_info("No interface-id.");
1950 goto cleanup; 1951 goto cleanup;
1951 } 1952 }
1952 for (dp = downstreams; dp; dp = dp->next) { 1953 for (dp = downstreams; dp; dp = dp->next) {
1953 /* Get the first matching one. */ 1954 /* Get the first matching one. */
1954 if (!memcmp(&dp->link.sin6_addr, 1955 if (!memcmp(&dp->link.sin6_addr,
1955 &packet->dhcpv6_link_address, 1956 &packet->dhcpv6_link_address,
1956 sizeof(struct in6_addr))) 1957 sizeof(struct in6_addr)))
1957 break; 1958 break;
1958 } 1959 }
1959 } 1960 }
1960 /* Why bother when there is no choice. */ 1961 /* Why bother when there is no choice. */
1961 if (!dp && downstreams && !downstreams->next) 1962 if (!dp && downstreams && !downstreams->next)
1962 dp = downstreams; 1963 dp = downstreams;
1963 if (!dp) { 1964 if (!dp) {
1964 log_info("Can't find the down interface."); 1965 log_info("Can't find the down interface.");
1965 goto cleanup; 1966 goto cleanup;
1966 } 1967 }
1967 memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len); 1968 memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len);
1968 to.sin6_addr = packet->dhcpv6_peer_address; 1969 to.sin6_addr = packet->dhcpv6_peer_address;
1969 1970
1970 /* Check if we should relay the carried message. */ 1971 /* Check if we should relay the carried message. */
1971 switch (msg->msg_type) { 1972 switch (msg->msg_type) {
1972 /* Relay-Reply of for another relay, not a client. */ 1973 /* Relay-Reply of for another relay, not a client. */
1973 case DHCPV6_RELAY_REPL: 1974 case DHCPV6_RELAY_REPL:
1974 to.sin6_port = local_port; 1975 to.sin6_port = local_port;
1975 1976
1976#if defined(RELAY_PORT) 1977#if defined(RELAY_PORT)
1977 oc = lookup_option(&dhcpv6_universe, packet->options, 1978 oc = lookup_option(&dhcpv6_universe, packet->options,
1978 D6O_RELAY_SOURCE_PORT); 1979 D6O_RELAY_SOURCE_PORT);
1979 if (oc != NULL) { 1980 if (oc != NULL) {
1980 u_int16_t down_relay_port; 1981 u_int16_t down_relay_port;
1981 1982
1982 memset(&down_port, 0, sizeof(down_port)); 1983 memset(&down_port, 0, sizeof(down_port));
1983 if (!evaluate_option_cache(&down_port, packet, NULL, 1984 if (!evaluate_option_cache(&down_port, packet, NULL,
1984 NULL, packet->options, NULL, 1985 NULL, packet->options, NULL,
1985 &global_scope, oc, MDL) || 1986 &global_scope, oc, MDL) ||
1986 (down_port.len != sizeof(u_int16_t))) { 1987 (down_port.len != sizeof(u_int16_t))) {
1987 log_info("Can't evaluate down " 1988 log_info("Can't evaluate down "
1988 "relay-source-port."); 1989 "relay-source-port.");
1989 goto cleanup; 1990 goto cleanup;
1990 } 1991 }
1991 memcpy(&down_relay_port, down_port.data, 1992 memcpy(&down_relay_port, down_port.data,
1992 sizeof(u_int16_t)); 1993 sizeof(u_int16_t));
1993 /* 1994 /*
1994 * If the down_relay_port value is non-zero, 1995 * If the down_relay_port value is non-zero,
1995 * that means our downstream relay agent uses 1996 * that means our downstream relay agent uses
1996 * a non-547 UDP source port sending 1997 * a non-547 UDP source port sending
1997 * relay-forw message to us. We need to use 1998 * relay-forw message to us. We need to use
1998 * the same UDP port sending reply back. 1999 * the same UDP port sending reply back.
1999 */ 2000 */
2000 if (down_relay_port) { 2001 if (down_relay_port) {
2001 to.sin6_port = down_relay_port; 2002 to.sin6_port = down_relay_port;
2002 } 2003 }
2003 } 2004 }
2004#endif 2005#endif
2005 2006
2006 /* Fall into: */ 2007 /* Fall into: */
2007 2008
2008 case DHCPV6_ADVERTISE: 2009 case DHCPV6_ADVERTISE:
2009 case DHCPV6_REPLY: 2010 case DHCPV6_REPLY:
2010 case DHCPV6_RECONFIGURE: 2011 case DHCPV6_RECONFIGURE:
2011 case DHCPV6_RELAY_FORW: 2012 case DHCPV6_RELAY_FORW:
2012 case DHCPV6_LEASEQUERY_REPLY: 2013 case DHCPV6_LEASEQUERY_REPLY:
2013 case DHCPV6_DHCPV4_RESPONSE: 2014 case DHCPV6_DHCPV4_RESPONSE:
2014 log_info("Relaying %s to %s port %d down.", 2015 log_info("Relaying %s to %s port %d down.",
2015 dhcpv6_type_names[msg->msg_type], 2016 dhcpv6_type_names[msg->msg_type],
2016 piaddr(peer), 2017 piaddr(peer),
2017 ntohs(to.sin6_port)); 2018 ntohs(to.sin6_port));
2018 break; 2019 break;
2019 2020
2020 case DHCPV6_SOLICIT: 2021 case DHCPV6_SOLICIT:
2021 case DHCPV6_REQUEST: 2022 case DHCPV6_REQUEST:
2022 case DHCPV6_CONFIRM: 2023 case DHCPV6_CONFIRM:
2023 case DHCPV6_RENEW: 2024 case DHCPV6_RENEW:
2024 case DHCPV6_REBIND: 2025 case DHCPV6_REBIND:
2025 case DHCPV6_RELEASE: 2026 case DHCPV6_RELEASE:
2026 case DHCPV6_DECLINE: 2027 case DHCPV6_DECLINE:
2027 case DHCPV6_INFORMATION_REQUEST: 2028 case DHCPV6_INFORMATION_REQUEST:
2028 case DHCPV6_LEASEQUERY: 2029 case DHCPV6_LEASEQUERY:
2029 case DHCPV6_DHCPV4_QUERY: 2030 case DHCPV6_DHCPV4_QUERY:
2030 log_info("Discarding %s to %s port %d down.", 2031 log_info("Discarding %s to %s port %d down.",
2031 dhcpv6_type_names[msg->msg_type], 2032 dhcpv6_type_names[msg->msg_type],
2032 piaddr(peer), 2033 piaddr(peer),
2033 ntohs(to.sin6_port)); 2034 ntohs(to.sin6_port));
2034 goto cleanup; 2035 goto cleanup;
2035 2036
2036 default: 2037 default:
2037 log_info("Unknown %d type to %s port %d down.", 2038 log_info("Unknown %d type to %s port %d down.",
2038 msg->msg_type, 2039 msg->msg_type,
2039 piaddr(peer), 2040 piaddr(peer),
2040 ntohs(to.sin6_port)); 2041 ntohs(to.sin6_port));
2041 goto cleanup; 2042 goto cleanup;
2042 } 2043 }
2043 2044
2044 /* Send the message to the downstream. */ 2045 /* Send the message to the downstream. */
2045 send_packet6(dp->ifp, (unsigned char *) relay_msg.data, 2046 send_packet6(dp->ifp, (unsigned char *) relay_msg.data,
2046 (size_t) relay_msg.len, &to); 2047 (size_t) relay_msg.len, &to);
2047 2048
2048 cleanup: 2049 cleanup:
2049 if (relay_msg.data != NULL) 2050 if (relay_msg.data != NULL)
2050 data_string_forget(&relay_msg, MDL); 2051 data_string_forget(&relay_msg, MDL);
2051 if (if_id.data != NULL) 2052 if (if_id.data != NULL)
2052 data_string_forget(&if_id, MDL); 2053 data_string_forget(&if_id, MDL);
2053} 2054}
2054#endif /* UNIT_TEST */ 
2055 2055
2056/* 2056/*
2057 * Called by the dispatch packet handler with a decoded packet. 2057 * Called by the dispatch packet handler with a decoded packet.
2058 */ 2058 */
2059void 2059void
2060dhcpv6(struct packet *packet) { 2060dhcpv6(struct packet *packet) {
2061#ifndef UNIT_TEST 
2062 struct stream_list *dp; 2061 struct stream_list *dp;
2063 2062
2064 /* Try all relay-replies downwards. */ 2063 /* Try all relay-replies downwards. */
2065 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) { 2064 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) {
2066 process_down6(packet); 2065 process_down6(packet);
2067 return; 2066 return;
2068 } 2067 }
2069 /* Others are candidates to go up if they come from down. */ 2068 /* Others are candidates to go up if they come from down. */
2070 for (dp = downstreams; dp; dp = dp->next) { 2069 for (dp = downstreams; dp; dp = dp->next) {
2071 if (packet->interface != dp->ifp) 2070 if (packet->interface != dp->ifp)
2072 continue; 2071 continue;
2073 process_up6(packet, dp); 2072 process_up6(packet, dp);
2074 return; 2073 return;
2075 } 2074 }
2076 /* Relay-forward could work from an unknown interface. */ 2075 /* Relay-forward could work from an unknown interface. */
2077 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) { 2076 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
2078 process_up6(packet, NULL); 2077 process_up6(packet, NULL);
2079 return; 2078 return;
2080 } 2079 }
2081 2080
2082 log_info("Can't process packet from interface '%s'.", 2081 log_info("Can't process packet from interface '%s'.",
2083 packet->interface->name); 2082 packet->interface->name);
2084#endif /* UNIT_TEST */ 
2085} 2083}
2086#endif /* DHCPv6 */ 2084#endif
2087 2085
2088/* Stub routines needed for linking with DHCP libraries. */ 2086/* Stub routines needed for linking with DHCP libraries. */
2089void 2087void
2090bootp(struct packet *packet) { 2088bootp(struct packet *packet) {
2091 return; 2089 return;
2092} 2090}
2093 2091
2094void 2092void
2095dhcp(struct packet *packet) { 2093dhcp(struct packet *packet) {
2096 return; 2094 return;
2097} 2095}
2098 2096
2099#if defined(DHCPv6) && defined(DHCP4o6) 2097#if defined(DHCPv6) && defined(DHCP4o6)
2100isc_result_t dhcpv4o6_handler(omapi_object_t *h) 2098isc_result_t dhcpv4o6_handler(omapi_object_t *h)
2101{ 2099{
2102 return ISC_R_NOTIMPLEMENTED; 2100 return ISC_R_NOTIMPLEMENTED;
2103} 2101}
2104#endif 2102#endif
2105 2103
2106void 2104void
2107classify(struct packet *p, struct class *c) { 2105classify(struct packet *p, struct class *c) {
2108 return; 2106 return;
2109} 2107}
2110 2108
2111int 2109int
2112check_collection(struct packet *p, struct lease *l, struct collection *c) { 2110check_collection(struct packet *p, struct lease *l, struct collection *c) {
2113 return 0; 2111 return 0;
2114} 2112}
2115 2113
2116isc_result_t 2114isc_result_t
2117find_class(struct class **class, const char *c1, const char *c2, int i) { 2115find_class(struct class **class, const char *c1, const char *c2, int i) {
2118 return ISC_R_NOTFOUND; 2116 return ISC_R_NOTFOUND;
2119} 2117}
2120 2118
2121int 2119int
2122parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { 2120parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
2123 return 0; 2121 return 0;
2124} 2122}
2125 2123
2126isc_result_t 2124isc_result_t
2127dhcp_set_control_state(control_object_state_t oldstate, 2125dhcp_set_control_state(control_object_state_t oldstate,
2128 control_object_state_t newstate) { 2126 control_object_state_t newstate) {
2129 char buf = 0; 2127 char buf = 0;
2130 2128
2131 if (newstate != server_shutdown) 2129 if (newstate != server_shutdown)
2132 return ISC_R_SUCCESS; 2130 return ISC_R_SUCCESS;
2133 2131
2134 /* Log shutdown on signal. */ 2132 /* Log shutdown on signal. */
2135 log_info("Received signal %d, initiating shutdown.", shutdown_signal); 2133 log_info("Received signal %d, initiating shutdown.", shutdown_signal);
2136 2134
2137 if (no_pid_file == ISC_FALSE) 2135 if (no_pid_file == ISC_FALSE)
2138 (void) unlink(path_dhcrelay_pid); 2136 (void) unlink(path_dhcrelay_pid);
2139 2137
2140 if (!no_daemon && dfd[0] != -1 && dfd[1] != -1) { 2138 if (!no_daemon && dfd[0] != -1 && dfd[1] != -1) {
2141 IGNORE_RET(write(dfd[1], &buf, 1)); 2139 IGNORE_RET(write(dfd[1], &buf, 1));
2142 (void) close(dfd[1]); 2140 (void) close(dfd[1]);
2143 dfd[0] = dfd[1] = -1; 2141 dfd[0] = dfd[1] = -1;
2144 } 2142 }
2145 exit(0); 2143 exit(0);
2146} 2144}
2147 2145
2148/*! 2146/*!
2149 * 2147 *
2150 * \brief Allocate an interface as requested with a given set of flags 2148 * \brief Allocate an interface as requested with a given set of flags
2151 * 2149 *
2152 * The requested interface is allocated, its flags field is set to 2150 * The requested interface is allocated, its flags field is set to
2153 * INTERFACE_REQUESTED OR'd with the given flags, and then added to 2151 * INTERFACE_REQUESTED OR'd with the given flags, and then added to
2154 * the list of interfaces. 2152 * the list of interfaces.
2155 * 2153 *
2156 * \param name - name of the requested interface 2154 * \param name - name of the requested interface
2157 * \param flags - additional flags for the interface 2155 * \param flags - additional flags for the interface
2158 * 2156 *
2159 * \return Nothing 2157 * \return Nothing
2160 */ 2158 */
2161void request_v4_interface(const char* name, int flags) { 2159void request_v4_interface(const char* name, int flags) {
2162 struct interface_info *tmp = NULL; 2160 struct interface_info *tmp = NULL;
2163 int len = strlen(name); 2161 int len = strlen(name);
2164 isc_result_t status; 2162 isc_result_t status;
2165 2163
2166 if (len >= sizeof(tmp->name)) { 2164 if (len >= sizeof(tmp->name)) {
2167 log_fatal("%s: interface name too long (is %d)", name, len); 2165 log_fatal("%s: interface name too long (is %d)", name, len);
2168 } 2166 }
2169 2167
2170 status = interface_allocate(&tmp, MDL); 2168 status = interface_allocate(&tmp, MDL);
2171 if (status != ISC_R_SUCCESS) { 2169 if (status != ISC_R_SUCCESS) {
2172 log_fatal("%s: interface_allocate: %s", name, 2170 log_fatal("%s: interface_allocate: %s", name,
2173 isc_result_totext(status)); 2171 isc_result_totext(status));
2174 } 2172 }
2175 2173
2176 log_debug("Requesting: %s as upstream: %c downstream: %c", name, 2174 log_debug("Requesting: %s as upstream: %c downstream: %c", name,
2177 (flags & INTERFACE_UPSTREAM ? 'Y' : 'N'), 2175 (flags & INTERFACE_UPSTREAM ? 'Y' : 'N'),
2178 (flags & INTERFACE_DOWNSTREAM ? 'Y' : 'N')); 2176 (flags & INTERFACE_DOWNSTREAM ? 'Y' : 'N'));
2179 2177
2180 memcpy(tmp->name, name, len); 2178 memcpy(tmp->name, name, len);
2181 interface_snorf(tmp, (INTERFACE_REQUESTED | flags)); 2179 interface_snorf(tmp, (INTERFACE_REQUESTED | flags));
2182 interface_dereference(&tmp, MDL); 2180 interface_dereference(&tmp, MDL);
2183} 2181}
 2182#endif /* UNIT_TEST */

cvs diff -r1.2 -r1.3 src/external/mpl/dhcp/dist/relay/tests/relay_unittests.c (switch to unified diff)

--- src/external/mpl/dhcp/dist/relay/tests/relay_unittests.c 2020/08/03 21:10:57 1.2
+++ src/external/mpl/dhcp/dist/relay/tests/relay_unittests.c 2021/05/26 22:52:32 1.3
@@ -1,413 +1,439 @@ @@ -1,413 +1,439 @@
1/* $NetBSD: relay_unittests.c,v 1.2 2020/08/03 21:10:57 christos Exp $ */ 1/* $NetBSD: relay_unittests.c,v 1.3 2021/05/26 22:52:32 christos Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2019-2020 by Internet Systems Consortium, Inc. ("ISC") 4 * Copyright (c) 2019-2020 by Internet Systems Consortium, Inc. ("ISC")
5 * 5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public 6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * 9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * 17 *
18 * Internet Systems Consortium, Inc. 18 * Internet Systems Consortium, Inc.
19 * 950 Charter Street 19 * 950 Charter Street
20 * Redwood City, CA 94063 20 * Redwood City, CA 94063
21 * <info@isc.org> 21 * <info@isc.org>
22 * https://www.isc.org/ 22 * https://www.isc.org/
23 * 23 *
24 */ 24 */
25 25
26#include <sys/cdefs.h> 26#include <sys/cdefs.h>
27__RCSID("$NetBSD: relay_unittests.c,v 1.2 2020/08/03 21:10:57 christos Exp $"); 27__RCSID("$NetBSD: relay_unittests.c,v 1.3 2021/05/26 22:52:32 christos Exp $");
28 28
29#include "config.h" 29#include "config.h"
30#include <atf-c.h> 30#include <atf-c.h>
31#include <omapip/omapip_p.h> 31#include <omapip/omapip_p.h>
32#include "dhcpd.h" 32#include "dhcpd.h"
33 33
34/* @brief Externs for dhcrelay.c functions under test */ 34/* @brief Externs for dhcrelay.c functions under test */
35extern int add_agent_options; 35extern int add_agent_options;
36extern int add_relay_agent_options(struct interface_info *, 36extern int add_relay_agent_options(struct interface_info *,
37 struct dhcp_packet *, unsigned, 37 struct dhcp_packet *, unsigned,
38 struct in_addr); 38 struct in_addr);
39 39
40extern int find_interface_by_agent_option(struct dhcp_packet *, 40extern int find_interface_by_agent_option(struct dhcp_packet *,
41 struct interface_info **, 41 struct interface_info **,
42 u_int8_t *, int); 42 u_int8_t *, int);
43 43
44extern int strip_relay_agent_options(struct interface_info *, 44extern int strip_relay_agent_options(struct interface_info *,
45 struct interface_info **, 45 struct interface_info **,
46 struct dhcp_packet *, unsigned); 46 struct dhcp_packet *, unsigned);
47 47
48/* @brief Add the given option data to a DHCPv4 packet 48/* @brief Add the given option data to a DHCPv4 packet
49* 49*
50* It first fills the packet.options buffer with the given pad character. 50* It first fills the packet.options buffer with the given pad character.
51* Next it copies the DHCP magic cookie value into the beginning of the 51* Next it copies the DHCP magic cookie value into the beginning of the
52* options buffer. Finally it appends the given data after the cookie. 52* options buffer. Finally it appends the given data after the cookie.
53* 53*
54* @param packet pointer to the packet 54* @param packet pointer to the packet
55* @param data pointer to the option data to copy into the packet's options 55* @param data pointer to the option data to copy into the packet's options
56* buffer 56* buffer
57* @param len length of the option data to copy 57* @param len length of the option data to copy
58* @param pad byte value with which to initialize the packet's options buffer 58* @param pad byte value with which to initialize the packet's options buffer
59* 59*
60* @return returns the new length of the packet 60* @return returns the new length of the packet
61*/ 61*/
62unsigned set_packet_options(struct dhcp_packet *packet, 62unsigned set_packet_options(struct dhcp_packet *packet,
63 unsigned char* data, unsigned len, 63 unsigned char* data, unsigned len,
64 unsigned char pad) { 64 unsigned char pad) {
65 unsigned new_len; 65 unsigned new_len;
66 memset(packet->options, pad, DHCP_MAX_OPTION_LEN); 66 memset(packet->options, pad, DHCP_MAX_OPTION_LEN);
67 67
68 // Add the COOKIE 68 // Add the COOKIE
69 new_len = 4; 69 new_len = 4;
70 memcpy(packet->options, DHCP_OPTIONS_COOKIE, new_len); 70 memcpy(packet->options, DHCP_OPTIONS_COOKIE, new_len);
71 71
72 new_len += len; 72 new_len += len;
73 if (new_len > DHCP_MAX_OPTION_LEN) { 73 if (new_len > DHCP_MAX_OPTION_LEN) {
74 return(0); 74 return(0);
75 } 75 }
76 76
77 memcpy(&packet->options[4], data, len); 77 memcpy(&packet->options[4], data, len);
78 return(new_len + DHCP_FIXED_NON_UDP); 78 return(new_len + DHCP_FIXED_NON_UDP);
79} 79}
80 80
81/* @brief Checks two sets of option data for equalit 81/* @brief Checks two sets of option data for equalit
82* 82*
83* It constructs the expected options content by creating an options buffer 83* It constructs the expected options content by creating an options buffer
84* filled with the pad value. Next it copies the DHCP magic cookie value 84* filled with the pad value. Next it copies the DHCP magic cookie value
85* into the beginning of the buffer and then appends the expected data after 85* into the beginning of the buffer and then appends the expected data after
86* the cookie. It the compares this buffer to the actual buffer passed in 86* the cookie. It the compares this buffer to the actual buffer passed in
87* for equality and returns the result. 87* for equality and returns the result.
88* 88*
89* @param actual_options pointer to the packet::options to be checked 89* @param actual_options pointer to the packet::options to be checked
90* @param expected_data pointer to the expected options data (everything after 90* @param expected_data pointer to the expected options data (everything after
91* the DHCP cookie) 91* the DHCP cookie)
92* @param data_len length of the expected options data 92* @param data_len length of the expected options data
93* @param pad byte value with which to initialize the packet's options buffer 93* @param pad byte value with which to initialize the packet's options buffer
94* 94*
95* @return zero it the sets of data match, non-zero otherwise 95* @return zero it the sets of data match, non-zero otherwise
96*/ 96*/
97int check_with_pad(unsigned char* actual_options, 97int check_with_pad(unsigned char* actual_options,
98 unsigned char *expected_data, 98 unsigned char *expected_data,
99 unsigned data_len, unsigned char pad) { 99 unsigned data_len, unsigned char pad) {
100 100
101 unsigned char exp_options[DHCP_MAX_OPTION_LEN]; 101 unsigned char exp_options[DHCP_MAX_OPTION_LEN];
102 unsigned new_len; 102 unsigned new_len;
103 103
104 memset(exp_options, pad, DHCP_MAX_OPTION_LEN); 104 memset(exp_options, pad, DHCP_MAX_OPTION_LEN);
105 new_len = 4; 105 new_len = 4;
106 memcpy(exp_options, DHCP_OPTIONS_COOKIE, new_len); 106 memcpy(exp_options, DHCP_OPTIONS_COOKIE, new_len);
107 107
108 new_len += data_len; 108 new_len += data_len;
109 if (new_len > DHCP_MAX_OPTION_LEN) { 109 if (new_len > DHCP_MAX_OPTION_LEN) {
110 return(-1); 110 return(-1);
111 } 111 }
112 112
113 memcpy(&exp_options[4], expected_data, data_len); 113 memcpy(&exp_options[4], expected_data, data_len);
114 return (memcmp(actual_options, exp_options, DHCP_MAX_OPTION_LEN)); 114 return (memcmp(actual_options, exp_options, DHCP_MAX_OPTION_LEN));
115} 115}
116 116
117ATF_TC(strip_relay_agent_options_test); 117ATF_TC(strip_relay_agent_options_test);
118 118
119ATF_TC_HEAD(strip_relay_agent_options_test, tc) { 119ATF_TC_HEAD(strip_relay_agent_options_test, tc) {
120 atf_tc_set_md_var(tc, "descr", "tests strip_relay-agent_options"); 120 atf_tc_set_md_var(tc, "descr", "tests strip_relay-agent_options");
121} 121}
122 122
123/* This Test exercises strip_relay_agent_options() function */ 123/* This Test exercises strip_relay_agent_options() function */
124ATF_TC_BODY(strip_relay_agent_options_test, tc) { 124ATF_TC_BODY(strip_relay_agent_options_test, tc) {
125 125
126 struct interface_info ifaces; 126 struct interface_info ifaces;
127 struct interface_info *matched; 127 struct interface_info *matched;
128 struct dhcp_packet packet; 128 struct dhcp_packet packet;
129 unsigned len; 129 unsigned len;
130 int ret; 130 int ret;
131 131
132 memset(&ifaces, 0x0, sizeof(ifaces)); 132 memset(&ifaces, 0x0, sizeof(ifaces));
133 matched = 0; 133 matched = 0;
134 memset(&packet, 0x0, sizeof(packet)); 134 memset(&packet, 0x0, sizeof(packet));
135 len = 0; 135 len = 0;
136 136
137 /* Make sure an empty packet is harmless. We set add_agent_options = 1 137 /* Make sure an empty packet is harmless. We set add_agent_options = 1
138 * to avoid early return when it's 0. */ 138 * to avoid early return when it's 0. */
139 add_agent_options = 1; 139 add_agent_options = 1;
140 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len); 140 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len);
141 if (ret != 0) { 141 if (ret != 0) {
142 atf_tc_fail("empty packet failed"); 142 atf_tc_fail("empty packet failed");
143 } 143 }
144 144
145 { 145 {
146 /* 146 /*
147 * Uses valid input option data to verify that: 147 * Uses valid input option data to verify that:
148 * - When add_agent_options is false, the output option data is the 148 * - When add_agent_options is false, the output option data is the
149 * the same as the input option data (i.e. nothing removed) 149 * the same as the input option data (i.e. nothing removed)
150 * - When add_agent_options is true, 0 length relay agent option has 150 * - When add_agent_options is true, 0 length relay agent option has
151 * been removed from the output option data 151 * been removed from the output option data
152 * - When add_agent_options is true, a relay agent option has 152 * - When add_agent_options is true, a relay agent option has
153 * been removed from the output option data 153 * been removed from the output option data
154 * 154 *
155 */ 155 */
156 156
157 unsigned char input_data[] = { 157 unsigned char input_data[] = {
158 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 158 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
159 0x52, 0x08, 0x01, 0x06, 0x65, /* Relay Agent Option, len = 8 */ 159 0x52, 0x08, 0x01, 0x06, 0x65, /* Relay Agent Option, len = 8 */
160 0x6e, 0x70, 0x30, 0x73, 0x4f, 160 0x6e, 0x70, 0x30, 0x73, 0x4f,
161 161
162 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 162 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
163 0x43, 0x00 /* Opt 0x43, len = 0 */ 163 0x43, 0x00 /* Opt 0x43, len = 0 */
164 }; 164 };
165 165
166 unsigned char input_data2[] = { 166 unsigned char input_data2[] = {
167 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 167 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
168 0x52, 0x00, /* Relay Agent Option, len = 0 */ 168 0x52, 0x00, /* Relay Agent Option, len = 0 */
169 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 169 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
170 0x43, 0x00 /* Opt 0x43, len = 0 */ 170 0x43, 0x00 /* Opt 0x43, len = 0 */
171 }; 171 };
172 172
173 unsigned char output_data[] = { 173 unsigned char output_data[] = {
174 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 174 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
175 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 175 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
176 0x43, 0x00 /* Opt 0x43, len = 0 */ 176 0x43, 0x00 /* Opt 0x43, len = 0 */
177 }; 177 };
178 178
179 unsigned char pad = 0x0; 179 unsigned char pad = 0x0;
180 len = set_packet_options(&packet, input_data, sizeof(input_data), pad); 180 len = set_packet_options(&packet, input_data, sizeof(input_data), pad);
181 if (len == 0) { 181 if (len == 0) {
182 atf_tc_fail("input_data: set_packet_options failed"); 182 atf_tc_fail("input_data: set_packet_options failed");
183 } 183 }
184 184
185 /* When add_agent_options = 0, no change should occur */ 185 /* When add_agent_options = 0, no change should occur */
186 add_agent_options = 0; 186 add_agent_options = 0;
187 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len); 187 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len);
188 if (ret != len) { 188 if (ret != len) {
189 atf_tc_fail("expected unchanged len %d, returned %d", len, ret); 189 atf_tc_fail("expected unchanged len %d, returned %d", len, ret);
190 } 190 }
191 191
192 if (check_with_pad(packet.options, input_data, sizeof(input_data), 192 if (check_with_pad(packet.options, input_data, sizeof(input_data),
193 pad) != 0) { 193 pad) != 0) {
194 atf_tc_fail("expected unchanged data, does not match"); 194 atf_tc_fail("expected unchanged data, does not match");
195 } 195 }
196 196
197 /* When add_agent_options = 1, it should remove the eight byte 197 /* When add_agent_options = 1, it should remove the eight byte
198 * relay agent option. */ 198 * relay agent option. */
199 add_agent_options = 1; 199 add_agent_options = 1;
200 200
201 /* Beause the inbound option data is less than the BOOTP_MIN_LEN, 201 /* Beause the inbound option data is less than the BOOTP_MIN_LEN,
202 * the output data should get padded out to BOOTP_MIN_LEN 202 * the output data should get padded out to BOOTP_MIN_LEN
203 * padded out to BOOTP_MIN_LEN */ 203 * padded out to BOOTP_MIN_LEN */
204 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len); 204 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len);
205 if (ret != BOOTP_MIN_LEN) { 205 if (ret != BOOTP_MIN_LEN) {
206 atf_tc_fail("input_data: len of %d, returned %d", 206 atf_tc_fail("input_data: len of %d, returned %d",
207 BOOTP_MIN_LEN, ret); 207 BOOTP_MIN_LEN, ret);
208 } 208 }
209 209
210 if (check_with_pad(packet.options, output_data, sizeof(output_data), 210 if (check_with_pad(packet.options, output_data, sizeof(output_data),
211 pad) != 0) { 211 pad) != 0) {
212 atf_tc_fail("input_data: expected data does not match"); 212 atf_tc_fail("input_data: expected data does not match");
213 } 213 }
214 214
215 /* Now let's repeat it with a relay agent option 0 bytes in length. */ 215 /* Now let's repeat it with a relay agent option 0 bytes in length. */
216 len = set_packet_options(&packet, input_data2, sizeof(input_data2), pad); 216 len = set_packet_options(&packet, input_data2, sizeof(input_data2), pad);
217 if (len == 0) { 217 if (len == 0) {
218 atf_tc_fail("input_data2 set_packet_options failed"); 218 atf_tc_fail("input_data2 set_packet_options failed");
219 } 219 }
220 220
221 /* Because the inbound option data is less than the BOOTP_MIN_LEN, 221 /* Because the inbound option data is less than the BOOTP_MIN_LEN,
222 * the output data should get padded out to BOOTP_MIN_LEN 222 * the output data should get padded out to BOOTP_MIN_LEN
223 * padded out to BOOTP_MIN_LEN */ 223 * padded out to BOOTP_MIN_LEN */
224 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len); 224 ret = strip_relay_agent_options(&ifaces, &matched, &packet, len);
225 if (ret != BOOTP_MIN_LEN) { 225 if (ret != BOOTP_MIN_LEN) {
226 atf_tc_fail("input_data2: len of %d, returned %d", 226 atf_tc_fail("input_data2: len of %d, returned %d",
227 BOOTP_MIN_LEN, ret); 227 BOOTP_MIN_LEN, ret);
228 } 228 }
229 229
230 if (check_with_pad(packet.options, output_data, sizeof(output_data), 230 if (check_with_pad(packet.options, output_data, sizeof(output_data),
231 pad) != 0) { 231 pad) != 0) {
232 atf_tc_fail("input_data2: expected output does not match"); 232 atf_tc_fail("input_data2: expected output does not match");
233 } 233 }
234 } 234 }
235 235
236 { 236 {
237 /* Verify that oversized packet filled with long options does not 237 /* Verify that oversized packet filled with long options does not
238 * cause overrun */ 238 * cause overrun */
239 239
240 /* We borrowed this union from discover.c:got_one() */ 240 /* We borrowed this union from discover.c:got_one() */
241 union { 241 union {
242 unsigned char packbuf [4095]; /* Packet input buffer. 242 unsigned char packbuf [4095]; /* Packet input buffer.
243 * Must be as large as largest 243 * Must be as large as largest
244 * possible MTU. */ 244 * possible MTU. */
245 struct dhcp_packet packet; 245 struct dhcp_packet packet;
246 } u; 246 } u;
247 247
248 unsigned char input_data[] = { 248 unsigned char input_data[] = {
249 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 249 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
250 0x52, 0x00, /* Relay Agent Option, len = 0 */ 250 0x52, 0x00, /* Relay Agent Option, len = 0 */
251 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 251 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
252 0x43, 0x00 /* Opt 0x43, len = 0 */ 252 0x43, 0x00 /* Opt 0x43, len = 0 */
253 }; 253 };
254 254
255 /* We'll pad it 0xFE, that way wherever we hit for "length" we'll 255 /* We'll pad it 0xFE, that way wherever we hit for "length" we'll
256 * have length of 254. Increasing the odds we'll push over the end. */ 256 * have length of 254. Increasing the odds we'll push over the end. */
257 unsigned char pad = 0xFE; 257 unsigned char pad = 0xFE;
258 memset(u.packbuf, pad, 4095); 258 memset(u.packbuf, pad, 4095);
259 259
260 len = set_packet_options(&u.packet, input_data, sizeof(input_data), pad); 260 len = set_packet_options(&u.packet, input_data, sizeof(input_data), pad);
261 if (len == 0) { 261 if (len == 0) {
262 atf_tc_fail("overrun: set_packet_options failed"); 262 atf_tc_fail("overrun: set_packet_options failed");
263 } 263 }
264 264
265 /* Enable option stripping by setting add_agent_options = 1 */ 265 /* Enable option stripping by setting add_agent_options = 1 */
266 add_agent_options = 1; 266 add_agent_options = 1;
267 267
268 /* strip_relay_agent_options() should detect the overrun and return 0 */ 268 /* strip_relay_agent_options() should detect the overrun and return 0 */
269 ret = strip_relay_agent_options(&ifaces, &matched, &u.packet, 4095); 269 ret = strip_relay_agent_options(&ifaces, &matched, &u.packet, 4095);
270 if (ret != 0) { 270 if (ret != 0) {
271 atf_tc_fail("overrun expected return len = 0, we got %d", ret); 271 atf_tc_fail("overrun expected return len = 0, we got %d", ret);
272 } 272 }
273 } 273 }
274} 274}
275 275
276ATF_TC(add_relay_agent_options_test); 276ATF_TC(add_relay_agent_options_test);
277 277
278ATF_TC_HEAD(add_relay_agent_options_test, tc) { 278ATF_TC_HEAD(add_relay_agent_options_test, tc) {
279 atf_tc_set_md_var(tc, "descr", "tests agent_relay-agent_options"); 279 atf_tc_set_md_var(tc, "descr", "tests agent_relay-agent_options");
280} 280}
281 281
282/* This Test exercises add_relay_agent_options() function */ 282/* This Test exercises add_relay_agent_options() function */
283ATF_TC_BODY(add_relay_agent_options_test, tc) { 283ATF_TC_BODY(add_relay_agent_options_test, tc) {
284 284
285 struct interface_info ifc; 285 struct interface_info ifc;
286 struct dhcp_packet packet; 286 struct dhcp_packet packet;
287 unsigned len; 287 unsigned len;
288 int ret; 288 int ret;
289 struct in_addr giaddr; 289 struct in_addr giaddr;
290 290
291 giaddr.s_addr = inet_addr("192.0.1.1"); 291 giaddr.s_addr = inet_addr("192.0.1.1");
292 292
293 u_int8_t circuit_id[] = { 0x01,0x02,0x03,0x04,0x05,0x06 }; 293 u_int8_t circuit_id[] = { 0x01,0x02,0x03,0x04,0x05,0x06 };
294 u_int8_t remote_id[] = { 0x11,0x22,0x33,0x44,0x55,0x66 }; 294 u_int8_t remote_id[] = { 0x11,0x22,0x33,0x44,0x55,0x66 };
295 295
296 memset(&ifc, 0x0, sizeof(ifc)); 296 memset(&ifc, 0x0, sizeof(ifc));
297 ifc.circuit_id = circuit_id; 297 ifc.circuit_id = circuit_id;
298 ifc.circuit_id_len = sizeof(circuit_id); 298 ifc.circuit_id_len = sizeof(circuit_id);
299 ifc.remote_id = remote_id; 299 ifc.remote_id = remote_id;
300 ifc.remote_id_len = sizeof(remote_id); 300 ifc.remote_id_len = sizeof(remote_id);
301 301
302 memset(&packet, 0x0, sizeof(packet)); 302 memset(&packet, 0x0, sizeof(packet));
303 len = 0; 303 len = 0;
304 304
305 /* Make sure an empty packet is harmless */ 305 /* Make sure an empty packet is harmless */
306 ret = add_relay_agent_options(&ifc, &packet, len, giaddr); 306 ret = add_relay_agent_options(&ifc, &packet, len, giaddr);
307 if (ret != 0) { 307 if (ret != 0) {
308 atf_tc_fail("empty packet failed"); 308 atf_tc_fail("empty packet failed");
309 } 309 }
310 310
311 { 311 {
312 /* 312 /*
313 * Uses valid input option data to verify that: 313 * Uses valid input option data to verify that:
314 * - When add_agent_options is false, the output option data is the 314 * - When add_agent_options is false, the output option data is the
315 * the same as the input option data (i.e. nothing removed) 315 * the same as the input option data (i.e. nothing removed)
316 * - When add_agent_options is true, the relay agent option has 316 * - When add_agent_options is true, the relay agent option has
317 * been removed from the output option data 317 * been removed from the output option data
318 * - When add_agent_options is true, 0 length relay agent option has 318 * - When add_agent_options is true, 0 length relay agent option has
319 * been removed from the output option data 319 * been removed from the output option data
320 * 320 *
321 */ 321 */
322 322
323 unsigned char input_data[] = { 323 unsigned char input_data[] = {
324 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 324 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
325 0x52, 0x08, 0x01, 0x06, 0x65, /* Relay Agent Option, len = 8 */ 325 0x52, 0x08, 0x01, 0x06, 0x65, /* Relay Agent Option, len = 8 */
326 0x6e, 0x70, 0x30, 0x73, 0x4f, 326 0x6e, 0x70, 0x30, 0x73, 0x4f,
327 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 327 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
328 0x43, 0x00 /* Opt 0x43, len = 0 */ 328 0x43, 0x00 /* Opt 0x43, len = 0 */
329 }; 329 };
330 330
331 unsigned char input_data2[] = { 331 unsigned char input_data2[] = {
332 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 332 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
333 0x52, 0x00, /* Relay Agent Option, len = 0 */ 333 0x52, 0x00, /* Relay Agent Option, len = 0 */
334 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 334 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
335 0x43, 0x00 /* Opt 0x43, len = 0 */ 335 0x43, 0x00 /* Opt 0x43, len = 0 */
336 }; 336 };
337 337
338 unsigned char output_data[] = { 338 unsigned char output_data[] = {
339 0x35, 0x00, /* DHCP_TYPE = DISCOVER */ 339 0x35, 0x00, /* DHCP_TYPE = DISCOVER */
340 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */ 340 0x42, 0x02, 0x00, 0x10, /* Opt 0x42, len = 2 */
341 0x43, 0x00, /* Opt 0x43, len = 0 */ 341 0x43, 0x00, /* Opt 0x43, len = 0 */
342 0x52, 0x10, /* Relay Agent, len = 16 */ 342 0x52, 0x10, /* Relay Agent, len = 16 */
343 0x1, 0x6, /* Circuit id, len = 6 */ 343 0x1, 0x6, /* Circuit id, len = 6 */
344 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 344 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
345 0x2, 0x6, /* Remete id, len = 6 */ 345 0x2, 0x6, /* Remete id, len = 6 */
346 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xff 346 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xff
347 }; 347 };
348 348
349 unsigned char pad = 0x0; 349 unsigned char pad = 0x0;
350 len = set_packet_options(&packet, input_data, sizeof(input_data), pad); 350 len = set_packet_options(&packet, input_data, sizeof(input_data), pad);
351 if (len == 0) { 351 if (len == 0) {
352 atf_tc_fail("input_data: set_packet_options failed"); 352 atf_tc_fail("input_data: set_packet_options failed");
353 } 353 }
354 354
355 /* When add_agent_options = 0, no change should occur */ 355 /* When add_agent_options = 0, no change should occur */
356 add_agent_options = 0; 356 add_agent_options = 0;
357 ret = add_relay_agent_options(&ifc, &packet, len, giaddr); 357 ret = add_relay_agent_options(&ifc, &packet, len, giaddr);
358 if (ret != len) { 358 if (ret != len) {
359 atf_tc_fail("expected unchanged len %d, returned %d", len, ret); 359 atf_tc_fail("expected unchanged len %d, returned %d", len, ret);
360 } 360 }
361 361
362 if (check_with_pad(packet.options, input_data, sizeof(input_data), 362 if (check_with_pad(packet.options, input_data, sizeof(input_data),
363 pad) != 0) { 363 pad) != 0) {
364 atf_tc_fail("expected unchanged data, does not match"); 364 atf_tc_fail("expected unchanged data, does not match");
365 } 365 }
366 366
367 /* When add_agent_options = 1, it should remove the eight byte 367 /* When add_agent_options = 1, it should remove the eight byte
368 * relay agent option. */ 368 * relay agent option. */
369 add_agent_options = 1; 369 add_agent_options = 1;
370 370
371 /* Because the inbound option data is less than the BOOTP_MIN_LEN, 371 /* Because the inbound option data is less than the BOOTP_MIN_LEN,
372 * the output data should get padded out to BOOTP_MIN_LEN 372 * the output data should get padded out to BOOTP_MIN_LEN
373 * padded out to BOOTP_MIN_LEN */ 373 * padded out to BOOTP_MIN_LEN */
374 ret = add_relay_agent_options(&ifc, &packet, len, giaddr); 374 ret = add_relay_agent_options(&ifc, &packet, len, giaddr);
375 if (ret != BOOTP_MIN_LEN) { 375 if (ret != BOOTP_MIN_LEN) {
376 atf_tc_fail("input_data: len of %d, returned %d", 376 atf_tc_fail("input_data: len of %d, returned %d",
377 BOOTP_MIN_LEN, ret); 377 BOOTP_MIN_LEN, ret);
378 } 378 }
379 379
380 if (check_with_pad(packet.options, output_data, sizeof(output_data), 380 if (check_with_pad(packet.options, output_data, sizeof(output_data),
381 pad) != 0) { 381 pad) != 0) {
382 atf_tc_fail("input_data: expected data does not match"); 382 atf_tc_fail("input_data: expected data does not match");
383 } 383 }
384 384
385 /* Now let's repeat it with a relay agent option 0 bytes in length. */ 385 /* Now let's repeat it with a relay agent option 0 bytes in length. */
386 len = set_packet_options(&packet, input_data2, sizeof(input_data2), 386 len = set_packet_options(&packet, input_data2, sizeof(input_data2),
387 pad); 387 pad);
388 if (len == 0) { 388 if (len == 0) {
389 atf_tc_fail("input_data2 set_packet_options failed"); 389 atf_tc_fail("input_data2 set_packet_options failed");
390 } 390 }
391 391
392 /* Because the inbound option data is less than the BOOTP_MIN_LEN, 392 /* Because the inbound option data is less than the BOOTP_MIN_LEN,
393 * the output data should get padded out to BOOTP_MIN_LEN 393 * the output data should get padded out to BOOTP_MIN_LEN
394 * padded out to BOOTP_MIN_LEN */ 394 * padded out to BOOTP_MIN_LEN */
395 ret = add_relay_agent_options(&ifc, &packet, len, giaddr); 395 ret = add_relay_agent_options(&ifc, &packet, len, giaddr);
396 if (ret != BOOTP_MIN_LEN) { 396 if (ret != BOOTP_MIN_LEN) {
397 atf_tc_fail("input_data2: len of %d, returned %d", 397 atf_tc_fail("input_data2: len of %d, returned %d",
398 BOOTP_MIN_LEN, ret); 398 BOOTP_MIN_LEN, ret);
399 } 399 }
400 400
401 if (check_with_pad(packet.options, output_data, sizeof(output_data), 401 if (check_with_pad(packet.options, output_data, sizeof(output_data),
402 pad) != 0) { 402 pad) != 0) {
403 atf_tc_fail("input_data2: expected output does not match"); 403 atf_tc_fail("input_data2: expected output does not match");
404 } 404 }
405 } 405 }
406} 406}
407 407
408ATF_TP_ADD_TCS(tp) { 408ATF_TP_ADD_TCS(tp) {
409 ATF_TP_ADD_TC(tp, strip_relay_agent_options_test); 409 ATF_TP_ADD_TC(tp, strip_relay_agent_options_test);
410 ATF_TP_ADD_TC(tp, add_relay_agent_options_test); 410 ATF_TP_ADD_TC(tp, add_relay_agent_options_test);
411 411
412 return (atf_no_error()); 412 return (atf_no_error());
413} 413}
 414
 415/* Below are dummy function definitions to satisfy "required" symbols */
 416isc_result_t find_class (struct class **c, const char *s,
 417 const char *file, int line) {
 418 return 0;
 419}
 420
 421int check_collection (struct packet *packet, struct lease *lease,
 422 struct collection *collection) {
 423 return 0;
 424}
 425
 426void classify (struct packet *packet, struct class *class){}
 427void bootp(struct packet *packet){}
 428void dhcp(struct packet *packet){}
 429void dhcpv6(struct packet *packet){}
 430
 431int parse_allow_deny (struct option_cache **oc, struct parse *cfile,
 432 int flag) {
 433 return 0;
 434}
 435
 436isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
 437 control_object_state_t newstate) {
 438 return (ISC_R_SUCCESS);
 439}

cvs diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/server/dhcpd.c (switch to unified diff)

--- src/external/mpl/dhcp/dist/server/dhcpd.c 2020/08/03 21:10:57 1.3
+++ src/external/mpl/dhcp/dist/server/dhcpd.c 2021/05/26 22:52:32 1.4
@@ -1,1228 +1,1228 @@ @@ -1,1228 +1,1228 @@
1/* $NetBSD: dhcpd.c,v 1.3 2020/08/03 21:10:57 christos Exp $ */ 1/* $NetBSD: dhcpd.c,v 1.4 2021/05/26 22:52:32 christos Exp $ */
2 2
3/* dhcpd.c 3/* dhcpd.c
4 4
5 DHCP Server Daemon. */ 5 DHCP Server Daemon. */
6 6
7/* 7/*
8 * Copyright (c) 2004-2020 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004-2021 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1996-2003 by Internet Software Consortium 9 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * 10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public 11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this 12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 * 14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * 22 *
23 * Internet Systems Consortium, Inc. 23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street 24 * 950 Charter Street
25 * Redwood City, CA 94063 25 * Redwood City, CA 94063
26 * <info@isc.org> 26 * <info@isc.org>
27 * https://www.isc.org/ 27 * https://www.isc.org/
28 * 28 *
29 */ 29 */
30 30
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32__RCSID("$NetBSD: dhcpd.c,v 1.3 2020/08/03 21:10:57 christos Exp $"); 32__RCSID("$NetBSD: dhcpd.c,v 1.4 2021/05/26 22:52:32 christos Exp $");
33 33
34static const char copyright[] = 34static const char copyright[] =
35"Copyright 2004-2020 Internet Systems Consortium."; 35"Copyright 2004-2021 Internet Systems Consortium.";
36static const char arr [] = "All rights reserved."; 36static const char arr [] = "All rights reserved.";
37static const char message [] = "Internet Systems Consortium DHCP Server"; 37static const char message [] = "Internet Systems Consortium DHCP Server";
38static const char url [] = 38static const char url [] =
39"For info, please visit https://www.isc.org/software/dhcp/"; 39"For info, please visit https://www.isc.org/software/dhcp/";
40 40
41#include "dhcpd.h" 41#include "dhcpd.h"
42#include <omapip/omapip_p.h> 42#include <omapip/omapip_p.h>
43#include <syslog.h> 43#include <syslog.h>
44#include <signal.h> 44#include <signal.h>
45#include <errno.h> 45#include <errno.h>
46#include <limits.h> 46#include <limits.h>
47#include <sys/types.h> 47#include <sys/types.h>
48#include <sys/time.h> 48#include <sys/time.h>
49#include <isc/file.h> 49#include <isc/file.h>
50 50
51#if defined (PARANOIA) 51#if defined (PARANOIA)
52# include <sys/types.h> 52# include <sys/types.h>
53# include <unistd.h> 53# include <unistd.h>
54# include <pwd.h> 54# include <pwd.h>
55/* get around the ISC declaration of group */ 55/* get around the ISC declaration of group */
56# define group real_group 56# define group real_group
57# include <grp.h> 57# include <grp.h>
58# undef group 58# undef group
59 59
60/* global values so db.c can look at them */ 60/* global values so db.c can look at them */
61uid_t set_uid = 0; 61uid_t set_uid = 0;
62gid_t set_gid = 0; 62gid_t set_gid = 0;
63#endif /* PARANOIA */ 63#endif /* PARANOIA */
64 64
65struct class unknown_class; 65struct class unknown_class;
66struct class known_class; 66struct class known_class;
67 67
68struct iaddr server_identifier; 68struct iaddr server_identifier;
69int server_identifier_matched; 69int server_identifier_matched;
70 70
71#if defined (NSUPDATE) 71#if defined (NSUPDATE)
72 72
73/* This stuff is always executed to figure the default values for certain 73/* This stuff is always executed to figure the default values for certain
74 ddns variables. */ 74 ddns variables. */
75char std_nsupdate [] = " \n\ 75char std_nsupdate [] = " \n\
76option server.ddns-hostname = \n\ 76option server.ddns-hostname = \n\
77 pick (option fqdn.hostname, option host-name, config-option host-name); \n\ 77 pick (option fqdn.hostname, option host-name, config-option host-name); \n\
78option server.ddns-domainname = config-option domain-name; \n\ 78option server.ddns-domainname = config-option domain-name; \n\
79option server.ddns-rev-domainname = \"in-addr.arpa.\";"; 79option server.ddns-rev-domainname = \"in-addr.arpa.\";";
80 80
81/* Stores configured DDNS conflict detection flags */ 81/* Stores configured DDNS conflict detection flags */
82u_int16_t ddns_conflict_mask; 82u_int16_t ddns_conflict_mask;
83#endif /* NSUPDATE */ 83#endif /* NSUPDATE */
84 84
85int ddns_update_style; 85int ddns_update_style;
86int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */ 86int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */
87int server_id_check = 0; /* 0 = default, don't check server id, 1 = do check */ 87int server_id_check = 0; /* 0 = default, don't check server id, 1 = do check */
88 88
89#ifdef DHCPv6 89#ifdef DHCPv6
90int prefix_length_mode = PLM_PREFER; 90int prefix_length_mode = PLM_PREFER;
91int do_release_on_roam = 0; /* 0 = default, do not release v6 leases on roam */ 91int do_release_on_roam = 0; /* 0 = default, do not release v6 leases on roam */
92#endif 92#endif
93 93
94#ifdef EUI_64 94#ifdef EUI_64
95int persist_eui64 = 1; /* 1 = write EUI64 leases to disk, 0 = don't */ 95int persist_eui64 = 1; /* 1 = write EUI64 leases to disk, 0 = don't */
96#endif 96#endif
97 97
98int authoring_byte_order = 0; /* 0 = not set */ 98int authoring_byte_order = 0; /* 0 = not set */
99int lease_id_format = TOKEN_OCTAL; /* octal by default */ 99int lease_id_format = TOKEN_OCTAL; /* octal by default */
100u_int32_t abandon_lease_time = DEFAULT_ABANDON_LEASE_TIME; 100u_int32_t abandon_lease_time = DEFAULT_ABANDON_LEASE_TIME;
101 101
102const char *path_dhcpd_conf = _PATH_DHCPD_CONF; 102const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
103const char *path_dhcpd_db = _PATH_DHCPD_DB; 103const char *path_dhcpd_db = _PATH_DHCPD_DB;
104const char *path_dhcpd_pid = _PATH_DHCPD_PID; 104const char *path_dhcpd_pid = _PATH_DHCPD_PID;
105/* False (default) => we write and use a pid file */ 105/* False (default) => we write and use a pid file */
106isc_boolean_t no_pid_file = ISC_FALSE; 106isc_boolean_t no_pid_file = ISC_FALSE;
107 107
108int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX; 108int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
109 109
110static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0; 110static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
111int omapi_port; 111int omapi_port;
112 112
113#if defined (TRACING) 113#if defined (TRACING)
114trace_type_t *trace_srandom; 114trace_type_t *trace_srandom;
115#endif 115#endif
116 116
117uint16_t local_port = 0; 117uint16_t local_port = 0;
118uint16_t remote_port = 0; 118uint16_t remote_port = 0;
119libdhcp_callbacks_t dhcpd_callbacks = { 119libdhcp_callbacks_t dhcpd_callbacks = {
120 &local_port, 120 &local_port,
121 &remote_port, 121 &remote_port,
122 classify, 122 classify,
123 check_collection, 123 check_collection,
124 dhcp, 124 dhcp,
125#ifdef DHCPv6 125#ifdef DHCPv6
126 dhcpv6, 126 dhcpv6,
127#endif /* DHCPv6 */ 127#endif /* DHCPv6 */
128 bootp, 128 bootp,
129 find_class, 129 find_class,
130 parse_allow_deny, 130 parse_allow_deny,
131 dhcp_set_control_state, 131 dhcp_set_control_state,
132}; 132};
133 133
134char *progname; 134char *progname;
135 135
136static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) { 136static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
137 return ISC_R_SUCCESS; 137 return ISC_R_SUCCESS;
138} 138}
139 139
140static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) { 140static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
141 if (a != omapi_key) 141 if (a != omapi_key)
142 return DHCP_R_INVALIDKEY; 142 return DHCP_R_INVALIDKEY;
143 return ISC_R_SUCCESS; 143 return ISC_R_SUCCESS;
144} 144}
145 145
146static void omapi_listener_start (void *foo) 146static void omapi_listener_start (void *foo)
147{ 147{
148 omapi_object_t *listener; 148 omapi_object_t *listener;
149 isc_result_t result; 149 isc_result_t result;
150 struct timeval tv; 150 struct timeval tv;
151 151
152 listener = (omapi_object_t *)0; 152 listener = (omapi_object_t *)0;
153 result = omapi_generic_new (&listener, MDL); 153 result = omapi_generic_new (&listener, MDL);
154 if (result != ISC_R_SUCCESS) 154 if (result != ISC_R_SUCCESS)
155 log_fatal ("Can't allocate new generic object: %s", 155 log_fatal ("Can't allocate new generic object: %s",
156 isc_result_totext (result)); 156 isc_result_totext (result));
157 result = omapi_protocol_listen (listener, 157 result = omapi_protocol_listen (listener,
158 (unsigned)omapi_port, 1); 158 (unsigned)omapi_port, 1);
159 if (result == ISC_R_SUCCESS && omapi_key) 159 if (result == ISC_R_SUCCESS && omapi_key)
160 result = omapi_protocol_configure_security 160 result = omapi_protocol_configure_security
161 (listener, verify_addr, verify_auth); 161 (listener, verify_addr, verify_auth);
162 if (result != ISC_R_SUCCESS) { 162 if (result != ISC_R_SUCCESS) {
163 log_error ("Can't start OMAPI protocol: %s", 163 log_error ("Can't start OMAPI protocol: %s",
164 isc_result_totext (result)); 164 isc_result_totext (result));
165 tv.tv_sec = cur_tv.tv_sec + 5; 165 tv.tv_sec = cur_tv.tv_sec + 5;
166 tv.tv_usec = cur_tv.tv_usec; 166 tv.tv_usec = cur_tv.tv_usec;
167 add_timeout (&tv, omapi_listener_start, 0, 0, 0); 167 add_timeout (&tv, omapi_listener_start, 0, 0, 0);
168 } 168 }
169 omapi_object_dereference (&listener, MDL); 169 omapi_object_dereference (&listener, MDL);
170} 170}
171 171
172#ifndef UNIT_TEST 172#ifndef UNIT_TEST
173 173
174#define DHCPD_USAGE0 \ 174#define DHCPD_USAGE0 \
175"[-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n" 175"[-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
176 176
177#ifdef DHCPv6 177#ifdef DHCPv6
178#ifdef DHCP4o6 178#ifdef DHCP4o6
179#define DHCPD_USAGE1 \ 179#define DHCPD_USAGE1 \
180" [-4|-6] [-4o6 <port>]\n" \ 180" [-4|-6] [-4o6 <port>]\n" \
181" [-cf config-file] [-lf lease-file]\n" 181" [-cf config-file] [-lf lease-file]\n"
182#else /* DHCP4o6 */ 182#else /* DHCP4o6 */
183#define DHCPD_USAGE1 \ 183#define DHCPD_USAGE1 \
184" [-4|-6] [-cf config-file] [-lf lease-file]\n" 184" [-4|-6] [-cf config-file] [-lf lease-file]\n"
185#endif /* DHCP4o6 */ 185#endif /* DHCP4o6 */
186#else /* !DHCPv6 */ 186#else /* !DHCPv6 */
187#define DHCPD_USAGE1 \ 187#define DHCPD_USAGE1 \
188" [-cf config-file] [-lf lease-file]\n" 188" [-cf config-file] [-lf lease-file]\n"
189#endif /* DHCPv6 */ 189#endif /* DHCPv6 */
190 190
191#if defined (PARANOIA) 191#if defined (PARANOIA)
192#define DHCPD_USAGEP \ 192#define DHCPD_USAGEP \
193" [-user user] [-group group] [-chroot dir]\n" 193" [-user user] [-group group] [-chroot dir]\n"
194#else 194#else
195#define DHCPD_USAGEP "" 195#define DHCPD_USAGEP ""
196#endif /* PARANOIA */ 196#endif /* PARANOIA */
197 197
198#if defined (TRACING) 198#if defined (TRACING)
199#define DHCPD_USAGET \ 199#define DHCPD_USAGET \
200" [-tf trace-output-file]\n" \ 200" [-tf trace-output-file]\n" \
201" [-play trace-input-file]\n" 201" [-play trace-input-file]\n"
202#else 202#else
203#define DHCPD_USAGET "" 203#define DHCPD_USAGET ""
204#endif /* TRACING */ 204#endif /* TRACING */
205 205
206#define DHCPD_USAGEC \ 206#define DHCPD_USAGEC \
207" [-pf pid-file] [--no-pid] [-s server]\n" \ 207" [-pf pid-file] [--no-pid] [-s server]\n" \
208" [if0 [...ifN]]" 208" [if0 [...ifN]]"
209 209
210#define DHCPD_USAGEH "{--version|--help|-h}" 210#define DHCPD_USAGEH "{--version|--help|-h}"
211 211
212/*! 212/*!
213 * 213 *
214 * \brief Print the generic usage message 214 * \brief Print the generic usage message
215 * 215 *
216 * If the user has provided an incorrect command line print out 216 * If the user has provided an incorrect command line print out
217 * the description of the command line. The arguments provide 217 * the description of the command line. The arguments provide
218 * a way for the caller to request more specific information about 218 * a way for the caller to request more specific information about
219 * the error be printed as well. Mostly this will be that some 219 * the error be printed as well. Mostly this will be that some
220 * comamnd doesn't include its argument. 220 * comamnd doesn't include its argument.
221 * 221 *
222 * \param sfmt - The basic string and format for the specific error 222 * \param sfmt - The basic string and format for the specific error
223 * \param sarg - Generally the offending argument from the comamnd line. 223 * \param sarg - Generally the offending argument from the comamnd line.
224 * 224 *
225 * \return Nothing 225 * \return Nothing
226 */ 226 */
227 227
228#include <sys/cdefs.h> 228#include <sys/cdefs.h>
229__RCSID("$NetBSD: dhcpd.c,v 1.3 2020/08/03 21:10:57 christos Exp $"); 229__RCSID("$NetBSD: dhcpd.c,v 1.4 2021/05/26 22:52:32 christos Exp $");
230static char use_noarg[] = "No argument for command: %s "; 230static char use_noarg[] = "No argument for command: %s ";
231 231
232static void 232static void
233usage(const char *sfmt, const char *sarg) { 233usage(const char *sfmt, const char *sarg) {
234 log_info("%s %s", message, PACKAGE_VERSION); 234 log_info("%s %s", message, PACKAGE_VERSION);
235 log_info(copyright); 235 log_info(copyright);
236 log_info(arr); 236 log_info(arr);
237 log_info(url); 237 log_info(url);
238 238
239 /* If desired print out the specific error message */ 239 /* If desired print out the specific error message */
240#ifdef PRINT_SPECIFIC_CL_ERRORS 240#ifdef PRINT_SPECIFIC_CL_ERRORS
241 if (sfmt != NULL) 241 if (sfmt != NULL)
242 log_error(sfmt, sarg); 242 log_error(sfmt, sarg);
243#endif 243#endif
244 244
245 log_fatal("Usage: %s %s%s%s%s%s\n %s %s", 245 log_fatal("Usage: %s %s%s%s%s%s\n %s %s",
246 isc_file_basename(progname), 246 isc_file_basename(progname),
247 DHCPD_USAGE0, 247 DHCPD_USAGE0,
248 DHCPD_USAGE1, 248 DHCPD_USAGE1,
249 DHCPD_USAGEP, 249 DHCPD_USAGEP,
250 DHCPD_USAGET, 250 DHCPD_USAGET,
251 DHCPD_USAGEC, 251 DHCPD_USAGEC,
252 isc_file_basename(progname), 252 isc_file_basename(progname),
253 DHCPD_USAGEH); 253 DHCPD_USAGEH);
254} 254}
255 255
256/* Note: If we add unit tests to test setup_chroot it will 256/* Note: If we add unit tests to test setup_chroot it will
257 * need to be moved to be outside the ifndef UNIT_TEST block. 257 * need to be moved to be outside the ifndef UNIT_TEST block.
258 */ 258 */
259 259
260#if defined (PARANOIA) 260#if defined (PARANOIA)
261/* to be used in one of two possible scenarios */ 261/* to be used in one of two possible scenarios */
262static void setup_chroot (char *chroot_dir) { 262static void setup_chroot (char *chroot_dir) {
263 if (geteuid()) 263 if (geteuid())
264 log_fatal ("you must be root to use chroot"); 264 log_fatal ("you must be root to use chroot");
265 265
266 if (chroot(chroot_dir)) { 266 if (chroot(chroot_dir)) {
267 log_fatal ("chroot(\"%s\"): %m", chroot_dir); 267 log_fatal ("chroot(\"%s\"): %m", chroot_dir);
268 } 268 }
269 if (chdir ("/")) { 269 if (chdir ("/")) {
270 /* probably permission denied */ 270 /* probably permission denied */
271 log_fatal ("chdir(\"/\"): %m"); 271 log_fatal ("chdir(\"/\"): %m");
272 } 272 }
273} 273}
274#endif /* PARANOIA */ 274#endif /* PARANOIA */
275 275
276int 276int
277main(int argc, char **argv) { 277main(int argc, char **argv) {
278 int fd; 278 int fd;
279 int i, status; 279 int i, status;
280 struct servent *ent; 280 struct servent *ent;
281 char *s; 281 char *s;
282 int cftest = 0; 282 int cftest = 0;
283 int lftest = 0; 283 int lftest = 0;
284 int pid; 284 int pid;
285 char pbuf [20]; 285 char pbuf [20];
286#ifndef DEBUG 286#ifndef DEBUG
287 int daemon = 1; 287 int daemon = 1;
288 int dfd[2] = { -1, -1 }; 288 int dfd[2] = { -1, -1 };
289#endif 289#endif
290 int quiet = 0; 290 int quiet = 0;
291 char *server = (char *)0; 291 char *server = (char *)0;
292 isc_result_t result; 292 isc_result_t result;
293 unsigned seed; 293 unsigned seed;
294 struct interface_info *ip; 294 struct interface_info *ip;
295#if defined (NSUPDATE) 295#if defined (NSUPDATE)
296 struct parse *parse; 296 struct parse *parse;
297 int lose; 297 int lose;
298#endif 298#endif
299 int have_dhcpd_conf = 0; 299 int have_dhcpd_conf = 0;
300 int have_dhcpd_db = 0; 300 int have_dhcpd_db = 0;
301 int have_dhcpd_pid = 0; 301 int have_dhcpd_pid = 0;
302#ifdef DHCPv6 302#ifdef DHCPv6
303 int local_family_set = 0; 303 int local_family_set = 0;
304#ifdef DHCP4o6 304#ifdef DHCP4o6
305 u_int16_t dhcp4o6_port = 0; 305 u_int16_t dhcp4o6_port = 0;
306#endif /* DHCP4o6 */ 306#endif /* DHCP4o6 */
307#endif /* DHCPv6 */ 307#endif /* DHCPv6 */
308#if defined (TRACING) 308#if defined (TRACING)
309 char *traceinfile = (char *)0; 309 char *traceinfile = (char *)0;
310 char *traceoutfile = (char *)0; 310 char *traceoutfile = (char *)0;
311#endif 311#endif
312 312
313#if defined (PARANOIA) 313#if defined (PARANOIA)
314 char *set_user = 0; 314 char *set_user = 0;
315 char *set_group = 0; 315 char *set_group = 0;
316 char *set_chroot = 0; 316 char *set_chroot = 0;
317#endif /* PARANOIA */ 317#endif /* PARANOIA */
318 318
319 libdhcp_callbacks_register(&dhcpd_callbacks); 319 libdhcp_callbacks_register(&dhcpd_callbacks);
320 320
321#ifdef OLD_LOG_NAME 321#ifdef OLD_LOG_NAME
322 progname = "dhcpd"; 322 progname = "dhcpd";
323#else 323#else
324 progname = argv[0]; 324 progname = argv[0];
325#endif 325#endif
326 326
327 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and 327 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
328 2 (stderr) are open. To do this, we assume that when we 328 2 (stderr) are open. To do this, we assume that when we
329 open a file the lowest available file descriptor is used. */ 329 open a file the lowest available file descriptor is used. */
330 fd = open("/dev/null", O_RDWR); 330 fd = open("/dev/null", O_RDWR);
331 if (fd == 0) 331 if (fd == 0)
332 fd = open("/dev/null", O_RDWR); 332 fd = open("/dev/null", O_RDWR);
333 if (fd == 1) 333 if (fd == 1)
334 fd = open("/dev/null", O_RDWR); 334 fd = open("/dev/null", O_RDWR);
335 if (fd == 2) 335 if (fd == 2)
336 log_perror = 0; /* No sense logging to /dev/null. */ 336 log_perror = 0; /* No sense logging to /dev/null. */
337 else if (fd != -1) 337 else if (fd != -1)
338 close(fd); 338 close(fd);
339 339
340 /* Parse arguments changing daemon */ 340 /* Parse arguments changing daemon */
341 for (i = 1; i < argc; i++) { 341 for (i = 1; i < argc; i++) {
342 if (!strcmp (argv [i], "-f")) { 342 if (!strcmp (argv [i], "-f")) {
343#ifndef DEBUG 343#ifndef DEBUG
344 daemon = 0; 344 daemon = 0;
345#endif 345#endif
346 } else if (!strcmp (argv [i], "-d")) { 346 } else if (!strcmp (argv [i], "-d")) {
347#ifndef DEBUG 347#ifndef DEBUG
348 daemon = 0; 348 daemon = 0;
349#endif 349#endif
350 } else if (!strcmp (argv [i], "-t")) { 350 } else if (!strcmp (argv [i], "-t")) {
351#ifndef DEBUG 351#ifndef DEBUG
352 daemon = 0; 352 daemon = 0;
353#endif 353#endif
354 } else if (!strcmp (argv [i], "-T")) { 354 } else if (!strcmp (argv [i], "-T")) {
355#ifndef DEBUG 355#ifndef DEBUG
356 daemon = 0; 356 daemon = 0;
357#endif 357#endif
358 } else if (!strcmp (argv [i], "--version")) { 358 } else if (!strcmp (argv [i], "--version")) {
359 const char vstring[] = "isc-dhcpd-"; 359 const char vstring[] = "isc-dhcpd-";
360 IGNORE_RET(write(STDERR_FILENO, vstring, 360 IGNORE_RET(write(STDERR_FILENO, vstring,
361 strlen(vstring))); 361 strlen(vstring)));
362 IGNORE_RET(write(STDERR_FILENO, 362 IGNORE_RET(write(STDERR_FILENO,
363 PACKAGE_VERSION, 363 PACKAGE_VERSION,
364 strlen(PACKAGE_VERSION))); 364 strlen(PACKAGE_VERSION)));
365 IGNORE_RET(write(STDERR_FILENO, "\n", 1)); 365 IGNORE_RET(write(STDERR_FILENO, "\n", 1));
366 exit (0); 366 exit (0);
367 } else if (!strcmp(argv[i], "--help") || 367 } else if (!strcmp(argv[i], "--help") ||
368 !strcmp(argv[i], "-h")) { 368 !strcmp(argv[i], "-h")) {
369 const char *pname = isc_file_basename(progname); 369 const char *pname = isc_file_basename(progname);
370 IGNORE_RET(write(STDERR_FILENO, "Usage: ", 7)); 370 IGNORE_RET(write(STDERR_FILENO, "Usage: ", 7));
371 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname))); 371 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
372 IGNORE_RET(write(STDERR_FILENO, " ", 1)); 372 IGNORE_RET(write(STDERR_FILENO, " ", 1));
373 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGE0, 373 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGE0,
374 strlen(DHCPD_USAGE0))); 374 strlen(DHCPD_USAGE0)));
375 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGE1, 375 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGE1,
376 strlen(DHCPD_USAGE1))); 376 strlen(DHCPD_USAGE1)));
377#if defined (PARANOIA) 377#if defined (PARANOIA)
378 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEP, 378 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEP,
379 strlen(DHCPD_USAGEP))); 379 strlen(DHCPD_USAGEP)));
380#endif 380#endif
381#if defined (TRACING) 381#if defined (TRACING)
382 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGET, 382 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGET,
383 strlen(DHCPD_USAGET))); 383 strlen(DHCPD_USAGET)));
384#endif 384#endif
385 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEC, 385 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEC,
386 strlen(DHCPD_USAGEC))); 386 strlen(DHCPD_USAGEC)));
387 IGNORE_RET(write(STDERR_FILENO, "\n", 1)); 387 IGNORE_RET(write(STDERR_FILENO, "\n", 1));
388 IGNORE_RET(write(STDERR_FILENO, " ", 7)); 388 IGNORE_RET(write(STDERR_FILENO, " ", 7));
389 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname))); 389 IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
390 IGNORE_RET(write(STDERR_FILENO, " ", 1)); 390 IGNORE_RET(write(STDERR_FILENO, " ", 1));
391 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEH, 391 IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEH,
392 strlen(DHCPD_USAGEH))); 392 strlen(DHCPD_USAGEH)));
393 IGNORE_RET(write(STDERR_FILENO, "\n", 1)); 393 IGNORE_RET(write(STDERR_FILENO, "\n", 1));
394 exit(0); 394 exit(0);
395#ifdef TRACING 395#ifdef TRACING
396 } else if (!strcmp (argv [i], "-play")) { 396 } else if (!strcmp (argv [i], "-play")) {
397#ifndef DEBUG 397#ifndef DEBUG
398 daemon = 0; 398 daemon = 0;
399#endif 399#endif
400#endif 400#endif
401 } 401 }
402 } 402 }
403 403
404#ifndef DEBUG 404#ifndef DEBUG
405 /* When not forbidden prepare to become a daemon */ 405 /* When not forbidden prepare to become a daemon */
406 if (daemon) { 406 if (daemon) {
407 if (pipe(dfd) == -1) 407 if (pipe(dfd) == -1)
408 log_fatal("Can't get pipe: %m"); 408 log_fatal("Can't get pipe: %m");
409 if ((pid = fork ()) < 0) 409 if ((pid = fork ()) < 0)
410 log_fatal("Can't fork daemon: %m"); 410 log_fatal("Can't fork daemon: %m");
411 if (pid != 0) { 411 if (pid != 0) {
412 /* Parent: wait for the child to start */ 412 /* Parent: wait for the child to start */
413 int n; 413 int n;
414 414
415 (void) close(dfd[1]); 415 (void) close(dfd[1]);
416 do { 416 do {
417 char buf; 417 char buf;
418 418
419 n = read(dfd[0], &buf, 1); 419 n = read(dfd[0], &buf, 1);
420 if (n == 1) 420 if (n == 1)
421 _exit((int)buf); 421 _exit((int)buf);
422 } while (n == -1 && errno == EINTR); 422 } while (n == -1 && errno == EINTR);
423 _exit(1); 423 _exit(1);
424 } 424 }
425 /* Child */ 425 /* Child */
426 (void) close(dfd[0]); 426 (void) close(dfd[0]);
427 } 427 }
428#endif 428#endif
429 429
430 /* Set up the isc and dns library managers */ 430 /* Set up the isc and dns library managers */
431 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, 431 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB,
432 NULL, NULL); 432 NULL, NULL);
433 if (status != ISC_R_SUCCESS) 433 if (status != ISC_R_SUCCESS)
434 log_fatal("Can't initialize context: %s", 434 log_fatal("Can't initialize context: %s",
435 isc_result_totext(status)); 435 isc_result_totext(status));
436 436
437 /* Set up the client classification system. */ 437 /* Set up the client classification system. */
438 classification_setup (); 438 classification_setup ();
439 439
440 /* Initialize the omapi system. */ 440 /* Initialize the omapi system. */
441 result = omapi_init (); 441 result = omapi_init ();
442 if (result != ISC_R_SUCCESS) 442 if (result != ISC_R_SUCCESS)
443 log_fatal ("Can't initialize OMAPI: %s", 443 log_fatal ("Can't initialize OMAPI: %s",
444 isc_result_totext (result)); 444 isc_result_totext (result));
445 445
446 /* Set up the OMAPI wrappers for common objects. */ 446 /* Set up the OMAPI wrappers for common objects. */
447 dhcp_db_objects_setup (); 447 dhcp_db_objects_setup ();
448 /* Set up the OMAPI wrappers for various server database internal 448 /* Set up the OMAPI wrappers for various server database internal
449 objects. */ 449 objects. */
450 dhcp_common_objects_setup (); 450 dhcp_common_objects_setup ();
451 451
452 /* Initially, log errors to stderr as well as to syslogd. */ 452 /* Initially, log errors to stderr as well as to syslogd. */
453 openlog (isc_file_basename(progname), 453 openlog (isc_file_basename(progname),
454 DHCP_LOG_OPTIONS, DHCPD_LOG_FACILITY); 454 DHCP_LOG_OPTIONS, DHCPD_LOG_FACILITY);
455 455
456 for (i = 1; i < argc; i++) { 456 for (i = 1; i < argc; i++) {
457 if (!strcmp (argv [i], "-p")) { 457 if (!strcmp (argv [i], "-p")) {
458 if (++i == argc) 458 if (++i == argc)
459 usage(use_noarg, argv[i-1]); 459 usage(use_noarg, argv[i-1]);
460 local_port = validate_port (argv [i]); 460 local_port = validate_port (argv [i]);
461 log_debug ("binding to user-specified port %d", 461 log_debug ("binding to user-specified port %d",
462 ntohs (local_port)); 462 ntohs (local_port));
463 } else if (!strcmp (argv [i], "-f")) { 463 } else if (!strcmp (argv [i], "-f")) {
464#ifndef DEBUG 464#ifndef DEBUG
465 /* daemon = 0; */ 465 /* daemon = 0; */
466#endif 466#endif
467 } else if (!strcmp (argv [i], "-d")) { 467 } else if (!strcmp (argv [i], "-d")) {
468#ifndef DEBUG 468#ifndef DEBUG
469 /* daemon = 0; */ 469 /* daemon = 0; */
470#endif 470#endif
471 log_perror = -1; 471 log_perror = -1;
472 } else if (!strcmp (argv [i], "-s")) { 472 } else if (!strcmp (argv [i], "-s")) {
473 if (++i == argc) 473 if (++i == argc)
474 usage(use_noarg, argv[i-1]); 474 usage(use_noarg, argv[i-1]);
475 server = argv [i]; 475 server = argv [i];
476#if defined (PARANOIA) 476#if defined (PARANOIA)
477 } else if (!strcmp (argv [i], "-user")) { 477 } else if (!strcmp (argv [i], "-user")) {
478 if (++i == argc) 478 if (++i == argc)
479 usage(use_noarg, argv[i-1]); 479 usage(use_noarg, argv[i-1]);
480 set_user = argv [i]; 480 set_user = argv [i];
481 } else if (!strcmp (argv [i], "-group")) { 481 } else if (!strcmp (argv [i], "-group")) {
482 if (++i == argc) 482 if (++i == argc)
483 usage(use_noarg, argv[i-1]); 483 usage(use_noarg, argv[i-1]);
484 set_group = argv [i]; 484 set_group = argv [i];
485 } else if (!strcmp (argv [i], "-chroot")) { 485 } else if (!strcmp (argv [i], "-chroot")) {
486 if (++i == argc) 486 if (++i == argc)
487 usage(use_noarg, argv[i-1]); 487 usage(use_noarg, argv[i-1]);
488 set_chroot = argv [i]; 488 set_chroot = argv [i];
489#endif /* PARANOIA */ 489#endif /* PARANOIA */
490 } else if (!strcmp (argv [i], "-cf")) { 490 } else if (!strcmp (argv [i], "-cf")) {
491 if (++i == argc) 491 if (++i == argc)
492 usage(use_noarg, argv[i-1]); 492 usage(use_noarg, argv[i-1]);
493 path_dhcpd_conf = argv [i]; 493 path_dhcpd_conf = argv [i];
494 have_dhcpd_conf = 1; 494 have_dhcpd_conf = 1;
495 } else if (!strcmp (argv [i], "-lf")) { 495 } else if (!strcmp (argv [i], "-lf")) {
496 if (++i == argc) 496 if (++i == argc)
497 usage(use_noarg, argv[i-1]); 497 usage(use_noarg, argv[i-1]);
498 path_dhcpd_db = argv [i]; 498 path_dhcpd_db = argv [i];
499 have_dhcpd_db = 1; 499 have_dhcpd_db = 1;
500 } else if (!strcmp (argv [i], "-pf")) { 500 } else if (!strcmp (argv [i], "-pf")) {
501 if (++i == argc) 501 if (++i == argc)
502 usage(use_noarg, argv[i-1]); 502 usage(use_noarg, argv[i-1]);
503 path_dhcpd_pid = argv [i]; 503 path_dhcpd_pid = argv [i];
504 have_dhcpd_pid = 1; 504 have_dhcpd_pid = 1;
505 } else if (!strcmp(argv[i], "--no-pid")) { 505 } else if (!strcmp(argv[i], "--no-pid")) {
506 no_pid_file = ISC_TRUE; 506 no_pid_file = ISC_TRUE;
507 } else if (!strcmp (argv [i], "-t")) { 507 } else if (!strcmp (argv [i], "-t")) {
508 /* test configurations only */ 508 /* test configurations only */
509#ifndef DEBUG 509#ifndef DEBUG
510 /* daemon = 0; */ 510 /* daemon = 0; */
511#endif 511#endif
512 cftest = 1; 512 cftest = 1;
513 log_perror = -1; 513 log_perror = -1;
514 } else if (!strcmp (argv [i], "-T")) { 514 } else if (!strcmp (argv [i], "-T")) {
515 /* test configurations and lease file only */ 515 /* test configurations and lease file only */
516#ifndef DEBUG 516#ifndef DEBUG
517 /* daemon = 0; */ 517 /* daemon = 0; */
518#endif 518#endif
519 cftest = 1; 519 cftest = 1;
520 lftest = 1; 520 lftest = 1;
521 log_perror = -1; 521 log_perror = -1;
522 } else if (!strcmp (argv [i], "-q")) { 522 } else if (!strcmp (argv [i], "-q")) {
523 quiet = 1; 523 quiet = 1;
524 quiet_interface_discovery = 1; 524 quiet_interface_discovery = 1;
525#ifdef DHCPv6 525#ifdef DHCPv6
526 } else if (!strcmp(argv[i], "-4")) { 526 } else if (!strcmp(argv[i], "-4")) {
527 if (local_family_set && (local_family != AF_INET)) { 527 if (local_family_set && (local_family != AF_INET)) {
528 log_fatal("Server cannot run in both IPv4 and " 528 log_fatal("Server cannot run in both IPv4 and "
529 "IPv6 mode at the same time."); 529 "IPv6 mode at the same time.");
530 } 530 }
531 local_family = AF_INET; 531 local_family = AF_INET;
532 local_family_set = 1; 532 local_family_set = 1;
533 } else if (!strcmp(argv[i], "-6")) { 533 } else if (!strcmp(argv[i], "-6")) {
534 if (local_family_set && (local_family != AF_INET6)) { 534 if (local_family_set && (local_family != AF_INET6)) {
535 log_fatal("Server cannot run in both IPv4 and " 535 log_fatal("Server cannot run in both IPv4 and "
536 "IPv6 mode at the same time."); 536 "IPv6 mode at the same time.");
537 } 537 }
538 local_family = AF_INET6; 538 local_family = AF_INET6;
539 local_family_set = 1; 539 local_family_set = 1;
540#ifdef DHCP4o6 540#ifdef DHCP4o6
541 } else if (!strcmp(argv[i], "-4o6")) { 541 } else if (!strcmp(argv[i], "-4o6")) {
542 if (++i == argc) 542 if (++i == argc)
543 usage(use_noarg, argv[i-1]); 543 usage(use_noarg, argv[i-1]);
544 dhcp4o6_port = validate_port_pair(argv[i]); 544 dhcp4o6_port = validate_port_pair(argv[i]);
545 545
546 log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d", 546 log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d",
547 ntohs(dhcp4o6_port), 547 ntohs(dhcp4o6_port),
548 ntohs(dhcp4o6_port) + 1); 548 ntohs(dhcp4o6_port) + 1);
549 dhcpv4_over_dhcpv6 = 1; 549 dhcpv4_over_dhcpv6 = 1;
550#endif /* DHCP4o6 */ 550#endif /* DHCP4o6 */
551#endif /* DHCPv6 */ 551#endif /* DHCPv6 */
552#if defined (TRACING) 552#if defined (TRACING)
553 } else if (!strcmp (argv [i], "-tf")) { 553 } else if (!strcmp (argv [i], "-tf")) {
554 if (++i == argc) 554 if (++i == argc)
555 usage(use_noarg, argv[i-1]); 555 usage(use_noarg, argv[i-1]);
556 traceoutfile = argv [i]; 556 traceoutfile = argv [i];
557 } else if (!strcmp (argv [i], "-play")) { 557 } else if (!strcmp (argv [i], "-play")) {
558 if (++i == argc) 558 if (++i == argc)
559 usage(use_noarg, argv[i-1]); 559 usage(use_noarg, argv[i-1]);
560 traceinfile = argv [i]; 560 traceinfile = argv [i];
561 trace_replay_init (); 561 trace_replay_init ();
562#endif /* TRACING */ 562#endif /* TRACING */
563 } else if (argv [i][0] == '-') { 563 } else if (argv [i][0] == '-') {
564 usage("Unknown command %s", argv[i]); 564 usage("Unknown command %s", argv[i]);
565 } else { 565 } else {
566 struct interface_info *tmp = 566 struct interface_info *tmp =
567 (struct interface_info *)0; 567 (struct interface_info *)0;
568 if (strlen(argv[i]) >= sizeof(tmp->name)) 568 if (strlen(argv[i]) >= sizeof(tmp->name))
569 log_fatal("%s: interface name too long " 569 log_fatal("%s: interface name too long "
570 "(is %ld)", 570 "(is %ld)",
571 argv[i], (long)strlen(argv[i])); 571 argv[i], (long)strlen(argv[i]));
572 result = interface_allocate (&tmp, MDL); 572 result = interface_allocate (&tmp, MDL);
573 if (result != ISC_R_SUCCESS) 573 if (result != ISC_R_SUCCESS)
574 log_fatal ("Insufficient memory to %s %s: %s", 574 log_fatal ("Insufficient memory to %s %s: %s",
575 "record interface", argv [i], 575 "record interface", argv [i],
576 isc_result_totext (result)); 576 isc_result_totext (result));
577 strcpy (tmp -> name, argv [i]); 577 strcpy (tmp -> name, argv [i]);
578 if (interfaces) { 578 if (interfaces) {
579 interface_reference (&tmp -> next, 579 interface_reference (&tmp -> next,
580 interfaces, MDL); 580 interfaces, MDL);
581 interface_dereference (&interfaces, MDL); 581 interface_dereference (&interfaces, MDL);
582 } 582 }
583 interface_reference (&interfaces, tmp, MDL); 583 interface_reference (&interfaces, tmp, MDL);
584 tmp -> flags = INTERFACE_REQUESTED; 584 tmp -> flags = INTERFACE_REQUESTED;
585 } 585 }
586 } 586 }
587 587
588#if defined(DHCPv6) && defined(DHCP4o6) 588#if defined(DHCPv6) && defined(DHCP4o6)
589 if (dhcpv4_over_dhcpv6) { 589 if (dhcpv4_over_dhcpv6) {
590 if (!local_family_set) 590 if (!local_family_set)
591 log_error("please specify the address family " 591 log_error("please specify the address family "
592 "with DHPv4 over DHCPv6 [-4|-6]."); 592 "with DHPv4 over DHCPv6 [-4|-6].");
593 if ((local_family == AF_INET) && (interfaces != NULL)) 593 if ((local_family == AF_INET) && (interfaces != NULL))
594 log_fatal("DHCPv4 server in DHPv4 over DHCPv6 " 594 log_fatal("DHCPv4 server in DHPv4 over DHCPv6 "
595 "mode with command line specified " 595 "mode with command line specified "
596 "interfaces."); 596 "interfaces.");
597 } 597 }
598#endif /* DHCPv6 && DHCP4o6 */ 598#endif /* DHCPv6 && DHCP4o6 */
599 599
600 if (!have_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) { 600 if (!have_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
601 path_dhcpd_conf = s; 601 path_dhcpd_conf = s;
602 } 602 }
603 603
604#ifdef DHCPv6 604#ifdef DHCPv6
605 if (local_family == AF_INET6) { 605 if (local_family == AF_INET6) {
606 /* DHCPv6: override DHCPv4 lease and pid filenames */ 606 /* DHCPv6: override DHCPv4 lease and pid filenames */
607 if (!have_dhcpd_db) { 607 if (!have_dhcpd_db) {
608 if ((s = getenv ("PATH_DHCPD6_DB"))) 608 if ((s = getenv ("PATH_DHCPD6_DB")))
609 path_dhcpd_db = s; 609 path_dhcpd_db = s;
610 else 610 else
611 path_dhcpd_db = _PATH_DHCPD6_DB; 611 path_dhcpd_db = _PATH_DHCPD6_DB;
612 } 612 }
613 if (!have_dhcpd_pid) { 613 if (!have_dhcpd_pid) {
614 if ((s = getenv ("PATH_DHCPD6_PID"))) 614 if ((s = getenv ("PATH_DHCPD6_PID")))
615 path_dhcpd_pid = s; 615 path_dhcpd_pid = s;
616 else 616 else
617 path_dhcpd_pid = _PATH_DHCPD6_PID; 617 path_dhcpd_pid = _PATH_DHCPD6_PID;
618 } 618 }
619 } else 619 } else
620#endif /* DHCPv6 */ 620#endif /* DHCPv6 */
621 { 621 {
622 if (!have_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) { 622 if (!have_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
623 path_dhcpd_db = s; 623 path_dhcpd_db = s;
624 have_dhcpd_db = 1; 624 have_dhcpd_db = 1;
625 } 625 }
626 if (!have_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) { 626 if (!have_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
627 path_dhcpd_pid = s; 627 path_dhcpd_pid = s;
628 have_dhcpd_pid = 1; 628 have_dhcpd_pid = 1;
629 } 629 }
630 } 630 }
631 631
632 /* 632 /*
633 * convert relative path names to absolute, for files that need 633 * convert relative path names to absolute, for files that need
634 * to be reopened after chdir() has been called 634 * to be reopened after chdir() has been called
635 */ 635 */
636 if (have_dhcpd_db && path_dhcpd_db[0] != '/') { 636 if (have_dhcpd_db && path_dhcpd_db[0] != '/') {
637 path_dhcpd_db = absolute_path(path_dhcpd_db); 637 path_dhcpd_db = absolute_path(path_dhcpd_db);
638 } 638 }
639 639
640 if (!quiet) { 640 if (!quiet) {
641 log_info("%s %s", message, PACKAGE_VERSION); 641 log_info("%s %s", message, PACKAGE_VERSION);
642 log_info (copyright); 642 log_info (copyright);
643 log_info (arr); 643 log_info (arr);
644 log_info (url); 644 log_info (url);
645 } else { 645 } else {
646 log_perror = 0; 646 log_perror = 0;
647 } 647 }
648 648
649#ifndef DEBUG 649#ifndef DEBUG
650 /* 650 /*
651 * We need to fork before we call the context create 651 * We need to fork before we call the context create
652 * call that creates the worker threads! 652 * call that creates the worker threads!
653 */ 653 */
654 if (daemon) { 654 if (daemon) {
655 /* First part of becoming a daemon... */ 655 /* First part of becoming a daemon... */
656 if ((pid = fork ()) < 0) 656 if ((pid = fork ()) < 0)
657 log_fatal ("Can't fork daemon: %m"); 657 log_fatal ("Can't fork daemon: %m");
658 else if (pid) 658 else if (pid)
659 exit (0); 659 exit (0);
660 } 660 }
661#endif 661#endif
662 662
663 /* Set up the isc and dns library managers */ 663 /* Set up the isc and dns library managers */
664 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL); 664 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL);
665 if (status != ISC_R_SUCCESS) 665 if (status != ISC_R_SUCCESS)
666 log_fatal("Can't initialize context: %s", 666 log_fatal("Can't initialize context: %s",
667 isc_result_totext(status)); 667 isc_result_totext(status));
668 668
669 /* Set up the client classification system. */ 669 /* Set up the client classification system. */
670 classification_setup (); 670 classification_setup ();
671  671
672#if defined (TRACING) 672#if defined (TRACING)
673 trace_init (set_time, MDL); 673 trace_init (set_time, MDL);
674 if (traceoutfile) { 674 if (traceoutfile) {
675 result = trace_begin (traceoutfile, MDL); 675 result = trace_begin (traceoutfile, MDL);
676 if (result != ISC_R_SUCCESS) 676 if (result != ISC_R_SUCCESS)
677 log_fatal ("Unable to begin trace: %s", 677 log_fatal ("Unable to begin trace: %s",
678 isc_result_totext (result)); 678 isc_result_totext (result));
679 } 679 }
680 interface_trace_setup (); 680 interface_trace_setup ();
681 parse_trace_setup (); 681 parse_trace_setup ();
682 trace_srandom = trace_type_register ("random-seed", (void *)0, 682 trace_srandom = trace_type_register ("random-seed", (void *)0,
683 trace_seed_input, 683 trace_seed_input,
684 trace_seed_stop, MDL); 684 trace_seed_stop, MDL);
685#if defined (NSUPDATE) 685#if defined (NSUPDATE)
686 trace_ddns_init(); 686 trace_ddns_init();
687#endif /* NSUPDATE */ 687#endif /* NSUPDATE */
688#endif 688#endif
689 689
690#if defined (PARANOIA) 690#if defined (PARANOIA)
691 /* get user and group info if those options were given */ 691 /* get user and group info if those options were given */
692 if (set_user) { 692 if (set_user) {
693 struct passwd *tmp_pwd; 693 struct passwd *tmp_pwd;
694 694
695 if (geteuid()) 695 if (geteuid())
696 log_fatal ("you must be root to set user"); 696 log_fatal ("you must be root to set user");
697 697
698 if (!(tmp_pwd = getpwnam(set_user))) 698 if (!(tmp_pwd = getpwnam(set_user)))
699 log_fatal ("no such user: %s", set_user); 699 log_fatal ("no such user: %s", set_user);
700 700
701 set_uid = tmp_pwd->pw_uid; 701 set_uid = tmp_pwd->pw_uid;
702 702
703 /* use the user's group as the default gid */ 703 /* use the user's group as the default gid */
704 if (!set_group) 704 if (!set_group)
705 set_gid = tmp_pwd->pw_gid; 705 set_gid = tmp_pwd->pw_gid;
706 } 706 }
707 707
708 if (set_group) { 708 if (set_group) {
709/* get around the ISC declaration of group */ 709/* get around the ISC declaration of group */
710#define group real_group 710#define group real_group
711 struct group *tmp_grp; 711 struct group *tmp_grp;
712 712
713 if (geteuid()) 713 if (geteuid())
714 log_fatal ("you must be root to set group"); 714 log_fatal ("you must be root to set group");
715 715
716 if (!(tmp_grp = getgrnam(set_group))) 716 if (!(tmp_grp = getgrnam(set_group)))
717 log_fatal ("no such group: %s", set_group); 717 log_fatal ("no such group: %s", set_group);
718 718
719 set_gid = tmp_grp->gr_gid; 719 set_gid = tmp_grp->gr_gid;
720#undef group 720#undef group
721 } 721 }
722 722
723# if defined (EARLY_CHROOT) 723# if defined (EARLY_CHROOT)
724 if (set_chroot) setup_chroot (set_chroot); 724 if (set_chroot) setup_chroot (set_chroot);
725# endif /* EARLY_CHROOT */ 725# endif /* EARLY_CHROOT */
726#endif /* PARANOIA */ 726#endif /* PARANOIA */
727 727
728 /* Default to the DHCP/BOOTP port. */ 728 /* Default to the DHCP/BOOTP port. */
729 if (!local_port) 729 if (!local_port)
730 { 730 {
731 if ((s = getenv ("DHCPD_PORT"))) { 731 if ((s = getenv ("DHCPD_PORT"))) {
732 local_port = validate_port (s); 732 local_port = validate_port (s);
733 log_debug ("binding to environment-specified port %d", 733 log_debug ("binding to environment-specified port %d",
734 ntohs (local_port)); 734 ntohs (local_port));
735 } else { 735 } else {
736 if (local_family == AF_INET) { 736 if (local_family == AF_INET) {
737 ent = getservbyname("dhcp", "udp"); 737 ent = getservbyname("dhcp", "udp");
738 if (ent == NULL) { 738 if (ent == NULL) {
739 local_port = htons(67); 739 local_port = htons(67);
740 } else { 740 } else {
741 local_port = ent->s_port; 741 local_port = ent->s_port;
742 } 742 }
743 } else { 743 } else {
744 /* INSIST(local_family == AF_INET6); */ 744 /* INSIST(local_family == AF_INET6); */
745 ent = getservbyname("dhcpv6-server", "udp"); 745 ent = getservbyname("dhcpv6-server", "udp");
746 if (ent == NULL) { 746 if (ent == NULL) {
747 local_port = htons(547); 747 local_port = htons(547);
748 } else { 748 } else {
749 local_port = ent->s_port; 749 local_port = ent->s_port;
750 } 750 }
751 } 751 }
752#ifndef __CYGWIN32__ /* XXX */ 752#ifndef __CYGWIN32__ /* XXX */
753 endservent (); 753 endservent ();
754#endif 754#endif
755 } 755 }
756 } 756 }
757 757
758 if (local_family == AF_INET) { 758 if (local_family == AF_INET) {
759 remote_port = htons(ntohs(local_port) + 1); 759 remote_port = htons(ntohs(local_port) + 1);
760 } else { 760 } else {
761 /* INSIST(local_family == AF_INET6); */ 761 /* INSIST(local_family == AF_INET6); */
762 ent = getservbyname("dhcpv6-client", "udp"); 762 ent = getservbyname("dhcpv6-client", "udp");
763 if (ent == NULL) { 763 if (ent == NULL) {
764 remote_port = htons(546); 764 remote_port = htons(546);
765 } else { 765 } else {
766 remote_port = ent->s_port; 766 remote_port = ent->s_port;
767 } 767 }
768 } 768 }
769 769
770 if (server) { 770 if (server) {
771 if (local_family != AF_INET) { 771 if (local_family != AF_INET) {
772 log_fatal("You can only specify address to send " 772 log_fatal("You can only specify address to send "
773 "replies to when running an IPv4 server."); 773 "replies to when running an IPv4 server.");
774 } 774 }
775 if (!inet_aton (server, &limited_broadcast)) { 775 if (!inet_aton (server, &limited_broadcast)) {
776 struct hostent *he; 776 struct hostent *he;
777 he = gethostbyname (server); 777 he = gethostbyname (server);
778 if (he) { 778 if (he) {
779 memcpy (&limited_broadcast, 779 memcpy (&limited_broadcast,
780 he -> h_addr_list [0], 780 he -> h_addr_list [0],
781 sizeof limited_broadcast); 781 sizeof limited_broadcast);
782 } else 782 } else
783 limited_broadcast.s_addr = INADDR_BROADCAST; 783 limited_broadcast.s_addr = INADDR_BROADCAST;
784 } 784 }
785 } else { 785 } else {
786 limited_broadcast.s_addr = INADDR_BROADCAST; 786 limited_broadcast.s_addr = INADDR_BROADCAST;
787 } 787 }
788 788
789 /* Get the current time... */ 789 /* Get the current time... */
790 gettimeofday(&cur_tv, NULL); 790 gettimeofday(&cur_tv, NULL);
791 791
792 /* Set up the initial dhcp option universe. */ 792 /* Set up the initial dhcp option universe. */
793 initialize_common_option_spaces (); 793 initialize_common_option_spaces ();
794 initialize_server_option_spaces (); 794 initialize_server_option_spaces ();
795 795
796 /* Add the ddns update style enumeration prior to parsing. */ 796 /* Add the ddns update style enumeration prior to parsing. */
797 add_enumeration (&ddns_styles); 797 add_enumeration (&ddns_styles);
798 add_enumeration (&syslog_enum); 798 add_enumeration (&syslog_enum);
799#if defined (LDAP_CONFIGURATION) 799#if defined (LDAP_CONFIGURATION)
800 add_enumeration (&ldap_methods); 800 add_enumeration (&ldap_methods);
801#if defined (LDAP_USE_SSL) 801#if defined (LDAP_USE_SSL)
802 add_enumeration (&ldap_ssl_usage_enum); 802 add_enumeration (&ldap_ssl_usage_enum);
803 add_enumeration (&ldap_tls_reqcert_enum); 803 add_enumeration (&ldap_tls_reqcert_enum);
804 add_enumeration (&ldap_tls_crlcheck_enum); 804 add_enumeration (&ldap_tls_crlcheck_enum);
805#endif 805#endif
806#endif 806#endif
807 807
808 if (!group_allocate (&root_group, MDL)) 808 if (!group_allocate (&root_group, MDL))
809 log_fatal ("Can't allocate root group!"); 809 log_fatal ("Can't allocate root group!");
810 root_group -> authoritative = 0; 810 root_group -> authoritative = 0;
811 811
812 /* Set up various hooks. */ 812 /* Set up various hooks. */
813 dhcp_interface_setup_hook = dhcpd_interface_setup_hook; 813 dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
814 bootp_packet_handler = do_packet; 814 bootp_packet_handler = do_packet;
815#ifdef DHCPv6 815#ifdef DHCPv6
816 add_enumeration (&prefix_length_modes); 816 add_enumeration (&prefix_length_modes);
817 dhcpv6_packet_handler = do_packet6; 817 dhcpv6_packet_handler = do_packet6;
818#endif /* DHCPv6 */ 818#endif /* DHCPv6 */
819 819
820#if defined (NSUPDATE) 820#if defined (NSUPDATE)
821 /* Set up the standard name service updater routine. */ 821 /* Set up the standard name service updater routine. */
822 parse = NULL; 822 parse = NULL;
823 status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1, 823 status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1,
824 "standard name service update routine", 0); 824 "standard name service update routine", 0);
825 if (status != ISC_R_SUCCESS) 825 if (status != ISC_R_SUCCESS)
826 log_fatal ("can't begin parsing name service updater!"); 826 log_fatal ("can't begin parsing name service updater!");
827 827
828 if (parse != NULL) { 828 if (parse != NULL) {
829 lose = 0; 829 lose = 0;
830 if (!(parse_executable_statements(&root_group->statements, 830 if (!(parse_executable_statements(&root_group->statements,
831 parse, &lose, context_any))) { 831 parse, &lose, context_any))) {
832 end_parse(&parse); 832 end_parse(&parse);
833 log_fatal("can't parse standard name service updater!"); 833 log_fatal("can't parse standard name service updater!");
834 } 834 }
835 end_parse(&parse); 835 end_parse(&parse);
836 } 836 }
837#endif 837#endif
838 838
839 /* Initialize icmp support... */ 839 /* Initialize icmp support... */
840 if (!cftest && !lftest) 840 if (!cftest && !lftest)
841 icmp_startup (1, lease_pinged); 841 icmp_startup (1, lease_pinged);
842 842
843#if defined (TRACING) 843#if defined (TRACING)
844 if (traceinfile) { 844 if (traceinfile) {
845 if (!have_dhcpd_db) { 845 if (!have_dhcpd_db) {
846 log_error ("%s", ""); 846 log_error ("%s", "");
847 log_error ("** You must specify a lease file with -lf."); 847 log_error ("** You must specify a lease file with -lf.");
848 log_error (" Dhcpd will not overwrite your default"); 848 log_error (" Dhcpd will not overwrite your default");
849 log_fatal (" lease file when playing back a trace. **"); 849 log_fatal (" lease file when playing back a trace. **");
850 } 850 }
851 trace_file_replay (traceinfile); 851 trace_file_replay (traceinfile);
852 852
853#if defined (DEBUG_MEMORY_LEAKAGE) && \ 853#if defined (DEBUG_MEMORY_LEAKAGE) && \
854 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 854 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
855 free_everything (); 855 free_everything ();
856 omapi_print_dmalloc_usage_by_caller (); 856 omapi_print_dmalloc_usage_by_caller ();
857#endif 857#endif
858 858
859 exit (0); 859 exit (0);
860 } 860 }
861#endif 861#endif
862 862
863#ifdef DHCPv6 863#ifdef DHCPv6
864 /* set up DHCPv6 hashes */ 864 /* set up DHCPv6 hashes */
865 if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) { 865 if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) {
866 log_fatal("Out of memory creating hash for active IA_NA."); 866 log_fatal("Out of memory creating hash for active IA_NA.");
867 } 867 }
868 if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) { 868 if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) {
869 log_fatal("Out of memory creating hash for active IA_TA."); 869 log_fatal("Out of memory creating hash for active IA_TA.");
870 } 870 }
871 if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) { 871 if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) {
872 log_fatal("Out of memory creating hash for active IA_PD."); 872 log_fatal("Out of memory creating hash for active IA_PD.");
873 } 873 }
874#endif /* DHCPv6 */ 874#endif /* DHCPv6 */
875 875
876 /* Read the dhcpd.conf file... */ 876 /* Read the dhcpd.conf file... */
877 if (readconf () != ISC_R_SUCCESS) 877 if (readconf () != ISC_R_SUCCESS)
878 log_fatal ("Configuration file errors encountered -- exiting"); 878 log_fatal ("Configuration file errors encountered -- exiting");
879 879
880 postconf_initialization (quiet); 880 postconf_initialization (quiet);
881 881
882#if defined (FAILOVER_PROTOCOL) 882#if defined (FAILOVER_PROTOCOL)
883 dhcp_failover_sanity_check(); 883 dhcp_failover_sanity_check();
884#endif 884#endif
885 885
886#if defined(DHCPv6) && defined(DHCP4o6) 886#if defined(DHCPv6) && defined(DHCP4o6)
887 if (dhcpv4_over_dhcpv6) { 887 if (dhcpv4_over_dhcpv6) {
888 if ((local_family == AF_INET) && (interfaces != NULL)) 888 if ((local_family == AF_INET) && (interfaces != NULL))
889 log_fatal("DHCPv4 server in DHPv4 over DHCPv6 " 889 log_fatal("DHCPv4 server in DHPv4 over DHCPv6 "
890 "mode with config file specified " 890 "mode with config file specified "
891 "interfaces."); 891 "interfaces.");
892 } 892 }
893#endif /* DHCPv6 && DHCP4o6 */ 893#endif /* DHCPv6 && DHCP4o6 */
894 894
895#if defined (PARANOIA) && !defined (EARLY_CHROOT) 895#if defined (PARANOIA) && !defined (EARLY_CHROOT)
896 if (set_chroot) setup_chroot (set_chroot); 896 if (set_chroot) setup_chroot (set_chroot);
897#endif /* PARANOIA && !EARLY_CHROOT */ 897#endif /* PARANOIA && !EARLY_CHROOT */
898 898
899#ifdef DHCPv6 899#ifdef DHCPv6
900 /* log info about ipv6_ponds with large address ranges */ 900 /* log info about ipv6_ponds with large address ranges */
901 report_jumbo_ranges(); 901 report_jumbo_ranges();
902#endif 902#endif
903 903
904 /* test option should cause an early exit */ 904 /* test option should cause an early exit */
905 if (cftest && !lftest) { 905 if (cftest && !lftest) {
906 exit(0); 906 exit(0);
907 } 907 }
908 908
909 /* 909 /*
910 * First part of dealing with pid files. Check to see if 910 * First part of dealing with pid files. Check to see if
911 * we should continue running or not. We run if: 911 * we should continue running or not. We run if:
912 * - we are testing the lease file out 912 * - we are testing the lease file out
913 * - we don't have a pid file to check 913 * - we don't have a pid file to check
914 * - there is no other process running 914 * - there is no other process running
915 */ 915 */
916 if ((lftest == 0) && (no_pid_file == ISC_FALSE)) { 916 if ((lftest == 0) && (no_pid_file == ISC_FALSE)) {
917 /*Read previous pid file. */ 917 /*Read previous pid file. */
918 if ((i = open(path_dhcpd_pid, O_RDONLY)) >= 0) { 918 if ((i = open(path_dhcpd_pid, O_RDONLY)) >= 0) {
919 status = read(i, pbuf, (sizeof pbuf) - 1); 919 status = read(i, pbuf, (sizeof pbuf) - 1);
920 close(i); 920 close(i);
921 if (status > 0) { 921 if (status > 0) {
922 pbuf[status] = 0; 922 pbuf[status] = 0;
923 pid = atoi(pbuf); 923 pid = atoi(pbuf);
924 924
925 /* 925 /*
926 * If there was a previous server process and 926 * If there was a previous server process and
927 * it is still running, abort 927 * it is still running, abort
928 */ 928 */
929 if (!pid || 929 if (!pid ||
930 (pid != getpid() && kill(pid, 0) == 0)) 930 (pid != getpid() && kill(pid, 0) == 0))
931 log_fatal("There's already a " 931 log_fatal("There's already a "
932 "DHCP server running."); 932 "DHCP server running.");
933 } 933 }
934 } 934 }
935 } 935 }
936 936
937 group_write_hook = group_writer; 937 group_write_hook = group_writer;
938 938
939 /* Start up the database... */ 939 /* Start up the database... */
940 db_startup (lftest); 940 db_startup (lftest);
941 941
942 if (lftest) 942 if (lftest)
943 exit (0); 943 exit (0);
944 944
945 /* Discover all the network interfaces and initialize them. */ 945 /* Discover all the network interfaces and initialize them. */
946#if defined(DHCPv6) && defined(DHCP4o6) 946#if defined(DHCPv6) && defined(DHCP4o6)
947 if (dhcpv4_over_dhcpv6) { 947 if (dhcpv4_over_dhcpv6) {
948 int real_family = local_family; 948 int real_family = local_family;
949 local_family = AF_INET6; 949 local_family = AF_INET6;
950 /* The DHCPv4 side of DHCPv4-over-DHCPv6 service 950 /* The DHCPv4 side of DHCPv4-over-DHCPv6 service
951 uses a specific discovery which doesn't register 951 uses a specific discovery which doesn't register
952 DHCPv6 sockets. */ 952 DHCPv6 sockets. */
953 if (real_family == AF_INET) 953 if (real_family == AF_INET)
954 discover_interfaces(DISCOVER_SERVER46); 954 discover_interfaces(DISCOVER_SERVER46);
955 else 955 else
956 discover_interfaces(DISCOVER_SERVER); 956 discover_interfaces(DISCOVER_SERVER);
957 local_family = real_family; 957 local_family = real_family;
958 } else 958 } else
959#endif /* DHCPv6 && DHCP4o6 */ 959#endif /* DHCPv6 && DHCP4o6 */
960 discover_interfaces(DISCOVER_SERVER); 960 discover_interfaces(DISCOVER_SERVER);
961 961
962#ifdef DHCPv6 962#ifdef DHCPv6
963 /* 963 /*
964 * Remove addresses from our pools that we should not issue 964 * Remove addresses from our pools that we should not issue
965 * to clients. 965 * to clients.
966 * 966 *
967 * We currently have no support for this in IPv4. It is not 967 * We currently have no support for this in IPv4. It is not
968 * as important in IPv4, as making pools with ranges that 968 * as important in IPv4, as making pools with ranges that
969 * leave out interfaces and hosts is fairly straightforward 969 * leave out interfaces and hosts is fairly straightforward
970 * using range notation, but not so handy with CIDR notation. 970 * using range notation, but not so handy with CIDR notation.
971 */ 971 */
972 if (local_family == AF_INET6) { 972 if (local_family == AF_INET6) {
973 mark_hosts_unavailable(); 973 mark_hosts_unavailable();
974 mark_phosts_unavailable(); 974 mark_phosts_unavailable();
975 mark_interfaces_unavailable(); 975 mark_interfaces_unavailable();
976 } 976 }
977#endif /* DHCPv6 */ 977#endif /* DHCPv6 */
978 978
979 /* Make up a seed for the random number generator from current 979 /* Make up a seed for the random number generator from current
980 time plus the sum of the last four bytes of each 980 time plus the sum of the last four bytes of each
981 interface's hardware address interpreted as an integer. 981 interface's hardware address interpreted as an integer.
982 Not much entropy, but we're booting, so we're not likely to 982 Not much entropy, but we're booting, so we're not likely to
983 find anything better. */ 983 find anything better. */
984 seed = 0; 984 seed = 0;
985 for (ip = interfaces; ip; ip = ip -> next) { 985 for (ip = interfaces; ip; ip = ip -> next) {
986 int junk; 986 int junk;
987 memcpy (&junk, 987 memcpy (&junk,
988 &ip -> hw_address.hbuf [ip -> hw_address.hlen - 988 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
989 sizeof seed], sizeof seed); 989 sizeof seed], sizeof seed);
990 seed += junk; 990 seed += junk;
991 } 991 }
992 srandom (seed + cur_time); 992 srandom (seed + cur_time);
993#if defined (TRACING) 993#if defined (TRACING)
994 trace_seed_stash (trace_srandom, seed + cur_time); 994 trace_seed_stash (trace_srandom, seed + cur_time);
995#endif 995#endif
996 postdb_startup (); 996 postdb_startup ();
997 997
998#ifdef DHCPv6 998#ifdef DHCPv6
999 /* 999 /*
1000 * Set server DHCPv6 identifier - we go in order: 1000 * Set server DHCPv6 identifier - we go in order:
1001 * dhcp6.server-id in the config file 1001 * dhcp6.server-id in the config file
1002 * server-duid from the lease file 1002 * server-duid from the lease file
1003 * server-duid from the config file (the config file is read first 1003 * server-duid from the config file (the config file is read first
1004 * and the lease file overwrites the config file information) 1004 * and the lease file overwrites the config file information)
1005 * generate a new one from the interface hardware addresses. 1005 * generate a new one from the interface hardware addresses.
1006 * In all cases we write it out to the lease file. 1006 * In all cases we write it out to the lease file.
1007 * See dhcpv6.c for discussion of setting DUID. 1007 * See dhcpv6.c for discussion of setting DUID.
1008 */ 1008 */
1009 if ((set_server_duid_from_option() != ISC_R_SUCCESS) && 1009 if ((set_server_duid_from_option() != ISC_R_SUCCESS) &&
1010 (!server_duid_isset()) && 1010 (!server_duid_isset()) &&
1011 (generate_new_server_duid() != ISC_R_SUCCESS)) { 1011 (generate_new_server_duid() != ISC_R_SUCCESS)) {
1012 log_fatal("Unable to set server identifier."); 1012 log_fatal("Unable to set server identifier.");
1013 } 1013 }
1014 write_server_duid(); 1014 write_server_duid();
1015#ifdef DHCP4o6 1015#ifdef DHCP4o6
1016 if (dhcpv4_over_dhcpv6) 1016 if (dhcpv4_over_dhcpv6)
1017 dhcp4o6_setup(dhcp4o6_port); 1017 dhcp4o6_setup(dhcp4o6_port);
1018#endif /* DHCP4o6 */ 1018#endif /* DHCP4o6 */
1019#endif /* DHCPv6 */ 1019#endif /* DHCPv6 */
1020 1020
1021#ifndef DEBUG 1021#ifndef DEBUG
1022 /* 1022 /*
1023 * Second part of dealing with pid files. Now 1023 * Second part of dealing with pid files. Now
1024 * that we have forked we can write our pid if 1024 * that we have forked we can write our pid if
1025 * appropriate. 1025 * appropriate.
1026 */ 1026 */
1027 if (no_pid_file == ISC_FALSE) { 1027 if (no_pid_file == ISC_FALSE) {
1028 i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644); 1028 i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1029 if (i >= 0) { 1029 if (i >= 0) {
1030 sprintf(pbuf, "%d\n", (int) getpid()); 1030 sprintf(pbuf, "%d\n", (int) getpid());
1031 IGNORE_RET(write(i, pbuf, strlen(pbuf))); 1031 IGNORE_RET(write(i, pbuf, strlen(pbuf)));
1032 close(i); 1032 close(i);
1033 } else { 1033 } else {
1034 log_error("Can't create PID file %s: %m.", 1034 log_error("Can't create PID file %s: %m.",
1035 path_dhcpd_pid); 1035 path_dhcpd_pid);
1036 } 1036 }
1037 } 1037 }
1038 1038
1039#if defined (PARANOIA) 1039#if defined (PARANOIA)
1040 /* change uid to the specified one */ 1040 /* change uid to the specified one */
1041 1041
1042 if (set_gid) { 1042 if (set_gid) {
1043 if (setgroups (0, (void *)0)) 1043 if (setgroups (0, (void *)0))
1044 log_fatal ("setgroups: %m"); 1044 log_fatal ("setgroups: %m");
1045 if (setgid (set_gid)) 1045 if (setgid (set_gid))
1046 log_fatal ("setgid(%d): %m", (int) set_gid); 1046 log_fatal ("setgid(%d): %m", (int) set_gid);
1047 } 1047 }
1048 1048
1049 if (set_uid) { 1049 if (set_uid) {
1050 if (setuid (set_uid)) 1050 if (setuid (set_uid))
1051 log_fatal ("setuid(%d): %m", (int) set_uid); 1051 log_fatal ("setuid(%d): %m", (int) set_uid);
1052 } 1052 }
1053#endif /* PARANOIA */ 1053#endif /* PARANOIA */
1054 1054
1055 /* If we were requested to log to stdout on the command line, 1055 /* If we were requested to log to stdout on the command line,
1056 keep doing so; otherwise, stop. */ 1056 keep doing so; otherwise, stop. */
1057 if (log_perror == -1) 1057 if (log_perror == -1)
1058 log_perror = 1; 1058 log_perror = 1;
1059 else 1059 else
1060 log_perror = 0; 1060 log_perror = 0;
1061 1061
1062 if (daemon) { 1062 if (daemon) {
1063 if (dfd[0] != -1 && dfd[1] != -1) { 1063 if (dfd[0] != -1 && dfd[1] != -1) {
1064 char buf = 0; 1064 char buf = 0;
1065 1065
1066 if (write(dfd[1], &buf, 1) != 1) 1066 if (write(dfd[1], &buf, 1) != 1)
1067 log_fatal("write to parent: %m"); 1067 log_fatal("write to parent: %m");
1068 (void) close(dfd[1]); 1068 (void) close(dfd[1]);
1069 dfd[0] = dfd[1] = -1; 1069 dfd[0] = dfd[1] = -1;
1070 } 1070 }
1071 1071
1072 /* Become session leader and get pid... */ 1072 /* Become session leader and get pid... */
1073 (void) setsid(); 1073 (void) setsid();
1074 1074
1075 /* Close standard I/O descriptors. */ 1075 /* Close standard I/O descriptors. */
1076 (void) close(0); 1076 (void) close(0);
1077 (void) close(1); 1077 (void) close(1);
1078 (void) close(2); 1078 (void) close(2);
1079 1079
1080 /* Reopen them on /dev/null. */ 1080 /* Reopen them on /dev/null. */
1081 (void) open("/dev/null", O_RDWR); 1081 (void) open("/dev/null", O_RDWR);
1082 (void) open("/dev/null", O_RDWR); 1082 (void) open("/dev/null", O_RDWR);
1083 (void) open("/dev/null", O_RDWR); 1083 (void) open("/dev/null", O_RDWR);
1084 log_perror = 0; /* No sense logging to /dev/null. */ 1084 log_perror = 0; /* No sense logging to /dev/null. */
1085 1085
1086 IGNORE_RET (chdir("/")); 1086 IGNORE_RET (chdir("/"));
1087 } 1087 }
1088#endif /* !DEBUG */ 1088#endif /* !DEBUG */
1089 1089
1090#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 1090#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
1091 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 1091 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1092 dmalloc_cutoff_generation = dmalloc_generation; 1092 dmalloc_cutoff_generation = dmalloc_generation;
1093 dmalloc_longterm = dmalloc_outstanding; 1093 dmalloc_longterm = dmalloc_outstanding;
1094 dmalloc_outstanding = 0; 1094 dmalloc_outstanding = 0;
1095#endif 1095#endif
1096 1096
1097 omapi_set_int_value ((omapi_object_t *)dhcp_control_object, 1097 omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
1098 (omapi_object_t *)0, "state", server_running); 1098 (omapi_object_t *)0, "state", server_running);
1099 1099
1100#if defined(ENABLE_GENTLE_SHUTDOWN) 1100#if defined(ENABLE_GENTLE_SHUTDOWN)
1101 /* no signal handlers until we deal with the side effects */ 1101 /* no signal handlers until we deal with the side effects */
1102 /* install signal handlers */ 1102 /* install signal handlers */
1103 signal(SIGINT, dhcp_signal_handler); /* control-c */ 1103 signal(SIGINT, dhcp_signal_handler); /* control-c */
1104 signal(SIGTERM, dhcp_signal_handler); /* kill */ 1104 signal(SIGTERM, dhcp_signal_handler); /* kill */
1105#endif 1105#endif
1106 1106
1107 /* Log that we are about to start working */ 1107 /* Log that we are about to start working */
1108 log_info("Server starting service."); 1108 log_info("Server starting service.");
1109 1109
1110 /* 1110 /*
1111 * Receive packets and dispatch them... 1111 * Receive packets and dispatch them...
1112 * dispatch() will never return. 1112 * dispatch() will never return.
1113 */ 1113 */
1114 dispatch (); 1114 dispatch ();
1115 1115
1116 /* Let's return status code */ 1116 /* Let's return status code */
1117 return 0; 1117 return 0;
1118} 1118}
1119#endif /* !UNIT_TEST */ 1119#endif /* !UNIT_TEST */
1120 1120
1121void postconf_initialization (int quiet) 1121void postconf_initialization (int quiet)
1122{ 1122{
1123 struct option_state *options = NULL; 1123 struct option_state *options = NULL;
1124 struct data_string db; 1124 struct data_string db;
1125 struct option_cache *oc; 1125 struct option_cache *oc;
1126 char *s; 1126 char *s;
1127 isc_result_t result; 1127 isc_result_t result;
1128 int tmp; 1128 int tmp;
1129#if defined (NSUPDATE) 1129#if defined (NSUPDATE)
1130 struct in_addr local4, *local4_ptr = NULL; 1130 struct in_addr local4, *local4_ptr = NULL;
1131 struct in6_addr local6, *local6_ptr = NULL; 1131 struct in6_addr local6, *local6_ptr = NULL;
1132#endif 1132#endif
1133 1133
1134 /* Now try to get the lease file name. */ 1134 /* Now try to get the lease file name. */
1135 option_state_allocate(&options, MDL); 1135 option_state_allocate(&options, MDL);
1136 1136
1137 execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, 1137 execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
1138 options, &global_scope, root_group, 1138 options, &global_scope, root_group,
1139 NULL, NULL); 1139 NULL, NULL);
1140 memset(&db, 0, sizeof db); 1140 memset(&db, 0, sizeof db);
1141 oc = lookup_option(&server_universe, options, SV_LEASE_FILE_NAME); 1141 oc = lookup_option(&server_universe, options, SV_LEASE_FILE_NAME);
1142 if (oc && 1142 if (oc &&
1143 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, 1143 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1144 &global_scope, oc, MDL)) { 1144 &global_scope, oc, MDL)) {
1145 s = dmalloc(db.len + 1, MDL); 1145 s = dmalloc(db.len + 1, MDL);
1146 if (!s) 1146 if (!s)
1147 log_fatal("no memory for lease db filename."); 1147 log_fatal("no memory for lease db filename.");
1148 memcpy(s, db.data, db.len); 1148 memcpy(s, db.data, db.len);
1149 s[db.len] = 0; 1149 s[db.len] = 0;
1150 data_string_forget(&db, MDL); 1150 data_string_forget(&db, MDL);
1151 path_dhcpd_db = s; 1151 path_dhcpd_db = s;
1152 } 1152 }
1153 1153
1154 oc = lookup_option(&server_universe, options, SV_PID_FILE_NAME); 1154 oc = lookup_option(&server_universe, options, SV_PID_FILE_NAME);
1155 if (oc && 1155 if (oc &&
1156 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, 1156 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1157 &global_scope, oc, MDL)) { 1157 &global_scope, oc, MDL)) {
1158 s = dmalloc(db.len + 1, MDL); 1158 s = dmalloc(db.len + 1, MDL);
1159 if (!s) 1159 if (!s)
1160 log_fatal("no memory for pid filename."); 1160 log_fatal("no memory for pid filename.");
1161 memcpy(s, db.data, db.len); 1161 memcpy(s, db.data, db.len);
1162 s[db.len] = 0; 1162 s[db.len] = 0;
1163 data_string_forget(&db, MDL); 1163 data_string_forget(&db, MDL);
1164 path_dhcpd_pid = s; 1164 path_dhcpd_pid = s;
1165 } 1165 }
1166 1166
1167#ifdef DHCPv6 1167#ifdef DHCPv6
1168 if (local_family == AF_INET6) { 1168 if (local_family == AF_INET6) {
1169 /* 1169 /*
1170 * Override lease file name with dhcpv6 lease file name, 1170 * Override lease file name with dhcpv6 lease file name,
1171 * if it was set; then, do the same with the pid file name 1171 * if it was set; then, do the same with the pid file name
1172 */ 1172 */
1173 oc = lookup_option(&server_universe, options, 1173 oc = lookup_option(&server_universe, options,
1174 SV_DHCPV6_LEASE_FILE_NAME); 1174 SV_DHCPV6_LEASE_FILE_NAME);
1175 if (oc && 1175 if (oc &&
1176 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, 1176 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1177 &global_scope, oc, MDL)) { 1177 &global_scope, oc, MDL)) {
1178 s = dmalloc(db.len + 1, MDL); 1178 s = dmalloc(db.len + 1, MDL);
1179 if (!s) 1179 if (!s)
1180 log_fatal("no memory for lease db filename."); 1180 log_fatal("no memory for lease db filename.");
1181 memcpy(s, db.data, db.len); 1181 memcpy(s, db.data, db.len);
1182 s[db.len] = 0; 1182 s[db.len] = 0;
1183 data_string_forget(&db, MDL); 1183 data_string_forget(&db, MDL);
1184 path_dhcpd_db = s; 1184 path_dhcpd_db = s;
1185 } 1185 }
1186 1186
1187 oc = lookup_option(&server_universe, options, 1187 oc = lookup_option(&server_universe, options,
1188 SV_DHCPV6_PID_FILE_NAME); 1188 SV_DHCPV6_PID_FILE_NAME);
1189 if (oc && 1189 if (oc &&
1190 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, 1190 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1191 &global_scope, oc, MDL)) { 1191 &global_scope, oc, MDL)) {
1192 s = dmalloc(db.len + 1, MDL); 1192 s = dmalloc(db.len + 1, MDL);
1193 if (!s) 1193 if (!s)
1194 log_fatal("no memory for pid filename."); 1194 log_fatal("no memory for pid filename.");
1195 memcpy(s, db.data, db.len); 1195 memcpy(s, db.data, db.len);
1196 s[db.len] = 0; 1196 s[db.len] = 0;
1197 data_string_forget(&db, MDL); 1197 data_string_forget(&db, MDL);
1198 path_dhcpd_pid = s; 1198 path_dhcpd_pid = s;
1199 } 1199 }
1200 1200
1201 oc = lookup_option(&server_universe, options, 1201 oc = lookup_option(&server_universe, options,
1202 SV_LOCAL_ADDRESS6); 1202 SV_LOCAL_ADDRESS6);
1203 if (oc && 1203 if (oc &&
1204 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, 1204 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1205 &global_scope, oc, MDL)) { 1205 &global_scope, oc, MDL)) {
1206 if (db.len == 16) { 1206 if (db.len == 16) {
1207 memcpy(&local_address6, db.data, 16); 1207 memcpy(&local_address6, db.data, 16);
1208 } else 1208 } else
1209 log_fatal("invalid local address " 1209 log_fatal("invalid local address "
1210 "data length"); 1210 "data length");
1211 data_string_forget(&db, MDL); 1211 data_string_forget(&db, MDL);
1212 } 1212 }
1213 1213
1214 oc = lookup_option(&server_universe, options, 1214 oc = lookup_option(&server_universe, options,
1215 SV_BIND_LOCAL_ADDRESS6); 1215 SV_BIND_LOCAL_ADDRESS6);
1216 if (oc && 1216 if (oc &&
1217 evaluate_boolean_option_cache(NULL, NULL, NULL, 1217 evaluate_boolean_option_cache(NULL, NULL, NULL,
1218 NULL, options, NULL, 1218 NULL, options, NULL,
1219 &global_scope, oc, MDL)) { 1219 &global_scope, oc, MDL)) {
1220 bind_local_address6 = 1; 1220 bind_local_address6 = 1;
1221 } 1221 }
1222 1222
1223 } 1223 }
1224#endif /* DHCPv6 */ 1224#endif /* DHCPv6 */
1225 1225
1226 omapi_port = -1; 1226 omapi_port = -1;
1227 oc = lookup_option(&server_universe, options, SV_OMAPI_PORT); 1227 oc = lookup_option(&server_universe, options, SV_OMAPI_PORT);
1228 if (oc && 1228 if (oc &&