blob: d4bb3507b70828a6034da513f7f04d628b5e0fe3 [file] [log] [blame]
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001/* vi: set sw=4 ts=4: */
2/*
3 * DHCPv6 client.
4 *
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +02005 * WARNING: THIS CODE IS INCOMPLETE.
Denys Vlasenko9ba75042011-11-07 15:55:39 +01006 *
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +02007 * Copyright (C) 2011-2017 Denys Vlasenko.
Denys Vlasenko9ba75042011-11-07 15:55:39 +01008 *
9 * Licensed under GPLv2, see file LICENSE in this source tree.
10 */
Denys Vlasenko9ba75042011-11-07 15:55:39 +010011//config:config UDHCPC6
Denys Vlasenko68b653b2017-07-27 10:53:09 +020012//config: bool "udhcpc6"
Mike Frysinger3da46c82012-05-02 21:45:35 -040013//config: default n # not yet ready
14//config: depends on FEATURE_IPV6
15//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020016//config: udhcpc6 is a DHCPv6 client
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +020017//config:
18//config:config FEATURE_UDHCPC6_RFC3646
19//config: bool "Support RFC 3646 (DNS server and search list)"
20//config: default y
21//config: depends on UDHCPC6
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: List of DNS servers and domain search list can be requested with
24//config: "-O dns" and "-O search". If server gives these values,
25//config: they will be set in environment variables "dns" and "search".
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +020026//config:
27//config:config FEATURE_UDHCPC6_RFC4704
28//config: bool "Support RFC 4704 (Client FQDN)"
29//config: default y
30//config: depends on UDHCPC6
31//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020032//config: You can request FQDN to be given by server using "-O fqdn".
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +020033//config:
34//config:config FEATURE_UDHCPC6_RFC4833
35//config: bool "Support RFC 4833 (Timezones)"
36//config: default y
37//config: depends on UDHCPC6
38//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020039//config: You can request POSIX timezone with "-O tz" and timezone name
40//config: with "-O timezone".
Denys Vlasenko9ba75042011-11-07 15:55:39 +010041
42//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP))
43
Denys Vlasenko8cab6672012-04-20 14:48:00 +020044//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +020045//kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC3646) += domain_codec.o
46//kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC4704) += domain_codec.o
Denys Vlasenko9ba75042011-11-07 15:55:39 +010047
48#include <syslog.h>
49/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
50#define WANT_PIDFILE 1
51#include "common.h"
52#include "dhcpd.h"
53#include "dhcpc.h"
54#include "d6_common.h"
55
56#include <netinet/if_ether.h>
57#include <netpacket/packet.h>
58#include <linux/filter.h>
59
60/* "struct client_config_t client_config" is in bb_common_bufsiz1 */
61
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +020062static const struct dhcp_optflag d6_optflags[] = {
63#if ENABLE_FEATURE_UDHCPC6_RFC3646
64 { OPTION_6RD | OPTION_LIST | OPTION_REQ, D6_OPT_DNS_SERVERS },
65 { OPTION_DNS_STRING | OPTION_LIST | OPTION_REQ, D6_OPT_DOMAIN_LIST },
66#endif
67#if ENABLE_FEATURE_UDHCPC6_RFC4704
68 { OPTION_DNS_STRING, D6_OPT_CLIENT_FQDN },
69#endif
70#if ENABLE_FEATURE_UDHCPC6_RFC4833
71 { OPTION_STRING, D6_OPT_TZ_POSIX },
72 { OPTION_STRING, D6_OPT_TZ_NAME },
73#endif
74 { 0, 0 }
75};
76/* Must match d6_optflags[] order */
77static const char d6_option_strings[] ALIGN1 =
78#if ENABLE_FEATURE_UDHCPC6_RFC3646
79 "dns" "\0" /* D6_OPT_DNS_SERVERS */
80 "search" "\0" /* D6_OPT_DOMAIN_LIST */
81#endif
82#if ENABLE_FEATURE_UDHCPC6_RFC4704
83 "fqdn" "\0" /* D6_OPT_CLIENT_FQDN */
84#endif
85#if ENABLE_FEATURE_UDHCPC6_RFC4833
86 "tz" "\0" /* D6_OPT_TZ_POSIX */
87 "timezone" "\0" /* D6_OPT_TZ_NAME */
88#endif
89 "\0";
Denys Vlasenko9ba75042011-11-07 15:55:39 +010090
91#if ENABLE_LONG_OPTS
Denys Vlasenko7e21f042011-11-08 11:39:41 +010092static const char udhcpc6_longopts[] ALIGN1 =
Denys Vlasenko9ba75042011-11-07 15:55:39 +010093 "interface\0" Required_argument "i"
94 "now\0" No_argument "n"
95 "pidfile\0" Required_argument "p"
96 "quit\0" No_argument "q"
97 "release\0" No_argument "R"
98 "request\0" Required_argument "r"
99 "script\0" Required_argument "s"
100 "timeout\0" Required_argument "T"
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100101 "retries\0" Required_argument "t"
102 "tryagain\0" Required_argument "A"
103 "syslog\0" No_argument "S"
104 "request-option\0" Required_argument "O"
105 "no-default-options\0" No_argument "o"
106 "foreground\0" No_argument "f"
Denys Vlasenkoed820cc2017-05-08 15:11:02 +0200107 USE_FOR_MMU(
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100108 "background\0" No_argument "b"
Denys Vlasenkoed820cc2017-05-08 15:11:02 +0200109 )
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100110/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a")
111 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
112 ;
113#endif
114/* Must match getopt32 option string order */
115enum {
116 OPT_i = 1 << 0,
117 OPT_n = 1 << 1,
118 OPT_p = 1 << 2,
119 OPT_q = 1 << 3,
120 OPT_R = 1 << 4,
121 OPT_r = 1 << 5,
122 OPT_s = 1 << 6,
123 OPT_T = 1 << 7,
124 OPT_t = 1 << 8,
125 OPT_S = 1 << 9,
126 OPT_A = 1 << 10,
127 OPT_O = 1 << 11,
128 OPT_o = 1 << 12,
129 OPT_x = 1 << 13,
130 OPT_f = 1 << 14,
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100131/* The rest has variable bit positions, need to be clever */
Denys Vlasenko7e21f042011-11-08 11:39:41 +0100132 OPTBIT_f = 14,
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100133 USE_FOR_MMU( OPTBIT_b,)
134 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
135 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
136 USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,)
137 ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
138 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,)
139};
140
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200141#if ENABLE_FEATURE_UDHCPC6_RFC4704
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200142static const char opt_fqdn_req[] = {
143 (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff),
Denys Vlasenko470bebe2017-06-27 18:31:08 +0200144 0, 2, /* optlen */
145 0, /* flags: */
146 /* S=0: server SHOULD NOT perform AAAA RR updates */
147 /* O=0: client MUST set this bit to 0 */
148 /* N=0: server SHOULD perform updates (PTR RR only in our case, since S=0) */
149 0 /* empty DNS-encoded name */
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200150};
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200151#endif
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100152
153/*** Utility functions ***/
154
155static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code)
156{
157 /* "length minus 4" */
158 int len_m4 = option_end - option - 4;
159 while (len_m4 >= 0) {
160 /* Next option's len is too big? */
Denys Vlasenko68c5b282011-11-07 16:21:24 +0100161 if (option[3] > len_m4)
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100162 return NULL; /* yes. bogus packet! */
163 /* So far we treat any opts with code >255
164 * or len >255 as bogus, and stop at once.
165 * This simplifies big-endian handling.
166 */
Denys Vlasenko68c5b282011-11-07 16:21:24 +0100167 if (option[0] != 0 || option[2] != 0)
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100168 return NULL;
169 /* Option seems to be valid */
170 /* Does its code match? */
Denys Vlasenko68c5b282011-11-07 16:21:24 +0100171 if (option[1] == code)
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100172 return option; /* yes! */
Denys Vlasenko68c5b282011-11-07 16:21:24 +0100173 len_m4 -= option[3] + 4;
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200174 option += option[3] + 4;
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100175 }
176 return NULL;
177}
178
179static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code)
180{
181 uint8_t *opt = d6_find_option(option, option_end, code);
182 if (!opt)
183 return opt;
Ron Yorstond840c5d2015-07-19 23:05:20 +0200184 return xmemdup(opt, opt[3] + 4);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100185}
186
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100187
188/*** Script execution code ***/
189
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100190static char** new_env(void)
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100191{
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100192 client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx);
193 return &client6_data.env_ptr[client6_data.env_idx++];
194}
195
196/* put all the parameters into the environment */
197static void option_to_env(uint8_t *option, uint8_t *option_end)
198{
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200199#if ENABLE_FEATURE_UDHCPC6_RFC3646
200 int addrs, option_offset;
201#endif
Denys Vlasenkoab030612017-03-27 22:49:12 +0200202 /* "length minus 4" */
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100203 int len_m4 = option_end - option - 4;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200204
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100205 while (len_m4 >= 0) {
206 uint32_t v32;
207 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
208
209 if (option[0] != 0 || option[2] != 0)
210 break;
211
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200212 /* Check if option-length exceeds size of option */
213 if (option[3] > len_m4)
214 break;
215
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100216 switch (option[1]) {
217 //case D6_OPT_CLIENTID:
218 //case D6_OPT_SERVERID:
219 case D6_OPT_IA_NA:
220 case D6_OPT_IA_PD:
221 option_to_env(option + 16, option + 4 + option[3]);
222 break;
223 //case D6_OPT_IA_TA:
224 case D6_OPT_IAADDR:
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200225/* 0 1 2 3
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100226 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
227 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228 * | OPTION_IAADDR | option-len |
229 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230 * | |
231 * | IPv6 address |
232 * | |
233 * | |
234 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
235 * | preferred-lifetime |
236 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
237 * | valid-lifetime |
238 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239 */
240 sprint_nip6(ipv6str, option + 4);
241 *new_env() = xasprintf("ipv6=%s", ipv6str);
242
243 move_from_unaligned32(v32, option + 4 + 16 + 4);
244 *new_env() = xasprintf("lease=%u", (unsigned)v32);
245 break;
246
247 //case D6_OPT_ORO:
248 //case D6_OPT_PREFERENCE:
249 //case D6_OPT_ELAPSED_TIME:
250 //case D6_OPT_RELAY_MSG:
251 //case D6_OPT_AUTH:
252 //case D6_OPT_UNICAST:
253 //case D6_OPT_STATUS_CODE:
254 //case D6_OPT_RAPID_COMMIT:
255 //case D6_OPT_USER_CLASS:
256 //case D6_OPT_VENDOR_CLASS:
257 //case D6_OPT_VENDOR_OPTS:
258 //case D6_OPT_INTERFACE_ID:
259 //case D6_OPT_RECONF_MSG:
260 //case D6_OPT_RECONF_ACCEPT:
261
262 case D6_OPT_IAPREFIX:
263/* 0 1 2 3
264 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
265 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
266 * | OPTION_IAPREFIX | option-length |
267 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268 * | preferred-lifetime |
269 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
270 * | valid-lifetime |
271 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
272 * | prefix-length | |
273 * +-+-+-+-+-+-+-+-+ IPv6 prefix |
274 * | (16 octets) |
275 * | |
276 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277 * | |
278 * +-+-+-+-+-+-+-+-+
279 */
280 //move_from_unaligned32(v32, option + 4 + 4);
281 //*new_env() = xasprintf("lease=%u", (unsigned)v32);
282
283 sprint_nip6(ipv6str, option + 4 + 4 + 1);
284 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4]));
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200285 break;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200286#if ENABLE_FEATURE_UDHCPC6_RFC3646
287 case D6_OPT_DNS_SERVERS: {
288 char *dlist;
289
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200290 /* Make sure payload-size is a multiple of 16 */
291 if ((option[3] & 0x0f) != 0)
292 break;
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200293
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200294 /* Get the number of addresses on the option */
295 addrs = option[3] >> 4;
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200296
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200297 /* Setup environment variable */
298 *new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
299 dlist = stpcpy(dlist, "dns=");
300 option_offset = 0;
301
302 while (addrs--) {
303 sprint_nip6(dlist, option + 4 + option_offset);
304 dlist += 39;
305 option_offset += 16;
306 if (addrs)
307 *dlist++ = ' ';
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200308 }
309
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200310 break;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200311 }
312 case D6_OPT_DOMAIN_LIST: {
313 char *dlist;
314
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200315 dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
316 if (!dlist)
317 break;
318 *new_env() = dlist;
319 break;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200320 }
321#endif
322#if ENABLE_FEATURE_UDHCPC6_RFC4704
323 case D6_OPT_CLIENT_FQDN: {
324 char *dlist;
325
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200326 if (option[3] == 0)
327 break;
328 /* Work around broken ISC DHCPD6.
329 * ISC DHCPD6 does not implement RFC 4704 correctly: It says the first
330 * byte of option-payload should contain flags where the bits 7-3 are
331 * reserved for future use and MUST be zero. Instead ISC DHCPD6 just
332 * writes the entire FQDN as string to option-payload. We assume a
333 * broken server here if any of the reserved bits are set.
334 */
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200335 if (option[4] & 0xf8) {
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200336 *new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4);
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200337 break;
338 }
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200339 dlist = dname_dec(option + 5, (/*(option[2] << 8) |*/ option[3]) - 1, "fqdn=");
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200340 if (!dlist)
341 break;
342 *new_env() = dlist;
343 break;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200344 }
345#endif
346#if ENABLE_FEATURE_UDHCPC6_RFC4833
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200347 /* RFC 4833 Timezones */
348 case D6_OPT_TZ_POSIX:
349 *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4);
350 break;
351 case D6_OPT_TZ_NAME:
352 *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
353 break;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200354#endif
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100355 }
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100356 len_m4 -= 4 + option[3];
Denys Vlasenko64d58aa2017-03-27 22:22:09 +0200357 option += 4 + option[3];
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100358 }
359}
360
361static char **fill_envp(struct d6_packet *packet)
362{
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100363 char **envp, **curr;
364
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100365 client6_data.env_ptr = NULL;
366 client6_data.env_idx = 0;
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100367
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100368 *new_env() = xasprintf("interface=%s", client_config.interface);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100369
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100370 if (packet)
371 option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options));
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100372
Denys Vlasenkoa092a892011-11-16 20:17:12 +0100373 envp = curr = client6_data.env_ptr;
374 while (*curr)
375 putenv(*curr++);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100376
377 return envp;
378}
379
380/* Call a script with a par file and env vars */
381static void d6_run_script(struct d6_packet *packet, const char *name)
382{
383 char **envp, **curr;
384 char *argv[3];
385
386 envp = fill_envp(packet);
387
388 /* call script */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200389 log1("executing %s %s", client_config.script, name);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100390 argv[0] = (char*) client_config.script;
391 argv[1] = (char*) name;
392 argv[2] = NULL;
393 spawn_and_wait(argv);
394
395 for (curr = envp; *curr; curr++) {
396 log2(" %s", *curr);
397 bb_unsetenv_and_free(*curr);
398 }
399 free(envp);
400}
401
402
403/*** Sending/receiving packets ***/
404
405static ALWAYS_INLINE uint32_t random_xid(void)
406{
407 uint32_t t = rand() & htonl(0x00ffffff);
408 return t;
409}
410
411/* Initialize the packet with the proper defaults */
412static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid)
413{
414 struct d6_option *clientid;
415
416 memset(packet, 0, sizeof(*packet));
417
418 packet->d6_xid32 = xid;
419 packet->d6_msg_type = type;
420
421 clientid = (void*)client_config.clientid;
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200422 return mempcpy(packet->d6_options, clientid, clientid->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100423}
424
425static uint8_t *add_d6_client_options(uint8_t *ptr)
426{
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200427 uint8_t *start = ptr;
428 unsigned option;
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100429
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200430 ptr += 4;
431 for (option = 1; option < 256; option++) {
432 if (client_config.opt_mask[option >> 3] & (1 << (option & 7))) {
433 ptr[0] = (option >> 8);
434 ptr[1] = option;
435 ptr += 2;
436 }
437 }
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100438
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200439 if ((ptr - start - 4) != 0) {
440 start[0] = (D6_OPT_ORO >> 8);
441 start[1] = D6_OPT_ORO;
442 start[2] = ((ptr - start - 4) >> 8);
443 start[3] = (ptr - start - 4);
444 } else
445 ptr = start;
446
447#if ENABLE_FEATURE_UDHCPC6_RFC4704
448 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
449#endif
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100450 /* Add -x options if any */
451 //...
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +0200452
453 return ptr;
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100454}
455
456static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end)
457{
458 static const uint8_t FF02__1_2[16] = {
459 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
461 };
462
463 return d6_send_raw_packet(
464 packet, (end - (uint8_t*) packet),
Denys Vlasenkoe09f5e32017-03-27 22:10:15 +0200465 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100466 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR,
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100467 client_config.ifindex
468 );
469}
470
471/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
472 *
473 * RFC 3315 17.1.1. Creation of Solicit Messages
474 *
475 * The client MUST include a Client Identifier option to identify itself
476 * to the server. The client includes IA options for any IAs to which
477 * it wants the server to assign addresses. The client MAY include
478 * addresses in the IAs as a hint to the server about addresses for
479 * which the client has a preference. ...
480 *
481 * The client uses IA_NA options to request the assignment of non-
482 * temporary addresses and uses IA_TA options to request the assignment
483 * of temporary addresses. Either IA_NA or IA_TA options, or a
484 * combination of both, can be included in DHCP messages.
485 *
486 * The client SHOULD include an Option Request option (see section 22.7)
487 * to indicate the options the client is interested in receiving. The
488 * client MAY additionally include instances of those options that are
489 * identified in the Option Request option, with data values as hints to
490 * the server about parameter values the client would like to have
491 * returned.
492 *
493 * The client includes a Reconfigure Accept option (see section 22.20)
494 * if the client is willing to accept Reconfigure messages from the
495 * server.
496 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
497 | OPTION_CLIENTID | option-len |
498 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
499 . .
500 . DUID .
501 . (variable length) .
502 . .
503 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
504
505
506 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
507 | OPTION_IA_NA | option-len |
508 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
509 | IAID (4 octets) |
510 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
511 | T1 |
512 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513 | T2 |
514 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
515 | |
516 . IA_NA-options .
517 . .
518 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
519
520
521 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
522 | OPTION_IAADDR | option-len |
523 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
524 | |
525 | IPv6 address |
526 | |
527 | |
528 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
529 | preferred-lifetime |
530 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
531 | valid-lifetime |
532 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533 . .
534 . IAaddr-options .
535 . .
536 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537
538
539 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540 | OPTION_ORO | option-len |
541 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 | requested-option-code-1 | requested-option-code-2 |
543 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544 | ... |
545 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546
547
548 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
549 | OPTION_RECONF_ACCEPT | 0 |
550 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
551 */
552/* NOINLINE: limit stack usage in caller */
553static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6)
554{
555 struct d6_packet packet;
556 uint8_t *opt_ptr;
557 unsigned len;
558
559 /* Fill in: msg type, client id */
560 opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid);
561
562 /* Create new IA_NA, optionally with included IAADDR with requested IP */
563 free(client6_data.ia_na);
564 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
565 client6_data.ia_na = xzalloc(len);
566 client6_data.ia_na->code = D6_OPT_IA_NA;
567 client6_data.ia_na->len = len - 4;
568 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
569 if (requested_ipv6) {
570 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
571 iaaddr->code = D6_OPT_IAADDR;
572 iaaddr->len = 16+4+4;
573 memcpy(iaaddr->data, requested_ipv6, 16);
574 }
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200575 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100576
577 /* Add options:
578 * "param req" option according to -O, options specified with -x
579 */
580 opt_ptr = add_d6_client_options(opt_ptr);
581
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200582 bb_error_msg("sending %s", "discover");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100583 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
584}
585
586/* Multicast a DHCPv6 request message
587 *
588 * RFC 3315 18.1.1. Creation and Transmission of Request Messages
589 *
590 * The client uses a Request message to populate IAs with addresses and
591 * obtain other configuration information. The client includes one or
592 * more IA options in the Request message. The server then returns
593 * addresses and other information about the IAs to the client in IA
594 * options in a Reply message.
595 *
596 * The client generates a transaction ID and inserts this value in the
597 * "transaction-id" field.
598 *
599 * The client places the identifier of the destination server in a
600 * Server Identifier option.
601 *
602 * The client MUST include a Client Identifier option to identify itself
603 * to the server. The client adds any other appropriate options,
604 * including one or more IA options (if the client is requesting that
605 * the server assign it some network addresses).
606 *
607 * The client MUST include an Option Request option (see section 22.7)
608 * to indicate the options the client is interested in receiving. The
609 * client MAY include options with data values as hints to the server
610 * about parameter values the client would like to have returned.
611 *
612 * The client includes a Reconfigure Accept option (see section 22.20)
613 * indicating whether or not the client is willing to accept Reconfigure
614 * messages from the server.
615 */
616/* NOINLINE: limit stack usage in caller */
617static NOINLINE int send_d6_select(uint32_t xid)
618{
619 struct d6_packet packet;
620 uint8_t *opt_ptr;
621
622 /* Fill in: msg type, client id */
623 opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid);
624
625 /* server id */
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200626 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100627 /* IA NA (contains requested IP) */
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200628 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100629
630 /* Add options:
631 * "param req" option according to -O, options specified with -x
632 */
633 opt_ptr = add_d6_client_options(opt_ptr);
634
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200635 bb_error_msg("sending %s", "select");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100636 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
637}
638
639/* Unicast or broadcast a DHCP renew message
640 *
641 * RFC 3315 18.1.3. Creation and Transmission of Renew Messages
642 *
643 * To extend the valid and preferred lifetimes for the addresses
644 * associated with an IA, the client sends a Renew message to the server
645 * from which the client obtained the addresses in the IA containing an
646 * IA option for the IA. The client includes IA Address options in the
647 * IA option for the addresses associated with the IA. The server
648 * determines new lifetimes for the addresses in the IA according to the
649 * administrative configuration of the server. The server may also add
650 * new addresses to the IA. The server may remove addresses from the IA
651 * by setting the preferred and valid lifetimes of those addresses to
652 * zero.
653 *
654 * The server controls the time at which the client contacts the server
655 * to extend the lifetimes on assigned addresses through the T1 and T2
656 * parameters assigned to an IA.
657 *
658 * At time T1 for an IA, the client initiates a Renew/Reply message
659 * exchange to extend the lifetimes on any addresses in the IA. The
660 * client includes an IA option with all addresses currently assigned to
661 * the IA in its Renew message.
662 *
663 * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no
664 * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind
665 * message, respectively, at the client's discretion.
666 *
667 * The client sets the "msg-type" field to RENEW. The client generates
668 * a transaction ID and inserts this value in the "transaction-id"
669 * field.
670 *
671 * The client places the identifier of the destination server in a
672 * Server Identifier option.
673 *
674 * The client MUST include a Client Identifier option to identify itself
675 * to the server. The client adds any appropriate options, including
676 * one or more IA options. The client MUST include the list of
677 * addresses the client currently has associated with the IAs in the
678 * Renew message.
679 *
680 * The client MUST include an Option Request option (see section 22.7)
681 * to indicate the options the client is interested in receiving. The
682 * client MAY include options with data values as hints to the server
683 * about parameter values the client would like to have returned.
684 */
685/* NOINLINE: limit stack usage in caller */
686static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
687{
688 struct d6_packet packet;
689 uint8_t *opt_ptr;
690
691 /* Fill in: msg type, client id */
692 opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid);
693
694 /* server id */
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200695 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100696 /* IA NA (contains requested IP) */
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200697 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100698
699 /* Add options:
700 * "param req" option according to -O, options specified with -x
701 */
702 opt_ptr = add_d6_client_options(opt_ptr);
703
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200704 bb_error_msg("sending %s", "renew");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100705 if (server_ipv6)
706 return d6_send_kernel_packet(
707 &packet, (opt_ptr - (uint8_t*) &packet),
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100708 our_cur_ipv6, CLIENT_PORT6,
Denys Vlasenkoed898ed2017-03-27 22:32:44 +0200709 server_ipv6, SERVER_PORT6,
710 client_config.ifindex
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100711 );
712 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
713}
714
715/* Unicast a DHCP release message */
716static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
717{
718 struct d6_packet packet;
719 uint8_t *opt_ptr;
720
721 /* Fill in: msg type, client id */
722 opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid());
723 /* server id */
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200724 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100725 /* IA NA (contains our current IP) */
Denys Vlasenko234b82c2017-06-26 19:42:48 +0200726 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100727
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200728 bb_error_msg("sending %s", "release");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100729 return d6_send_kernel_packet(
730 &packet, (opt_ptr - (uint8_t*) &packet),
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100731 our_cur_ipv6, CLIENT_PORT6,
Denys Vlasenkoed898ed2017-03-27 22:32:44 +0200732 server_ipv6, SERVER_PORT6,
733 client_config.ifindex
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100734 );
735}
736
737/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
738/* NOINLINE: limit stack usage in caller */
Denys Vlasenkoed898ed2017-03-27 22:32:44 +0200739static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_packet *d6_pkt, int fd)
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100740{
741 int bytes;
742 struct ip6_udp_d6_packet packet;
743
744 bytes = safe_read(fd, &packet, sizeof(packet));
745 if (bytes < 0) {
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200746 log1("packet read error, ignoring");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100747 /* NB: possible down interface, etc. Caller should pause. */
748 return bytes; /* returns -1 */
749 }
750
751 if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) {
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200752 log1("packet is too short, ignoring");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100753 return -2;
754 }
755
756 if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) {
757 /* packet is bigger than sizeof(packet), we did partial read */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200758 log1("oversized packet, ignoring");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100759 return -2;
760 }
761
762 /* ignore any extra garbage bytes */
763 bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen);
764
765 /* make sure its the right packet for us, and that it passes sanity checks */
766 if (packet.ip6.ip6_nxt != IPPROTO_UDP
767 || (packet.ip6.ip6_vfc >> 4) != 6
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100768 || packet.udp.dest != htons(CLIENT_PORT6)
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100769 /* || bytes > (int) sizeof(packet) - can't happen */
770 || packet.udp.len != packet.ip6.ip6_plen
771 ) {
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200772 log1("unrelated/bogus packet, ignoring");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100773 return -2;
774 }
775
776//How to do this for ipv6?
777// /* verify UDP checksum. IP header has to be modified for this */
778// memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
779// /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
780// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
781// check = packet.udp.check;
782// packet.udp.check = 0;
783// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200784// log1("packet with bad UDP checksum received, ignoring");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100785// return -2;
786// }
787
Denys Vlasenkoed898ed2017-03-27 22:32:44 +0200788 if (peer_ipv6)
789 *peer_ipv6 = packet.ip6.ip6_src; /* struct copy */
790
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200791 log1("received %s", "a packet");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100792 d6_dump_packet(&packet.data);
793
794 bytes -= sizeof(packet.ip6) + sizeof(packet.udp);
795 memcpy(d6_pkt, &packet.data, bytes);
796 return bytes;
797}
798
799
800/*** Main ***/
801
802static int sockfd = -1;
803
804#define LISTEN_NONE 0
805#define LISTEN_KERNEL 1
806#define LISTEN_RAW 2
807static smallint listen_mode;
808
809/* initial state: (re)start DHCP negotiation */
810#define INIT_SELECTING 0
811/* discover was sent, DHCPOFFER reply received */
812#define REQUESTING 1
813/* select/renew was sent, DHCPACK reply received */
814#define BOUND 2
815/* half of lease passed, want to renew it by sending unicast renew requests */
816#define RENEWING 3
817/* renew requests were not answered, lease is almost over, send broadcast renew */
818#define REBINDING 4
819/* manually requested renew (SIGUSR1) */
820#define RENEW_REQUESTED 5
821/* release, possibly manually requested (SIGUSR2) */
822#define RELEASED 6
823static smallint state;
824
825static int d6_raw_socket(int ifindex)
826{
827 int fd;
828 struct sockaddr_ll sock;
829
830 /*
831 * Comment:
832 *
833 * I've selected not to see LL header, so BPF doesn't see it, too.
834 * The filter may also pass non-IP and non-ARP packets, but we do
835 * a more complete check when receiving the message in userspace.
836 *
837 * and filter shamelessly stolen from:
838 *
839 * http://www.flamewarmaster.de/software/dhcpclient/
840 *
841 * There are a few other interesting ideas on that page (look under
842 * "Motivation"). Use of netlink events is most interesting. Think
843 * of various network servers listening for events and reconfiguring.
844 * That would obsolete sending HUP signals and/or make use of restarts.
845 *
846 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
847 * License: GPL v2.
848 *
849 * TODO: make conditional?
850 */
851#if 0
852 static const struct sock_filter filter_instr[] = {
853 /* load 9th byte (protocol) */
854 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
855 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
856 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
857 /* L1: load halfword from offset 6 (flags and frag offset) */
858 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
859 /* jump to L4 if any bits in frag offset field are set, else to L2 */
860 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
861 /* L2: skip IP header (load index reg with header len) */
862 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
863 /* load udp destination port from halfword[header_len + 2] */
864 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100865 /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100866 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
867 /* L3: accept packet */
Denys Vlasenkoffc3a932014-02-19 14:17:11 +0100868 BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100869 /* L4: discard packet */
870 BPF_STMT(BPF_RET|BPF_K, 0),
871 };
872 static const struct sock_fprog filter_prog = {
873 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
874 /* casting const away: */
875 .filter = (struct sock_filter *) filter_instr,
876 };
877#endif
878
Denys Vlasenko168f0ef2017-07-21 12:04:22 +0200879 log2("opening raw socket on ifindex %d", ifindex);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100880
881 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
Denys Vlasenko168f0ef2017-07-21 12:04:22 +0200882 log2("got raw socket fd %d", fd);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100883
Denys Vlasenko2b9acc62017-09-29 14:09:02 +0200884 memset(&sock, 0, sizeof(sock)); /* let's be deterministic */
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100885 sock.sll_family = AF_PACKET;
886 sock.sll_protocol = htons(ETH_P_IPV6);
887 sock.sll_ifindex = ifindex;
Denys Vlasenko2b9acc62017-09-29 14:09:02 +0200888 /*sock.sll_hatype = ARPHRD_???;*/
889 /*sock.sll_pkttype = PACKET_???;*/
890 /*sock.sll_halen = ???;*/
891 /*sock.sll_addr[8] = ???;*/
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100892 xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
893
894#if 0
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100895 if (CLIENT_PORT6 == 546) {
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100896 /* Use only if standard port is in use */
897 /* Ignoring error (kernel may lack support for this) */
898 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
899 sizeof(filter_prog)) >= 0)
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200900 log1("attached filter to raw socket fd %d", fd); // log?
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100901 }
902#endif
903
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200904 log1("created raw socket");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100905
906 return fd;
907}
908
909static void change_listen_mode(int new_mode)
910{
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200911 log1("entering listen mode: %s",
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100912 new_mode != LISTEN_NONE
913 ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
914 : "none"
915 );
916
917 listen_mode = new_mode;
918 if (sockfd >= 0) {
919 close(sockfd);
920 sockfd = -1;
921 }
922 if (new_mode == LISTEN_KERNEL)
Denys Vlasenko04ac6e02013-01-28 15:25:35 +0100923 sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_config.interface);
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100924 else if (new_mode != LISTEN_NONE)
925 sockfd = d6_raw_socket(client_config.ifindex);
926 /* else LISTEN_NONE: sockfd stays closed */
927}
928
929/* Called only on SIGUSR1 */
930static void perform_renew(void)
931{
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200932 bb_error_msg("performing DHCP renew");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100933 switch (state) {
934 case BOUND:
935 change_listen_mode(LISTEN_KERNEL);
936 case RENEWING:
937 case REBINDING:
938 state = RENEW_REQUESTED;
939 break;
940 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
941 d6_run_script(NULL, "deconfig");
942 case REQUESTING:
943 case RELEASED:
944 change_listen_mode(LISTEN_RAW);
945 state = INIT_SELECTING;
946 break;
947 case INIT_SELECTING:
948 break;
949 }
950}
951
952static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
953{
954 /* send release packet */
Denys Vlasenko44399e02016-07-03 20:26:44 +0200955 if (state == BOUND
956 || state == RENEWING
957 || state == REBINDING
958 || state == RENEW_REQUESTED
959 ) {
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200960 bb_error_msg("unicasting a release");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100961 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100962 }
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +0200963 bb_error_msg("entering released state");
Peter Korsgaardb6355e22016-08-26 18:46:34 +0200964/*
965 * We can be here on: SIGUSR2,
966 * or on exit (SIGTERM) and -R "release on quit" is specified.
967 * Users requested to be notified in all cases, even if not in one
968 * of the states above.
969 */
970 d6_run_script(NULL, "deconfig");
Denys Vlasenko9ba75042011-11-07 15:55:39 +0100971 change_listen_mode(LISTEN_NONE);
972 state = RELEASED;
973}
974
975///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
976///{
977/// uint8_t *storage;
978/// int len = strnlen(str, 255);
979/// storage = xzalloc(len + extra + OPT_DATA);
980/// storage[OPT_CODE] = code;
981/// storage[OPT_LEN] = len + extra;
982/// memcpy(storage + extra + OPT_DATA, str, len);
983/// return storage;
984///}
985
986#if BB_MMU
987static void client_background(void)
988{
989 bb_daemonize(0);
990 logmode &= ~LOGMODE_STDIO;
991 /* rewrite pidfile, as our pid is different now */
992 write_pidfile(client_config.pidfile);
993}
994#endif
995
996//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
997//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
998//usage:#else
999//usage:# define IF_UDHCP_VERBOSE(...)
1000//usage:#endif
1001//usage:#define udhcpc6_trivial_usage
Denys Vlasenko7e21f042011-11-08 11:39:41 +01001002//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001003//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
1004//usage:#define udhcpc6_full_usage "\n"
1005//usage: IF_LONG_OPTS(
1006//usage: "\n -i,--interface IFACE Interface to use (default eth0)"
1007//usage: "\n -p,--pidfile FILE Create pidfile"
1008//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1009//usage: "\n -B,--broadcast Request broadcast replies"
1010//usage: "\n -t,--retries N Send up to N discover packets"
1011//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)"
1012//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)"
1013//usage: "\n -f,--foreground Run in foreground"
1014//usage: USE_FOR_MMU(
1015//usage: "\n -b,--background Background if lease is not obtained"
1016//usage: )
1017//usage: "\n -n,--now Exit if lease is not obtained"
1018//usage: "\n -q,--quit Exit after obtaining lease"
1019//usage: "\n -R,--release Release IP on exit"
1020//usage: "\n -S,--syslog Log to syslog too"
1021//usage: IF_FEATURE_UDHCP_PORT(
Denys Vlasenko7e21f042011-11-08 11:39:41 +01001022//usage: "\n -P,--client-port N Use port N (default 546)"
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001023//usage: )
1024////usage: IF_FEATURE_UDHCPC_ARPING(
1025////usage: "\n -a,--arping Use arping to validate offered address"
1026////usage: )
1027//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
1028//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
1029//usage: "\n -r,--request IP Request this IP address"
1030//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1031//usage: "\n Examples of string, numeric, and hex byte opts:"
1032//usage: "\n -x hostname:bbox - option 12"
1033//usage: "\n -x lease:3600 - option 51 (lease time)"
1034//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1035//usage: IF_UDHCP_VERBOSE(
1036//usage: "\n -v Verbose"
1037//usage: )
1038//usage: )
1039//usage: IF_NOT_LONG_OPTS(
1040//usage: "\n -i IFACE Interface to use (default eth0)"
1041//usage: "\n -p FILE Create pidfile"
1042//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1043//usage: "\n -B Request broadcast replies"
1044//usage: "\n -t N Send up to N discover packets"
1045//usage: "\n -T N Pause between packets (default 3 seconds)"
1046//usage: "\n -A N Wait N seconds (default 20) after failure"
1047//usage: "\n -f Run in foreground"
1048//usage: USE_FOR_MMU(
1049//usage: "\n -b Background if lease is not obtained"
1050//usage: )
1051//usage: "\n -n Exit if lease is not obtained"
1052//usage: "\n -q Exit after obtaining lease"
1053//usage: "\n -R Release IP on exit"
1054//usage: "\n -S Log to syslog too"
1055//usage: IF_FEATURE_UDHCP_PORT(
Denys Vlasenko7e21f042011-11-08 11:39:41 +01001056//usage: "\n -P N Use port N (default 546)"
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001057//usage: )
1058////usage: IF_FEATURE_UDHCPC_ARPING(
1059////usage: "\n -a Use arping to validate offered address"
1060////usage: )
1061//usage: "\n -O OPT Request option OPT from server (cumulative)"
1062//usage: "\n -o Don't request any options (unless -O is given)"
1063//usage: "\n -r IP Request this IP address"
1064//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1065//usage: "\n Examples of string, numeric, and hex byte opts:"
1066//usage: "\n -x hostname:bbox - option 12"
1067//usage: "\n -x lease:3600 - option 51 (lease time)"
1068//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1069//usage: IF_UDHCP_VERBOSE(
1070//usage: "\n -v Verbose"
1071//usage: )
1072//usage: )
1073//usage: "\nSignals:"
1074//usage: "\n USR1 Renew lease"
1075//usage: "\n USR2 Release lease"
1076
1077
1078int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1079int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1080{
1081 const char *str_r;
1082 IF_FEATURE_UDHCP_PORT(char *str_P;)
1083 void *clientid_mac_ptr;
1084 llist_t *list_O = NULL;
1085 llist_t *list_x = NULL;
1086 int tryagain_timeout = 20;
1087 int discover_timeout = 3;
1088 int discover_retries = 3;
1089 struct in6_addr srv6_buf;
1090 struct in6_addr ipv6_buf;
1091 struct in6_addr *requested_ipv6;
1092 uint32_t xid = 0;
1093 int packet_num;
1094 int timeout; /* must be signed */
1095 unsigned already_waited_sec;
1096 unsigned opt;
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001097 int retval;
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001098
Denys Vlasenkodf70a432016-04-21 18:54:36 +02001099 setup_common_bufsiz();
1100
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001101 /* Default options */
Denys Vlasenko04ac6e02013-01-28 15:25:35 +01001102 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
1103 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;)
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001104 client_config.interface = "eth0";
1105 client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1106
1107 /* Parse command line */
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001108 opt = getopt32long(argv, "^"
1109 /* O,x: list; -T,-t,-A take numeric param */
1110 "i:np:qRr:s:T:+t:+SA:+O:*ox:*f"
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001111 USE_FOR_MMU("b")
1112 ///IF_FEATURE_UDHCPC_ARPING("a")
1113 IF_FEATURE_UDHCP_PORT("P:")
1114 "v"
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001115 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */
Denys Vlasenko036585a2017-08-08 16:38:18 +02001116 , udhcpc6_longopts
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001117 , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
1118 , &client_config.script /* s */
1119 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1120 , &list_O
1121 , &list_x
1122 IF_FEATURE_UDHCP_PORT(, &str_P)
1123 IF_UDHCP_VERBOSE(, &dhcp_verbose)
Denys Vlasenko7e21f042011-11-08 11:39:41 +01001124 );
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001125 requested_ipv6 = NULL;
1126 if (opt & OPT_r) {
1127 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1128 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1129 requested_ipv6 = &ipv6_buf;
1130 }
1131#if ENABLE_FEATURE_UDHCP_PORT
1132 if (opt & OPT_P) {
Denys Vlasenko04ac6e02013-01-28 15:25:35 +01001133 CLIENT_PORT6 = xatou16(str_P);
1134 SERVER_PORT6 = CLIENT_PORT6 + 1;
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001135 }
1136#endif
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001137 while (list_O) {
1138 char *optstr = llist_pop(&list_O);
1139 unsigned n = bb_strtou(optstr, NULL, 0);
1140 if (errno || n > 254) {
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +02001141 n = udhcp_option_idx(optstr, d6_option_strings);
1142 n = d6_optflags[n].code;
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001143 }
1144 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1145 }
Denys Vlasenko293c9452012-07-27 13:25:07 +02001146 if (!(opt & OPT_o)) {
Denys Vlasenko293c9452012-07-27 13:25:07 +02001147 unsigned i, n;
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +02001148 for (i = 0; (n = d6_optflags[i].code) != 0; i++) {
1149 if (d6_optflags[i].flags & OPTION_REQ) {
Denys Vlasenko293c9452012-07-27 13:25:07 +02001150 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1151 }
1152 }
Denys Vlasenko293c9452012-07-27 13:25:07 +02001153 }
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001154 while (list_x) {
1155 char *optstr = llist_pop(&list_x);
1156 char *colon = strchr(optstr, ':');
1157 if (colon)
1158 *colon = ' ';
1159 /* now it looks similar to udhcpd's config file line:
1160 * "optname optval", using the common routine: */
Denys Vlasenkoba4fbca2017-06-28 19:18:17 +02001161 udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings);
Denys Vlasenko741bfa92017-05-08 15:02:07 +02001162 if (colon)
1163 *colon = ':'; /* restore it for NOMMU reexec */
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001164 }
1165
Denys Vlasenkoe09f5e32017-03-27 22:10:15 +02001166 if (d6_read_interface(client_config.interface,
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001167 &client_config.ifindex,
Denys Vlasenkoe09f5e32017-03-27 22:10:15 +02001168 &client6_data.ll_ip6,
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001169 client_config.client_mac)
1170 ) {
1171 return 1;
1172 }
1173
1174 /* Create client ID based on mac, set clientid_mac_ptr */
1175 {
1176 struct d6_option *clientid;
1177 clientid = xzalloc(2+2+2+2+6);
1178 clientid->code = D6_OPT_CLIENTID;
1179 clientid->len = 2+2+6;
Denys Vlasenko68c5b282011-11-07 16:21:24 +01001180 clientid->data[1] = 3; /* DUID-LL */
1181 clientid->data[3] = 1; /* ethernet */
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001182 clientid_mac_ptr = clientid->data + 2+2;
1183 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1184 client_config.clientid = (void*)clientid;
1185 }
1186
1187#if !BB_MMU
1188 /* on NOMMU reexec (i.e., background) early */
1189 if (!(opt & OPT_f)) {
1190 bb_daemonize_or_rexec(0 /* flags */, argv);
1191 logmode = LOGMODE_NONE;
1192 }
1193#endif
1194 if (opt & OPT_S) {
1195 openlog(applet_name, LOG_PID, LOG_DAEMON);
1196 logmode |= LOGMODE_SYSLOG;
1197 }
1198
1199 /* Make sure fd 0,1,2 are open */
1200 bb_sanitize_stdio();
1201 /* Equivalent of doing a fflush after every \n */
1202 setlinebuf(stdout);
1203 /* Create pidfile */
1204 write_pidfile(client_config.pidfile);
1205 /* Goes to stdout (unless NOMMU) and possibly syslog */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001206 bb_error_msg("started, v"BB_VER);
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001207 /* Set up the signal pipe */
1208 udhcp_sp_setup();
1209 /* We want random_xid to be random... */
1210 srand(monotonic_us());
1211
1212 state = INIT_SELECTING;
1213 d6_run_script(NULL, "deconfig");
1214 change_listen_mode(LISTEN_RAW);
1215 packet_num = 0;
1216 timeout = 0;
1217 already_waited_sec = 0;
1218
1219 /* Main event loop. select() waits on signal pipe and possibly
1220 * on sockfd.
1221 * "continue" statements in code below jump to the top of the loop.
1222 */
1223 for (;;) {
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001224 int tv;
1225 struct pollfd pfds[2];
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001226 struct d6_packet packet;
1227 uint8_t *packet_end;
1228 /* silence "uninitialized!" warning */
1229 unsigned timestamp_before_wait = timestamp_before_wait;
1230
1231 //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
1232
1233 /* Was opening raw or udp socket here
1234 * if (listen_mode != LISTEN_NONE && sockfd < 0),
1235 * but on fast network renew responses return faster
1236 * than we open sockets. Thus this code is moved
1237 * to change_listen_mode(). Thus we open listen socket
1238 * BEFORE we send renew request (see "case BOUND:"). */
1239
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001240 udhcp_sp_fd_set(pfds, sockfd);
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001241
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001242 tv = timeout - already_waited_sec;
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001243 retval = 0;
1244 /* If we already timed out, fall through with retval = 0, else... */
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001245 if (tv > 0) {
Denys Vlasenkode6cb412017-07-24 12:01:28 +02001246 log1("waiting %u seconds", tv);
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001247 timestamp_before_wait = (unsigned)monotonic_sec();
Denys Vlasenko7c67f1e2017-02-17 19:20:32 +01001248 retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX);
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001249 if (retval < 0) {
1250 /* EINTR? A signal was caught, don't panic */
1251 if (errno == EINTR) {
1252 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1253 continue;
1254 }
1255 /* Else: an error occured, panic! */
Denys Vlasenkode6cb412017-07-24 12:01:28 +02001256 bb_perror_msg_and_die("poll");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001257 }
1258 }
1259
1260 /* If timeout dropped to zero, time to become active:
1261 * resend discover/renew/whatever
1262 */
1263 if (retval == 0) {
1264 /* When running on a bridge, the ifindex may have changed
1265 * (e.g. if member interfaces were added/removed
1266 * or if the status of the bridge changed).
1267 * Refresh ifindex and client_mac:
1268 */
Denys Vlasenkoe09f5e32017-03-27 22:10:15 +02001269 if (d6_read_interface(client_config.interface,
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001270 &client_config.ifindex,
Denys Vlasenkoe09f5e32017-03-27 22:10:15 +02001271 &client6_data.ll_ip6,
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001272 client_config.client_mac)
1273 ) {
1274 goto ret0; /* iface is gone? */
1275 }
Denys Vlasenkoe09f5e32017-03-27 22:10:15 +02001276
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001277 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1278
1279 /* We will restart the wait in any case */
1280 already_waited_sec = 0;
1281
1282 switch (state) {
1283 case INIT_SELECTING:
Felix Fietkau1c7a58d2012-09-27 16:22:24 +02001284 if (!discover_retries || packet_num < discover_retries) {
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001285 if (packet_num == 0)
1286 xid = random_xid();
1287 /* multicast */
1288 send_d6_discover(xid, requested_ipv6);
1289 timeout = discover_timeout;
1290 packet_num++;
1291 continue;
1292 }
1293 leasefail:
1294 d6_run_script(NULL, "leasefail");
1295#if BB_MMU /* -b is not supported on NOMMU */
1296 if (opt & OPT_b) { /* background if no lease */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001297 bb_error_msg("no lease, forking to background");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001298 client_background();
1299 /* do not background again! */
1300 opt = ((opt & ~OPT_b) | OPT_f);
1301 } else
1302#endif
1303 if (opt & OPT_n) { /* abort if no lease */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001304 bb_error_msg("no lease, failing");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001305 retval = 1;
1306 goto ret;
1307 }
1308 /* wait before trying again */
1309 timeout = tryagain_timeout;
1310 packet_num = 0;
1311 continue;
1312 case REQUESTING:
Felix Fietkau1c7a58d2012-09-27 16:22:24 +02001313 if (!discover_retries || packet_num < discover_retries) {
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001314 /* send multicast select packet */
1315 send_d6_select(xid);
1316 timeout = discover_timeout;
1317 packet_num++;
1318 continue;
1319 }
1320 /* Timed out, go back to init state.
1321 * "discover...select...discover..." loops
1322 * were seen in the wild. Treat them similarly
1323 * to "no response to discover" case */
1324 change_listen_mode(LISTEN_RAW);
1325 state = INIT_SELECTING;
1326 goto leasefail;
1327 case BOUND:
1328 /* 1/2 lease passed, enter renewing state */
1329 state = RENEWING;
1330 client_config.first_secs = 0; /* make secs field count from 0 */
1331 change_listen_mode(LISTEN_KERNEL);
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001332 log1("entering renew state");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001333 /* fall right through */
1334 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
1335 case_RENEW_REQUESTED:
1336 case RENEWING:
1337 if (timeout > 60) {
1338 /* send an unicast renew request */
1339 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1340 * a new UDP socket for sending inside send_renew.
1341 * I hazard to guess existing listening socket
1342 * is somehow conflicting with it, but why is it
1343 * not deterministic then?! Strange.
1344 * Anyway, it does recover by eventually failing through
1345 * into INIT_SELECTING state.
1346 */
1347 send_d6_renew(xid, &srv6_buf, requested_ipv6);
1348 timeout >>= 1;
1349 continue;
1350 }
1351 /* Timed out, enter rebinding state */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001352 log1("entering rebinding state");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001353 state = REBINDING;
1354 /* fall right through */
1355 case REBINDING:
1356 /* Switch to bcast receive */
1357 change_listen_mode(LISTEN_RAW);
1358 /* Lease is *really* about to run out,
1359 * try to find DHCP server using broadcast */
1360 if (timeout > 0) {
1361 /* send a broadcast renew request */
1362 send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6);
1363 timeout >>= 1;
1364 continue;
1365 }
1366 /* Timed out, enter init state */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001367 bb_error_msg("lease lost, entering init state");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001368 d6_run_script(NULL, "deconfig");
1369 state = INIT_SELECTING;
1370 client_config.first_secs = 0; /* make secs field count from 0 */
1371 /*timeout = 0; - already is */
1372 packet_num = 0;
1373 continue;
1374 /* case RELEASED: */
1375 }
1376 /* yah, I know, *you* say it would never happen */
1377 timeout = INT_MAX;
1378 continue; /* back to main loop */
1379 } /* if select timed out */
1380
1381 /* select() didn't timeout, something happened */
1382
1383 /* Is it a signal? */
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001384 /* note: udhcp_sp_read checks poll result before reading */
1385 switch (udhcp_sp_read(pfds)) {
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001386 case SIGUSR1:
1387 client_config.first_secs = 0; /* make secs field count from 0 */
1388 already_waited_sec = 0;
1389 perform_renew();
1390 if (state == RENEW_REQUESTED) {
1391 /* We might be either on the same network
1392 * (in which case renew might work),
1393 * or we might be on a completely different one
1394 * (in which case renew won't ever succeed).
1395 * For the second case, must make sure timeout
1396 * is not too big, or else we can send
1397 * futile renew requests for hours.
1398 * (Ab)use -A TIMEOUT value (usually 20 sec)
1399 * as a cap on the timeout.
1400 */
1401 if (timeout > tryagain_timeout)
1402 timeout = tryagain_timeout;
1403 goto case_RENEW_REQUESTED;
1404 }
1405 /* Start things over */
1406 packet_num = 0;
1407 /* Kill any timeouts, user wants this to hurry along */
1408 timeout = 0;
1409 continue;
1410 case SIGUSR2:
1411 perform_d6_release(&srv6_buf, requested_ipv6);
1412 timeout = INT_MAX;
1413 continue;
1414 case SIGTERM:
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001415 bb_error_msg("received %s", "SIGTERM");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001416 goto ret0;
1417 }
1418
1419 /* Is it a packet? */
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001420 if (listen_mode == LISTEN_NONE || !pfds[1].revents)
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001421 continue; /* no */
1422
1423 {
1424 int len;
1425
1426 /* A packet is ready, read it */
1427 if (listen_mode == LISTEN_KERNEL)
1428 len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd);
1429 else
1430 len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd);
1431 if (len == -1) {
1432 /* Error is severe, reopen socket */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001433 bb_error_msg("read error: %s, reopening socket", strerror(errno));
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001434 sleep(discover_timeout); /* 3 seconds by default */
1435 change_listen_mode(listen_mode); /* just close and reopen */
1436 }
1437 /* If this packet will turn out to be unrelated/bogus,
1438 * we will go back and wait for next one.
1439 * Be sure timeout is properly decreased. */
1440 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1441 if (len < 0)
1442 continue;
1443 packet_end = (uint8_t*)&packet + len;
1444 }
1445
1446 if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) {
1447 log1("xid %x (our is %x), ignoring packet",
1448 (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid);
1449 continue;
1450 }
1451
1452 switch (state) {
1453 case INIT_SELECTING:
1454 if (packet.d6_msg_type == D6_MSG_ADVERTISE)
1455 goto type_is_ok;
1456 /* DHCPv6 has "Rapid Commit", when instead of Advertise,
1457 * server sends Reply right away.
1458 * Fall through to check for this case.
1459 */
1460 case REQUESTING:
1461 case RENEWING:
1462 case RENEW_REQUESTED:
1463 case REBINDING:
1464 if (packet.d6_msg_type == D6_MSG_REPLY) {
1465 uint32_t lease_seconds;
1466 struct d6_option *option, *iaaddr;
1467 type_is_ok:
1468 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
Denys Vlasenko64d58aa2017-03-27 22:22:09 +02001469 if (option && (option->data[0] | option->data[1]) != 0) {
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001470 /* return to init state */
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001471 bb_error_msg("received DHCP NAK (%u)", option->data[4]);
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001472 d6_run_script(&packet, "nak");
1473 if (state != REQUESTING)
1474 d6_run_script(NULL, "deconfig");
1475 change_listen_mode(LISTEN_RAW);
1476 sleep(3); /* avoid excessive network traffic */
1477 state = INIT_SELECTING;
1478 client_config.first_secs = 0; /* make secs field count from 0 */
1479 requested_ipv6 = NULL;
1480 timeout = 0;
1481 packet_num = 0;
1482 already_waited_sec = 0;
1483 continue;
1484 }
1485 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1486 if (!option) {
1487 bb_error_msg("no server ID, ignoring packet");
1488 continue;
1489 /* still selecting - this server looks bad */
1490 }
1491//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1492//server_id variable is used solely for creation of proper server_id option
1493//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1494 free(client6_data.server_id);
1495 client6_data.server_id = option;
1496 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1497 /* enter requesting state */
1498 state = REQUESTING;
1499 timeout = 0;
1500 packet_num = 0;
1501 already_waited_sec = 0;
1502 continue;
1503 }
1504 /* It's a D6_MSG_REPLY */
1505/*
1506 * RFC 3315 18.1.8. Receipt of Reply Messages
1507 *
1508 * Upon the receipt of a valid Reply message in response to a Solicit
1509 * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or
1510 * Information-request message, the client extracts the configuration
1511 * information contained in the Reply. The client MAY choose to report
1512 * any status code or message from the status code option in the Reply
1513 * message.
1514 *
1515 * The client SHOULD perform duplicate address detection [17] on each of
1516 * the addresses in any IAs it receives in the Reply message before
1517 * using that address for traffic. If any of the addresses are found to
1518 * be in use on the link, the client sends a Decline message to the
1519 * server as described in section 18.1.7.
1520 *
1521 * If the Reply was received in response to a Solicit (with a Rapid
1522 * Commit option), Request, Renew or Rebind message, the client updates
1523 * the information it has recorded about IAs from the IA options
1524 * contained in the Reply message:
1525 *
1526 * - Record T1 and T2 times.
1527 *
1528 * - Add any new addresses in the IA option to the IA as recorded by
1529 * the client.
1530 *
1531 * - Update lifetimes for any addresses in the IA option that the
1532 * client already has recorded in the IA.
1533 *
1534 * - Discard any addresses from the IA, as recorded by the client, that
1535 * have a valid lifetime of 0 in the IA Address option.
1536 *
1537 * - Leave unchanged any information about addresses the client has
1538 * recorded in the IA but that were not included in the IA from the
1539 * server.
1540 *
1541 * Management of the specific configuration information is detailed in
1542 * the definition of each option in section 22.
1543 *
1544 * If the client receives a Reply message with a Status Code containing
1545 * UnspecFail, the server is indicating that it was unable to process
1546 * the message due to an unspecified failure condition. If the client
1547 * retransmits the original message to the same server to retry the
1548 * desired operation, the client MUST limit the rate at which it
1549 * retransmits the message and limit the duration of the time during
1550 * which it retransmits the message.
1551 *
1552 * When the client receives a Reply message with a Status Code option
1553 * with the value UseMulticast, the client records the receipt of the
1554 * message and sends subsequent messages to the server through the
1555 * interface on which the message was received using multicast. The
1556 * client resends the original message using multicast.
1557 *
1558 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1559 * | OPTION_IA_NA | option-len |
1560 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1561 * | IAID (4 octets) |
1562 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1563 * | T1 |
1564 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1565 * | T2 |
1566 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1567 * | |
1568 * . IA_NA-options .
1569 * . .
1570 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1571 *
1572 *
1573 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1574 * | OPTION_IAADDR | option-len |
1575 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1576 * | |
1577 * | IPv6 address |
1578 * | |
1579 * | |
1580 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1581 * | preferred-lifetime |
1582 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1583 * | valid-lifetime |
1584 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1585 * . .
1586 * . IAaddr-options .
1587 * . .
1588 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1589 */
1590 free(client6_data.ia_na);
1591 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1592 if (!client6_data.ia_na) {
Denys Vlasenkoa092a892011-11-16 20:17:12 +01001593 bb_error_msg("no %s option, ignoring packet", "IA_NA");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001594 continue;
1595 }
1596 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1597 bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len);
1598 continue;
1599 }
Denys Vlasenkoa092a892011-11-16 20:17:12 +01001600 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001601 client6_data.ia_na->data + client6_data.ia_na->len,
1602 D6_OPT_IAADDR
1603 );
1604 if (!iaaddr) {
Denys Vlasenkoa092a892011-11-16 20:17:12 +01001605 bb_error_msg("no %s option, ignoring packet", "IAADDR");
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001606 continue;
1607 }
1608 if (iaaddr->len < (16 + 4 + 4)) {
1609 bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len);
1610 continue;
1611 }
1612 /* Note: the address is sufficiently aligned for cast:
1613 * we _copied_ IA-NA, and copy is always well-aligned.
1614 */
1615 requested_ipv6 = (struct in6_addr*) iaaddr->data;
1616 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1617 lease_seconds = ntohl(lease_seconds);
1618 /* paranoia: must not be too small and not prone to overflows */
1619 if (lease_seconds < 0x10)
1620 lease_seconds = 0x10;
1621/// TODO: check for 0 lease time?
Denys Vlasenko52a515d2017-02-16 23:25:44 +01001622 if (lease_seconds > 0x7fffffff / 1000)
1623 lease_seconds = 0x7fffffff / 1000;
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001624 /* enter bound state */
1625 timeout = lease_seconds / 2;
Denys Vlasenko8f2e99c2016-03-30 18:41:23 +02001626 bb_error_msg("lease obtained, lease time %u",
Denys Vlasenko9ba75042011-11-07 15:55:39 +01001627 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1628 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1629
1630 state = BOUND;
1631 change_listen_mode(LISTEN_NONE);
1632 if (opt & OPT_q) { /* quit after lease */
1633 goto ret0;
1634 }
1635 /* future renew failures should not exit (JM) */
1636 opt &= ~OPT_n;
1637#if BB_MMU /* NOMMU case backgrounded earlier */
1638 if (!(opt & OPT_f)) {
1639 client_background();
1640 /* do not background again! */
1641 opt = ((opt & ~OPT_b) | OPT_f);
1642 }
1643#endif
1644 already_waited_sec = 0;
1645 continue; /* back to main loop */
1646 }
1647 continue;
1648 /* case BOUND: - ignore all packets */
1649 /* case RELEASED: - ignore all packets */
1650 }
1651 /* back to main loop */
1652 } /* for (;;) - main loop ends */
1653
1654 ret0:
1655 if (opt & OPT_R) /* release on quit */
1656 perform_d6_release(&srv6_buf, requested_ipv6);
1657 retval = 0;
1658 ret:
1659 /*if (client_config.pidfile) - remove_pidfile has its own check */
1660 remove_pidfile(client_config.pidfile);
1661 return retval;
1662}