1 /* dhcp6.c - DHCP6 client for dynamic network configuration.
2 *
3 * Copyright 2015 Rajni Kant <rajnikant12345@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 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
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, ...);
dummy(char * format,...)130 static void dummy(char *format, ...)
131 {
132 return;
133 }
134
logit(char * format,...)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
get_mac(uint8_t * mac,char * interface)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
fill_option(uint16_t option_id,uint16_t option_len,uint8_t ** dhmesg)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
fill_clientID()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.
fill_optionRequest()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
fill_elapsedTime()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
fill_iaid()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)
mode_raw()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 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
generate_transection_id()258 static 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
set_timeout(int seconds)268 static void set_timeout(int seconds)
269 {
270 TT.tv.tv_sec = seconds;
271 TT.tv.tv_usec = 100000;
272 }
273
send_msg(int type)274 static 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
get_msg_ptr(uint8_t * data,int data_length,int msgtype)302 uint8_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
check_server_id(uint8_t * data,int data_length)320 static 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
check_client_id(uint8_t * data,int data_length)325 static 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
validate_ids()336 static 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
parse_ia_na(uint8_t * data,int data_length)351 static 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
write_pid(char * path)405 static 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
fill_envp(DHCP_DATA * res)419 static 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.
run_script(DHCP_DATA * res,char * name)430 static 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
lease_fail()468 static 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.
signal_handler(int sig)487 static 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
setup_signal()526 static 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
dhcp6_main(void)535 void 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