merge local changes between dhcp-4.4.2 and dhcp-4.4.2-P1diff -r1.3 -r1.4 src/external/mpl/dhcp/dist/client/dhclient.c
(christos)
--- 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 | |||
49 | TIME default_lease_time = 43200; /* 12 hours... */ | 49 | TIME default_lease_time = 43200; /* 12 hours... */ | |
50 | TIME max_lease_time = 86400; /* 24 hours... */ | 50 | TIME max_lease_time = 86400; /* 24 hours... */ | |
51 | 51 | |||
52 | const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; | 52 | const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; | |
53 | const char *path_dhclient_db = NULL; | 53 | const char *path_dhclient_db = NULL; | |
54 | const char *path_dhclient_pid = NULL; | 54 | const char *path_dhclient_pid = NULL; | |
55 | static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT; | 55 | static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT; | |
56 | char *path_dhclient_script = path_dhclient_script_array; | 56 | char *path_dhclient_script = path_dhclient_script_array; | |
57 | const char *path_dhclient_duid = NULL; | 57 | const char *path_dhclient_duid = NULL; | |
58 | 58 | |||
59 | static void add_to_tail(struct client_lease** lease_list, struct client_lease* lease); | 59 | static 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 */ | |
62 | isc_boolean_t no_pid_file = ISC_FALSE; | 62 | isc_boolean_t no_pid_file = ISC_FALSE; | |
63 | isc_boolean_t hw_mismatch_drop = ISC_TRUE; | 63 | isc_boolean_t hw_mismatch_drop = ISC_TRUE; | |
64 | 64 | |||
65 | int dhcp_max_agent_option_packet_length = 0; | 65 | int dhcp_max_agent_option_packet_length = 0; | |
66 | 66 | |||
67 | int interfaces_requested = 0; | 67 | int interfaces_requested = 0; | |
68 | int interfaces_left = 0; | 68 | int interfaces_left = 0; | |
69 | 69 | |||
70 | struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; | 70 | struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; | |
71 | struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; | 71 | struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; | |
72 | struct in_addr inaddr_any; | 72 | struct in_addr inaddr_any; | |
73 | struct sockaddr_in sockaddr_broadcast; | 73 | struct sockaddr_in sockaddr_broadcast; | |
74 | struct in_addr giaddr; | 74 | struct in_addr giaddr; | |
75 | struct data_string default_duid; | 75 | struct data_string default_duid; | |
76 | int duid_type = 0; | 76 | int duid_type = 0; | |
77 | int duid_v4 = 0; | 77 | int duid_v4 = 0; | |
78 | int std_dhcid = 0; | 78 | int std_dhcid = 0; | |
79 | 79 | |||
80 | int decline_wait_time = 10; /* Default to 10 secs per, RFC 2131, 3.1.5 */ | 80 | int 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 | |
87 | static const char copyright[] = "Copyright 2004-2020 Internet Systems Consortium."; | 87 | static const char copyright[] = "Copyright 2004-2021 Internet Systems Consortium."; | |
88 | static const char arr [] = "All rights reserved."; | 88 | static const char arr [] = "All rights reserved."; | |
89 | static const char message [] = "Internet Systems Consortium DHCP Client"; | 89 | static const char message [] = "Internet Systems Consortium DHCP Client"; | |
90 | static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/"; | 90 | static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/"; | |
91 | #endif /* UNIT_TEST */ | 91 | #endif /* UNIT_TEST */ | |
92 | 92 | |||
93 | u_int16_t local_port = 0; | 93 | u_int16_t local_port = 0; | |
94 | u_int16_t remote_port = 0; | 94 | u_int16_t remote_port = 0; | |
95 | #if defined(DHCPv6) && defined(DHCP4o6) | 95 | #if defined(DHCPv6) && defined(DHCP4o6) | |
96 | int dhcp4o6_state = -1; /* -1 = stopped, 0 = polling, 1 = started */ | 96 | int dhcp4o6_state = -1; /* -1 = stopped, 0 = polling, 1 = started */ | |
97 | #endif | 97 | #endif | |
98 | int no_daemon = 0; | 98 | int no_daemon = 0; | |
99 | int dfd[2] = { -1, -1 }; | 99 | int dfd[2] = { -1, -1 }; | |
100 | struct string_list *client_env = NULL; | 100 | struct string_list *client_env = NULL; | |
101 | int client_env_count = 0; | 101 | int client_env_count = 0; | |
102 | int onetry = 0; | 102 | int onetry = 0; | |
103 | int quiet = 1; | 103 | int quiet = 1; | |
104 | int nowait = 0; | 104 | int nowait = 0; | |
105 | int stateless = 0; | 105 | int stateless = 0; | |
106 | int wanted_ia_na = -1; /* the absolute value is the real one. */ | 106 | int wanted_ia_na = -1; /* the absolute value is the real one. */ | |
107 | int wanted_ia_ta = 0; | 107 | int wanted_ia_ta = 0; | |
108 | int wanted_ia_pd = 0; | 108 | int wanted_ia_pd = 0; | |
109 | int require_all_ias = 0; /* If the user requires all of the IAs to | 109 | int 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) | |
113 | int dad_wait_time = 0; | 113 | int dad_wait_time = 0; | |
114 | int prefix_len_hint = 0; | 114 | int prefix_len_hint = 0; | |
115 | #endif | 115 | #endif | |
116 | 116 | |||
117 | int address_prefix_len = DHCLIENT_DEFAULT_PREFIX_LEN; | 117 | int address_prefix_len = DHCLIENT_DEFAULT_PREFIX_LEN; | |
118 | char *mockup_relay = NULL; | 118 | char *mockup_relay = NULL; | |
119 | 119 | |||
120 | libdhcp_callbacks_t dhclient_callbacks = { | 120 | libdhcp_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 | |||
135 | char *progname = NULL; | 135 | char *progname = NULL; | |
136 | 136 | |||
137 | void run_stateless(int exit_mode, u_int16_t port); | 137 | void run_stateless(int exit_mode, u_int16_t port); | |
138 | 138 | |||
139 | static isc_result_t write_duid(struct data_string *duid); | 139 | static isc_result_t write_duid(struct data_string *duid); | |
140 | static void add_reject(struct packet *packet); | 140 | static void add_reject(struct packet *packet); | |
141 | 141 | |||
142 | static int check_domain_name(const char *ptr, size_t len, int dots); | 142 | static int check_domain_name(const char *ptr, size_t len, int dots); | |
143 | static int check_domain_name_list(const char *ptr, size_t len, int dots); | 143 | static int check_domain_name_list(const char *ptr, size_t len, int dots); | |
144 | static int check_option_values(struct universe *universe, unsigned int opt, | 144 | static 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) | |
148 | static void dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, | 148 | static 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 | |||
152 | static void | 152 | static void | |
153 | setup(void) { | 153 | setup(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 | |||
176 | static void | 176 | static void | |
177 | go_daemon(void) | 177 | go_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 | |||
203 | static void | 203 | static void | |
204 | add_interfaces(char **ifaces, int nifaces) | 204 | add_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) | |
247 | static void dhcp4o6_poll(void *dummy); | 247 | static void dhcp4o6_poll(void *dummy); | |
248 | static void dhcp4o6_resume(void); | 248 | static void dhcp4o6_resume(void); | |
249 | static void recv_dhcpv4_response(struct data_string *raw); | 249 | static void recv_dhcpv4_response(struct data_string *raw); | |
250 | static int send_dhcpv4_query(struct client_state *client, int broadcast); | 250 | static int send_dhcpv4_query(struct client_state *client, int broadcast); | |
251 | 251 | |||
252 | static void dhcp4o6_stop(void); | 252 | static void dhcp4o6_stop(void); | |
253 | static void forw_dhcpv4_response(struct packet *packet); | 253 | static void forw_dhcpv4_response(struct packet *packet); | |
254 | static void forw_dhcpv4_query(struct data_string *raw); | 254 | static 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 | */ | |
261 | static const char use_noarg[] = "No argument for command: %s"; | 261 | static const char use_noarg[] = "No argument for command: %s"; | |
262 | #ifdef DHCPv6 | 262 | #ifdef DHCPv6 | |
263 | static const char use_v6command[] = "Command not used for DHCPv4: %s"; | 263 | static 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 | |||
294 | static void | 294 | static void | |
295 | usage(const char *sfmt, const char *sarg) | 295 | usage(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 | |||
316 | extern void initialize_client_option_spaces(void); | 316 | extern void initialize_client_option_spaces(void); | |
317 | 317 | |||
318 | int | 318 | int | |
319 | main(int argc, char **argv) { | 319 | main(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 | |||
1068 | void run_stateless(int exit_mode, u_int16_t port) | 1068 | void 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 | |||
1172 | isc_result_t find_class (struct class **c, | 1172 | isc_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 | |||
1178 | int check_collection (packet, lease, collection) | 1178 | int 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 | |||
1186 | void classify (packet, class) | 1186 | void 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 | |||
1192 | void unbill_class (lease) | 1192 | void unbill_class (lease) | |
1193 | struct lease *lease; | 1193 | struct lease *lease; | |
1194 | { | 1194 | { | |
1195 | } | 1195 | } | |
1196 | 1196 | |||
1197 | int find_subnet (struct subnet **sp, | 1197 | int 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 | |||
1235 | void state_reboot (cpp) | 1235 | void 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 | |||
1288 | void state_init (cpp) | 1288 | void 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 | |||
1314 | void state_selecting (cpp) | 1314 | void 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 | |||
1396 | static isc_boolean_t | 1396 | static isc_boolean_t | |
1397 | compare_hw_address(const char *name, struct packet *packet) { | 1397 | compare_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 | |||
1419 | void dhcpack (packet) | 1419 | void 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 | |||
1582 | void bind_lease (client) | 1582 | void 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 | |||
1675 | void state_bound (cpp) | 1675 | void 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 | |||
1717 | void state_stop (cpp) | 1717 | void 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 | |||
1741 | int commit_leases () | 1741 | int commit_leases () | |
1742 | { | 1742 | { | |
1743 | return 0; | 1743 | return 0; | |
1744 | } | 1744 | } | |
1745 | 1745 | |||
1746 | int write_lease (lease) | 1746 | int write_lease (lease) | |
1747 | struct lease *lease; | 1747 | struct lease *lease; | |
1748 | { | 1748 | { | |
1749 | return 0; | 1749 | return 0; | |
1750 | } | 1750 | } | |
1751 | 1751 | |||
1752 | int write_host (host) | 1752 | int 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 | |||
1758 | void db_startup (testp) | 1758 | void db_startup (testp) | |
1759 | int testp; | 1759 | int testp; | |
1760 | { | 1760 | { | |
1761 | } | 1761 | } | |
1762 | 1762 | |||
1763 | void bootp (packet) | 1763 | void 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 | |||
1796 | void dhcp (packet) | 1796 | void 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 | |
1847 | void | 1847 | void | |
1848 | dhcpv6(struct packet *packet) { | 1848 | dhcpv6(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 | */ | |
1925 | static void forw_dhcpv4_response(struct packet *packet) | 1925 | static 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 | */ | |
2007 | static void recv_dhcpv4_response(struct data_string *raw) | 2007 | static 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 | |||
2083 | void dhcpoffer (packet) | 2083 | void 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 | |||
2213 | struct client_lease *packet_to_lease (packet, client) | 2213 | struct 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. */ |
--- 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 | |||
38 | struct collection default_collection = { NULL, "default", NULL }; | 38 | struct collection default_collection = { NULL, "default", NULL }; | |
39 | struct collection *collections = &default_collection; | 39 | struct 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 | |||
44 | struct enumeration *enumerations; | 44 | struct enumeration *enumerations; | |
45 | 45 | |||
46 | void add_enumeration (struct enumeration *enumeration) | 46 | void 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 | |||
52 | struct enumeration *find_enumeration (const char *name, int length) | 52 | struct 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 | |||
63 | struct enumeration_value *find_enumeration_value (const char *name, | 63 | struct 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 | */ | |
86 | void skip_to_semi (cfile) | 86 | void 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. */ | |
103 | void skip_to_rbrace (cfile, brace_count) | 103 | void 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 | |||
144 | int parse_semi (cfile) | 144 | int 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 | |||
161 | int parse_string (cfile, sptr, lptr) | 161 | int 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 | |||
201 | char *parse_host_name (cfile) | 201 | char *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 | |||
273 | int parse_ip_addr_or_hostname (expr, cfile, uniform) | 273 | int 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 | |||
341 | int parse_ip_addr (cfile, addr) | 341 | int 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 | */ | |
355 | static int | 355 | static int | |
356 | is_hex_string(const char *s) { | 356 | is_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 | |||
376 | int | 376 | int | |
377 | parse_ip6_addr(struct parse *cfile, struct iaddr *addr) { | 377 | parse_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 | */ | |
436 | int | 436 | int | |
437 | parse_ip6_addr_expr(struct expression **expr, | 437 | parse_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 | */ | |
450 | int | 450 | int | |
451 | parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) { | 451 | parse_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 | |||
493 | int | 493 | int | |
494 | parse_ip_addr_with_subnet(cfile, match) | 494 | parse_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 | |||
587 | void parse_hardware_param (cfile, hardware) | 587 | void 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 | |||
662 | void parse_lease_time (cfile, timep) | 662 | void 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 | |||
706 | unsigned char *parse_numeric_aggregate (cfile, buf, | 706 | unsigned 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 | |||
810 | void convert_num (cfile, buf, str, base, size) | 810 | void 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 | */ | |
947 | TIME | 947 | TIME | |
948 | parse_date_core(cfile) | 948 | parse_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 | |||
4779 | int parse_option_data (expr, cfile, lookups, option) | 4779 | int parse_option_data (expr, cfile, lookups, option) | |
4780 | struct expression **expr; | 4780 | struct expression **expr; | |
4781 | struct parse *cfile; | 4781 | struct parse *cfile; | |
4782 | int lookups; | 4782 | int lookups; | |
4783 | struct option *option; | 4783 | struct 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 | |||
4886 | int parse_option_statement (result, cfile, lookups, option, op) | 4886 | int 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 | |||
4945 | int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) | 4945 | int 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 | |||
5248 | int parse_option_decl (oc, cfile) | 5248 | int 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 | |||
5532 | parse_exit: | 5532 | parse_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); | |
5536 | exit: | 5536 | exit: | |
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 | |||
5544 | int parse_X (cfile, buf, max) | 5544 | int 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 | |||
5593 | int parse_warn (struct parse *cfile, const char *fmt, ...) | 5594 | int 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 | |||
5653 | struct expression * | 5654 | struct expression * | |
5654 | parse_domain_list(struct parse *cfile, int compress) | 5655 | parse_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 | |||
5734 | struct expression * | 5735 | struct expression * | |
5735 | parse_domain_name(struct parse *cfile) | 5736 | parse_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 | } |
--- 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 | |||
23 | ATF_TC(option_refcnt); | 23 | ATF_TC(option_refcnt); | |
24 | 24 | |||
25 | ATF_TC_HEAD(option_refcnt, tc) | 25 | ATF_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 | */ | |
34 | ATF_TC_BODY(option_refcnt, tc) | 34 | ATF_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 | |||
73 | ATF_TC(pretty_print_option); | 73 | ATF_TC(pretty_print_option); | |
74 | 74 | |||
75 | ATF_TC_HEAD(pretty_print_option, tc) | 75 | ATF_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 | */ | |
87 | ATF_TC_BODY(pretty_print_option, tc) | 87 | ATF_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 | |||
134 | ATF_TC(parse_X); | |||
135 | ||||
136 | ATF_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. */ | |||
143 | static 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 | */ | |||
164 | ATF_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. */ | |
138 | ATF_TP_ADD_TCS(tp) | 221 | ATF_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 | } |
--- 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 | |||
40 | TIME default_lease_time = 43200; /* 12 hours... */ | 40 | TIME default_lease_time = 43200; /* 12 hours... */ | |
41 | TIME max_lease_time = 86400; /* 24 hours... */ | 41 | TIME max_lease_time = 86400; /* 24 hours... */ | |
42 | struct tree_cache *global_options[256]; | 42 | struct tree_cache *global_options[256]; | |
43 | 43 | |||
44 | struct option *requested_opts[2]; | 44 | struct option *requested_opts[2]; | |
45 | 45 | |||
46 | /* Needed to prevent linking against conflex.c. */ | 46 | /* Needed to prevent linking against conflex.c. */ | |
47 | int lexline; | 47 | int lexline; | |
48 | int lexchar; | 48 | int lexchar; | |
49 | char *token_line; | 49 | char *token_line; | |
50 | char *tlname; | 50 | char *tlname; | |
51 | 51 | |||
52 | const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID; | 52 | const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID; | |
53 | isc_boolean_t no_dhcrelay_pid = ISC_FALSE; | 53 | isc_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 */ | |
55 | isc_boolean_t no_pid_file = ISC_FALSE; | 55 | isc_boolean_t no_pid_file = ISC_FALSE; | |
56 | 56 | |||
57 | int bogus_agent_drops = 0; /* Packets dropped because agent option | 57 | int 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. */ | |
61 | int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a | 61 | int 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. */ | |
63 | int client_packets_relayed = 0; /* Packets relayed from client to server. */ | 63 | int client_packets_relayed = 0; /* Packets relayed from client to server. */ | |
64 | int server_packet_errors = 0; /* Errors sending packets to servers. */ | 64 | int server_packet_errors = 0; /* Errors sending packets to servers. */ | |
65 | int server_packets_relayed = 0; /* Packets relayed from server to client. */ | 65 | int server_packets_relayed = 0; /* Packets relayed from server to client. */ | |
66 | int client_packet_errors = 0; /* Errors sending packets to clients. */ | 66 | int client_packet_errors = 0; /* Errors sending packets to clients. */ | |
67 | 67 | |||
68 | int add_agent_options = 0; /* If nonzero, add relay agent options. */ | 68 | int add_agent_options = 0; /* If nonzero, add relay agent options. */ | |
69 | int add_rfc3527_suboption = 0; /* If nonzero, add RFC3527 link selection sub-option. */ | 69 | int add_rfc3527_suboption = 0; /* If nonzero, add RFC3527 link selection sub-option. */ | |
70 | 70 | |||
71 | int agent_option_errors = 0; /* Number of packets forwarded without | 71 | int 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. */ | |
73 | int drop_agent_mismatches = 0; /* If nonzero, drop server replies that | 73 | int 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. */ | |
75 | int corrupt_agent_options = 0; /* Number of packets dropped because | 75 | int corrupt_agent_options = 0; /* Number of packets dropped because | |
76 | relay agent information option was bad. */ | 76 | relay agent information option was bad. */ | |
77 | int missing_agent_option = 0; /* Number of packets dropped because no | 77 | int 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. */ | |
79 | int bad_circuit_id = 0; /* Circuit ID option in matching RAI option | 79 | int 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. */ | |
81 | int missing_circuit_id = 0; /* Circuit ID option in matching RAI option | 81 | int missing_circuit_id = 0; /* Circuit ID option in matching RAI option | |
82 | was missing. */ | 82 | was missing. */ | |
83 | int max_hop_count = 10; /* Maximum hop count */ | 83 | int max_hop_count = 10; /* Maximum hop count */ | |
84 | 84 | |||
85 | int no_daemon = 0; | 85 | int no_daemon = 0; | |
86 | int dfd[2] = { -1, -1 }; | 86 | int 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. */ | |
90 | isc_boolean_t use_if_id = ISC_FALSE; | 90 | isc_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. */ | |
94 | int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN; | 94 | int 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: */ | |
98 | enum { forward_and_append, /* Forward and append our own relay option. */ | 98 | enum { 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 | |||
103 | u_int16_t local_port = 0; | 103 | u_int16_t local_port = 0; | |
104 | u_int16_t remote_port = 0; | 104 | u_int16_t remote_port = 0; | |
105 | 105 | |||
106 | /* Relay agent server list. */ | 106 | /* Relay agent server list. */ | |
107 | struct server_list { | 107 | struct 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 | |||
112 | struct interface_info *uplink = NULL; | 112 | struct interface_info *uplink = NULL; | |
113 | 113 | |||
114 | #ifdef DHCPv6 | 114 | #ifdef DHCPv6 | |
115 | struct stream_list { | 115 | struct 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 | |
123 | static struct stream_list *parse_downstream(char *); | 123 | static struct stream_list *parse_downstream(char *); | |
124 | static struct stream_list *parse_upstream(char *); | 124 | static struct stream_list *parse_upstream(char *); | |
125 | static void setup_streams(void); | 125 | static 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 | */ | |
134 | char *dhcrelay_sub_id = NULL; | 134 | char *dhcrelay_sub_id = NULL; | |
135 | #endif | 135 | #endif | |
136 | 136 | |||
137 | libdhcp_callbacks_t dhcrelay_callbacks = { | 137 | libdhcp_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 | |
153 | static void do_relay4(struct interface_info *, struct dhcp_packet *, | 153 | static 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 | |||
158 | extern int add_relay_agent_options(struct interface_info *, | 158 | extern 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); | |
161 | extern int find_interface_by_agent_option(struct dhcp_packet *, | 161 | extern 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 | |||
164 | extern int strip_relay_agent_options(struct interface_info *, | 164 | extern 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 | |
169 | static void request_v4_interface(const char* name, int flags); | 169 | static void request_v4_interface(const char* name, int flags); | |
170 | 170 | |||
171 | static const char copyright[] = | 171 | static const char copyright[] = | |
172 | "Copyright 2004-2020 Internet Systems Consortium."; | 172 | "Copyright 2004-2021 Internet Systems Consortium."; | |
173 | static const char arr[] = "All rights reserved."; | 173 | static const char arr[] = "All rights reserved."; | |
174 | static const char message[] = | 174 | static const char message[] = | |
175 | "Internet Systems Consortium DHCP Relay Agent"; | 175 | "Internet Systems Consortium DHCP Relay Agent"; | |
176 | static const char url[] = | 176 | static 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 | |||
179 | char *progname; | 179 | char *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 $"); | |
268 | static const char use_noarg[] = "No argument for command: %s"; | 268 | static const char use_noarg[] = "No argument for command: %s"; | |
269 | #ifdef RELAY_PORT | 269 | #ifdef RELAY_PORT | |
270 | static const char use_port_defined[] = "Port already set, %s inappropriate"; | 270 | static 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) | |
272 | static const char bpf_sock_support[] = "Only LPF and BPF are supported: %s"; | 272 | static 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 | |
276 | static const char use_badproto[] = "Protocol already set, %s inappropriate"; | 276 | static const char use_badproto[] = "Protocol already set, %s inappropriate"; | |
277 | static const char use_v4command[] = "Command not used for DHCPv6: %s"; | 277 | static const char use_v4command[] = "Command not used for DHCPv6: %s"; | |
278 | static const char use_v6command[] = "Command not used for DHCPv4: %s"; | 278 | static const char use_v6command[] = "Command not used for DHCPv4: %s"; | |
279 | #endif | 279 | #endif | |
280 | 280 | |||
281 | static void | 281 | static void | |
282 | usage(const char *sfmt, const char *sarg) { | 282 | usage(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 | |||
302 | int | 302 | int | |
303 | main(int argc, char **argv) { | 303 | main(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 | |||
865 | static void | 865 | static void | |
866 | do_relay4(struct interface_info *ip, struct dhcp_packet *packet, | 866 | do_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 | |||
1019 | int | 1019 | int | |
1020 | strip_relay_agent_options(struct interface_info *in, | 1020 | strip_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 | |||
1156 | int | 1156 | int | |
1157 | find_interface_by_agent_option(struct dhcp_packet *packet, | 1157 | find_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 | */ | |
1220 | int | 1220 | int | |
1221 | add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet, | 1221 | add_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 | */ | |
1473 | static struct stream_list * | 1474 | static struct stream_list * | |
1474 | parse_downstream(char *arg) { | 1475 | parse_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 | */ | |
1553 | static struct stream_list * | 1554 | static struct stream_list * | |
1554 | parse_upstream(char *arg) { | 1555 | parse_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 | */ | |
1620 | static void | 1621 | static void | |
1621 | setup_streams(void) { | 1622 | setup_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 | */ | |
1683 | static const int required_forw_opts[] = { | 1684 | static 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 | */ | |
1696 | static void | 1697 | static void | |
1697 | process_up6(struct packet *packet, struct stream_list *dp) { | 1698 | process_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 | */ | |
1871 | static void | 1872 | static void | |
1872 | process_down6(struct packet *packet) { | 1873 | process_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 | */ | |
2059 | void | 2059 | void | |
2060 | dhcpv6(struct packet *packet) { | 2060 | dhcpv6(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. */ | |
2089 | void | 2087 | void | |
2090 | bootp(struct packet *packet) { | 2088 | bootp(struct packet *packet) { | |
2091 | return; | 2089 | return; | |
2092 | } | 2090 | } | |
2093 | 2091 | |||
2094 | void | 2092 | void | |
2095 | dhcp(struct packet *packet) { | 2093 | dhcp(struct packet *packet) { | |
2096 | return; | 2094 | return; | |
2097 | } | 2095 | } | |
2098 | 2096 | |||
2099 | #if defined(DHCPv6) && defined(DHCP4o6) | 2097 | #if defined(DHCPv6) && defined(DHCP4o6) | |
2100 | isc_result_t dhcpv4o6_handler(omapi_object_t *h) | 2098 | isc_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 | |||
2106 | void | 2104 | void | |
2107 | classify(struct packet *p, struct class *c) { | 2105 | classify(struct packet *p, struct class *c) { | |
2108 | return; | 2106 | return; | |
2109 | } | 2107 | } | |
2110 | 2108 | |||
2111 | int | 2109 | int | |
2112 | check_collection(struct packet *p, struct lease *l, struct collection *c) { | 2110 | check_collection(struct packet *p, struct lease *l, struct collection *c) { | |
2113 | return 0; | 2111 | return 0; | |
2114 | } | 2112 | } | |
2115 | 2113 | |||
2116 | isc_result_t | 2114 | isc_result_t | |
2117 | find_class(struct class **class, const char *c1, const char *c2, int i) { | 2115 | find_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 | |||
2121 | int | 2119 | int | |
2122 | parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { | 2120 | parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { | |
2123 | return 0; | 2121 | return 0; | |
2124 | } | 2122 | } | |
2125 | 2123 | |||
2126 | isc_result_t | 2124 | isc_result_t | |
2127 | dhcp_set_control_state(control_object_state_t oldstate, | 2125 | dhcp_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 | */ | |
2161 | void request_v4_interface(const char* name, int flags) { | 2159 | void 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 */ |
--- 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 */ | |
35 | extern int add_agent_options; | 35 | extern int add_agent_options; | |
36 | extern int add_relay_agent_options(struct interface_info *, | 36 | extern 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 | |||
40 | extern int find_interface_by_agent_option(struct dhcp_packet *, | 40 | extern 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 | |||
44 | extern int strip_relay_agent_options(struct interface_info *, | 44 | extern 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 | */ | |
62 | unsigned set_packet_options(struct dhcp_packet *packet, | 62 | unsigned 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 | */ | |
97 | int check_with_pad(unsigned char* actual_options, | 97 | int 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 | |||
117 | ATF_TC(strip_relay_agent_options_test); | 117 | ATF_TC(strip_relay_agent_options_test); | |
118 | 118 | |||
119 | ATF_TC_HEAD(strip_relay_agent_options_test, tc) { | 119 | ATF_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 */ | |
124 | ATF_TC_BODY(strip_relay_agent_options_test, tc) { | 124 | ATF_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 | |||
276 | ATF_TC(add_relay_agent_options_test); | 276 | ATF_TC(add_relay_agent_options_test); | |
277 | 277 | |||
278 | ATF_TC_HEAD(add_relay_agent_options_test, tc) { | 278 | ATF_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 */ | |
283 | ATF_TC_BODY(add_relay_agent_options_test, tc) { | 283 | ATF_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 | |||
408 | ATF_TP_ADD_TCS(tp) { | 408 | ATF_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 */ | |||
416 | isc_result_t find_class (struct class **c, const char *s, | |||
417 | const char *file, int line) { | |||
418 | return 0; | |||
419 | } | |||
420 | ||||
421 | int check_collection (struct packet *packet, struct lease *lease, | |||
422 | struct collection *collection) { | |||
423 | return 0; | |||
424 | } | |||
425 | ||||
426 | void classify (struct packet *packet, struct class *class){} | |||
427 | void bootp(struct packet *packet){} | |||
428 | void dhcp(struct packet *packet){} | |||
429 | void dhcpv6(struct packet *packet){} | |||
430 | ||||
431 | int parse_allow_deny (struct option_cache **oc, struct parse *cfile, | |||
432 | int flag) { | |||
433 | return 0; | |||
434 | } | |||
435 | ||||
436 | isc_result_t dhcp_set_control_state (control_object_state_t oldstate, | |||
437 | control_object_state_t newstate) { | |||
438 | return (ISC_R_SUCCESS); | |||
439 | } |
--- 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 | |||
34 | static const char copyright[] = | 34 | static const char copyright[] = | |
35 | "Copyright 2004-2020 Internet Systems Consortium."; | 35 | "Copyright 2004-2021 Internet Systems Consortium."; | |
36 | static const char arr [] = "All rights reserved."; | 36 | static const char arr [] = "All rights reserved."; | |
37 | static const char message [] = "Internet Systems Consortium DHCP Server"; | 37 | static const char message [] = "Internet Systems Consortium DHCP Server"; | |
38 | static const char url [] = | 38 | static 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 */ | |
61 | uid_t set_uid = 0; | 61 | uid_t set_uid = 0; | |
62 | gid_t set_gid = 0; | 62 | gid_t set_gid = 0; | |
63 | #endif /* PARANOIA */ | 63 | #endif /* PARANOIA */ | |
64 | 64 | |||
65 | struct class unknown_class; | 65 | struct class unknown_class; | |
66 | struct class known_class; | 66 | struct class known_class; | |
67 | 67 | |||
68 | struct iaddr server_identifier; | 68 | struct iaddr server_identifier; | |
69 | int server_identifier_matched; | 69 | int 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. */ | |
75 | char std_nsupdate [] = " \n\ | 75 | char std_nsupdate [] = " \n\ | |
76 | option server.ddns-hostname = \n\ | 76 | option 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\ | |
78 | option server.ddns-domainname = config-option domain-name; \n\ | 78 | option server.ddns-domainname = config-option domain-name; \n\ | |
79 | option server.ddns-rev-domainname = \"in-addr.arpa.\";"; | 79 | option server.ddns-rev-domainname = \"in-addr.arpa.\";"; | |
80 | 80 | |||
81 | /* Stores configured DDNS conflict detection flags */ | 81 | /* Stores configured DDNS conflict detection flags */ | |
82 | u_int16_t ddns_conflict_mask; | 82 | u_int16_t ddns_conflict_mask; | |
83 | #endif /* NSUPDATE */ | 83 | #endif /* NSUPDATE */ | |
84 | 84 | |||
85 | int ddns_update_style; | 85 | int ddns_update_style; | |
86 | int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */ | 86 | int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */ | |
87 | int server_id_check = 0; /* 0 = default, don't check server id, 1 = do check */ | 87 | int server_id_check = 0; /* 0 = default, don't check server id, 1 = do check */ | |
88 | 88 | |||
89 | #ifdef DHCPv6 | 89 | #ifdef DHCPv6 | |
90 | int prefix_length_mode = PLM_PREFER; | 90 | int prefix_length_mode = PLM_PREFER; | |
91 | int do_release_on_roam = 0; /* 0 = default, do not release v6 leases on roam */ | 91 | int 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 | |
95 | int persist_eui64 = 1; /* 1 = write EUI64 leases to disk, 0 = don't */ | 95 | int persist_eui64 = 1; /* 1 = write EUI64 leases to disk, 0 = don't */ | |
96 | #endif | 96 | #endif | |
97 | 97 | |||
98 | int authoring_byte_order = 0; /* 0 = not set */ | 98 | int authoring_byte_order = 0; /* 0 = not set */ | |
99 | int lease_id_format = TOKEN_OCTAL; /* octal by default */ | 99 | int lease_id_format = TOKEN_OCTAL; /* octal by default */ | |
100 | u_int32_t abandon_lease_time = DEFAULT_ABANDON_LEASE_TIME; | 100 | u_int32_t abandon_lease_time = DEFAULT_ABANDON_LEASE_TIME; | |
101 | 101 | |||
102 | const char *path_dhcpd_conf = _PATH_DHCPD_CONF; | 102 | const char *path_dhcpd_conf = _PATH_DHCPD_CONF; | |
103 | const char *path_dhcpd_db = _PATH_DHCPD_DB; | 103 | const char *path_dhcpd_db = _PATH_DHCPD_DB; | |
104 | const char *path_dhcpd_pid = _PATH_DHCPD_PID; | 104 | const 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 */ | |
106 | isc_boolean_t no_pid_file = ISC_FALSE; | 106 | isc_boolean_t no_pid_file = ISC_FALSE; | |
107 | 107 | |||
108 | int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX; | 108 | int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX; | |
109 | 109 | |||
110 | static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0; | 110 | static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0; | |
111 | int omapi_port; | 111 | int omapi_port; | |
112 | 112 | |||
113 | #if defined (TRACING) | 113 | #if defined (TRACING) | |
114 | trace_type_t *trace_srandom; | 114 | trace_type_t *trace_srandom; | |
115 | #endif | 115 | #endif | |
116 | 116 | |||
117 | uint16_t local_port = 0; | 117 | uint16_t local_port = 0; | |
118 | uint16_t remote_port = 0; | 118 | uint16_t remote_port = 0; | |
119 | libdhcp_callbacks_t dhcpd_callbacks = { | 119 | libdhcp_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 | |||
134 | char *progname; | 134 | char *progname; | |
135 | 135 | |||
136 | static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) { | 136 | static 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 | |||
140 | static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) { | 140 | static 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 | |||
146 | static void omapi_listener_start (void *foo) | 146 | static 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 $"); | |
230 | static char use_noarg[] = "No argument for command: %s "; | 230 | static char use_noarg[] = "No argument for command: %s "; | |
231 | 231 | |||
232 | static void | 232 | static void | |
233 | usage(const char *sfmt, const char *sarg) { | 233 | usage(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 */ | |
262 | static void setup_chroot (char *chroot_dir) { | 262 | static 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 | |||
276 | int | 276 | int | |
277 | main(int argc, char **argv) { | 277 | main(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 | |||
1121 | void postconf_initialization (int quiet) | 1121 | void 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 && |