dhcp6.c 19 KB

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