X-Git-Url: https://git.decadent.org.uk/gitweb/?p=odhcp6c.git;a=blobdiff_plain;f=src%2Fodhcp6c.c;h=e5e415c98409fc13e1548f20d043f1034f4f3a47;hp=2c5bfad4342f3c4298ef517355b12b512ac89b42;hb=bbcc9cfa44372f58cb33d556d9b7c57f6ee96b61;hpb=0131c7ed248d8a39480afd455de800c242ae5350 diff --git a/src/odhcp6c.c b/src/odhcp6c.c index 2c5bfad..e5e415c 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -43,7 +43,11 @@ static int usage(void); static uint8_t *state_data[_STATE_MAX] = {NULL}; static size_t state_len[_STATE_MAX] = {0}; -static volatile int do_signal = 0; +static volatile bool signal_io = false; +static volatile bool signal_usr1 = false; +static volatile bool signal_usr2 = false; +static volatile bool signal_term = false; + static int urandom_fd = -1, allow_slaac_only = 0; static bool bound = false, release = true; static time_t last_update = 0; @@ -61,12 +65,16 @@ int main(_unused int argc, char* const argv[]) enum odhcp6c_ia_mode ia_na_mode = IA_MODE_TRY; enum odhcp6c_ia_mode ia_pd_mode = IA_MODE_TRY; static struct in6_addr ifid = IN6ADDR_ANY_INIT; - int sol_timeout = 120; + int sol_timeout = DHCPV6_SOL_MAX_RT; + +#ifdef EXT_BFD_PING + int bfd_interval = 0, bfd_loss = 3; +#endif - bool help = false, daemonize = false; + bool help = false, daemonize = false, strict_options = false; int logopt = LOG_PID; int c, request_pd = 0; - while ((c = getopt(argc, argv, "S::N:P:Fc:i:r:s:kt:hedp:")) != -1) { + while ((c = getopt(argc, argv, "S::N:P:FB:c:i:r:Rs:kt:hedp:")) != -1) { switch (c) { case 'S': allow_slaac_only = (optarg) ? atoi(optarg) : -1; @@ -100,6 +108,12 @@ int main(_unused int argc, char* const argv[]) ia_pd_mode = IA_MODE_FORCE; break; +#ifdef EXT_BFD_PING + case 'B': + bfd_interval = atoi(optarg); + break; +#endif + case 'c': l = script_unhexlify(&buf[4], sizeof(buf) - 4, optarg); if (l > 0) { @@ -130,6 +144,10 @@ int main(_unused int argc, char* const argv[]) } break; + case 'R': + strict_options = true; + break; + case 's': script = optarg; break; @@ -175,7 +193,7 @@ int main(_unused int argc, char* const argv[]) signal(SIGUSR2, sighandler); if ((urandom_fd = open("/dev/urandom", O_CLOEXEC | O_RDONLY)) < 0 || - init_dhcpv6(ifname, request_pd, sol_timeout) || + init_dhcpv6(ifname, request_pd, strict_options, sol_timeout) || ra_init(ifname, &ifid) || script_init(script, ifname)) { syslog(LOG_ERR, "failed to initialize: %s", strerror(errno)); return 3; @@ -207,121 +225,139 @@ int main(_unused int argc, char* const argv[]) script_call("started"); - while (do_signal != SIGTERM) { // Main logic + while (!signal_term) { // Main logic odhcp6c_clear_state(STATE_SERVER_ID); odhcp6c_clear_state(STATE_IA_NA); odhcp6c_clear_state(STATE_IA_PD); odhcp6c_clear_state(STATE_SNTP_IP); - odhcp6c_clear_state(STATE_SNTP_FQDN); + odhcp6c_clear_state(STATE_NTP_IP); + odhcp6c_clear_state(STATE_NTP_FQDN); odhcp6c_clear_state(STATE_SIP_IP); odhcp6c_clear_state(STATE_SIP_FQDN); dhcpv6_set_ia_mode(ia_na_mode, ia_pd_mode); bound = false; - // Server candidates need deep-delete - size_t cand_len; - struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len); - for (size_t i = 0; i < cand_len / sizeof(*cand); ++i) { - free(cand[i].ia_na); - free(cand[i].ia_pd); - } - odhcp6c_clear_state(STATE_SERVER_CAND); - syslog(LOG_NOTICE, "(re)starting transaction on %s", ifname); - do_signal = 0; - int res = dhcpv6_request(DHCPV6_MSG_SOLICIT); + signal_usr1 = signal_usr2 = false; + int mode = dhcpv6_request(DHCPV6_MSG_SOLICIT); odhcp6c_signal_process(); - if (res <= 0) { - continue; // Might happen if we got a signal - } else if (res == DHCPV6_STATELESS) { // Stateless mode - while (do_signal == 0 || do_signal == SIGUSR1) { - do_signal = 0; + if (mode < 0) + continue; + + do { + int res = dhcpv6_request(mode == DHCPV6_STATELESS ? + DHCPV6_MSG_INFO_REQ : DHCPV6_MSG_REQUEST); + bool signalled = odhcp6c_signal_process(); + + if (res > 0) + break; + else if (signalled) { + mode = -1; + break; + } + + mode = dhcpv6_promote_server_cand(); + } while (mode > DHCPV6_UNKNOWN); + + if (mode < 0) + continue; + + switch (mode) { + case DHCPV6_STATELESS: + bound = true; + syslog(LOG_NOTICE, "entering stateless-mode on %s", ifname); + + while (!signal_usr2 && !signal_term) { + signal_usr1 = false; + script_call("informed"); + + int res = dhcpv6_poll_reconfigure(); + odhcp6c_signal_process(); + + if (res > 0) + continue; + + if (signal_usr1) { + signal_usr1 = false; // Acknowledged + continue; + } + if (signal_usr2 || signal_term) + break; res = dhcpv6_request(DHCPV6_MSG_INFO_REQ); odhcp6c_signal_process(); - if (do_signal == SIGUSR1) + if (signal_usr1) continue; else if (res < 0) break; - else if (res > 0) - script_call("informed"); - - bound = true; - syslog(LOG_NOTICE, "entering stateless-mode on %s", ifname); - - if (dhcpv6_poll_reconfigure() > 0) - script_call("informed"); } + break; - continue; - } - - // Stateful mode - if (dhcpv6_request(DHCPV6_MSG_REQUEST) <= 0) - continue; - - odhcp6c_signal_process(); - script_call("bound"); - bound = true; - syslog(LOG_NOTICE, "entering stateful-mode on %s", ifname); + case DHCPV6_STATEFUL: + script_call("bound"); + bound = true; + syslog(LOG_NOTICE, "entering stateful-mode on %s", ifname); #ifdef EXT_BFD_PING - bfd_start(ifname, 3, 10); + if (bfd_interval > 0) + bfd_start(ifname, bfd_loss, bfd_interval); #endif - while (do_signal == 0 || do_signal == SIGUSR1) { - // Renew Cycle - // Wait for T1 to expire or until we get a reconfigure - int res = dhcpv6_poll_reconfigure(); - odhcp6c_signal_process(); - if (res > 0) { - script_call("updated"); - continue; - } + while (!signal_usr2 && !signal_term) { + // Renew Cycle + // Wait for T1 to expire or until we get a reconfigure + int res = dhcpv6_poll_reconfigure(); + odhcp6c_signal_process(); + if (res > 0) { + script_call("updated"); + continue; + } - // Handle signal, if necessary - if (do_signal == SIGUSR1) - do_signal = 0; // Acknowledged - else if (do_signal > 0) - break; // Other signal type - - size_t ia_pd_len, ia_na_len, ia_pd_new, ia_na_new; - odhcp6c_get_state(STATE_IA_PD, &ia_pd_len); - odhcp6c_get_state(STATE_IA_NA, &ia_na_len); - - // If we have any IAs, send renew, otherwise request - int r; - if (ia_pd_len == 0 && ia_na_len == 0) - r = dhcpv6_request(DHCPV6_MSG_REQUEST); - else - r = dhcpv6_request(DHCPV6_MSG_RENEW); - odhcp6c_signal_process(); - if (r > 0) { // Renew was succesfull - // Publish updates - script_call("updated"); - continue; // Renew was successful - } + // Handle signal, if necessary + if (signal_usr1) + signal_usr1 = false; // Acknowledged + if (signal_usr2 || signal_term) + break; // Other signal type - odhcp6c_clear_state(STATE_SERVER_ID); // Remove binding + // Send renew as T1 expired + size_t ia_pd_len, ia_na_len; + odhcp6c_get_state(STATE_IA_PD, &ia_pd_len); + odhcp6c_get_state(STATE_IA_NA, &ia_na_len); - // If we have IAs, try rebind otherwise restart - res = dhcpv6_request(DHCPV6_MSG_REBIND); - odhcp6c_signal_process(); + // If we have any IAs, send renew, otherwise request + if (ia_pd_len == 0 && ia_na_len == 0) + res = dhcpv6_request(DHCPV6_MSG_REQUEST); + else + res = dhcpv6_request(DHCPV6_MSG_RENEW); - odhcp6c_get_state(STATE_IA_PD, &ia_pd_new); - odhcp6c_get_state(STATE_IA_NA, &ia_na_new); - if (res <= 0 || (ia_pd_new == 0 && ia_pd_len) || - (ia_na_new == 0 && ia_na_len)) - break; // We lost all our IAs, restart - else if (res > 0) - script_call("rebound"); - } + odhcp6c_signal_process(); + if (res > 0) { // Renew was succesfull + // Publish updates + script_call("updated"); + continue; // Renew was successful + } + odhcp6c_clear_state(STATE_SERVER_ID); // Remove binding + + // If we have IAs, try rebind otherwise restart + res = dhcpv6_request(DHCPV6_MSG_REBIND); + odhcp6c_signal_process(); + + if (res > 0) + script_call("rebound"); + else { #ifdef EXT_BFD_PING - bfd_stop(); + bfd_stop(); #endif + break; + } + } + break; + default: + break; + } size_t ia_pd_len, ia_na_len, server_id_len; odhcp6c_get_state(STATE_IA_PD, &ia_pd_len); @@ -353,9 +389,13 @@ static int usage(void) " -N Mode for requesting addresses [try|force|none]\n" " -P Request IPv6-Prefix (0 = auto)\n" " -F Force IPv6-Prefix\n" +#ifdef EXT_BFD_PING + " -B Enable BFD ping check\n" +#endif " -c Override client-ID (base-16 encoded)\n" " -i Use a custom interface identifier for RA handling\n" " -r Options to be requested (comma-separated)\n" + " -R Do not request any options except those specified with -r\n" " -s