1/* vi: set sw=4 ts=4: */ 2/* 3 * DHCPv6 client. 4 * 5 * 2011-11. 6 * WARNING: THIS CODE IS INCOMPLETE. IT IS NOWHERE NEAR 7 * TO BE READY FOR PRODUCTION USE. 8 * 9 * Copyright (C) 2011 Denys Vlasenko. 10 * 11 * Licensed under GPLv2, see file LICENSE in this source tree. 12 */ 13 14//config:config UDHCPC6 15//config: bool "udhcp client for DHCPv6 (udhcpc6)" 16//config: default n # not yet ready 17//config: depends on FEATURE_IPV6 18//config: help 19//config: udhcpc6 is a DHCPv6 client 20 21//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) 22 23//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o 24 25 26#include <syslog.h> 27/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ 28#define WANT_PIDFILE 1 29#include "common.h" 30#include "dhcpd.h" 31#include "dhcpc.h" 32#include "d6_common.h" 33 34#include <netinet/if_ether.h> 35#include <netpacket/packet.h> 36#include <linux/filter.h> 37 38/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ 39 40 41#if ENABLE_LONG_OPTS 42static const char udhcpc6_longopts[] ALIGN1 = 43 "interface\0" Required_argument "i" 44 "now\0" No_argument "n" 45 "pidfile\0" Required_argument "p" 46 "quit\0" No_argument "q" 47 "release\0" No_argument "R" 48 "request\0" Required_argument "r" 49 "script\0" Required_argument "s" 50 "timeout\0" Required_argument "T" 51 "retries\0" Required_argument "t" 52 "tryagain\0" Required_argument "A" 53 "syslog\0" No_argument "S" 54 "request-option\0" Required_argument "O" 55 "no-default-options\0" No_argument "o" 56 "foreground\0" No_argument "f" 57 "background\0" No_argument "b" 58/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") 59 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") 60 ; 61#endif 62/* Must match getopt32 option string order */ 63enum { 64 OPT_i = 1 << 0, 65 OPT_n = 1 << 1, 66 OPT_p = 1 << 2, 67 OPT_q = 1 << 3, 68 OPT_R = 1 << 4, 69 OPT_r = 1 << 5, 70 OPT_s = 1 << 6, 71 OPT_T = 1 << 7, 72 OPT_t = 1 << 8, 73 OPT_S = 1 << 9, 74 OPT_A = 1 << 10, 75 OPT_O = 1 << 11, 76 OPT_o = 1 << 12, 77 OPT_x = 1 << 13, 78 OPT_f = 1 << 14, 79/* The rest has variable bit positions, need to be clever */ 80 OPTBIT_f = 14, 81 USE_FOR_MMU( OPTBIT_b,) 82 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 83 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 84 USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) 85 ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) 86 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) 87}; 88 89 90/*** Utility functions ***/ 91 92static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code) 93{ 94 /* "length minus 4" */ 95 int len_m4 = option_end - option - 4; 96 while (len_m4 >= 0) { 97 /* Next option's len is too big? */ 98 if (option[3] > len_m4) 99 return NULL; /* yes. bogus packet! */ 100 /* So far we treat any opts with code >255 101 * or len >255 as bogus, and stop at once. 102 * This simplifies big-endian handling. 103 */ 104 if (option[0] != 0 || option[2] != 0) 105 return NULL; 106 /* Option seems to be valid */ 107 /* Does its code match? */ 108 if (option[1] == code) 109 return option; /* yes! */ 110 option += option[3] + 4; 111 len_m4 -= option[3] + 4; 112 } 113 return NULL; 114} 115 116static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code) 117{ 118 uint8_t *opt = d6_find_option(option, option_end, code); 119 if (!opt) 120 return opt; 121 return memcpy(xmalloc(opt[3] + 4), opt, opt[3] + 4); 122} 123 124static void *d6_store_blob(void *dst, const void *src, unsigned len) 125{ 126 memcpy(dst, src, len); 127 return dst + len; 128} 129 130 131/*** Script execution code ***/ 132 133static char** new_env(void) 134{ 135 client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx); 136 return &client6_data.env_ptr[client6_data.env_idx++]; 137} 138 139/* put all the parameters into the environment */ 140static void option_to_env(uint8_t *option, uint8_t *option_end) 141{ 142 /* "length minus 4" */ 143 int len_m4 = option_end - option - 4; 144 while (len_m4 >= 0) { 145 uint32_t v32; 146 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; 147 148 if (option[0] != 0 || option[2] != 0) 149 break; 150 151 switch (option[1]) { 152 //case D6_OPT_CLIENTID: 153 //case D6_OPT_SERVERID: 154 case D6_OPT_IA_NA: 155 case D6_OPT_IA_PD: 156 option_to_env(option + 16, option + 4 + option[3]); 157 break; 158 //case D6_OPT_IA_TA: 159 case D6_OPT_IAADDR: 160/* 0 1 2 3 161 * 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 162 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 163 * | OPTION_IAADDR | option-len | 164 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 165 * | | 166 * | IPv6 address | 167 * | | 168 * | | 169 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 170 * | preferred-lifetime | 171 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 172 * | valid-lifetime | 173 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 174 */ 175 sprint_nip6(ipv6str, option + 4); 176 *new_env() = xasprintf("ipv6=%s", ipv6str); 177 178 move_from_unaligned32(v32, option + 4 + 16 + 4); 179 *new_env() = xasprintf("lease=%u", (unsigned)v32); 180 break; 181 182 //case D6_OPT_ORO: 183 //case D6_OPT_PREFERENCE: 184 //case D6_OPT_ELAPSED_TIME: 185 //case D6_OPT_RELAY_MSG: 186 //case D6_OPT_AUTH: 187 //case D6_OPT_UNICAST: 188 //case D6_OPT_STATUS_CODE: 189 //case D6_OPT_RAPID_COMMIT: 190 //case D6_OPT_USER_CLASS: 191 //case D6_OPT_VENDOR_CLASS: 192 //case D6_OPT_VENDOR_OPTS: 193 //case D6_OPT_INTERFACE_ID: 194 //case D6_OPT_RECONF_MSG: 195 //case D6_OPT_RECONF_ACCEPT: 196 197 case D6_OPT_IAPREFIX: 198/* 0 1 2 3 199 * 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 200 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 201 * | OPTION_IAPREFIX | option-length | 202 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 203 * | preferred-lifetime | 204 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 205 * | valid-lifetime | 206 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 207 * | prefix-length | | 208 * +-+-+-+-+-+-+-+-+ IPv6 prefix | 209 * | (16 octets) | 210 * | | 211 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 212 * | | 213 * +-+-+-+-+-+-+-+-+ 214 */ 215 //move_from_unaligned32(v32, option + 4 + 4); 216 //*new_env() = xasprintf("lease=%u", (unsigned)v32); 217 218 sprint_nip6(ipv6str, option + 4 + 4 + 1); 219 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); 220 } 221 option += 4 + option[3]; 222 len_m4 -= 4 + option[3]; 223 } 224} 225 226static char **fill_envp(struct d6_packet *packet) 227{ 228 char **envp, **curr; 229 230 client6_data.env_ptr = NULL; 231 client6_data.env_idx = 0; 232 233 *new_env() = xasprintf("interface=%s", client_config.interface); 234 235 if (packet) 236 option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options)); 237 238 envp = curr = client6_data.env_ptr; 239 while (*curr) 240 putenv(*curr++); 241 242 return envp; 243} 244 245/* Call a script with a par file and env vars */ 246static void d6_run_script(struct d6_packet *packet, const char *name) 247{ 248 char **envp, **curr; 249 char *argv[3]; 250 251 envp = fill_envp(packet); 252 253 /* call script */ 254 log1("Executing %s %s", client_config.script, name); 255 argv[0] = (char*) client_config.script; 256 argv[1] = (char*) name; 257 argv[2] = NULL; 258 spawn_and_wait(argv); 259 260 for (curr = envp; *curr; curr++) { 261 log2(" %s", *curr); 262 bb_unsetenv_and_free(*curr); 263 } 264 free(envp); 265} 266 267 268/*** Sending/receiving packets ***/ 269 270static ALWAYS_INLINE uint32_t random_xid(void) 271{ 272 uint32_t t = rand() & htonl(0x00ffffff); 273 return t; 274} 275 276/* Initialize the packet with the proper defaults */ 277static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) 278{ 279 struct d6_option *clientid; 280 281 memset(packet, 0, sizeof(*packet)); 282 283 packet->d6_xid32 = xid; 284 packet->d6_msg_type = type; 285 286 clientid = (void*)client_config.clientid; 287 return d6_store_blob(packet->d6_options, clientid, clientid->len + 2+2); 288} 289 290static uint8_t *add_d6_client_options(uint8_t *ptr) 291{ 292 return ptr; 293 //uint8_t c; 294 //int i, end, len; 295 296 /* Add a "param req" option with the list of options we'd like to have 297 * from stubborn DHCP servers. Pull the data from the struct in common.c. 298 * No bounds checking because it goes towards the head of the packet. */ 299 //... 300 301 /* Add -x options if any */ 302 //... 303} 304 305static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) 306{ 307 static const uint8_t FF02__1_2[16] = { 308 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 309 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 310 }; 311 312 return d6_send_raw_packet( 313 packet, (end - (uint8_t*) packet), 314 /*src*/ NULL, CLIENT_PORT6, 315 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR, 316 client_config.ifindex 317 ); 318} 319 320/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. 321 * 322 * RFC 3315 17.1.1. Creation of Solicit Messages 323 * 324 * The client MUST include a Client Identifier option to identify itself 325 * to the server. The client includes IA options for any IAs to which 326 * it wants the server to assign addresses. The client MAY include 327 * addresses in the IAs as a hint to the server about addresses for 328 * which the client has a preference. ... 329 * 330 * The client uses IA_NA options to request the assignment of non- 331 * temporary addresses and uses IA_TA options to request the assignment 332 * of temporary addresses. Either IA_NA or IA_TA options, or a 333 * combination of both, can be included in DHCP messages. 334 * 335 * The client SHOULD include an Option Request option (see section 22.7) 336 * to indicate the options the client is interested in receiving. The 337 * client MAY additionally include instances of those options that are 338 * identified in the Option Request option, with data values as hints to 339 * the server about parameter values the client would like to have 340 * returned. 341 * 342 * The client includes a Reconfigure Accept option (see section 22.20) 343 * if the client is willing to accept Reconfigure messages from the 344 * server. 345 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 346 | OPTION_CLIENTID | option-len | 347 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 348 . . 349 . DUID . 350 . (variable length) . 351 . . 352 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 353 354 355 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 356 | OPTION_IA_NA | option-len | 357 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 358 | IAID (4 octets) | 359 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 360 | T1 | 361 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 362 | T2 | 363 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 364 | | 365 . IA_NA-options . 366 . . 367 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 368 369 370 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 371 | OPTION_IAADDR | option-len | 372 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 373 | | 374 | IPv6 address | 375 | | 376 | | 377 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 378 | preferred-lifetime | 379 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 380 | valid-lifetime | 381 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 382 . . 383 . IAaddr-options . 384 . . 385 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 386 387 388 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 389 | OPTION_ORO | option-len | 390 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 391 | requested-option-code-1 | requested-option-code-2 | 392 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 393 | ... | 394 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 395 396 397 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 398 | OPTION_RECONF_ACCEPT | 0 | 399 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 400 */ 401/* NOINLINE: limit stack usage in caller */ 402static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6) 403{ 404 struct d6_packet packet; 405 uint8_t *opt_ptr; 406 unsigned len; 407 408 /* Fill in: msg type, client id */ 409 opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); 410 411 /* Create new IA_NA, optionally with included IAADDR with requested IP */ 412 free(client6_data.ia_na); 413 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; 414 client6_data.ia_na = xzalloc(len); 415 client6_data.ia_na->code = D6_OPT_IA_NA; 416 client6_data.ia_na->len = len - 4; 417 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ 418 if (requested_ipv6) { 419 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); 420 iaaddr->code = D6_OPT_IAADDR; 421 iaaddr->len = 16+4+4; 422 memcpy(iaaddr->data, requested_ipv6, 16); 423 } 424 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len); 425 426 /* Add options: 427 * "param req" option according to -O, options specified with -x 428 */ 429 opt_ptr = add_d6_client_options(opt_ptr); 430 431 bb_info_msg("Sending discover..."); 432 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 433} 434 435/* Multicast a DHCPv6 request message 436 * 437 * RFC 3315 18.1.1. Creation and Transmission of Request Messages 438 * 439 * The client uses a Request message to populate IAs with addresses and 440 * obtain other configuration information. The client includes one or 441 * more IA options in the Request message. The server then returns 442 * addresses and other information about the IAs to the client in IA 443 * options in a Reply message. 444 * 445 * The client generates a transaction ID and inserts this value in the 446 * "transaction-id" field. 447 * 448 * The client places the identifier of the destination server in a 449 * Server Identifier option. 450 * 451 * The client MUST include a Client Identifier option to identify itself 452 * to the server. The client adds any other appropriate options, 453 * including one or more IA options (if the client is requesting that 454 * the server assign it some network addresses). 455 * 456 * The client MUST include an Option Request option (see section 22.7) 457 * to indicate the options the client is interested in receiving. The 458 * client MAY include options with data values as hints to the server 459 * about parameter values the client would like to have returned. 460 * 461 * The client includes a Reconfigure Accept option (see section 22.20) 462 * indicating whether or not the client is willing to accept Reconfigure 463 * messages from the server. 464 */ 465/* NOINLINE: limit stack usage in caller */ 466static NOINLINE int send_d6_select(uint32_t xid) 467{ 468 struct d6_packet packet; 469 uint8_t *opt_ptr; 470 471 /* Fill in: msg type, client id */ 472 opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); 473 474 /* server id */ 475 opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 476 /* IA NA (contains requested IP) */ 477 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 478 479 /* Add options: 480 * "param req" option according to -O, options specified with -x 481 */ 482 opt_ptr = add_d6_client_options(opt_ptr); 483 484 bb_info_msg("Sending select..."); 485 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 486} 487 488/* Unicast or broadcast a DHCP renew message 489 * 490 * RFC 3315 18.1.3. Creation and Transmission of Renew Messages 491 * 492 * To extend the valid and preferred lifetimes for the addresses 493 * associated with an IA, the client sends a Renew message to the server 494 * from which the client obtained the addresses in the IA containing an 495 * IA option for the IA. The client includes IA Address options in the 496 * IA option for the addresses associated with the IA. The server 497 * determines new lifetimes for the addresses in the IA according to the 498 * administrative configuration of the server. The server may also add 499 * new addresses to the IA. The server may remove addresses from the IA 500 * by setting the preferred and valid lifetimes of those addresses to 501 * zero. 502 * 503 * The server controls the time at which the client contacts the server 504 * to extend the lifetimes on assigned addresses through the T1 and T2 505 * parameters assigned to an IA. 506 * 507 * At time T1 for an IA, the client initiates a Renew/Reply message 508 * exchange to extend the lifetimes on any addresses in the IA. The 509 * client includes an IA option with all addresses currently assigned to 510 * the IA in its Renew message. 511 * 512 * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no 513 * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind 514 * message, respectively, at the client's discretion. 515 * 516 * The client sets the "msg-type" field to RENEW. The client generates 517 * a transaction ID and inserts this value in the "transaction-id" 518 * field. 519 * 520 * The client places the identifier of the destination server in a 521 * Server Identifier option. 522 * 523 * The client MUST include a Client Identifier option to identify itself 524 * to the server. The client adds any appropriate options, including 525 * one or more IA options. The client MUST include the list of 526 * addresses the client currently has associated with the IAs in the 527 * Renew message. 528 * 529 * The client MUST include an Option Request option (see section 22.7) 530 * to indicate the options the client is interested in receiving. The 531 * client MAY include options with data values as hints to the server 532 * about parameter values the client would like to have returned. 533 */ 534/* NOINLINE: limit stack usage in caller */ 535static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) 536{ 537 struct d6_packet packet; 538 uint8_t *opt_ptr; 539 540 /* Fill in: msg type, client id */ 541 opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); 542 543 /* server id */ 544 opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 545 /* IA NA (contains requested IP) */ 546 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 547 548 /* Add options: 549 * "param req" option according to -O, options specified with -x 550 */ 551 opt_ptr = add_d6_client_options(opt_ptr); 552 553 bb_info_msg("Sending renew..."); 554 if (server_ipv6) 555 return d6_send_kernel_packet( 556 &packet, (opt_ptr - (uint8_t*) &packet), 557 our_cur_ipv6, CLIENT_PORT6, 558 server_ipv6, SERVER_PORT6 559 ); 560 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 561} 562 563/* Unicast a DHCP release message */ 564static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) 565{ 566 struct d6_packet packet; 567 uint8_t *opt_ptr; 568 569 /* Fill in: msg type, client id */ 570 opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); 571 /* server id */ 572 opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 573 /* IA NA (contains our current IP) */ 574 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 575 576 bb_info_msg("Sending release..."); 577 return d6_send_kernel_packet( 578 &packet, (opt_ptr - (uint8_t*) &packet), 579 our_cur_ipv6, CLIENT_PORT6, 580 server_ipv6, SERVER_PORT6 581 ); 582} 583 584/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ 585/* NOINLINE: limit stack usage in caller */ 586static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6 587 UNUSED_PARAM 588 , struct d6_packet *d6_pkt, int fd) 589{ 590 int bytes; 591 struct ip6_udp_d6_packet packet; 592 593 bytes = safe_read(fd, &packet, sizeof(packet)); 594 if (bytes < 0) { 595 log1("Packet read error, ignoring"); 596 /* NB: possible down interface, etc. Caller should pause. */ 597 return bytes; /* returns -1 */ 598 } 599 600 if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) { 601 log1("Packet is too short, ignoring"); 602 return -2; 603 } 604 605 if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) { 606 /* packet is bigger than sizeof(packet), we did partial read */ 607 log1("Oversized packet, ignoring"); 608 return -2; 609 } 610 611 /* ignore any extra garbage bytes */ 612 bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen); 613 614 /* make sure its the right packet for us, and that it passes sanity checks */ 615 if (packet.ip6.ip6_nxt != IPPROTO_UDP 616 || (packet.ip6.ip6_vfc >> 4) != 6 617 || packet.udp.dest != htons(CLIENT_PORT6) 618 /* || bytes > (int) sizeof(packet) - can't happen */ 619 || packet.udp.len != packet.ip6.ip6_plen 620 ) { 621 log1("Unrelated/bogus packet, ignoring"); 622 return -2; 623 } 624 625//How to do this for ipv6? 626// /* verify UDP checksum. IP header has to be modified for this */ 627// memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); 628// /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ 629// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ 630// check = packet.udp.check; 631// packet.udp.check = 0; 632// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { 633// log1("Packet with bad UDP checksum received, ignoring"); 634// return -2; 635// } 636 637 log1("Received a packet"); 638 d6_dump_packet(&packet.data); 639 640 bytes -= sizeof(packet.ip6) + sizeof(packet.udp); 641 memcpy(d6_pkt, &packet.data, bytes); 642 return bytes; 643} 644 645 646/*** Main ***/ 647 648static int sockfd = -1; 649 650#define LISTEN_NONE 0 651#define LISTEN_KERNEL 1 652#define LISTEN_RAW 2 653static smallint listen_mode; 654 655/* initial state: (re)start DHCP negotiation */ 656#define INIT_SELECTING 0 657/* discover was sent, DHCPOFFER reply received */ 658#define REQUESTING 1 659/* select/renew was sent, DHCPACK reply received */ 660#define BOUND 2 661/* half of lease passed, want to renew it by sending unicast renew requests */ 662#define RENEWING 3 663/* renew requests were not answered, lease is almost over, send broadcast renew */ 664#define REBINDING 4 665/* manually requested renew (SIGUSR1) */ 666#define RENEW_REQUESTED 5 667/* release, possibly manually requested (SIGUSR2) */ 668#define RELEASED 6 669static smallint state; 670 671static int d6_raw_socket(int ifindex) 672{ 673 int fd; 674 struct sockaddr_ll sock; 675 676 /* 677 * Comment: 678 * 679 * I've selected not to see LL header, so BPF doesn't see it, too. 680 * The filter may also pass non-IP and non-ARP packets, but we do 681 * a more complete check when receiving the message in userspace. 682 * 683 * and filter shamelessly stolen from: 684 * 685 * http://www.flamewarmaster.de/software/dhcpclient/ 686 * 687 * There are a few other interesting ideas on that page (look under 688 * "Motivation"). Use of netlink events is most interesting. Think 689 * of various network servers listening for events and reconfiguring. 690 * That would obsolete sending HUP signals and/or make use of restarts. 691 * 692 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>. 693 * License: GPL v2. 694 * 695 * TODO: make conditional? 696 */ 697#if 0 698 static const struct sock_filter filter_instr[] = { 699 /* load 9th byte (protocol) */ 700 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), 701 /* jump to L1 if it is IPPROTO_UDP, else to L4 */ 702 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), 703 /* L1: load halfword from offset 6 (flags and frag offset) */ 704 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), 705 /* jump to L4 if any bits in frag offset field are set, else to L2 */ 706 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), 707 /* L2: skip IP header (load index reg with header len) */ 708 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), 709 /* load udp destination port from halfword[header_len + 2] */ 710 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), 711 /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */ 712 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), 713 /* L3: accept packet */ 714 BPF_STMT(BPF_RET|BPF_K, 0xffffffff), 715 /* L4: discard packet */ 716 BPF_STMT(BPF_RET|BPF_K, 0), 717 }; 718 static const struct sock_fprog filter_prog = { 719 .len = sizeof(filter_instr) / sizeof(filter_instr[0]), 720 /* casting const away: */ 721 .filter = (struct sock_filter *) filter_instr, 722 }; 723#endif 724 725 log1("Opening raw socket on ifindex %d", ifindex); //log2? 726 727 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); 728 log1("Got raw socket fd %d", fd); //log2? 729 730 sock.sll_family = AF_PACKET; 731 sock.sll_protocol = htons(ETH_P_IPV6); 732 sock.sll_ifindex = ifindex; 733 xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); 734 735#if 0 736 if (CLIENT_PORT6 == 546) { 737 /* Use only if standard port is in use */ 738 /* Ignoring error (kernel may lack support for this) */ 739 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, 740 sizeof(filter_prog)) >= 0) 741 log1("Attached filter to raw socket fd %d", fd); // log? 742 } 743#endif 744 745 log1("Created raw socket"); 746 747 return fd; 748} 749 750static void change_listen_mode(int new_mode) 751{ 752 log1("Entering listen mode: %s", 753 new_mode != LISTEN_NONE 754 ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") 755 : "none" 756 ); 757 758 listen_mode = new_mode; 759 if (sockfd >= 0) { 760 close(sockfd); 761 sockfd = -1; 762 } 763 if (new_mode == LISTEN_KERNEL) 764 sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_config.interface); 765 else if (new_mode != LISTEN_NONE) 766 sockfd = d6_raw_socket(client_config.ifindex); 767 /* else LISTEN_NONE: sockfd stays closed */ 768} 769 770/* Called only on SIGUSR1 */ 771static void perform_renew(void) 772{ 773 bb_info_msg("Performing a DHCP renew"); 774 switch (state) { 775 case BOUND: 776 change_listen_mode(LISTEN_KERNEL); 777 case RENEWING: 778 case REBINDING: 779 state = RENEW_REQUESTED; 780 break; 781 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ 782 d6_run_script(NULL, "deconfig"); 783 case REQUESTING: 784 case RELEASED: 785 change_listen_mode(LISTEN_RAW); 786 state = INIT_SELECTING; 787 break; 788 case INIT_SELECTING: 789 break; 790 } 791} 792 793static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) 794{ 795 /* send release packet */ 796 if (state == BOUND || state == RENEWING || state == REBINDING) { 797 bb_info_msg("Unicasting a release"); 798 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ 799 d6_run_script(NULL, "deconfig"); 800 } 801 bb_info_msg("Entering released state"); 802 803 change_listen_mode(LISTEN_NONE); 804 state = RELEASED; 805} 806 807///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 808///{ 809/// uint8_t *storage; 810/// int len = strnlen(str, 255); 811/// storage = xzalloc(len + extra + OPT_DATA); 812/// storage[OPT_CODE] = code; 813/// storage[OPT_LEN] = len + extra; 814/// memcpy(storage + extra + OPT_DATA, str, len); 815/// return storage; 816///} 817 818#if BB_MMU 819static void client_background(void) 820{ 821 bb_daemonize(0); 822 logmode &= ~LOGMODE_STDIO; 823 /* rewrite pidfile, as our pid is different now */ 824 write_pidfile(client_config.pidfile); 825} 826#endif 827 828//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 829//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ 830//usage:#else 831//usage:# define IF_UDHCP_VERBOSE(...) 832//usage:#endif 833//usage:#define udhcpc6_trivial_usage 834//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" 835//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 836//usage:#define udhcpc6_full_usage "\n" 837//usage: IF_LONG_OPTS( 838//usage: "\n -i,--interface IFACE Interface to use (default eth0)" 839//usage: "\n -p,--pidfile FILE Create pidfile" 840//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 841//usage: "\n -B,--broadcast Request broadcast replies" 842//usage: "\n -t,--retries N Send up to N discover packets" 843//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" 844//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" 845//usage: "\n -f,--foreground Run in foreground" 846//usage: USE_FOR_MMU( 847//usage: "\n -b,--background Background if lease is not obtained" 848//usage: ) 849//usage: "\n -n,--now Exit if lease is not obtained" 850//usage: "\n -q,--quit Exit after obtaining lease" 851//usage: "\n -R,--release Release IP on exit" 852//usage: "\n -S,--syslog Log to syslog too" 853//usage: IF_FEATURE_UDHCP_PORT( 854//usage: "\n -P,--client-port N Use port N (default 546)" 855//usage: ) 856////usage: IF_FEATURE_UDHCPC_ARPING( 857////usage: "\n -a,--arping Use arping to validate offered address" 858////usage: ) 859//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" 860//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" 861//usage: "\n -r,--request IP Request this IP address" 862//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 863//usage: "\n Examples of string, numeric, and hex byte opts:" 864//usage: "\n -x hostname:bbox - option 12" 865//usage: "\n -x lease:3600 - option 51 (lease time)" 866//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" 867//usage: IF_UDHCP_VERBOSE( 868//usage: "\n -v Verbose" 869//usage: ) 870//usage: ) 871//usage: IF_NOT_LONG_OPTS( 872//usage: "\n -i IFACE Interface to use (default eth0)" 873//usage: "\n -p FILE Create pidfile" 874//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 875//usage: "\n -B Request broadcast replies" 876//usage: "\n -t N Send up to N discover packets" 877//usage: "\n -T N Pause between packets (default 3 seconds)" 878//usage: "\n -A N Wait N seconds (default 20) after failure" 879//usage: "\n -f Run in foreground" 880//usage: USE_FOR_MMU( 881//usage: "\n -b Background if lease is not obtained" 882//usage: ) 883//usage: "\n -n Exit if lease is not obtained" 884//usage: "\n -q Exit after obtaining lease" 885//usage: "\n -R Release IP on exit" 886//usage: "\n -S Log to syslog too" 887//usage: IF_FEATURE_UDHCP_PORT( 888//usage: "\n -P N Use port N (default 546)" 889//usage: ) 890////usage: IF_FEATURE_UDHCPC_ARPING( 891////usage: "\n -a Use arping to validate offered address" 892////usage: ) 893//usage: "\n -O OPT Request option OPT from server (cumulative)" 894//usage: "\n -o Don't request any options (unless -O is given)" 895//usage: "\n -r IP Request this IP address" 896//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 897//usage: "\n Examples of string, numeric, and hex byte opts:" 898//usage: "\n -x hostname:bbox - option 12" 899//usage: "\n -x lease:3600 - option 51 (lease time)" 900//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" 901//usage: IF_UDHCP_VERBOSE( 902//usage: "\n -v Verbose" 903//usage: ) 904//usage: ) 905//usage: "\nSignals:" 906//usage: "\n USR1 Renew lease" 907//usage: "\n USR2 Release lease" 908 909 910int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 911int udhcpc6_main(int argc UNUSED_PARAM, char **argv) 912{ 913 const char *str_r; 914 IF_FEATURE_UDHCP_PORT(char *str_P;) 915 void *clientid_mac_ptr; 916 llist_t *list_O = NULL; 917 llist_t *list_x = NULL; 918 int tryagain_timeout = 20; 919 int discover_timeout = 3; 920 int discover_retries = 3; 921 struct in6_addr srv6_buf; 922 struct in6_addr ipv6_buf; 923 struct in6_addr *requested_ipv6; 924 uint32_t xid = 0; 925 int packet_num; 926 int timeout; /* must be signed */ 927 unsigned already_waited_sec; 928 unsigned opt; 929 int max_fd; 930 int retval; 931 fd_set rfds; 932 933 /* Default options */ 934 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;) 935 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;) 936 client_config.interface = "eth0"; 937 client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; 938 939 /* Parse command line */ 940 /* O,x: list; -T,-t,-A take numeric param */ 941 opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; 942 IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;) 943 opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f" 944 USE_FOR_MMU("b") 945 ///IF_FEATURE_UDHCPC_ARPING("a") 946 IF_FEATURE_UDHCP_PORT("P:") 947 "v" 948 , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ 949 , &client_config.script /* s */ 950 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ 951 , &list_O 952 , &list_x 953 IF_FEATURE_UDHCP_PORT(, &str_P) 954 IF_UDHCP_VERBOSE(, &dhcp_verbose) 955 ); 956 requested_ipv6 = NULL; 957 if (opt & OPT_r) { 958 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) 959 bb_error_msg_and_die("bad IPv6 address '%s'", str_r); 960 requested_ipv6 = &ipv6_buf; 961 } 962#if ENABLE_FEATURE_UDHCP_PORT 963 if (opt & OPT_P) { 964 CLIENT_PORT6 = xatou16(str_P); 965 SERVER_PORT6 = CLIENT_PORT6 + 1; 966 } 967#endif 968 while (list_O) { 969 char *optstr = llist_pop(&list_O); 970 unsigned n = bb_strtou(optstr, NULL, 0); 971 if (errno || n > 254) { 972 n = udhcp_option_idx(optstr); 973 n = dhcp_optflags[n].code; 974 } 975 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 976 } 977 if (!(opt & OPT_o)) { 978 /* 979 unsigned i, n; 980 for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) { 981 if (dhcp_optflags[i].flags & OPTION_REQ) { 982 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 983 } 984 } 985 */ 986 } 987 while (list_x) { 988 char *optstr = llist_pop(&list_x); 989 char *colon = strchr(optstr, ':'); 990 if (colon) 991 *colon = ' '; 992 /* now it looks similar to udhcpd's config file line: 993 * "optname optval", using the common routine: */ 994 udhcp_str2optset(optstr, &client_config.options); 995 } 996 997 if (udhcp_read_interface(client_config.interface, 998 &client_config.ifindex, 999 NULL, 1000 client_config.client_mac)
1001 ) { 1002 return 1; 1003 } 1004 1005 /* Create client ID based on mac, set clientid_mac_ptr */ 1006 { 1007 struct d6_option *clientid; 1008 clientid = xzalloc(2+2+2+2+6); 1009 clientid->code = D6_OPT_CLIENTID; 1010 clientid->len = 2+2+6; 1011 clientid->data[1] = 3; /* DUID-LL */ 1012 clientid->data[3] = 1; /* ethernet */ 1013 clientid_mac_ptr = clientid->data + 2+2; 1014 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1015 client_config.clientid = (void*)clientid; 1016 } 1017 1018#if !BB_MMU 1019 /* on NOMMU reexec (i.e., background) early */ 1020 if (!(opt & OPT_f)) { 1021 bb_daemonize_or_rexec(0 /* flags */, argv); 1022 logmode = LOGMODE_NONE; 1023 } 1024#endif 1025 if (opt & OPT_S) { 1026 openlog(applet_name, LOG_PID, LOG_DAEMON); 1027 logmode |= LOGMODE_SYSLOG; 1028 } 1029 1030 /* Make sure fd 0,1,2 are open */ 1031 bb_sanitize_stdio(); 1032 /* Equivalent of doing a fflush after every \n */ 1033 setlinebuf(stdout); 1034 /* Create pidfile */ 1035 write_pidfile(client_config.pidfile); 1036 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1037 bb_info_msg("%s (v"BB_VER") started", applet_name); 1038 /* Set up the signal pipe */ 1039 udhcp_sp_setup(); 1040 /* We want random_xid to be random... */ 1041 srand(monotonic_us()); 1042 1043 state = INIT_SELECTING; 1044 d6_run_script(NULL, "deconfig"); 1045 change_listen_mode(LISTEN_RAW); 1046 packet_num = 0; 1047 timeout = 0; 1048 already_waited_sec = 0; 1049 1050 /* Main event loop. select() waits on signal pipe and possibly 1051 * on sockfd. 1052 * "continue" statements in code below jump to the top of the loop. 1053 */ 1054 for (;;) { 1055 struct timeval tv; 1056 struct d6_packet packet; 1057 uint8_t *packet_end; 1058 /* silence "uninitialized!" warning */ 1059 unsigned timestamp_before_wait = timestamp_before_wait; 1060 1061 //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); 1062 1063 /* Was opening raw or udp socket here 1064 * if (listen_mode != LISTEN_NONE && sockfd < 0), 1065 * but on fast network renew responses return faster 1066 * than we open sockets. Thus this code is moved 1067 * to change_listen_mode(). Thus we open listen socket 1068 * BEFORE we send renew request (see "case BOUND:"). */ 1069 1070 max_fd = udhcp_sp_fd_set(&rfds, sockfd); 1071 1072 tv.tv_sec = timeout - already_waited_sec; 1073 tv.tv_usec = 0; 1074 retval = 0; 1075 /* If we already timed out, fall through with retval = 0, else... */ 1076 if ((int)tv.tv_sec > 0) { 1077 log1("Waiting on select %u seconds", (int)tv.tv_sec); 1078 timestamp_before_wait = (unsigned)monotonic_sec(); 1079 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 1080 if (retval < 0) { 1081 /* EINTR? A signal was caught, don't panic */ 1082 if (errno == EINTR) { 1083 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; 1084 continue; 1085 } 1086 /* Else: an error occured, panic! */ 1087 bb_perror_msg_and_die("select"); 1088 } 1089 } 1090 1091 /* If timeout dropped to zero, time to become active: 1092 * resend discover/renew/whatever 1093 */ 1094 if (retval == 0) { 1095 /* When running on a bridge, the ifindex may have changed 1096 * (e.g. if member interfaces were added/removed 1097 * or if the status of the bridge changed). 1098 * Refresh ifindex and client_mac: 1099 */ 1100 if (udhcp_read_interface(client_config.interface, 1101 &client_config.ifindex, 1102 NULL, 1103 client_config.client_mac) 1104 ) { 1105 goto ret0; /* iface is gone? */ 1106 } 1107 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1108 1109 /* We will restart the wait in any case */ 1110 already_waited_sec = 0; 1111 1112 switch (state) { 1113 case INIT_SELECTING: 1114 if (!discover_retries || packet_num < discover_retries) { 1115 if (packet_num == 0) 1116 xid = random_xid(); 1117 /* multicast */ 1118 send_d6_discover(xid, requested_ipv6); 1119 timeout = discover_timeout; 1120 packet_num++; 1121 continue; 1122 } 1123 leasefail: 1124 d6_run_script(NULL, "leasefail"); 1125#if BB_MMU /* -b is not supported on NOMMU */ 1126 if (opt & OPT_b) { /* background if no lease */ 1127 bb_info_msg("No lease, forking to background"); 1128 client_background(); 1129 /* do not background again! */ 1130 opt = ((opt & ~OPT_b) | OPT_f); 1131 } else 1132#endif 1133 if (opt & OPT_n) { /* abort if no lease */ 1134 bb_info_msg("No lease, failing"); 1135 retval = 1; 1136 goto ret; 1137 } 1138 /* wait before trying again */ 1139 timeout = tryagain_timeout; 1140 packet_num = 0; 1141 continue; 1142 case REQUESTING: 1143 if (!discover_retries || packet_num < discover_retries) { 1144 /* send multicast select packet */ 1145 send_d6_select(xid); 1146 timeout = discover_timeout; 1147 packet_num++; 1148 continue; 1149 } 1150 /* Timed out, go back to init state. 1151 * "discover...select...discover..." loops 1152 * were seen in the wild. Treat them similarly 1153 * to "no response to discover" case */ 1154 change_listen_mode(LISTEN_RAW); 1155 state = INIT_SELECTING; 1156 goto leasefail; 1157 case BOUND: 1158 /* 1/2 lease passed, enter renewing state */ 1159 state = RENEWING; 1160 client_config.first_secs = 0; /* make secs field count from 0 */ 1161 change_listen_mode(LISTEN_KERNEL); 1162 log1("Entering renew state"); 1163 /* fall right through */ 1164 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ 1165 case_RENEW_REQUESTED: 1166 case RENEWING: 1167 if (timeout > 60) { 1168 /* send an unicast renew request */ 1169 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind 1170 * a new UDP socket for sending inside send_renew. 1171 * I hazard to guess existing listening socket 1172 * is somehow conflicting with it, but why is it 1173 * not deterministic then?! Strange. 1174 * Anyway, it does recover by eventually failing through 1175 * into INIT_SELECTING state. 1176 */ 1177 send_d6_renew(xid, &srv6_buf, requested_ipv6); 1178 timeout >>= 1; 1179 continue; 1180 } 1181 /* Timed out, enter rebinding state */ 1182 log1("Entering rebinding state"); 1183 state = REBINDING; 1184 /* fall right through */ 1185 case REBINDING: 1186 /* Switch to bcast receive */ 1187 change_listen_mode(LISTEN_RAW); 1188 /* Lease is *really* about to run out, 1189 * try to find DHCP server using broadcast */ 1190 if (timeout > 0) { 1191 /* send a broadcast renew request */ 1192 send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); 1193 timeout >>= 1; 1194 continue; 1195 } 1196 /* Timed out, enter init state */ 1197 bb_info_msg("Lease lost, entering init state"); 1198 d6_run_script(NULL, "deconfig"); 1199 state = INIT_SELECTING; 1200 client_config.first_secs = 0; /* make secs field count from 0 */ 1201 /*timeout = 0; - already is */ 1202 packet_num = 0; 1203 continue; 1204 /* case RELEASED: */ 1205 } 1206 /* yah, I know, *you* say it would never happen */ 1207 timeout = INT_MAX; 1208 continue; /* back to main loop */ 1209 } /* if select timed out */ 1210 1211 /* select() didn't timeout, something happened */ 1212 1213 /* Is it a signal? */ 1214 /* note: udhcp_sp_read checks FD_ISSET before reading */ 1215 switch (udhcp_sp_read(&rfds)) { 1216 case SIGUSR1: 1217 client_config.first_secs = 0; /* make secs field count from 0 */ 1218 already_waited_sec = 0; 1219 perform_renew(); 1220 if (state == RENEW_REQUESTED) { 1221 /* We might be either on the same network 1222 * (in which case renew might work), 1223 * or we might be on a completely different one 1224 * (in which case renew won't ever succeed). 1225 * For the second case, must make sure timeout 1226 * is not too big, or else we can send 1227 * futile renew requests for hours. 1228 * (Ab)use -A TIMEOUT value (usually 20 sec) 1229 * as a cap on the timeout. 1230 */ 1231 if (timeout > tryagain_timeout) 1232 timeout = tryagain_timeout; 1233 goto case_RENEW_REQUESTED; 1234 } 1235 /* Start things over */ 1236 packet_num = 0; 1237 /* Kill any timeouts, user wants this to hurry along */ 1238 timeout = 0; 1239 continue; 1240 case SIGUSR2: 1241 perform_d6_release(&srv6_buf, requested_ipv6); 1242 timeout = INT_MAX; 1243 continue; 1244 case SIGTERM: 1245 bb_info_msg("Received SIGTERM"); 1246 goto ret0; 1247 } 1248 1249 /* Is it a packet? */ 1250 if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) 1251 continue; /* no */ 1252 1253 { 1254 int len; 1255 1256 /* A packet is ready, read it */ 1257 if (listen_mode == LISTEN_KERNEL) 1258 len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd); 1259 else 1260 len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd); 1261 if (len == -1) { 1262 /* Error is severe, reopen socket */ 1263 bb_info_msg("Read error: %s, reopening socket", strerror(errno)); 1264 sleep(discover_timeout); /* 3 seconds by default */ 1265 change_listen_mode(listen_mode); /* just close and reopen */ 1266 } 1267 /* If this packet will turn out to be unrelated/bogus, 1268 * we will go back and wait for next one. 1269 * Be sure timeout is properly decreased. */ 1270 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; 1271 if (len < 0) 1272 continue; 1273 packet_end = (uint8_t*)&packet + len; 1274 } 1275 1276 if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) { 1277 log1("xid %x (our is %x), ignoring packet", 1278 (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid); 1279 continue; 1280 } 1281 1282 switch (state) { 1283 case INIT_SELECTING: 1284 if (packet.d6_msg_type == D6_MSG_ADVERTISE) 1285 goto type_is_ok; 1286 /* DHCPv6 has "Rapid Commit", when instead of Advertise, 1287 * server sends Reply right away. 1288 * Fall through to check for this case. 1289 */ 1290 case REQUESTING: 1291 case RENEWING: 1292 case RENEW_REQUESTED: 1293 case REBINDING: 1294 if (packet.d6_msg_type == D6_MSG_REPLY) { 1295 uint32_t lease_seconds; 1296 struct d6_option *option, *iaaddr; 1297 type_is_ok: 1298 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); 1299 if (option && option->data[4] != 0) { 1300 /* return to init state */ 1301 bb_info_msg("Received DHCP NAK (%u)", option->data[4]); 1302 d6_run_script(&packet, "nak"); 1303 if (state != REQUESTING) 1304 d6_run_script(NULL, "deconfig"); 1305 change_listen_mode(LISTEN_RAW); 1306 sleep(3); /* avoid excessive network traffic */ 1307 state = INIT_SELECTING; 1308 client_config.first_secs = 0; /* make secs field count from 0 */ 1309 requested_ipv6 = NULL; 1310 timeout = 0; 1311 packet_num = 0; 1312 already_waited_sec = 0; 1313 continue; 1314 } 1315 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); 1316 if (!option) { 1317 bb_error_msg("no server ID, ignoring packet"); 1318 continue; 1319 /* still selecting - this server looks bad */ 1320 } 1321//Note: we do not bother comparing server IDs in Advertise and Reply msgs. 1322//server_id variable is used solely for creation of proper server_id option 1323//in outgoing packets. (why DHCPv6 even introduced it is a mystery). 1324 free(client6_data.server_id); 1325 client6_data.server_id = option; 1326 if (packet.d6_msg_type == D6_MSG_ADVERTISE) { 1327 /* enter requesting state */ 1328 state = REQUESTING; 1329 timeout = 0; 1330 packet_num = 0; 1331 already_waited_sec = 0; 1332 continue; 1333 } 1334 /* It's a D6_MSG_REPLY */ 1335/* 1336 * RFC 3315 18.1.8. Receipt of Reply Messages 1337 * 1338 * Upon the receipt of a valid Reply message in response to a Solicit 1339 * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or 1340 * Information-request message, the client extracts the configuration 1341 * information contained in the Reply. The client MAY choose to report 1342 * any status code or message from the status code option in the Reply 1343 * message. 1344 * 1345 * The client SHOULD perform duplicate address detection [17] on each of 1346 * the addresses in any IAs it receives in the Reply message before 1347 * using that address for traffic. If any of the addresses are found to 1348 * be in use on the link, the client sends a Decline message to the 1349 * server as described in section 18.1.7. 1350 * 1351 * If the Reply was received in response to a Solicit (with a Rapid 1352 * Commit option), Request, Renew or Rebind message, the client updates 1353 * the information it has recorded about IAs from the IA options 1354 * contained in the Reply message: 1355 * 1356 * - Record T1 and T2 times. 1357 * 1358 * - Add any new addresses in the IA option to the IA as recorded by 1359 * the client. 1360 * 1361 * - Update lifetimes for any addresses in the IA option that the 1362 * client already has recorded in the IA. 1363 * 1364 * - Discard any addresses from the IA, as recorded by the client, that 1365 * have a valid lifetime of 0 in the IA Address option. 1366 * 1367 * - Leave unchanged any information about addresses the client has 1368 * recorded in the IA but that were not included in the IA from the 1369 * server. 1370 * 1371 * Management of the specific configuration information is detailed in 1372 * the definition of each option in section 22. 1373 * 1374 * If the client receives a Reply message with a Status Code containing 1375 * UnspecFail, the server is indicating that it was unable to process 1376 * the message due to an unspecified failure condition. If the client 1377 * retransmits the original message to the same server to retry the 1378 * desired operation, the client MUST limit the rate at which it 1379 * retransmits the message and limit the duration of the time during 1380 * which it retransmits the message. 1381 * 1382 * When the client receives a Reply message with a Status Code option 1383 * with the value UseMulticast, the client records the receipt of the 1384 * message and sends subsequent messages to the server through the 1385 * interface on which the message was received using multicast. The 1386 * client resends the original message using multicast. 1387 * 1388 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1389 * | OPTION_IA_NA | option-len | 1390 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1391 * | IAID (4 octets) | 1392 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1393 * | T1 | 1394 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1395 * | T2 | 1396 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1397 * | | 1398 * . IA_NA-options . 1399 * . . 1400 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1401 * 1402 * 1403 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1404 * | OPTION_IAADDR | option-len | 1405 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1406 * | | 1407 * | IPv6 address | 1408 * | | 1409 * | | 1410 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1411 * | preferred-lifetime | 1412 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1413 * | valid-lifetime | 1414 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1415 * . . 1416 * . IAaddr-options . 1417 * . . 1418 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1419 */ 1420 free(client6_data.ia_na); 1421 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); 1422 if (!client6_data.ia_na) { 1423 bb_error_msg("no %s option, ignoring packet", "IA_NA"); 1424 continue; 1425 } 1426 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { 1427 bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); 1428 continue; 1429 } 1430 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4, 1431 client6_data.ia_na->data + client6_data.ia_na->len, 1432 D6_OPT_IAADDR 1433 ); 1434 if (!iaaddr) { 1435 bb_error_msg("no %s option, ignoring packet", "IAADDR"); 1436 continue; 1437 } 1438 if (iaaddr->len < (16 + 4 + 4)) { 1439 bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len); 1440 continue; 1441 } 1442 /* Note: the address is sufficiently aligned for cast: 1443 * we _copied_ IA-NA, and copy is always well-aligned. 1444 */ 1445 requested_ipv6 = (struct in6_addr*) iaaddr->data; 1446 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); 1447 lease_seconds = ntohl(lease_seconds); 1448 /* paranoia: must not be too small and not prone to overflows */ 1449 if (lease_seconds < 0x10) 1450 lease_seconds = 0x10; 1451/// TODO: check for 0 lease time? 1452 if (lease_seconds >= 0x10000000) 1453 lease_seconds = 0x0fffffff; 1454 /* enter bound state */ 1455 timeout = lease_seconds / 2; 1456 bb_info_msg("Lease obtained, lease time %u", 1457 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); 1458 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1459 1460 state = BOUND; 1461 change_listen_mode(LISTEN_NONE); 1462 if (opt & OPT_q) { /* quit after lease */ 1463 goto ret0; 1464 } 1465 /* future renew failures should not exit (JM) */ 1466 opt &= ~OPT_n; 1467#if BB_MMU /* NOMMU case backgrounded earlier */ 1468 if (!(opt & OPT_f)) { 1469 client_background(); 1470 /* do not background again! */ 1471 opt = ((opt & ~OPT_b) | OPT_f); 1472 } 1473#endif 1474 already_waited_sec = 0; 1475 continue; /* back to main loop */ 1476 } 1477 continue; 1478 /* case BOUND: - ignore all packets */ 1479 /* case RELEASED: - ignore all packets */ 1480 } 1481 /* back to main loop */ 1482 } /* for (;;) - main loop ends */ 1483 1484 ret0: 1485 if (opt & OPT_R) /* release on quit */ 1486 perform_d6_release(&srv6_buf, requested_ipv6); 1487 retval = 0; 1488 ret: 1489 /*if (client_config.pidfile) - remove_pidfile has its own check */ 1490 remove_pidfile(client_config.pidfile); 1491 return retval; 1492} 1493