1 /* dhcp6.c - DHCP6 client for dynamic network configuration. 2 * 3 * Copyright 2015 Rajni Kant <rajnikant12345 (at) gmail.com> 4 * 5 * Not in SUSv4. 6 USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY)) 7 8 config DHCP6 9 bool "dhcp6" 10 default n 11 help 12 usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE] 13 14 Configure network dynamicaly using DHCP. 15 16 -i Interface to use (default eth0) 17 -p Create pidfile 18 -s Run PROG at DHCP events 19 -t Send up to N Solicit packets 20 -T Pause between packets (default 3 seconds) 21 -A Wait N seconds after failure (default 20) 22 -f Run in foreground 23 -b Background if lease is not obtained 24 -n Exit if lease is not obtained 25 -q Exit after obtaining lease 26 -R Release IP on exit 27 -S Log to syslog too 28 -r Request this IP address 29 -v Verbose 30 31 Signals: 32 USR1 Renew current lease 33 USR2 Release current lease 34 */ 35 #define FOR_dhcp6 36 #include "toys.h" 37 #include <linux/sockios.h> 38 #include <linux/if_ether.h> 39 #include <netinet/ip.h> 40 #include <netinet/ip6.h> 41 #include <netinet/udp.h> 42 #include <linux/if_packet.h> 43 #include <syslog.h> 44 45 GLOBALS( 46 char *interface_name, *pidfile, *script; 47 long retry, timeout, errortimeout; 48 char *req_ip; 49 int length, state, request_length, sock, sock1, status, retval, retries; 50 struct timeval tv; 51 uint8_t transction_id[3]; 52 struct sockaddr_in6 input_socket6; 53 ) 54 55 #define DHCP6SOLICIT 1 56 #define DHCP6ADVERTISE 2 // server -> client 57 #define DHCP6REQUEST 3 58 #define DHCP6CONFIRM 4 59 #define DHCP6RENEW 5 60 #define DHCP6REBIND 6 61 #define DHCP6REPLY 7 // server -> client 62 #define DHCP6RELEASE 8 63 #define DHCP6DECLINE 9 64 #define DHCP6RECONFIGURE 10 // server -> client 65 #define DHCP6INFOREQUEST 11 66 #define DHCP6RELAYFLOW 12 // relay -> relay/server 67 #define DHCP6RELAYREPLY 13 // server/relay -> relay 68 69 // DHCPv6 option codes (partial). See RFC 3315 70 #define DHCP6_OPT_CLIENTID 1 71 #define DHCP6_OPT_SERVERID 2 72 #define DHCP6_OPT_IA_NA 3 73 #define DHCP6_OPT_IA_ADDR 5 74 #define DHCP6_OPT_ORO 6 75 #define DHCP6_OPT_PREFERENCE 7 76 #define DHCP6_OPT_ELAPSED_TIME 8 77 #define DHCP6_OPT_RELAY_MSG 9 78 #define DHCP6_OPT_STATUS_CODE 13 79 #define DHCP6_OPT_IA_PD 25 80 #define DHCP6_OPT_IA_PREFIX 26 81 82 #define DHCP6_STATUS_SUCCESS 0 83 #define DHCP6_STATUS_NOADDRSAVAIL 2 84 85 #define DHCP6_DUID_LLT 1 86 #define DHCP6_DUID_EN 2 87 #define DHCP6_DUID_LL 3 88 #define DHCP6_DUID_UUID 4 89 90 #define DHCPC_SERVER_PORT 547 91 #define DHCPC_CLIENT_PORT 546 92 93 #define LOG_SILENT 0x0 94 #define LOG_CONSOLE 0x1 95 #define LOG_SYSTEM 0x2 96 97 typedef struct __attribute__((packed)) dhcp6_msg_s { 98 uint8_t msgtype, transaction_id[3], options[524]; 99 } dhcp6_msg_t; 100 101 typedef struct __attribute__((packed)) optval_duid_llt { 102 uint16_t type; 103 uint16_t hwtype; 104 uint32_t time; 105 uint8_t lladdr[6]; 106 } DUID; 107 108 typedef struct __attribute__((packed)) optval_ia_na { 109 uint32_t iaid, t1, t2; 110 } IA_NA; 111 112 typedef struct __attribute__((packed)) dhcp6_raw_s { 113 struct ip6_hdr iph; 114 struct udphdr udph; 115 dhcp6_msg_t dhcp6; 116 } dhcp6_raw_t; 117 118 typedef struct __attribute__((packed)) dhcp_data_client { 119 uint16_t status_code; 120 uint32_t iaid , t1,t2, pf_lf, va_lf; 121 uint8_t ipaddr[17] ; 122 } DHCP_DATA; 123 124 static DHCP_DATA dhcp_data; 125 static dhcp6_raw_t *mymsg; 126 static dhcp6_msg_t mesg; 127 static DUID *duid; 128 129 static void (*dbg)(char *format, ...); 130 static void dummy(char *format, ...) 131 { 132 return; 133 } 134 135 static void logit(char *format, ...) 136 { 137 int used; 138 char *msg; 139 va_list p, t; 140 uint8_t infomode = LOG_SILENT; 141 142 if (toys.optflags & FLAG_S) infomode |= LOG_SYSTEM; 143 if(toys.optflags & FLAG_v) infomode |= LOG_CONSOLE; 144 va_start(p, format); 145 va_copy(t, p); 146 used = vsnprintf(NULL, 0, format, t); 147 used++; 148 va_end(t); 149 150 msg = xmalloc(used); 151 vsnprintf(msg, used, format, p); 152 va_end(p); 153 154 if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg); 155 if (infomode & LOG_CONSOLE) printf("%s", msg); 156 free(msg); 157 return; 158 } 159 160 static void get_mac(uint8_t *mac, char *interface) 161 { 162 int fd; 163 struct ifreq req; 164 165 if (!mac) return; 166 fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW); 167 req.ifr_addr.sa_family = AF_INET6; 168 xstrncpy(req.ifr_name, interface, IFNAMSIZ); 169 xioctl(fd, SIOCGIFHWADDR, &req); 170 memcpy(mac, req.ifr_hwaddr.sa_data, 6); 171 xclose(fd); 172 } 173 174 static void fill_option(uint16_t option_id, uint16_t option_len, uint8_t **dhmesg) 175 { 176 uint8_t *tmp = *dhmesg; 177 178 *((uint16_t*)tmp) = htons(option_id); 179 *(uint16_t*)(tmp+2) = htons(option_len); 180 *dhmesg += 4; 181 TT.length += 4; 182 } 183 184 static void fill_clientID() 185 { 186 uint8_t *tmp = &mesg.options[TT.length]; 187 188 if(!duid) { 189 uint8_t mac[7] = {0,}; 190 duid = (DUID*)malloc(sizeof(DUID)); 191 duid->type = htons(1); 192 duid->hwtype = htons(1); 193 duid->time = htonl((uint32_t)(time(NULL) - 946684800) & 0xffffffff); 194 fill_option(DHCP6_OPT_CLIENTID,14,&tmp); 195 get_mac(mac, TT.interface_name); 196 memcpy(duid->lladdr,mac, 6); 197 memcpy(tmp,(uint8_t*)duid,sizeof(DUID)); 198 } 199 else { 200 fill_option(DHCP6_OPT_CLIENTID,14,&tmp); 201 memcpy(tmp,(uint8_t*)duid,sizeof(DUID)); 202 } 203 TT.length += sizeof(DUID); 204 } 205 206 // TODO: make it generic for multiple options. 207 static void fill_optionRequest() 208 { 209 uint8_t *tmp = &mesg.options[TT.length]; 210 211 fill_option(DHCP6_OPT_ORO,4,&tmp); 212 *(uint16_t*)(tmp+4) = htons(23); 213 *(uint16_t*)(tmp+6) = htons(24); 214 TT.length += 4; 215 } 216 217 static void fill_elapsedTime() 218 { 219 uint8_t *tmp = &mesg.options[TT.length]; 220 221 fill_option(DHCP6_OPT_ELAPSED_TIME, 2, &tmp); 222 *(uint16_t*)(tmp+6) = htons(0); 223 TT.length += 2; 224 } 225 226 static void fill_iaid() 227 { 228 IA_NA iana; 229 uint8_t *tmp = &mesg.options[TT.length]; 230 231 fill_option(DHCP6_OPT_IA_NA, 12, &tmp); 232 iana.iaid = rand(); 233 iana.t1 = 0xffffffff; 234 iana.t2 = 0xffffffff; 235 memcpy(tmp, (uint8_t*)&iana, sizeof(IA_NA)); 236 TT.length += sizeof(IA_NA); 237 } 238 239 //static void mode_raw(int *sock_t) 240 static void mode_raw() 241 { 242 int constone = 1; 243 struct sockaddr_ll sockll; 244 245 if (TT.sock > 0) xclose(TT.sock); 246 TT.sock = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); 247 248 memset(&sockll, 0, sizeof(sockll)); 249 sockll.sll_family = AF_PACKET; 250 sockll.sll_protocol = htons(ETH_P_IPV6); 251 sockll.sll_ifindex = if_nametoindex(TT.interface_name); 252 if (bind(TT.sock, (struct sockaddr *) &sockll, sizeof(sockll))) { 253 xclose(TT.sock); 254 error_exit("MODE RAW : Bind fail.\n"); 255 } 256 if (setsockopt(TT.sock, SOL_PACKET, PACKET_HOST,&constone, sizeof(int)) < 0) { 257 if (errno != ENOPROTOOPT) error_exit("MODE RAW : Bind fail.\n"); 258 } 259 } 260 261 static void generate_transection_id() 262 { 263 int i, r = rand() % 0xffffff; 264 265 for (i=0; i<3; i++) { 266 TT.transction_id[i] = r%0xff; 267 r = r/10; 268 } 269 } 270 271 static void set_timeout(int seconds) 272 { 273 TT.tv.tv_sec = seconds; 274 TT.tv.tv_usec = 100000; 275 } 276 277 static void send_msg(int type) 278 { 279 struct sockaddr_in6 addr6; 280 int sendlength = 0; 281 282 memset(&addr6, 0, sizeof(addr6)); 283 addr6.sin6_family = AF_INET6; 284 addr6.sin6_port = htons(DHCPC_SERVER_PORT); //SERVER_PORT 285 inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr); 286 mesg.msgtype = type; 287 generate_transection_id(); 288 memcpy(mesg.transaction_id, TT.transction_id, 3); 289 290 if (type == DHCP6SOLICIT) { 291 TT.length = 0; 292 fill_clientID(); 293 fill_optionRequest(); 294 fill_elapsedTime(); 295 fill_iaid(); 296 sendlength = sizeof(dhcp6_msg_t) - 524 + TT.length; 297 } else if (type == DHCP6REQUEST || type == DHCP6RELEASE || type == DHCP6RENEW) 298 sendlength = TT.request_length; 299 dbg("Sending message type: %d\n", type); 300 sendlength = sendto(TT.sock1, &mesg, sendlength , 0,(struct sockaddr *)&addr6, 301 sizeof(struct sockaddr_in6 )); 302 if (sendlength <= 0) dbg("Error in sending message type: %d\n", type); 303 } 304 305 uint8_t *get_msg_ptr(uint8_t *data, int data_length, int msgtype) 306 { 307 uint16_t type = *((uint16_t*)data), length = *((uint16_t*)(data+2)); 308 309 type = ntohs(type); 310 if (type == msgtype) return data; 311 length = ntohs(length); 312 while (type != msgtype) { 313 data_length -= (4 + length); 314 if (data_length <= 0) break; 315 data = data + 4 + length; 316 type = ntohs(*((uint16_t*)data)); 317 length = ntohs(*((uint16_t*)(data+2))); 318 if (type == msgtype) return data; 319 } 320 return NULL; 321 } 322 323 static uint8_t *check_server_id(uint8_t *data, int data_length) 324 { 325 return get_msg_ptr(data, data_length, DHCP6_OPT_SERVERID); 326 } 327 328 static int check_client_id(uint8_t *data, int data_length) 329 { 330 if ((data = get_msg_ptr(data, data_length, DHCP6_OPT_CLIENTID))) { 331 DUID one = *((DUID*)(data+4)); 332 DUID two = *((DUID*)&mesg.options[4]); 333 334 if (!memcmp(&one, &two, sizeof(DUID))) return 1; 335 } 336 return 0; 337 } 338 339 static int validate_ids() 340 { 341 if (!check_server_id(mymsg->dhcp6.options, 342 TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) { 343 dbg("Invalid server id: %d\n"); 344 return 0; 345 } 346 if (!check_client_id(mymsg->dhcp6.options, 347 TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) { 348 dbg("Invalid client id: %d\n"); 349 return 0; 350 } 351 return 1; 352 } 353 354 static void parse_ia_na(uint8_t *data, int data_length) 355 { 356 uint8_t *t = get_msg_ptr(data, data_length, DHCP6_OPT_IA_NA); 357 uint16_t iana_len, content_len = 0; 358 359 memset(&dhcp_data,0,sizeof(dhcp_data)); 360 if (!t) return; 361 362 iana_len = ntohs(*((uint16_t*)(t+2))); 363 dhcp_data.iaid = ntohl(*((uint32_t*)(t+4))); 364 dhcp_data.t1 = ntohl(*((uint32_t*)(t+8))); 365 dhcp_data.t2 = ntohl(*((uint32_t*)(t+12))); 366 t += 16; 367 iana_len -= 12; 368 369 while(iana_len > 0) { 370 uint16_t sub_type = ntohs(*((uint16_t*)(t))); 371 372 switch (sub_type) { 373 case DHCP6_OPT_IA_ADDR: 374 content_len = ntohs(*((uint16_t*)(t+2))); 375 memcpy(dhcp_data.ipaddr,t+4,16); 376 if (TT.state == DHCP6SOLICIT) { 377 if (TT.req_ip) { 378 struct addrinfo *res = NULL; 379 380 if(!getaddrinfo(TT.req_ip, NULL, NULL,&res)) { 381 dbg("Requesting IP: %s\n", TT.req_ip); 382 memcpy (&TT.input_socket6, res->ai_addr, res->ai_addrlen); 383 memcpy(t+4, TT.input_socket6.sin6_addr.__in6_u.__u6_addr8, 16); 384 } else xprintf("Invalid IP: %s\n",TT.req_ip); 385 freeaddrinfo(res); 386 } 387 } 388 dhcp_data.pf_lf = ntohl(*((uint32_t*)(t+20))); 389 dhcp_data.va_lf = ntohl(*((uint32_t*)(t+24))); 390 iana_len -= (content_len + 4); 391 t += (content_len + 4); 392 break; 393 case DHCP6_OPT_STATUS_CODE: 394 content_len = ntohs(*((uint16_t*)(t+2))); 395 dhcp_data.status_code = ntohs(*((uint16_t*)(t+4))); 396 iana_len -= (content_len + 4); 397 t += (content_len + 4); 398 break; 399 default: 400 content_len = ntohs(*((uint16_t*)(t+2))); 401 iana_len -= (content_len + 4); 402 t += (content_len + 4); 403 break; 404 } 405 } 406 } 407 408 static void write_pid(char *path) 409 { 410 int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666); 411 412 if (pidfile > 0) { 413 char pidbuf[12]; 414 415 sprintf(pidbuf, "%u", (unsigned)getpid()); 416 write(pidfile, pidbuf, strlen(pidbuf)); 417 close(pidfile); 418 } 419 } 420 421 // Creates environment pointers from RES to use in script 422 static int fill_envp(DHCP_DATA *res) 423 { 424 int ret = setenv("interface", TT.interface_name, 1); 425 426 if (ret) return ret; 427 inet_ntop(AF_INET6, res->ipaddr, toybuf, INET6_ADDRSTRLEN); 428 ret = setenv("ip",(const char*)toybuf , 1); 429 return ret; 430 } 431 432 // Executes Script NAME. 433 static void run_script(DHCP_DATA *res, char *name) 434 { 435 volatile int error = 0; 436 struct stat sts; 437 pid_t pid; 438 char *argv[3]; 439 char *script = (toys.optflags & FLAG_s) ? TT.script 440 : "/usr/share/dhcp/default.script"; 441 442 if (stat(script, &sts) == -1 && errno == ENOENT) return; 443 if (!res || fill_envp(res)) { 444 dbg("Failed to create environment variables.\n"); 445 return; 446 } 447 dbg("Executing %s %s\n", script, name); 448 argv[0] = (char*)script; 449 argv[1] = (char*)name; 450 argv[2] = NULL; 451 fflush(NULL); 452 453 pid = vfork(); 454 if (pid < 0) { 455 dbg("Fork failed.\n"); 456 return; 457 } 458 if (!pid) { 459 execvp(argv[0], argv); 460 error = errno; 461 _exit(111); 462 } 463 if (error) { 464 waitpid(pid, NULL, 0); 465 errno = error; 466 perror_msg("script exec failed"); 467 } 468 dbg("script complete.\n"); 469 } 470 471 static void lease_fail() 472 { 473 dbg("Lease failed.\n"); 474 run_script(NULL, "leasefail"); 475 if (toys.optflags & FLAG_n) { 476 xclose(TT.sock); 477 xclose(TT.sock1); 478 error_exit("Lease Failed, Exiting."); 479 } 480 if (toys.optflags & FLAG_b) { 481 dbg("Lease failed. Going to daemon mode.\n"); 482 if (daemon(0,0)) perror_exit("daemonize"); 483 if (toys.optflags & FLAG_p) write_pid(TT.pidfile); 484 toys.optflags &= ~FLAG_b; 485 toys.optflags |= FLAG_f; 486 } 487 } 488 489 // Generic signal handler real handling is done in main funcrion. 490 static void signal_handler(int sig) 491 { 492 dbg("Caught signal: %d\n", sig); 493 switch (sig) { 494 case SIGUSR1: 495 dbg("SIGUSR1.\n"); 496 if (TT.state == DHCP6RELEASE || TT.state == DHCP6REQUEST ) { 497 TT.state = DHCP6SOLICIT; 498 set_timeout(0); 499 return; 500 } 501 dbg("SIGUSR1 sending renew.\n"); 502 send_msg(DHCP6RENEW); 503 TT.state = DHCP6RENEW; 504 TT.retries = 0; 505 set_timeout(0); 506 break; 507 case SIGUSR2: 508 dbg("SIGUSR2.\n"); 509 if (TT.state == DHCP6RELEASE) return; 510 if (TT.state != DHCP6CONFIRM ) return; 511 dbg("SIGUSR2 sending release.\n"); 512 send_msg(DHCP6RELEASE); 513 TT.state = DHCP6RELEASE; 514 TT.retries = 0; 515 set_timeout(0); 516 break; 517 case SIGTERM: 518 case SIGINT: 519 dbg((sig == SIGTERM)?"SIGTERM.\n":"SIGINT.\n"); 520 if ((toys.optflags & FLAG_R) && TT.state == DHCP6CONFIRM) 521 send_msg(DHCP6RELEASE); 522 if(sig == SIGINT) exit(0); 523 break; 524 default: break; 525 } 526 } 527 528 // signal setup for SIGUSR1 SIGUSR2 SIGTERM 529 static int setup_signal() 530 { 531 signal(SIGUSR1, signal_handler); 532 signal(SIGUSR2, signal_handler); 533 signal(SIGTERM, signal_handler); 534 signal(SIGINT, signal_handler); 535 return 0; 536 } 537 538 void dhcp6_main(void) 539 { 540 struct sockaddr_in6 sinaddr6; 541 int constone = 1; 542 fd_set rfds; 543 544 srand(time(NULL)); 545 setlinebuf(stdout); 546 dbg = dummy; 547 TT.state = DHCP6SOLICIT; 548 549 if (toys.optflags & FLAG_v) dbg = logit; 550 if (!TT.interface_name) TT.interface_name = "eth0"; 551 if (toys.optflags & FLAG_p) write_pid(TT.pidfile); 552 if (!TT.retry) TT.retry = 3; 553 if (!TT.timeout) TT.timeout = 3; 554 if (!TT.errortimeout) TT.errortimeout = 20; 555 if (toys.optflags & FLAG_S) { 556 openlog("DHCP6 :", LOG_PID, LOG_DAEMON); 557 dbg = logit; 558 } 559 560 dbg("Interface: %s\n", TT.interface_name); 561 dbg("pid file: %s\n", TT.pidfile); 562 dbg("Retry count: %d\n", TT.retry); 563 dbg("Timeout : %d\n", TT.timeout); 564 dbg("Error timeout: %d\n", TT.errortimeout); 565 566 567 568 setup_signal(); 569 TT.sock1 = xsocket(PF_INET6, SOCK_DGRAM, 0); 570 memset(&sinaddr6, 0, sizeof(sinaddr6)); 571 sinaddr6.sin6_family = AF_INET6; 572 sinaddr6.sin6_port = htons(DHCPC_CLIENT_PORT); 573 sinaddr6.sin6_scope_id = if_nametoindex(TT.interface_name); 574 sinaddr6.sin6_addr = in6addr_any ; 575 576 xsetsockopt(TT.sock1, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone)); 577 578 if (bind(TT.sock1, (struct sockaddr *)&sinaddr6, sizeof(sinaddr6))) { 579 xclose(TT.sock1); 580 error_exit("bind failed"); 581 } 582 583 mode_raw(); 584 set_timeout(0); 585 for (;;) { 586 int maxfd = TT.sock; 587 588 if (TT.sock >= 0) FD_SET(TT.sock, &rfds); 589 TT.retval = 0; 590 if ((TT.retval = select(maxfd + 1, &rfds, NULL, NULL, &TT.tv)) < 0) { 591 if(errno == EINTR) continue; 592 perror_exit("Error in select"); 593 } 594 if (!TT.retval) { 595 if (TT.state == DHCP6SOLICIT || TT.state == DHCP6CONFIRM) { 596 dbg("State is solicit, sending solicit packet\n"); 597 run_script(NULL, "deconfig"); 598 send_msg(DHCP6SOLICIT); 599 TT.state = DHCP6SOLICIT; 600 TT.retries++; 601 if(TT.retries > TT.retry) set_timeout(TT.errortimeout); 602 else if (TT.retries == TT.retry) { 603 dbg("State is solicit, retry count is max.\n"); 604 lease_fail(); 605 set_timeout(TT.errortimeout); 606 } else set_timeout(TT.timeout); 607 continue; 608 } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW || 609 TT.state == DHCP6RELEASE) { 610 dbg("State is %d , sending packet\n", TT.state); 611 send_msg(TT.state); 612 TT.retries++; 613 if (TT.retries > TT.retry) set_timeout(TT.errortimeout); 614 else if (TT.retries == TT.retry) { 615 lease_fail(); 616 set_timeout(TT.errortimeout); 617 } else set_timeout(TT.timeout); 618 continue; 619 } 620 } else if (FD_ISSET(TT.sock, &rfds)) { 621 if ((TT.status = read(TT.sock, toybuf, sizeof(toybuf))) <= 0) continue; 622 mymsg = (dhcp6_raw_t*)toybuf; 623 if (ntohs(mymsg->udph.dest) == 546 && 624 !memcmp(mymsg->dhcp6.transaction_id, TT.transction_id, 3)) { 625 if (TT.state == DHCP6SOLICIT) { 626 if (mymsg->dhcp6.msgtype == DHCP6ADVERTISE ) { 627 if (!validate_ids()) { 628 dbg("Invalid id recieved, solicit.\n"); 629 TT.state = DHCP6SOLICIT; 630 continue; 631 } 632 dbg("Got reply to request or solicit.\n"); 633 TT.retries = 0; 634 set_timeout(0); 635 TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg); 636 memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length); 637 parse_ia_na(mesg.options, TT.request_length); 638 dbg("Status code:%d\n", dhcp_data.status_code); 639 inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN); 640 dbg("Advertiesed IP: %s\n", toybuf); 641 TT.state = DHCP6REQUEST; 642 } else { 643 dbg("Invalid solicit.\n"); 644 continue; 645 } 646 } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ) { 647 if (mymsg->dhcp6.msgtype == DHCP6REPLY) { 648 if (!validate_ids()) { 649 dbg("Invalid id recieved, %d.\n", TT.state); 650 TT.state = DHCP6REQUEST; 651 continue; 652 } 653 dbg("Got reply to request or renew.\n"); 654 TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg); 655 memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length); 656 parse_ia_na(mymsg->dhcp6.options, TT.request_length); 657 dbg("Status code:%d\n", dhcp_data.status_code); 658 inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN); 659 dbg("Got IP: %s\n", toybuf); 660 TT.retries = 0; 661 run_script(&dhcp_data, (TT.state == DHCP6REQUEST) ? 662 "request" : "renew"); 663 if (toys.optflags & FLAG_q) { 664 if (toys.optflags & FLAG_R) send_msg(DHCP6RELEASE); 665 break; 666 } 667 TT.state = DHCP6CONFIRM; 668 set_timeout((dhcp_data.va_lf)?dhcp_data.va_lf:INT_MAX); 669 dbg("Setting timeout to intmax."); 670 if (TT.state == DHCP6REQUEST || !(toys.optflags & FLAG_f)) { 671 dbg("Making it a daemon\n"); 672 if (daemon(0,0)) perror_exit("daemonize"); 673 toys.optflags |= FLAG_f; 674 if (toys.optflags & FLAG_p) write_pid(TT.pidfile); 675 } 676 dbg("Making it a foreground.\n"); 677 continue; 678 } else { 679 dbg("Invalid reply.\n"); 680 continue; 681 } 682 } else if (TT.state == DHCP6RELEASE) { 683 dbg("Got reply to release.\n"); 684 run_script(NULL, "release"); 685 set_timeout(INT_MAX); 686 } 687 } 688 } 689 } 690 xclose(TT.sock1); 691 xclose(TT.sock); 692 } 693