/* * Setup expiration timers for SA. This is used for ISAKMP SAs, but also * possible to use for application SAs if the application does not deal * with expirations itself. An example is the Linux FreeS/WAN KLIPS IPsec * stack. */ int sa_setup_expirations(struct sa *sa) { struct timeval expiration; u_int64_t seconds = sa->seconds; /* * Set the soft timeout to a random percentage between 85 & 95 of * the negotiated lifetime to break strictly synchronized * renegotiations. This works better when the randomization is on the * order of processing plus network-roundtrip times, or larger. * I.e. it depends on configuration and negotiated lifetimes. * It is not good to do the decrease on the hard timeout, because then * we may drop our SA before our peer. * XXX Better scheme to come? */ if (!sa->soft_death) { gettimeofday(&expiration, 0); /* * XXX This should probably be configuration controlled * somehow. */ seconds = sa->seconds * (850 + rand_32() % 100) / 1000; LOG_DBG((LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds", sa, seconds)); expiration.tv_sec += seconds; sa->soft_death = timer_add_event("sa_soft_expire", sa_soft_expire, sa, &expiration); if (!sa->soft_death) { /* If we don't give up we might start leaking... */ sa_delete(sa, 1); return -1; } sa_reference(sa); } if (!sa->death) { gettimeofday(&expiration, 0); LOG_DBG((LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds", sa, sa->seconds)); expiration.tv_sec += sa->seconds; sa->death = timer_add_event("sa_hard_expire", sa_hard_expire, sa, &expiration); if (!sa->death) { /* If we don't give up we might start leaking... */ sa_delete(sa, 1); return -1; } sa_reference(sa); } return 0; }
/* Tear down a connection, can be phase 1 or 2. */ static void ui_teardown(char *cmd) { struct sockaddr_in addr; struct sockaddr_in6 addr6; struct sa *sa; int phase; char name[201]; /* If no phase is given, we default to phase 2. */ phase = 2; if (sscanf(cmd, "t main %200s", name) == 1) phase = 1; else if (sscanf(cmd, "t quick %200s", name) == 1) phase = 2; else if (sscanf(cmd, "t %200s", name) != 1) { log_print("ui_teardown: command \"%s\" malformed", cmd); return; } LOG_DBG((LOG_UI, 10, "ui_teardown: teardown connection \"%s\", " "phase %d", name, phase)); bzero(&addr, sizeof(addr)); bzero(&addr6, sizeof(addr6)); if (inet_pton(AF_INET, name, &addr.sin_addr) == 1) { addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; while ((sa = sa_lookup_by_peer((struct sockaddr *)&addr, SA_LEN((struct sockaddr *)&addr), phase)) != 0) { if (sa->name) connection_teardown(sa->name); sa_delete(sa, 1); } } else if (inet_pton(AF_INET6, name, &addr6.sin6_addr) == 1) { addr6.sin6_len = sizeof(addr6); addr6.sin6_family = AF_INET6; while ((sa = sa_lookup_by_peer((struct sockaddr *)&addr6, SA_LEN((struct sockaddr *)&addr6), phase)) != 0) { if (sa->name) connection_teardown(sa->name); sa_delete(sa, 1); } } else { if (phase == 2) connection_teardown(name); while ((sa = sa_lookup_by_name(name, phase)) != 0) sa_delete(sa, 1); } }
/* Teardown all SAs. */ void sa_teardown_all(void) { int i; struct sa *sa, *next = 0; LOG_DBG((LOG_SA, 70, "sa_teardown_all:")); /* Get Phase 2 SAs. */ for (i = 0; i <= bucket_mask; i++) for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = next) { next = LIST_NEXT(sa, link); if (sa->phase == 2) { /* * Teardown the phase 2 SAs by name, similar * to ui_teardown. */ LOG_DBG((LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name ? sa->name : "<unnamed>")); if (sa->name) connection_teardown(sa->name); sa_delete(sa, 1); } } }
static void ui_delete(char *cmd) { char cookies_str[ISAKMP_HDR_COOKIES_LEN * 2 + 1]; char message_id_str[ISAKMP_HDR_MESSAGE_ID_LEN * 2 + 1]; u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN]; u_int8_t message_id_buf[ISAKMP_HDR_MESSAGE_ID_LEN]; u_int8_t *message_id = message_id_buf; struct sa *sa; if (sscanf(cmd, "d %32s %8s", cookies_str, message_id_str) != 2) { log_print("ui_delete: command \"%s\" malformed", cmd); return; } if (strcmp(message_id_str, "-") == 0) message_id = 0; if (hex2raw(cookies_str, cookies, ISAKMP_HDR_COOKIES_LEN) == -1 || (message_id && hex2raw(message_id_str, message_id_buf, ISAKMP_HDR_MESSAGE_ID_LEN) == -1)) { log_print("ui_delete: command \"%s\" has bad arguments", cmd); return; } sa = sa_lookup(cookies, message_id); if (!sa) { log_print("ui_delete: command \"%s\" found no SA", cmd); return; } LOG_DBG((LOG_UI, 20, "ui_delete: deleting SA for cookie \"%s\" msgid \"%s\"", cookies_str, message_id_str)); sa_delete(sa, 1); }
/* SA has passed its best before date. */ static void sa_hard_expire(void *v_sa) { struct sa *sa = v_sa; sa->death = 0; sa_release(sa); if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) == SA_FLAG_STAYALIVE) exchange_establish(sa->name, 0, 0, 1); sa_delete(sa, 1); }
static void daemon_shutdown(void) { /* Perform a (protocol-wise) clean shutdown of the daemon. */ struct sa *sa; if (sigtermed == 1) { log_print("isakmpd: shutting down..."); if (delete_sas && strncmp("no", conf_get_str("General", "Delete-SAs"), 2)) { /* * Delete all active SAs. First IPsec SAs, then * ISAKMPD. Each DELETE is another (outgoing) message. */ while ((sa = sa_find(phase2_sa_check, NULL))) sa_delete(sa, 1); while ((sa = sa_find(phase1_sa_check, NULL))) sa_delete(sa, 1); } /* We only want to do this once. */ sigtermed++; } if (transport_prio_sendqs_empty()) { /* * When the prioritized transport sendq:s are empty, i.e all * the DELETE notifications have been sent, we can shutdown. */ log_packet_stop(); log_print("isakmpd: exit"); exit(0); } }
static void daemon_shutdown (void) { /* Perform a (protocol-wise) clean shutdown of the daemon. */ struct sa *sa; if (sigtermed == 1) { log_print ("isakmpd: shutting down..."); /* Delete all active phase 2 SAs. */ while ((sa = sa_find (phase2_sa_check, NULL))) { /* Each DELETE is another (outgoing) message. */ sa_delete (sa, 1); } sigtermed++; } if (transport_prio_sendqs_empty ()) { /* * When the prioritized transport sendq:s are empty, i.e all * the DELETE notifications have been sent, we can shutdown. */ #ifdef USE_DEBUG log_packet_stop (); #endif /* Remove FIFO and pid files. */ unlink (ui_fifo); unlink (pid_file); log_print ("isakmpd: exit"); exit (0); } }