/***************************************************************************************** 函数名称: dpd_timeout 功能描述: dpd超时处理,删除连接 输入参数: st 输出参数: 无 返 回 值: 无 ------------------------------------------------------------------------------------------- 最近一次修改记录 : 修改作者: 王之云 修改目的: 超时处理 修改日期: 2012年3月20日 ********************************************************************************************/ void dpd_timeout(struct state *st) { int action; struct ike_conn *c = st->st_connection; action = st->st_connection->dpd_action; so_serial_t newest = c->newest_isakmp_sa ; char buf_remoteip[20] = {0}; st->st_dpd_timeout_flag = 1; addrtot(&st->st_remoteaddr, 0, buf_remoteip, sizeof(buf_remoteip)); passert(IS_ISAKMP_SA_ESTABLISHED(st->st_state)); passert(action == DPD_ACTION_HOLD || action == DPD_ACTION_CLEAR || action == DPD_ACTION_RESTART || action == DPD_ACTION_RESTART_BY_PEER); if (newest != st->st_serialno && newest != SOS_NOBODY) { IPSEC_log(IPSEC_LOGLEVEL_WARNING, "Connection < %s > < %s > old state DPD TIMEOUT, " "We will delete state depend on it.!", st->st_connection->name, buf_remoteip); ipsec_release_state_by_parent(st); delete_state(st); return; } { IPSEC_log(IPSEC_LOGLEVEL_WARNING, "Connection < %s > < %s > DPD TIMEOUT, we will %s connection!", st->st_connection->name, buf_remoteip, action == DPD_ACTION_CLEAR ? "clear":"restart"); } switch(action) { case DPD_ACTION_CLEAR: release_connection(&c); break; case DPD_ACTION_RESTART: release_connection(&c); if(NULL != c) { start_initiate_connnection(c); } break; case DPD_ACTION_HOLD: case DPD_ACTION_RESTART_BY_PEER: /*未用到此两种情况*/ break; default : break; } }
static void connection_state(struct state *st, void *data) { struct log_conn_info *lc = data; if (!st || st == lc->ignore || !st->st_connection || !lc->conn) return; if (st->st_connection != lc->conn) { if (lc->conn->IPhost_pair != st->st_connection->IPhost_pair || !same_peer_ids(lc->conn, st->st_connection, NULL)) return; /* phase1 is shared with another connnection */ } /* ignore undefined states (ie., just deleted) */ if (st->st_state == STATE_UNDEFINED) return; if (IS_PHASE1(st->st_state)) { if (lc->tunnel < tun_phase1) lc->tunnel = tun_phase1; if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { if (lc->tunnel < tun_phase1up) lc->tunnel = tun_phase1up; lc->phase1 = p1_up; } else { if (lc->phase1 < p1_init) lc->phase1 = p1_init; if (IS_ISAKMP_ENCRYPTED(st->st_state) && lc->phase1 < p1_encrypt) lc->phase1 = p1_encrypt; if (IS_ISAKMP_AUTHENTICATED(st->st_state) && lc->phase1 < p1_auth) lc->phase1 = p1_auth; } } else lc->phase1 = p1_down; /* only phase one shares across connections, so we can quit now */ if (st->st_connection != lc->conn) return; if (IS_PHASE15(st->st_state)) { if (lc->tunnel < tun_phase15) lc->tunnel = tun_phase15; } if (IS_QUICK(st->st_state)) { if (lc->tunnel < tun_phase2) lc->tunnel = tun_phase2; if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { if (lc->tunnel < tun_up) lc->tunnel = tun_up; lc->phase2 = p2_up; } else { if (lc->phase2 < p2_neg) lc->phase2 = p2_neg; } } }
/* * delete all states that were created for a given connection, * additionally delete any states for which func(st, arg) * returns true. */ static void foreach_states_by_connection_func(struct connection *c , bool (*comparefunc)(struct state *st, struct connection *c, void *arg, int pass) , void (*successfunc)(struct state *st, struct connection *c, void *arg) , void *arg) { int pass; /* this kludge avoids an n^2 algorithm */ /* We take two passes so that we delete any ISAKMP SAs last. * This allows Delete Notifications to be sent. * ?? We could probably double the performance by caching any * ISAKMP SA states found in the first pass, avoiding a second. */ for (pass = 0; pass != 2; pass++) { int i; /* For each hash chain... */ for (i = 0; i < STATE_TABLE_SIZE; i++) { struct state *st; /* For each state in the hash chain... */ for (st = statetable[i]; st != NULL; ) { struct state *this = st; st = st->st_hashchain_next; /* before this is deleted */ /* on pass 2, ignore phase2 states */ if(pass == 1 && IS_ISAKMP_SA_ESTABLISHED(this->st_state)) { continue; } /* call comparison function */ if ((*comparefunc)(this, c, arg, pass)) { struct state *old_cur_state = cur_state == this? NULL : cur_state; #ifdef DEBUG lset_t old_cur_debugging = cur_debugging; #endif set_cur_state(this); (*successfunc)(this, c, arg); cur_state = old_cur_state; #ifdef DEBUG set_debugging(old_cur_debugging); #endif } } } } }
/** * 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); });
/* delete a state object */ void delete_state(struct state *st) { struct connection *const c = st->st_connection; struct state *old_cur_state = cur_state == st? NULL : cur_state; openswan_log("deleting state #%lu (%s)", st->st_serialno, enum_show(&state_names, st->st_state)); /* * for most IKEv2 things, we may have further things to do after marking the state deleted, * so we do not actually free it here at all, but back in the main loop when all the work is done. */ if(st->st_ikev2) { /* child sa*/ if(st->st_clonedfrom != 0) { DBG(DBG_CONTROL, DBG_log("received request to delete child state")); if(st->st_state == STATE_CHILDSA_DEL) { DBG(DBG_CONTROL, DBG_log("now deleting the child state")); } else { /* Only send request if child sa is established * otherwise continue with deletion */ if(IS_CHILD_SA_ESTABLISHED(st)) { DBG(DBG_CONTROL, DBG_log("sending Child SA delete equest")); send_delete(st); change_state(st, STATE_CHILDSA_DEL); /* actual deletion when we receive peer response*/ return; } } } else { DBG(DBG_CONTROL, DBG_log("considering request to delete IKE parent state")); /* parent sa */ if(st->st_state == STATE_IKESA_DEL) { DBG(DBG_CONTROL, DBG_log("now deleting the IKE (or parent) state")); } else { /* Another check to verify if a secured * INFORMATIONAL exchange can be sent or not */ if(st->st_skey_ei.ptr && st->st_skey_ai.ptr && st->st_skey_er.ptr && st->st_skey_ar.ptr) { DBG(DBG_CONTROL, DBG_log("sending IKE SA delete request")); send_delete(st); change_state(st, STATE_IKESA_DEL); /* actual deletion when we receive peer response*/ return; } } } } /* If DPD is enabled on this state object, clear any pending events */ if(st->st_dpd_event != NULL) delete_dpd_event(st); /* if there is a suspended state transition, disconnect us */ if (st->st_suspended_md != NULL) { passert(st->st_suspended_md->st == st); DBG(DBG_CONTROL, DBG_log("disconnecting state #%lu from md", st->st_serialno)); st->st_suspended_md->st = NULL; } /* tell the other side of any IPSEC SAs that are going down */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) || IS_ISAKMP_SA_ESTABLISHED(st->st_state)) send_delete(st); delete_event(st); /* delete any pending timer event */ /* Ditch anything pending on ISAKMP SA being established. * Note: this must be done before the unhash_state to prevent * flush_pending_by_state inadvertently and prematurely * deleting our connection. */ flush_pending_by_state(st); /* if there is anything in the cryptographic queue, then remove this * state from it. */ delete_cryptographic_continuation(st); /* effectively, this deletes any ISAKMP SA that this state represents */ unhash_state(st); /* tell kernel to delete any IPSEC SA * ??? we ought to tell peer to delete IPSEC SAs */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) || IS_CHILD_SA_ESTABLISHED(st)) delete_ipsec_sa(st, FALSE); else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) delete_ipsec_sa(st, TRUE); if (c->newest_ipsec_sa == st->st_serialno) c->newest_ipsec_sa = SOS_NOBODY; if (c->newest_isakmp_sa == st->st_serialno) c->newest_isakmp_sa = SOS_NOBODY; /* * fake a state change here while we are still associated with a * connection. Without this the state logging (when enabled) cannot * work out what happened. */ fake_state(st, STATE_UNDEFINED); st->st_connection = NULL; /* we might be about to free it */ cur_state = old_cur_state; /* without st_connection, st isn't complete */ connection_discard(c); change_state(st, STATE_UNDEFINED); release_whack(st); change_state(st, STATE_CHILDSA_DEL); }
/** * DPD out Responder * * @param st A state structure (phase 1) * @param n A notification (isakmp_notification) * @param pbs A PB Stream * @return stf_status */ stf_status dpd_inR(struct state *p1st , struct isakmp_notification *const n , pb_stream *pbs) { time_t tm = now(); u_int32_t seqno; if (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)) { loglog(RC_LOG_SERIOUS, "recevied R_U_THERE_ACK for unestablished ISKAMP SA"); return STF_FAIL; } if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) { loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid SPI length (%d)", n->isan_spisize); return STF_FAIL + PAYLOAD_MALFORMED; } if (memcmp(pbs->cur, p1st->st_icookie, COOKIE_SIZE) != 0) { /* RFC states we *SHOULD* check cookies, not MUST. So invalid cookies are technically valid, as per Geoffrey Huang */ loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid icookie"); } pbs->cur += COOKIE_SIZE; if (memcmp(pbs->cur, p1st->st_rcookie, COOKIE_SIZE) != 0) { /* RFC states we *SHOULD* check cookies, not MUST. So invalid cookies are technically valid, as per Geoffrey Huang */ loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid rcookie (tolerated)"); } pbs->cur += COOKIE_SIZE; if (pbs_left(pbs) != sizeof(seqno)) { loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid data length (%d)", (int) pbs_left(pbs)); return STF_FAIL + PAYLOAD_MALFORMED; } seqno = ntohl(*(u_int32_t *)pbs->cur); DBG(DBG_DPD, DBG_log("R_U_THERE_ACK, seqno received: %u expected: %u (state=#%lu)", seqno, p1st->st_dpd_expectseqno, p1st->st_serialno)); if (!p1st->st_dpd_expectseqno && seqno != p1st->st_dpd_expectseqno) { loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has unexpected sequence number (expected: %u got: %u", seqno, p1st->st_dpd_expectseqno); p1st->st_dpd_expectseqno = 0; /* do not update time stamp, so we'll send a new one sooner */ } else { /* update the time stamp */ p1st->st_last_dpd = tm; } p1st->st_dpd_expectseqno = 0; /* * since there was activity, kill any EVENT_DPD_TIMEOUT that might * be waiting. */ if(p1st->st_dpd_event != NULL && p1st->st_dpd_event->ev_type == EVENT_DPD_TIMEOUT) { delete_dpd_event(p1st); } return STF_IGNORE; }
/** * DPD in Initiator, out Responder * * @param st A state structure (the phase 1 state) * @param n A notification (isakmp_notification) * @param pbs A PB Stream * @return stf_status */ stf_status dpd_inI_outR(struct state *p1st , struct isakmp_notification *const n , pb_stream *pbs) { time_t tm = now(); u_int32_t seqno; if (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)) { loglog(RC_LOG_SERIOUS, "DPD Error: received R_U_THERE for unestablished ISKAMP SA"); return STF_IGNORE; } if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) { loglog(RC_LOG_SERIOUS, "DPD Error: R_U_THERE has invalid SPI length (%d)", n->isan_spisize); return STF_FAIL + PAYLOAD_MALFORMED; } if (memcmp(pbs->cur, p1st->st_icookie, COOKIE_SIZE) != 0) { /* RFC states we *SHOULD* check cookies, not MUST. So invalid cookies are technically valid, as per Geoffrey Huang */ loglog(RC_LOG_SERIOUS, "DPD Warning: R_U_THERE has invalid icookie (broken Cisco?)"); } pbs->cur += COOKIE_SIZE; if (memcmp(pbs->cur, p1st->st_rcookie, COOKIE_SIZE) != 0) { loglog(RC_LOG_SERIOUS, "DPD Warning: R_U_THERE has invalid rcookie (broken Cisco?)"); } pbs->cur += COOKIE_SIZE; if (pbs_left(pbs) != sizeof(seqno)) { loglog(RC_LOG_SERIOUS, "DPD Error: R_U_THERE has invalid data length (%d)", (int) pbs_left(pbs)); return STF_FAIL + PAYLOAD_MALFORMED; } seqno = ntohl(*(u_int32_t *)pbs->cur); if (p1st->st_dpd_peerseqno && seqno <= p1st->st_dpd_peerseqno) { loglog(RC_LOG_SERIOUS, "DPD Info: received old or duplicate R_U_THERE"); return STF_IGNORE; } DBG(DBG_DPD, DBG_log("received R_U_THERE seq:%u time:%lu (state=#%lu name=\"%s\")" , seqno , (unsigned long)tm , p1st->st_serialno, p1st->st_connection->name)); p1st->st_dpd_peerseqno = seqno; if (send_isakmp_notification(p1st, R_U_THERE_ACK , pbs->cur, pbs_left(pbs)) != STF_IGNORE) { loglog(RC_LOG_SERIOUS, "DPD Info: could not send R_U_THERE_ACK"); return STF_IGNORE; } /* update the time stamp */ p1st->st_last_dpd = tm; /* * since there was activity, kill any EVENT_DPD_TIMEOUT that might * be waiting. */ if(p1st->st_dpd_event != NULL && p1st->st_dpd_event->ev_type == EVENT_DPD_TIMEOUT) { delete_dpd_event(p1st); } return STF_IGNORE; }
/** * 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++; }
/***************************************************************************************** 函数名称: dpd_outI 功能描述: dpd 处理事件,当dpd第一次触发时添加一个超时事件, 如果是重传的dpd处理,不添加超时事件。 输入参数: p1st 输出参数: 无 返 回 值: 无 ------------------------------------------------------------------------------------------- 最近一次修改记录 : 修改作者: 王之云 修改目的: dpd_outI处理 修改日期: 2012年3月20日 ********************************************************************************************/ static void dpd_outI(struct state *p1st) { time_t tm; u_int32_t seqno; time_t timeout = p1st->st_connection->dpd_timeout; EV_ADD ev_arg; DBG(DBG_DPD, DBG_log("processing dpd for state #%lu (\"%s\")" , p1st->st_serialno , p1st->st_connection->name)); /* If no DPD, then get out of here */ if (!p1st->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(); if (!p1st->st_dpd_seqno) { p1st->st_dpd_seqno = dpd_seqno++; } seqno = htonl(p1st->st_dpd_seqno); /* 如果dpd事件为空,添加dpd事件 */ if(p1st->st_dpd_event == NULL) { ev_arg.u.st = p1st; event_schedule(EVENT_DPD, p1st->st_connection->dpd_delay, &ev_arg); } /* 如果dpd超时事件为空,添加dpd超时事件 */ if(p1st->st_dpd_timeout_event == NULL) { passert(timeout > 0); ev_arg.u.st = p1st; event_schedule(EVENT_DPD_TIMEOUT, timeout, &ev_arg); } 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(p1st->hidden_variables.st_is_dp_dev && p1st->st_connection->modecfg_quick_dpd ) { if (send_quick_isakmp_notification(p1st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "QUICK DPD Error: connection(%s) send R_U_THERE error\n", p1st->st_connection->name); return; } } else { if (send_isakmp_notification(p1st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "DPD Error: connection(%s) send R_U_THERE error\n", p1st->st_connection->name); return; } } p1st->st_dpd_expectseqno = p1st->st_dpd_seqno++; }
/***************************************************************************************** 函数名称: dpd_inR 功能描述: 处理R_U_THERE_ACK 报文,判断报文长度是否正确以及通过序列号判断 报文是否是自己想要的 输入参数: p1st,n,pbs 输出参数: 无 返 回 值: stf_status ------------------------------------------------------------------------------------------- 最近一次修改记录 : 修改作者: 王之云 修改目的: ACk处理 修改日期: 2012年3月20日 ********************************************************************************************/ stf_status dpd_inR(struct state *p1st, struct isakmp_notification *const n, pb_stream *pbs) { EV_ADD ev_arg; if(!p1st->hidden_variables.st_is_dp_dev) { time_t tm = now(); u_int32_t seqno; char buf_remoteip[20] = {0}; addrtot(&p1st->st_remoteaddr, 0, buf_remoteip, sizeof(buf_remoteip)); if (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "recevied R_U_THERE_ACK for unestablished ISKAMP SA"); return STF_FAIL; } if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) { IPSEC_log(IPSEC_LOGLEVEL_ERROR, "<%s> < %s > R_U_THERE_ACK has invalid SPI length (%d)", p1st->st_connection->name, buf_remoteip, n->isan_spisize); return STF_FAIL + PAYLOAD_MALFORMED; } if (memcmp(pbs->cur, p1st->st_icookie, COOKIE_SIZE) != 0) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "R_U_THERE_ACK has invalid icookie"); } pbs->cur += COOKIE_SIZE; if (memcmp(pbs->cur, p1st->st_rcookie, COOKIE_SIZE) != 0) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "R_U_THERE_ACK has invalid rcookie (tolerated)"); } pbs->cur += COOKIE_SIZE; if (pbs_left(pbs) != sizeof(seqno)) { IPSEC_log(IPSEC_LOGLEVEL_ERROR, "<%s> < %s > R_U_THERE_ACK has invalid data length (%d)", p1st->st_connection->name, buf_remoteip, (int) pbs_left(pbs)); return STF_FAIL + PAYLOAD_MALFORMED; } seqno = ntohl(*(u_int32_t *)pbs->cur); DBG(DBG_DPD, DBG_log("R_U_THERE_ACK, seqno received: %u expected: %u (state=#%lu)", seqno, p1st->st_dpd_expectseqno, p1st->st_serialno)); if (seqno != p1st->st_dpd_expectseqno) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "R_U_THERE_ACK has unexpected sequence number (expected: %u got: %u", seqno, p1st->st_dpd_expectseqno); return STF_IGNORE; } else { p1st->st_last_dpd = tm; } } if(p1st->st_dpd_timeout_event != NULL) { ev_arg.u.st = p1st; disable_event(EVENT_DPD_TIMEOUT, &ev_arg); } return STF_IGNORE; }
/***************************************************************************************** 函数名称: dpd_inI_outR 功能描述: 处理R_U_THERE报文,判断R_U_THERE报文长度是否正确以及 通过序列号判断自己想要的报文 输入参数: p1st,n,pbs 输出参数: stf_status 返 回 值: 无 ------------------------------------------------------------------------------------------- 最近一次修改记录 : 修改作者: 王之云 修改目的: dpd_outI处理 修改日期: 2012年3月20日 ********************************************************************************************/ stf_status dpd_inI_outR(struct state *p1st, struct isakmp_notification *const n, pb_stream *pbs) { time_t tm = now(); u_int32_t seqno; char buf_remoteip[20] = {0}; EV_ADD ev_arg; addrtot(&p1st->st_remoteaddr, 0, buf_remoteip, sizeof(buf_remoteip)); if (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state)) { return STF_IGNORE; } if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) { IPSEC_log(IPSEC_LOGLEVEL_ERROR, "<%s> < %s > DPD Error: R_U_THERE has invalid SPI length (%d)", p1st->st_connection->name, buf_remoteip, n->isan_spisize); return STF_FAIL + PAYLOAD_MALFORMED; } if (memcmp(pbs->cur, p1st->st_icookie, COOKIE_SIZE) != 0) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "DPD Warning: R_U_THERE has invalid icookie (broken Cisco?)"); } pbs->cur += COOKIE_SIZE; if (memcmp(pbs->cur, p1st->st_rcookie, COOKIE_SIZE) != 0) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "DPD Warning: R_U_THERE has invalid rcookie (broken Cisco?)"); } pbs->cur += COOKIE_SIZE; if (pbs_left(pbs) != sizeof(seqno)) { IPSEC_log(IPSEC_LOGLEVEL_ERROR, "<%s> < %s > DPD Error: R_U_THERE has invalid data length (%d)", p1st->st_connection->name, buf_remoteip, (int) pbs_left(pbs)); return STF_FAIL + PAYLOAD_MALFORMED; } seqno = ntohl(*(u_int32_t *)pbs->cur); if (p1st->st_dpd_peerseqno && seqno <= p1st->st_dpd_peerseqno) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "DPD Info: received old or duplicate R_U_THERE"); return STF_IGNORE; } DBG(DBG_DPD, DBG_log("received R_U_THERE seq:%u time:%lu (state=#%lu name=\"%s\")" , seqno , (unsigned long)tm , p1st->st_serialno, p1st->st_connection->name)); p1st->st_dpd_peerseqno = seqno; if (send_isakmp_notification(p1st, R_U_THERE_ACK , pbs->cur, pbs_left(pbs)) != STF_IGNORE) { IPSEC_log(IPSEC_LOGLEVEL_PRIVATE, "DPD Info: could not send R_U_THERE_ACK"); return STF_IGNORE; } p1st->st_last_dpd = tm; if(p1st->st_dpd_timeout_event != NULL) { ev_arg.u.st = p1st; disable_event(EVENT_DPD_TIMEOUT, &ev_arg); } return STF_IGNORE; }