/** * DPD Out Initiator * * @param p2st A state struct that is already in phase2 * @return void */ static void dpd_outI(struct state *p1st, struct state *st, bool eroute_care, deltatime_t delay, deltatime_t timeout) { monotime_t nw; monotime_t last; deltatime_t nextdelay; u_int32_t seqno; DBG(DBG_DPD, DBG_log("DPD: processing for state #%lu (\"%s\")", st->st_serialno, st->st_connection->name)); /* If no DPD, then get out of here */ if (!st->hidden_variables.st_peer_supports_dpd) { DBG(DBG_DPD, DBG_log("DPD: peer does not support dpd")); return; } /* If there is no state, there can be no DPD */ if (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)) { DBG(DBG_DPD, DBG_log("DPD: no phase1 state, so no DPD")); return; } /* find out when now is */ nw = mononow(); /* * pick least recent activity value, since with multiple phase 2s, * it may well be that one phase 2 is very active, while the other * for some reason, gets stomped upon by some network screw up. * * (this would only happen if the network was sensitive to different * SPI#, since for NAT-T, all traffic should be on the same UDP port. * At worst, this means that we send a bit more traffic then we need * to when there are multiple SAs and one is much less active. * * ??? the code actually picks the most recent. So much for comments. */ last = !monobefore(p1st->st_last_dpd, st->st_last_dpd) ? p1st->st_last_dpd : st->st_last_dpd; nextdelay = monotimediff(monotimesum(last, delay), nw); /* has there been enough activity of late? */ if (deltasecs(nextdelay) > 0) { /* Yes, just reschedule "phase 2" */ DBG(DBG_DPD, DBG_log("DPD: not yet time for dpd event: %ld < %ld", (long)nw.mono_secs, (long)(last.mono_secs + deltasecs(delay)))); event_schedule(EVENT_DPD, deltasecs(nextdelay), st); return; } /* now plan next check time */ /* ??? this test is nuts: it will always succeed! */ if (deltasecs(nextdelay) < 1) nextdelay = delay; /* * check the phase 2, if we are supposed to, * and return if it is active recently */ if (eroute_care && st->hidden_variables.st_nat_traversal == LEMPTY && !was_eroute_idle(st, delay)) { DBG(DBG_DPD, DBG_log("DPD: out event not sent, phase 2 active")); /* update phase 2 time stamp only */ st->st_last_dpd = nw; /* * Since there was activity, kill any EVENT_DPD_TIMEOUT that might * be waiting. This can happen when a R_U_THERE_ACK is lost, and * subsequently traffic started flowing over the SA again, and no * more DPD packets are sent to cancel the outstanding DPD timer. */ if (p1st->st_dpd_event != NULL && p1st->st_dpd_event->ev_type == EVENT_DPD_TIMEOUT) { DBG(DBG_DPD, DBG_log("DPD: deleting p1st DPD event")); delete_dpd_event(p1st); } event_schedule(EVENT_DPD, deltasecs(nextdelay), st); return; } if (st != p1st) { /* * reschedule next event, since we cannot do it from the activity * routine. */ event_schedule(EVENT_DPD, deltasecs(nextdelay), st); } if (p1st->st_dpd_seqno == 0) { /* Get a non-zero random value that has room to grow */ get_rnd_bytes((u_char *)&p1st->st_dpd_seqno, sizeof(p1st->st_dpd_seqno)); p1st->st_dpd_seqno &= 0x7fff; p1st->st_dpd_seqno++; } seqno = htonl(p1st->st_dpd_seqno); /* make sure that the timeout occurs. We do this before the send, * because the send may fail due to network issues, etc, and * the timeout has to occur anyway */ dpd_sched_timeout(p1st, nw, timeout); DBG(DBG_DPD, { ipstr_buf b; DBG_log("DPD: sending R_U_THERE %u to %s:%d (state #%lu)", p1st->st_dpd_seqno, ipstr(&p1st->st_remoteaddr, &b), p1st->st_remoteport, p1st->st_serialno); });
/** * DPD Out Initiator * * @param p2st A state struct that is already in phase2 * @return void */ static void dpd_outI(struct state *p1st, struct state *st, bool eroute_care ,time_t delay, time_t timeout) { time_t tm; time_t last; u_int32_t seqno; bool eroute_idle; time_t nextdelay; DBG(DBG_DPD, DBG_log("processing dpd for state #%lu (\"%s\")" , st->st_serialno , st->st_connection->name)); /* If no DPD, then get out of here */ if (!st->hidden_variables.st_dpd) return; /* If there is no state, there can be no DPD */ if (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)) return; /* find out when now is */ tm = now(); /* * pick least recent activity value, since with multiple phase 2s, * it may well be that one phase 2 is very active, while the other * for some reason, gets stomped upon by some network screw up. * * (this would only happen if the network was sensitive to different * SPI#, since for NAT-T, all traffic should be on the same UDP port. * At worst, this means that we send a bit more traffic then we need * to when there are multiple SAs and one is much less active. * */ last = (p1st->st_last_dpd > st->st_last_dpd ? st->st_last_dpd : p1st->st_last_dpd ); nextdelay = p1st->st_last_dpd + delay - tm; /* has there been enough activity of late? */ if(nextdelay > 0) { /* Yes, just reschedule "phase 2" */ DBG(DBG_DPD, DBG_log("not yet time for dpd event: %lu < %lu" , (unsigned long)tm , (unsigned long)(p1st->st_last_dpd + delay))); event_schedule(EVENT_DPD, nextdelay, st); return; } /* now plan next check time */ if(nextdelay < 1) { nextdelay = delay; } /* * check the phase 2, if we are supposed to, * and return if it is active recently */ if(eroute_care && !st->hidden_variables.st_nat_traversal) { eroute_idle = was_eroute_idle(st, delay); if(!eroute_idle) { DBG(DBG_DPD, DBG_log("dpd out event not sent, phase 2 active")); /* update phase 2 time stamp only */ st->st_last_dpd = tm; event_schedule(EVENT_DPD, nextdelay, st); return; } } if(st != p1st) { /* * reschedule next event, since we can not do it from the activity * routine. */ event_schedule(EVENT_DPD, nextdelay, st); } if (!p1st->st_dpd_seqno) { /* Get a non-zero random value that has room to grow */ get_rnd_bytes((u_char *)&p1st->st_dpd_seqno , sizeof(p1st->st_dpd_seqno)); p1st->st_dpd_seqno &= 0x7fff; p1st->st_dpd_seqno++; } seqno = htonl(p1st->st_dpd_seqno); /* make sure that the timeout occurs. We do this before the send, * because the send may fail due to network issues, etc, and * the timeout has to occur anyway */ dpd_sched_timeout(p1st, tm, timeout); DBG(DBG_DPD, DBG_log("sending R_U_THERE %u to %s:%d (state #%lu)" , seqno , ip_str(&p1st->st_remoteaddr) , p1st->st_remoteport , p1st->st_serialno)); if (send_isakmp_notification(p1st, R_U_THERE , &seqno, sizeof(seqno)) != STF_IGNORE) { loglog(RC_LOG_SERIOUS, "DPD Error: could not send R_U_THERE"); return; } st->st_last_dpd = tm; p1st->st_last_dpd = tm; p1st->st_dpd_expectseqno = p1st->st_dpd_seqno++; }