123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- /* dhcp6.c - DHCP6 client for dynamic network configuration.
- *
- * Copyright 2015 Rajni Kant <rajnikant12345@gmail.com>
- *
- * Not in SUSv4.
- USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
- config DHCP6
- bool "dhcp6"
- default n
- help
- usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
- Configure network dynamically using DHCP.
- -i Interface to use (default eth0)
- -p Create pidfile
- -s Run PROG at DHCP events
- -t Send up to N Solicit packets
- -T Pause between packets (default 3 seconds)
- -A Wait N seconds after failure (default 20)
- -f Run in foreground
- -b Background if lease is not obtained
- -n Exit if lease is not obtained
- -q Exit after obtaining lease
- -R Release IP on exit
- -S Log to syslog too
- -r Request this IP address
- -v Verbose
- Signals:
- USR1 Renew current lease
- USR2 Release current lease
- */
- #define FOR_dhcp6
- #include "toys.h"
- #include <linux/sockios.h>
- #include <linux/if_ether.h>
- #include <netinet/ip.h>
- #include <netinet/ip6.h>
- #include <netinet/udp.h>
- #include <linux/if_packet.h>
- #include <syslog.h>
- GLOBALS(
- char *interface_name, *pidfile, *script;
- long retry, timeout, errortimeout;
- char *req_ip;
- int length, state, request_length, sock, sock1, status, retval, retries;
- struct timeval tv;
- uint8_t transction_id[3];
- struct sockaddr_in6 input_socket6;
- )
- #define DHCP6SOLICIT 1
- #define DHCP6ADVERTISE 2 // server -> client
- #define DHCP6REQUEST 3
- #define DHCP6CONFIRM 4
- #define DHCP6RENEW 5
- #define DHCP6REBIND 6
- #define DHCP6REPLY 7 // server -> client
- #define DHCP6RELEASE 8
- #define DHCP6DECLINE 9
- #define DHCP6RECONFIGURE 10 // server -> client
- #define DHCP6INFOREQUEST 11
- #define DHCP6RELAYFLOW 12 // relay -> relay/server
- #define DHCP6RELAYREPLY 13 // server/relay -> relay
- // DHCPv6 option codes (partial). See RFC 3315
- #define DHCP6_OPT_CLIENTID 1
- #define DHCP6_OPT_SERVERID 2
- #define DHCP6_OPT_IA_NA 3
- #define DHCP6_OPT_IA_ADDR 5
- #define DHCP6_OPT_ORO 6
- #define DHCP6_OPT_PREFERENCE 7
- #define DHCP6_OPT_ELAPSED_TIME 8
- #define DHCP6_OPT_RELAY_MSG 9
- #define DHCP6_OPT_STATUS_CODE 13
- #define DHCP6_OPT_IA_PD 25
- #define DHCP6_OPT_IA_PREFIX 26
- #define DHCP6_STATUS_SUCCESS 0
- #define DHCP6_STATUS_NOADDRSAVAIL 2
- #define DHCP6_DUID_LLT 1
- #define DHCP6_DUID_EN 2
- #define DHCP6_DUID_LL 3
- #define DHCP6_DUID_UUID 4
- #define DHCPC_SERVER_PORT 547
- #define DHCPC_CLIENT_PORT 546
-
- #define LOG_SILENT 0x0
- #define LOG_CONSOLE 0x1
- #define LOG_SYSTEM 0x2
-
- typedef struct __attribute__((packed)) dhcp6_msg_s {
- uint8_t msgtype, transaction_id[3], options[524];
- } dhcp6_msg_t;
- typedef struct __attribute__((packed)) optval_duid_llt {
- uint16_t type;
- uint16_t hwtype;
- uint32_t time;
- uint8_t lladdr[6];
- } DUID;
- typedef struct __attribute__((packed)) optval_ia_na {
- uint32_t iaid, t1, t2;
- } IA_NA;
- typedef struct __attribute__((packed)) dhcp6_raw_s {
- struct ip6_hdr iph;
- struct udphdr udph;
- dhcp6_msg_t dhcp6;
- } dhcp6_raw_t;
- typedef struct __attribute__((packed)) dhcp_data_client {
- uint16_t status_code;
- uint32_t iaid , t1,t2, pf_lf, va_lf;
- uint8_t ipaddr[17] ;
- } DHCP_DATA;
- static DHCP_DATA dhcp_data;
- static dhcp6_raw_t *mymsg;
- static dhcp6_msg_t mesg;
- static DUID *duid;
- static void (*dbg)(char *format, ...);
- static void dummy(char *format, ...)
- {
- return;
- }
- static void logit(char *format, ...)
- {
- int used;
- char *msg;
- va_list p, t;
- uint8_t infomode = LOG_SILENT;
-
- if (toys.optflags & FLAG_S) infomode |= LOG_SYSTEM;
- if(toys.optflags & FLAG_v) infomode |= LOG_CONSOLE;
- va_start(p, format);
- va_copy(t, p);
- used = vsnprintf(NULL, 0, format, t);
- used++;
- va_end(t);
- msg = xmalloc(used);
- vsnprintf(msg, used, format, p);
- va_end(p);
- if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
- if (infomode & LOG_CONSOLE) printf("%s", msg);
- free(msg);
- return;
- }
- static void get_mac(uint8_t *mac, char *interface)
- {
- int fd;
- struct ifreq req;
-
- if (!mac) return;
- fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
- req.ifr_addr.sa_family = AF_INET6;
- xstrncpy(req.ifr_name, interface, IFNAMSIZ);
- xioctl(fd, SIOCGIFHWADDR, &req);
- memcpy(mac, req.ifr_hwaddr.sa_data, 6);
- xclose(fd);
- }
- static void fill_option(uint16_t option_id, uint16_t option_len, uint8_t **dhmesg)
- {
- uint8_t *tmp = *dhmesg;
-
- *((uint16_t*)tmp) = htons(option_id);
- *(uint16_t*)(tmp+2) = htons(option_len);
- *dhmesg += 4;
- TT.length += 4;
- }
- static void fill_clientID()
- {
- uint8_t *tmp = &mesg.options[TT.length];
-
- if(!duid) {
- uint8_t mac[7] = {0,};
- duid = (DUID*)malloc(sizeof(DUID));
- duid->type = htons(1);
- duid->hwtype = htons(1);
- duid->time = htonl((uint32_t)(time(NULL) - 946684800) & 0xffffffff);
- fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
- get_mac(mac, TT.interface_name);
- memcpy(duid->lladdr,mac, 6);
- memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
- }
- else {
- fill_option(DHCP6_OPT_CLIENTID,14,&tmp);
- memcpy(tmp,(uint8_t*)duid,sizeof(DUID));
- }
- TT.length += sizeof(DUID);
- }
- // TODO: make it generic for multiple options.
- static void fill_optionRequest()
- {
- uint8_t *tmp = &mesg.options[TT.length];
-
- fill_option(DHCP6_OPT_ORO,4,&tmp);
- *(uint16_t*)(tmp+4) = htons(23);
- *(uint16_t*)(tmp+6) = htons(24);
- TT.length += 4;
- }
- static void fill_elapsedTime()
- {
- uint8_t *tmp = &mesg.options[TT.length];
-
- fill_option(DHCP6_OPT_ELAPSED_TIME, 2, &tmp);
- *(uint16_t*)(tmp+6) = htons(0);
- TT.length += 2;
- }
- static void fill_iaid()
- {
- IA_NA iana;
- uint8_t *tmp = &mesg.options[TT.length];
-
- fill_option(DHCP6_OPT_IA_NA, 12, &tmp);
- iana.iaid = rand();
- iana.t1 = 0xffffffff;
- iana.t2 = 0xffffffff;
- memcpy(tmp, (uint8_t*)&iana, sizeof(IA_NA));
- TT.length += sizeof(IA_NA);
- }
- //static void mode_raw(int *sock_t)
- static void mode_raw()
- {
- int constone = 1;
- struct sockaddr_ll sockll;
-
- if (TT.sock > 0) xclose(TT.sock);
- TT.sock = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
-
- memset(&sockll, 0, sizeof(sockll));
- sockll.sll_family = AF_PACKET;
- sockll.sll_protocol = htons(ETH_P_IPV6);
- sockll.sll_ifindex = if_nametoindex(TT.interface_name);
- xbind(TT.sock, (struct sockaddr *) &sockll, sizeof(sockll));
- if (setsockopt(TT.sock, SOL_PACKET, PACKET_HOST,&constone, sizeof(int)) < 0) {
- if (errno != ENOPROTOOPT) error_exit("MODE RAW : Bind fail.\n");
- }
- }
- static void generate_transection_id()
- {
- int i, r = rand() % 0xffffff;
-
- for (i=0; i<3; i++) {
- TT.transction_id[i] = r%0xff;
- r = r/10;
- }
- }
- static void set_timeout(int seconds)
- {
- TT.tv.tv_sec = seconds;
- TT.tv.tv_usec = 100000;
- }
- static void send_msg(int type)
- {
- struct sockaddr_in6 addr6;
- int sendlength = 0;
-
- memset(&addr6, 0, sizeof(addr6));
- addr6.sin6_family = AF_INET6;
- addr6.sin6_port = htons(DHCPC_SERVER_PORT); //SERVER_PORT
- inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
- mesg.msgtype = type;
- generate_transection_id();
- memcpy(mesg.transaction_id, TT.transction_id, 3);
-
- if (type == DHCP6SOLICIT) {
- TT.length = 0;
- fill_clientID();
- fill_optionRequest();
- fill_elapsedTime();
- fill_iaid();
- sendlength = sizeof(dhcp6_msg_t) - 524 + TT.length;
- } else if (type == DHCP6REQUEST || type == DHCP6RELEASE || type == DHCP6RENEW)
- sendlength = TT.request_length;
- dbg("Sending message type: %d\n", type);
- sendlength = sendto(TT.sock1, &mesg, sendlength , 0,(struct sockaddr *)&addr6,
- sizeof(struct sockaddr_in6 ));
- if (sendlength <= 0) dbg("Error in sending message type: %d\n", type);
- }
- uint8_t *get_msg_ptr(uint8_t *data, int data_length, int msgtype)
- {
- uint16_t type = *((uint16_t*)data), length = *((uint16_t*)(data+2));
-
- type = ntohs(type);
- if (type == msgtype) return data;
- length = ntohs(length);
- while (type != msgtype) {
- data_length -= (4 + length);
- if (data_length <= 0) break;
- data = data + 4 + length;
- type = ntohs(*((uint16_t*)data));
- length = ntohs(*((uint16_t*)(data+2)));
- if (type == msgtype) return data;
- }
- return NULL;
- }
- static uint8_t *check_server_id(uint8_t *data, int data_length)
- {
- return get_msg_ptr(data, data_length, DHCP6_OPT_SERVERID);
- }
- static int check_client_id(uint8_t *data, int data_length)
- {
- if ((data = get_msg_ptr(data, data_length, DHCP6_OPT_CLIENTID))) {
- DUID one = *((DUID*)(data+4));
- DUID two = *((DUID*)&mesg.options[4]);
-
- if (!memcmp(&one, &two, sizeof(DUID))) return 1;
- }
- return 0;
- }
- static int validate_ids()
- {
- if (!check_server_id(mymsg->dhcp6.options,
- TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
- dbg("Invalid server id: %d\n");
- return 0;
- }
- if (!check_client_id(mymsg->dhcp6.options,
- TT.status - ((char*)&mymsg->dhcp6.options[0] - (char*)mymsg) )) {
- dbg("Invalid client id: %d\n");
- return 0;
- }
- return 1;
- }
- static void parse_ia_na(uint8_t *data, int data_length)
- {
- uint8_t *t = get_msg_ptr(data, data_length, DHCP6_OPT_IA_NA);
- uint16_t iana_len, content_len = 0;
-
- memset(&dhcp_data,0,sizeof(dhcp_data));
- if (!t) return;
-
- iana_len = ntohs(*((uint16_t*)(t+2)));
- dhcp_data.iaid = ntohl(*((uint32_t*)(t+4)));
- dhcp_data.t1 = ntohl(*((uint32_t*)(t+8)));
- dhcp_data.t2 = ntohl(*((uint32_t*)(t+12)));
- t += 16;
- iana_len -= 12;
-
- while(iana_len > 0) {
- uint16_t sub_type = ntohs(*((uint16_t*)(t)));
-
- switch (sub_type) {
- case DHCP6_OPT_IA_ADDR:
- content_len = ntohs(*((uint16_t*)(t+2)));
- memcpy(dhcp_data.ipaddr,t+4,16);
- if (TT.state == DHCP6SOLICIT) {
- if (TT.req_ip) {
- struct addrinfo *res = NULL;
-
- if(!getaddrinfo(TT.req_ip, NULL, NULL,&res)) {
- dbg("Requesting IP: %s\n", TT.req_ip);
- memcpy (&TT.input_socket6, res->ai_addr, res->ai_addrlen);
- memcpy(t+4, TT.input_socket6.sin6_addr.s6_addr, 16);
- } else xprintf("Invalid IP: %s\n",TT.req_ip);
- freeaddrinfo(res);
- }
- }
- dhcp_data.pf_lf = ntohl(*((uint32_t*)(t+20)));
- dhcp_data.va_lf = ntohl(*((uint32_t*)(t+24)));
- iana_len -= (content_len + 4);
- t += (content_len + 4);
- break;
- case DHCP6_OPT_STATUS_CODE:
- content_len = ntohs(*((uint16_t*)(t+2)));
- dhcp_data.status_code = ntohs(*((uint16_t*)(t+4)));
- iana_len -= (content_len + 4);
- t += (content_len + 4);
- break;
- default:
- content_len = ntohs(*((uint16_t*)(t+2)));
- iana_len -= (content_len + 4);
- t += (content_len + 4);
- break;
- }
- }
- }
- static void write_pid(char *path)
- {
- int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
-
- if (pidfile > 0) {
- char pidbuf[12];
- sprintf(pidbuf, "%u", (unsigned)getpid());
- write(pidfile, pidbuf, strlen(pidbuf));
- close(pidfile);
- }
- }
- // Creates environment pointers from RES to use in script
- static int fill_envp(DHCP_DATA *res)
- {
- int ret = setenv("interface", TT.interface_name, 1);
-
- if (ret) return ret;
- inet_ntop(AF_INET6, res->ipaddr, toybuf, INET6_ADDRSTRLEN);
- ret = setenv("ip",(const char*)toybuf , 1);
- return ret;
- }
- // Executes Script NAME.
- static void run_script(DHCP_DATA *res, char *name)
- {
- volatile int error = 0;
- struct stat sts;
- pid_t pid;
- char *argv[3];
- char *script = (toys.optflags & FLAG_s) ? TT.script
- : "/usr/share/dhcp/default.script";
- if (stat(script, &sts) == -1 && errno == ENOENT) return;
- if (!res || fill_envp(res)) {
- dbg("Failed to create environment variables.\n");
- return;
- }
- dbg("Executing %s %s\n", script, name);
- argv[0] = (char*)script;
- argv[1] = (char*)name;
- argv[2] = NULL;
- fflush(NULL);
- pid = vfork();
- if (pid < 0) {
- dbg("Fork failed.\n");
- return;
- }
- if (!pid) {
- execvp(argv[0], argv);
- error = errno;
- _exit(111);
- }
- if (error) {
- waitpid(pid, NULL, 0);
- errno = error;
- perror_msg("script exec failed");
- }
- dbg("script complete.\n");
- }
- static void lease_fail()
- {
- dbg("Lease failed.\n");
- run_script(NULL, "leasefail");
- if (toys.optflags & FLAG_n) {
- xclose(TT.sock);
- xclose(TT.sock1);
- error_exit("Lease Failed, Exiting.");
- }
- if (toys.optflags & FLAG_b) {
- dbg("Lease failed. Going to daemon mode.\n");
- if (daemon(0,0)) perror_exit("daemonize");
- if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
- toys.optflags &= ~FLAG_b;
- toys.optflags |= FLAG_f;
- }
- }
- // Generic signal handler real handling is done in main funcrion.
- static void signal_handler(int sig)
- {
- dbg("Caught signal: %d\n", sig);
- switch (sig) {
- case SIGUSR1:
- dbg("SIGUSR1.\n");
- if (TT.state == DHCP6RELEASE || TT.state == DHCP6REQUEST ) {
- TT.state = DHCP6SOLICIT;
- set_timeout(0);
- return;
- }
- dbg("SIGUSR1 sending renew.\n");
- send_msg(DHCP6RENEW);
- TT.state = DHCP6RENEW;
- TT.retries = 0;
- set_timeout(0);
- break;
- case SIGUSR2:
- dbg("SIGUSR2.\n");
- if (TT.state == DHCP6RELEASE) return;
- if (TT.state != DHCP6CONFIRM ) return;
- dbg("SIGUSR2 sending release.\n");
- send_msg(DHCP6RELEASE);
- TT.state = DHCP6RELEASE;
- TT.retries = 0;
- set_timeout(0);
- break;
- case SIGTERM:
- case SIGINT:
- dbg((sig == SIGTERM)?"SIGTERM.\n":"SIGINT.\n");
- if ((toys.optflags & FLAG_R) && TT.state == DHCP6CONFIRM)
- send_msg(DHCP6RELEASE);
- if(sig == SIGINT) exit(0);
- break;
- default: break;
- }
- }
- // signal setup for SIGUSR1 SIGUSR2 SIGTERM
- static int setup_signal()
- {
- signal(SIGUSR1, signal_handler);
- signal(SIGUSR2, signal_handler);
- signal(SIGTERM, signal_handler);
- signal(SIGINT, signal_handler);
- return 0;
- }
- void dhcp6_main(void)
- {
- struct sockaddr_in6 sinaddr6;
- int constone = 1;
- fd_set rfds;
-
- srand(time(NULL));
- setlinebuf(stdout);
- dbg = dummy;
- TT.state = DHCP6SOLICIT;
-
- if (toys.optflags & FLAG_v) dbg = logit;
- if (!TT.interface_name) TT.interface_name = "eth0";
- if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
- if (!TT.retry) TT.retry = 3;
- if (!TT.timeout) TT.timeout = 3;
- if (!TT.errortimeout) TT.errortimeout = 20;
- if (toys.optflags & FLAG_S) {
- openlog("DHCP6 :", LOG_PID, LOG_DAEMON);
- dbg = logit;
- }
-
- dbg("Interface: %s\n", TT.interface_name);
- dbg("pid file: %s\n", TT.pidfile);
- dbg("Retry count: %d\n", TT.retry);
- dbg("Timeout : %d\n", TT.timeout);
- dbg("Error timeout: %d\n", TT.errortimeout);
-
-
-
- setup_signal();
- TT.sock1 = xsocket(PF_INET6, SOCK_DGRAM, 0);
- memset(&sinaddr6, 0, sizeof(sinaddr6));
- sinaddr6.sin6_family = AF_INET6;
- sinaddr6.sin6_port = htons(DHCPC_CLIENT_PORT);
- sinaddr6.sin6_scope_id = if_nametoindex(TT.interface_name);
- sinaddr6.sin6_addr = in6addr_any ;
-
- xsetsockopt(TT.sock1, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
-
- xbind(TT.sock1, (struct sockaddr *)&sinaddr6, sizeof(sinaddr6));
-
- mode_raw();
- set_timeout(0);
- for (;;) {
- int maxfd = TT.sock;
-
- if (TT.sock >= 0) FD_SET(TT.sock, &rfds);
- TT.retval = 0;
- if ((TT.retval = select(maxfd + 1, &rfds, NULL, NULL, &TT.tv)) < 0) {
- if(errno == EINTR) continue;
- perror_exit("Error in select");
- }
- if (!TT.retval) {
- if (TT.state == DHCP6SOLICIT || TT.state == DHCP6CONFIRM) {
- dbg("State is solicit, sending solicit packet\n");
- run_script(NULL, "deconfig");
- send_msg(DHCP6SOLICIT);
- TT.state = DHCP6SOLICIT;
- TT.retries++;
- if(TT.retries > TT.retry) set_timeout(TT.errortimeout);
- else if (TT.retries == TT.retry) {
- dbg("State is solicit, retry count is max.\n");
- lease_fail();
- set_timeout(TT.errortimeout);
- } else set_timeout(TT.timeout);
- continue;
- } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ||
- TT.state == DHCP6RELEASE) {
- dbg("State is %d , sending packet\n", TT.state);
- send_msg(TT.state);
- TT.retries++;
- if (TT.retries > TT.retry) set_timeout(TT.errortimeout);
- else if (TT.retries == TT.retry) {
- lease_fail();
- set_timeout(TT.errortimeout);
- } else set_timeout(TT.timeout);
- continue;
- }
- } else if (FD_ISSET(TT.sock, &rfds)) {
- if ((TT.status = read(TT.sock, toybuf, sizeof(toybuf))) <= 0) continue;
- mymsg = (dhcp6_raw_t*)toybuf;
- if (ntohs(mymsg->udph.dest) == 546 &&
- !memcmp(mymsg->dhcp6.transaction_id, TT.transction_id, 3)) {
- if (TT.state == DHCP6SOLICIT) {
- if (mymsg->dhcp6.msgtype == DHCP6ADVERTISE ) {
- if (!validate_ids()) {
- dbg("Invalid id received, solicit.\n");
- TT.state = DHCP6SOLICIT;
- continue;
- }
- dbg("Got reply to request or solicit.\n");
- TT.retries = 0;
- set_timeout(0);
- TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
- memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
- parse_ia_na(mesg.options, TT.request_length);
- dbg("Status code:%d\n", dhcp_data.status_code);
- inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
- dbg("Advertiesed IP: %s\n", toybuf);
- TT.state = DHCP6REQUEST;
- } else {
- dbg("Invalid solicit.\n");
- continue;
- }
- } else if (TT.state == DHCP6REQUEST || TT.state == DHCP6RENEW ) {
- if (mymsg->dhcp6.msgtype == DHCP6REPLY) {
- if (!validate_ids()) {
- dbg("Invalid id received, %d.\n", TT.state);
- TT.state = DHCP6REQUEST;
- continue;
- }
- dbg("Got reply to request or renew.\n");
- TT.request_length = TT.status - ((char*)&mymsg->dhcp6 - (char*)mymsg);
- memcpy((uint8_t*)&mesg, &mymsg->dhcp6, TT.request_length);
- parse_ia_na(mymsg->dhcp6.options, TT.request_length);
- dbg("Status code:%d\n", dhcp_data.status_code);
- inet_ntop(AF_INET6, dhcp_data.ipaddr, toybuf, INET6_ADDRSTRLEN);
- dbg("Got IP: %s\n", toybuf);
- TT.retries = 0;
- run_script(&dhcp_data, (TT.state == DHCP6REQUEST) ?
- "request" : "renew");
- if (toys.optflags & FLAG_q) {
- if (toys.optflags & FLAG_R) send_msg(DHCP6RELEASE);
- break;
- }
- TT.state = DHCP6CONFIRM;
- set_timeout((dhcp_data.va_lf)?dhcp_data.va_lf:INT_MAX);
- dbg("Setting timeout to intmax.");
- if (TT.state == DHCP6REQUEST || !(toys.optflags & FLAG_f)) {
- dbg("Making it a daemon\n");
- if (daemon(0,0)) perror_exit("daemonize");
- toys.optflags |= FLAG_f;
- if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
- }
- dbg("Making it a foreground.\n");
- continue;
- } else {
- dbg("Invalid reply.\n");
- continue;
- }
- } else if (TT.state == DHCP6RELEASE) {
- dbg("Got reply to release.\n");
- run_script(NULL, "release");
- set_timeout(INT_MAX);
- }
- }
- }
- }
- xclose(TT.sock1);
- xclose(TT.sock);
- }
|