toybox/toys/pending/dhcp6.c
<<
>>
Prefs
   1/* dhcp6.c - DHCP6 client for dynamic network configuration.
   2 *
   3 * Copyright 2015 Rajni Kant <rajnikant12345@gmail.com>
   4 *
   5 * Not in SUSv4.
   6USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
   7
   8config 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 dynamically 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
  45GLOBALS(
  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  
  97typedef struct __attribute__((packed)) dhcp6_msg_s {
  98  uint8_t msgtype, transaction_id[3], options[524];
  99} dhcp6_msg_t;
 100
 101typedef 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
 108typedef struct __attribute__((packed)) optval_ia_na {
 109  uint32_t iaid, t1, t2;
 110} IA_NA;
 111
 112typedef 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
 118typedef 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
 124static DHCP_DATA dhcp_data;
 125static dhcp6_raw_t *mymsg;
 126static dhcp6_msg_t mesg;
 127static DUID *duid;
 128
 129static void (*dbg)(char *format, ...);
 130static void dummy(char *format, ...)
 131{
 132  return;
 133}
 134
 135static 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
 160static 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
 174static 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
 184static 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.
 207static 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
 217static 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
 226static 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)
 240static 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  xbind(TT.sock, (struct sockaddr *) &sockll, sizeof(sockll));
 253  if (setsockopt(TT.sock, SOL_PACKET, PACKET_HOST,&constone, sizeof(int)) < 0) {
 254    if (errno != ENOPROTOOPT) error_exit("MODE RAW : Bind fail.\n");
 255  }
 256}
 257
 258static void generate_transection_id() 
 259{
 260  int i, r = rand() % 0xffffff;
 261  
 262  for (i=0; i<3; i++) {
 263    TT.transction_id[i] = r%0xff;
 264    r = r/10;
 265  }  
 266}
 267
 268static void set_timeout(int seconds) 
 269{
 270  TT.tv.tv_sec = seconds;
 271  TT.tv.tv_usec = 100000;
 272}
 273
 274static void  send_msg(int type)
 275{
 276  struct sockaddr_in6 addr6;
 277  int sendlength = 0;
 278  
 279  memset(&addr6, 0, sizeof(addr6));
 280  addr6.sin6_family = AF_INET6;
 281  addr6.sin6_port = htons(DHCPC_SERVER_PORT); //SERVER_PORT
 282  inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
 283  mesg.msgtype = type;
 284  generate_transection_id();
 285  memcpy(mesg.transaction_id, TT.transction_id, 3);
 286  
 287  if (type  == DHCP6SOLICIT) {
 288    TT.length = 0;
 289    fill_clientID();
 290    fill_optionRequest();
 291    fill_elapsedTime();
 292    fill_iaid();
 293    sendlength = sizeof(dhcp6_msg_t) - 524 + TT.length;
 294  } else if (type == DHCP6REQUEST || type == DHCP6RELEASE || type == DHCP6RENEW) 
 295    sendlength = TT.request_length;
 296  dbg("Sending message type: %d\n", type);
 297  sendlength = sendto(TT.sock1, &mesg, sendlength , 0,(struct sockaddr *)&addr6,
 298          sizeof(struct sockaddr_in6 ));
 299  if (sendlength <= 0) dbg("Error in sending message type: %d\n", type);
 300}
 301
 302uint8_t *get_msg_ptr(uint8_t *data, int data_length, int msgtype)
 303{
 304  uint16_t type =  *((uint16_t*)data), length = *((uint16_t*)(data+2));
 305  
 306  type = ntohs(type);
 307  if (type == msgtype) return data;
 308  length = ntohs(length);
 309  while (type != msgtype) {
 310    data_length -= (4 + length);
 311    if (data_length <= 0) break;
 312    data = data + 4 + length;
 313    type = ntohs(*((uint16_t*)data));
 314    length = ntohs(*((uint16_t*)(data+2)));
 315    if (type == msgtype) return data;
 316  }
 317  return NULL;
 318}
 319
 320static uint8_t *check_server_id(uint8_t *data, int data_length)
 321{
 322  return get_msg_ptr(data,  data_length, DHCP6_OPT_SERVERID);
 323}
 324
 325static int check_client_id(uint8_t *data, int data_length)
 326{
 327  if ((data = get_msg_ptr(data,  data_length, DHCP6_OPT_CLIENTID))) {
 328    DUID one = *((DUID*)(data+4));
 329    DUID two = *((DUID*)&mesg.options[4]);
 330    
 331    if (!memcmp(&one, &two, sizeof(DUID))) return 1;
 332  }
 333  return 0;
 334}
 335
 336static int validate_ids() 
 337{
 338  if (!check_server_id(mymsg->dhcp6.options, 
 339    TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
 340    dbg("Invalid server id: %d\n");
 341    return 0;
 342  }
 343  if (!check_client_id(mymsg->dhcp6.options, 
 344    TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
 345    dbg("Invalid client id: %d\n");
 346    return 0;
 347  }
 348  return 1;
 349}
 350
 351static void parse_ia_na(uint8_t *data, int data_length) 
 352{
 353  uint8_t *t = get_msg_ptr(data, data_length, DHCP6_OPT_IA_NA);
 354  uint16_t iana_len, content_len = 0;
 355  
 356  memset(&dhcp_data,0,sizeof(dhcp_data));
 357  if (!t) return;
 358  
 359  iana_len = ntohs(*((uint16_t*)(t+2)));
 360  dhcp_data.iaid = ntohl(*((uint32_t*)(t+4)));
 361  dhcp_data.t1 = ntohl(*((uint32_t*)(t+8)));
 362  dhcp_data.t2 = ntohl(*((uint32_t*)(t+12)));
 363  t += 16;
 364  iana_len -= 12;
 365  
 366  while(iana_len > 0) {
 367    uint16_t sub_type = ntohs(*((uint16_t*)(t)));
 368    
 369    switch (sub_type) {
 370      case DHCP6_OPT_IA_ADDR:
 371        content_len = ntohs(*((uint16_t*)(t+2)));
 372        memcpy(dhcp_data.ipaddr,t+4,16);
 373        if (TT.state == DHCP6SOLICIT) {
 374          if (TT.req_ip) {
 375            struct addrinfo *res = NULL;
 376            
 377            if(!getaddrinfo(TT.req_ip, NULL, NULL,&res)) {
 378              dbg("Requesting IP: %s\n", TT.req_ip);
 379              memcpy (&TT.input_socket6, res->ai_addr, res->ai_addrlen);
 380              memcpy(t+4, TT.input_socket6.sin6_addr.s6_addr, 16);
 381            } else xprintf("Invalid IP: %s\n",TT.req_ip);
 382            freeaddrinfo(res);
 383          }
 384        }
 385        dhcp_data.pf_lf = ntohl(*((uint32_t*)(t+20)));
 386        dhcp_data.va_lf = ntohl(*((uint32_t*)(t+24)));
 387        iana_len -= (content_len + 4);
 388        t += (content_len + 4);
 389        break;
 390      case DHCP6_OPT_STATUS_CODE:
 391        content_len = ntohs(*((uint16_t*)(t+2)));
 392        dhcp_data.status_code = ntohs(*((uint16_t*)(t+4)));
 393        iana_len -= (content_len + 4);
 394        t += (content_len + 4);
 395        break;
 396      default:
 397        content_len = ntohs(*((uint16_t*)(t+2)));
 398        iana_len -= (content_len + 4);
 399        t += (content_len + 4);
 400        break;
 401    }
 402  }
 403}
 404
 405static void write_pid(char *path)
 406{
 407  int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
 408  
 409  if (pidfile > 0) {
 410    char pidbuf[12];
 411
 412    sprintf(pidbuf, "%u", (unsigned)getpid());
 413    write(pidfile, pidbuf, strlen(pidbuf));
 414    close(pidfile);
 415  }
 416}
 417
 418// Creates environment pointers from RES to use in script
 419static int fill_envp(DHCP_DATA *res)
 420{
 421  int ret = setenv("interface", TT.interface_name, 1);
 422  
 423  if (ret) return ret;
 424  inet_ntop(AF_INET6, res->ipaddr, toybuf, INET6_ADDRSTRLEN);
 425  ret = setenv("ip",(const char*)toybuf , 1);
 426  return ret;
 427}
 428
 429// Executes Script NAME.
 430static void run_script(DHCP_DATA *res,  char *name)
 431{
 432  volatile int error = 0;
 433  struct stat sts;
 434  pid_t pid;
 435  char *argv[3];  
 436  char *script = (toys.optflags & FLAG_s) ? TT.script
 437    : "/usr/share/dhcp/default.script";
 438
 439  if (stat(script, &sts) == -1 && errno == ENOENT) return;
 440  if (!res || fill_envp(res)) {
 441    dbg("Failed to create environment variables.\n");
 442    return;
 443  }
 444  dbg("Executing %s %s\n", script, name);
 445  argv[0] = (char*)script;
 446  argv[1] = (char*)name;
 447  argv[2] = NULL;
 448  fflush(NULL);
 449
 450  pid = vfork();
 451  if (pid < 0) {
 452    dbg("Fork failed.\n");
 453    return;
 454  }
 455  if (!pid) {
 456    execvp(argv[0], argv);
 457    error = errno;
 458    _exit(111);
 459  }
 460  if (error) {
 461    waitpid(pid, NULL, 0);
 462    errno = error;
 463    perror_msg("script exec failed");
 464  }
 465  dbg("script complete.\n");
 466}
 467
 468static void lease_fail()
 469{
 470  dbg("Lease failed.\n");
 471  run_script(NULL, "leasefail");
 472  if (toys.optflags & FLAG_n) {
 473    xclose(TT.sock);
 474    xclose(TT.sock1);
 475    error_exit("Lease Failed, Exiting.");
 476  }
 477  if (toys.optflags & FLAG_b) {
 478    dbg("Lease failed. Going to daemon mode.\n");
 479    if (daemon(0,0)) perror_exit("daemonize");
 480    if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
 481    toys.optflags &= ~FLAG_b;
 482    toys.optflags |= FLAG_f;
 483  }
 484}
 485
 486// Generic signal handler real handling is done in main funcrion.
 487static void signal_handler(int sig)
 488{
 489    dbg("Caught signal: %d\n", sig);
 490    switch (sig) {
 491    case SIGUSR1:
 492      dbg("SIGUSR1.\n");
 493      if (TT.state == DHCP6RELEASE || TT.state == DHCP6REQUEST ) {
 494        TT.state = DHCP6SOLICIT;
 495        set_timeout(0);
 496        return;
 497      }
 498      dbg("SIGUSR1 sending renew.\n");
 499      send_msg(DHCP6RENEW);
 500      TT.state = DHCP6RENEW;
 501      TT.retries = 0;
 502      set_timeout(0);
 503      break;
 504    case SIGUSR2:
 505      dbg("SIGUSR2.\n");
 506      if (TT.state == DHCP6RELEASE) return;
 507      if (TT.state != DHCP6CONFIRM ) return;
 508      dbg("SIGUSR2 sending release.\n");
 509      send_msg(DHCP6RELEASE);
 510      TT.state = DHCP6RELEASE;
 511      TT.retries = 0;
 512      set_timeout(0);
 513      break;
 514    case SIGTERM:
 515    case SIGINT:
 516      dbg((sig == SIGTERM)?"SIGTERM.\n":"SIGINT.\n");
 517      if ((toys.optflags & FLAG_R) && TT.state == DHCP6CONFIRM)
 518        send_msg(DHCP6RELEASE);
 519      if(sig == SIGINT) exit(0);
 520      break;
 521    default: break;
 522  }
 523}
 524
 525// signal setup for SIGUSR1 SIGUSR2 SIGTERM
 526static int setup_signal()
 527{
 528  signal(SIGUSR1, signal_handler);
 529  signal(SIGUSR2, signal_handler);
 530  signal(SIGTERM, signal_handler);
 531  signal(SIGINT, signal_handler);
 532  return 0;
 533}
 534
 535void dhcp6_main(void)
 536{
 537  struct sockaddr_in6  sinaddr6;
 538  int constone = 1;
 539  fd_set rfds;
 540  
 541  srand(time(NULL));  
 542  setlinebuf(stdout);
 543  dbg = dummy;
 544  TT.state = DHCP6SOLICIT;
 545  
 546  if (toys.optflags & FLAG_v) dbg = logit;
 547  if (!TT.interface_name) TT.interface_name = "eth0";
 548  if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
 549  if (!TT.retry) TT.retry = 3;
 550  if (!TT.timeout) TT.timeout = 3;
 551  if (!TT.errortimeout) TT.errortimeout = 20;
 552  if (toys.optflags & FLAG_S) {
 553    openlog("DHCP6 :", LOG_PID, LOG_DAEMON);
 554    dbg = logit;
 555  }
 556  
 557  dbg("Interface: %s\n", TT.interface_name);
 558  dbg("pid file: %s\n", TT.pidfile);
 559  dbg("Retry count: %d\n", TT.retry);
 560  dbg("Timeout : %d\n", TT.timeout);
 561  dbg("Error timeout: %d\n", TT.errortimeout);
 562  
 563  
 564  
 565  setup_signal();
 566  TT.sock1 = xsocket(PF_INET6, SOCK_DGRAM, 0);  
 567  memset(&sinaddr6, 0, sizeof(sinaddr6));
 568  sinaddr6.sin6_family = AF_INET6;
 569  sinaddr6.sin6_port = htons(DHCPC_CLIENT_PORT);
 570  sinaddr6.sin6_scope_id = if_nametoindex(TT.interface_name);
 571  sinaddr6.sin6_addr = in6addr_any ;
 572  
 573  xsetsockopt(TT.sock1, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
 574  
 575  xbind(TT.sock1, (struct sockaddr *)&sinaddr6, sizeof(sinaddr6));
 576  
 577  mode_raw();
 578  set_timeout(0);
 579  for (;;) {
 580    int maxfd = TT.sock;
 581    
 582    if (TT.sock >= 0) FD_SET(TT.sock, &rfds);
 583    TT.retval = 0;    
 584    if ((TT.retval = select(maxfd + 1, &rfds, NULL, NULL, &TT.tv)) < 0) {
 585      if(errno == EINTR) continue;
 586      perror_exit("Error in select");
 587    }
 588    if (!TT.retval) {
 589      if (TT.state == DHCP6SOLICIT || TT.state == DHCP6CONFIRM) {
 590        dbg("State is solicit, sending solicit packet\n");
 591        run_script(NULL, "deconfig");
 592        send_msg(DHCP6SOLICIT);
 593        TT.state = DHCP6SOLICIT;
 594        TT.retries++;
 595        if(TT.retries > TT.retry) set_timeout(TT.errortimeout);
 596        else if (TT.retries == TT.retry) {
 597          dbg("State is solicit, retry count is max.\n");
 598          lease_fail();
 599          set_timeout(TT.errortimeout);
 600        } else set_timeout(TT.timeout);
 601        continue;
 602      } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW || 
 603              TT.state == DHCP6RELEASE) {
 604        dbg("State is %d , sending packet\n", TT.state);
 605        send_msg(TT.state);
 606        TT.retries++;
 607        if (TT.retries > TT.retry) set_timeout(TT.errortimeout);
 608        else if (TT.retries == TT.retry) {
 609          lease_fail();
 610          set_timeout(TT.errortimeout);
 611        } else set_timeout(TT.timeout);
 612        continue;
 613      }
 614    } else if (FD_ISSET(TT.sock, &rfds)) {
 615      if ((TT.status = read(TT.sock, toybuf, sizeof(toybuf))) <= 0) continue;
 616      mymsg = (dhcp6_raw_t*)toybuf;
 617      if (ntohs(mymsg->udph.dest) == 546 && 
 618              !memcmp(mymsg->dhcp6.transaction_id, TT.transction_id, 3)) {
 619        if (TT.state == DHCP6SOLICIT) {
 620          if (mymsg->dhcp6.msgtype == DHCP6ADVERTISE ) {
 621            if (!validate_ids()) {
 622              dbg("Invalid id received, solicit.\n");
 623              TT.state = DHCP6SOLICIT;
 624              continue;
 625            }
 626            dbg("Got reply to request or solicit.\n");
 627            TT.retries = 0;
 628            set_timeout(0);
 629            TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
 630            memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
 631            parse_ia_na(mesg.options, TT.request_length);
 632            dbg("Status code:%d\n", dhcp_data.status_code);
 633            inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
 634            dbg("Advertiesed IP: %s\n", toybuf);
 635            TT.state = DHCP6REQUEST;
 636          } else {
 637            dbg("Invalid solicit.\n");
 638            continue;
 639          }
 640        } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ) {
 641          if (mymsg->dhcp6.msgtype == DHCP6REPLY) {
 642            if (!validate_ids()) {
 643              dbg("Invalid id received, %d.\n", TT.state);
 644              TT.state = DHCP6REQUEST;
 645              continue;
 646            }
 647            dbg("Got reply to request or renew.\n");
 648            TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
 649            memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
 650            parse_ia_na(mymsg->dhcp6.options, TT.request_length);
 651            dbg("Status code:%d\n", dhcp_data.status_code);
 652            inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
 653            dbg("Got IP: %s\n", toybuf);
 654            TT.retries = 0;
 655            run_script(&dhcp_data, (TT.state == DHCP6REQUEST) ?
 656              "request" : "renew");
 657            if (toys.optflags & FLAG_q) {
 658              if (toys.optflags & FLAG_R) send_msg(DHCP6RELEASE);
 659              break;
 660            }
 661            TT.state = DHCP6CONFIRM;
 662            set_timeout((dhcp_data.va_lf)?dhcp_data.va_lf:INT_MAX);
 663            dbg("Setting timeout to intmax.");
 664            if (TT.state == DHCP6REQUEST || !(toys.optflags & FLAG_f)) {
 665              dbg("Making it a daemon\n");
 666              if (daemon(0,0)) perror_exit("daemonize");
 667              toys.optflags |= FLAG_f;
 668              if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
 669            }
 670            dbg("Making it a foreground.\n");
 671            continue;
 672          } else {
 673            dbg("Invalid reply.\n");
 674            continue;
 675          }          
 676        } else if (TT.state == DHCP6RELEASE) {
 677          dbg("Got reply to release.\n");
 678          run_script(NULL, "release");
 679          set_timeout(INT_MAX);
 680        }
 681      }
 682    }
 683  } 
 684  xclose(TT.sock1);
 685  xclose(TT.sock);
 686}
 687