diff -uNr freeswan-1.99/pluto/Makefile freeswan-1.99.dpd/pluto/Makefile --- freeswan-1.99/pluto/Makefile 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/Makefile 2003-08-15 15:42:17.000000000 +0000 @@ -77,6 +77,7 @@ -DDEBUG \ -DGCC_LINT \ -DNAT_TRAVERSAL -DVIRTUAL_IP \ + -DDPD \ # -DLEAK_DETECTIVE CPPFLAGS = $(HDRDIRS) $(DEFINES) \ diff -uNr freeswan-1.99/pluto/connections.c freeswan-1.99.dpd/pluto/connections.c --- freeswan-1.99/pluto/connections.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/connections.c 2003-08-15 15:42:17.000000000 +0000 @@ -897,7 +897,10 @@ c->sa_rekey_margin = wm->sa_rekey_margin; c->sa_rekey_fuzz = wm->sa_rekey_fuzz; c->sa_keying_tries = wm->sa_keying_tries; - +#ifdef DPD + c->dpd_delay = wm->dpd_delay; + c->dpd_timeout = wm->dpd_timeout; +#endif c->addr_family = wm->addr_family; c->tunnel_addr_family = wm->tunnel_addr_family; diff -uNr freeswan-1.99/pluto/connections.h freeswan-1.99.dpd/pluto/connections.h --- freeswan-1.99/pluto/connections.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/connections.h 2003-08-15 15:42:17.000000000 +0000 @@ -121,6 +121,10 @@ time_t sa_rekey_margin; unsigned long sa_rekey_fuzz; unsigned long sa_keying_tries; +#ifdef DPD + time_t dpd_delay; + time_t dpd_timeout; +#endif struct end this, that; diff -uNr freeswan-1.99/pluto/constants.c freeswan-1.99.dpd/pluto/constants.c --- freeswan-1.99/pluto/constants.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/constants.c 2003-08-15 15:42:17.000000000 +0000 @@ -62,13 +62,21 @@ #ifdef NAT_TRAVERSAL "EVENT_NAT_T_KEEPALIVE", #endif +#ifdef DPD + "EVENT_DPD", + "EVENT_DPD_TIMEOUT", +#endif }; enum_names timer_event_names = -#ifdef NAT_TRAVERSAL - { EVENT_NULL, EVENT_NAT_T_KEEPALIVE, timer_event_name, NULL }; +#ifdef DEAD_PEER_DETECTION + { EVENT_NULL, EVENT_DPD_TIMEOUT, timer_event_name, NULL }; #else +# ifdef NAT_TRAVERSAL + { EVENT_NULL, EVENT_NAT_T_KEEPALIVE, timer_event_name, NULL }; +# else { EVENT_NULL, EVENT_SA_EXPIRE, timer_event_name, NULL }; +# endif #endif /* Domain of Interpretation */ @@ -620,6 +628,11 @@ /* Oakley Hash Algorithm attribute */ +/* Vendor ID */ +const char dpd_vid[] = {0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1, + 0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57, 0x01, 0x00}; +const int dpd_vid_length = sizeof(dpd_vid); + static const char *const oakley_hash_name[] = { "OAKLEY_MD5", "OAKLEY_SHA", diff -uNr freeswan-1.99/pluto/constants.h freeswan-1.99.dpd/pluto/constants.h --- freeswan-1.99/pluto/constants.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/constants.h 2003-08-15 15:42:17.000000000 +0000 @@ -235,6 +235,10 @@ #ifdef NAT_TRAVERSAL , EVENT_NAT_T_KEEPALIVE #endif +#ifdef DPD + , EVENT_DPD /* dead peer detection */ + , EVENT_DPD_TIMEOUT /* dead peer detection timeout */ +#endif }; #define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */ @@ -921,8 +925,15 @@ IPSEC_RESPONDER_LIFETIME = 24576, IPSEC_REPLAY_STATUS = 24577, IPSEC_INITIAL_CONTACT = 24578 +#ifdef DPD + , R_U_THERE = 36136 + , R_U_THERE_ACK = 36137 +#endif } notification_t; +/* Vendor IDs */ +extern const char dpd_vid[]; /* Dead Peer Detection */ +extern const int dpd_vid_length; /* Public key algorithm number * Same numbering as used in DNSsec diff -uNr freeswan-1.99/pluto/demux.c freeswan-1.99.dpd/pluto/demux.c --- freeswan-1.99/pluto/demux.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/demux.c 2003-08-15 15:42:17.000000000 +0000 @@ -863,7 +863,42 @@ static stf_status informational(struct msg_digest *md UNUSED) { - /* loglog(RC_LOG_SERIOUS, "received and ignored informational message"); */ +#ifdef DPD + struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N]; + + /* log contents of any notification payload */ + if (n_pld != NULL) + { + pb_stream *const n_pbs = &n_pld->pbs; + struct isakmp_notification *const n = &n_pld->payload.notification; + int disp_len; + char disp_buf[200]; + + switch (n->isan_type) + { + case R_U_THERE: + return dpd_inI_outR(md->st, n, n_pbs); + + case R_U_THERE_ACK: + return dpd_inR(md->st, n, n_pbs); + + default: + if (pbs_left(n_pbs) >= sizeof(disp_buf)-1) + disp_len = sizeof(disp_buf)-1; + else + disp_len = pbs_left(n_pbs); + memcpy(disp_buf, n_pbs->cur, disp_len); + disp_buf[disp_len] = '\0'; + + /* should indicate from where... FIXME */ + log("Notification: Pid=%d SPIsz=%d Type=%d Val=%s\n" + , n->isan_protoid, n->isan_spisize, n->isan_type + , disp_buf); + break; + } + } +#endif + loglog(RC_LOG_SERIOUS, "received and ignored informational message"); return STF_IGNORE; } @@ -1852,6 +1887,11 @@ cur_state = st = md->st; /* might have changed */ +#ifdef DPD + if( st && md->dpd) + st->st_dpd = md->dpd; +#endif + switch (result) { case STF_IGNORE: diff -uNr freeswan-1.99/pluto/demux.h freeswan-1.99.dpd/pluto/demux.h --- freeswan-1.99/pluto/demux.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/demux.h 2003-08-15 15:42:17.000000000 +0000 @@ -65,6 +65,10 @@ pb_stream rbody; /* room for reply body (after header) */ notification_t note; /* reason for failure */ +#ifdef DPD + bool dpd; /* Peer supports DPD */ +#endif + # define PAYLIMIT 20 struct payload_digest digest[PAYLIMIT], diff -uNr freeswan-1.99/pluto/ipsec_doi.c freeswan-1.99.dpd/pluto/ipsec_doi.c --- freeswan-1.99/pluto/ipsec_doi.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/ipsec_doi.c 2003-08-15 15:42:17.000000000 +0000 @@ -67,6 +67,10 @@ #include "virtual.h" #endif +#ifdef DPD +static void dpd_init(struct state *st); +#endif + static bool encrypt_message(pb_stream *pbs, struct state *st); /* forward declaration */ /* MAGIC: perform f, a function that returns notification_t @@ -75,6 +79,7 @@ #define RETURN_STF_FAILURE(f) \ { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; } + /* create output HDR as replica of input HDR */ void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np) @@ -935,6 +940,13 @@ } #endif +#ifdef DPD + /* Announce our ability to do Dead Peer Detection to the peer */ + if( !out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_vendor_id_desc, + &rbody, dpd_vid, dpd_vid_length, "V_ID")) + return STF_INTERNAL_ERROR; +#endif + close_message(&rbody); close_output_pbs(&reply); @@ -2963,6 +2975,13 @@ } #endif +#ifdef DPD + /* Announce our ability to do Dead Peer Detection to the peer */ + if( !out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_vendor_id_desc, + &md->rbody, dpd_vid, dpd_vid_length, "V_ID")) + return STF_INTERNAL_ERROR; +#endif + close_message(&md->rbody); /* save initiator SA for HASH */ @@ -4361,6 +4380,11 @@ if (c->gw_info != NULL) c->gw_info->last_worked_time = now(); +#ifdef DPD + if (st->st_connection->dpd_delay) + dpd_init(st); +#endif + return STF_OK; } @@ -4399,5 +4423,303 @@ gw->last_worked_time = now(); } +#ifdef DPD + if(st->st_connection->dpd_delay) + dpd_init(st); +#endif + return STF_OK; } + +#ifdef DPD +static stf_status +send_isakmp_notification(struct state *st, + u_int16_t type, const void *data, size_t len) +{ + msgid_t msgid; + pb_stream reply; + pb_stream rbody; + u_char old_new_iv[MAX_DIGEST_LEN]; + u_char old_iv[MAX_DIGEST_LEN]; + u_char + *r_hashval, /* where in reply to jam hash value */ + *r_hash_start; /* start of what is to be hashed */ + + msgid = generate_msgid(st); + + init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "ISAKMP notify"); + + /* HDR* */ + { + struct isakmp_hdr hdr; + + hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; + hdr.isa_np = ISAKMP_NEXT_HASH; + hdr.isa_xchg = ISAKMP_XCHG_INFO; + hdr.isa_msgid = msgid; + hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; + memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); + memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); + if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) + impossible(); + } + + /* HASH -- create and note space to be filled later */ + START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N); + + /* NOTIFY */ + { + pb_stream notify_pbs; + struct isakmp_notification isan; + + isan.isan_np = ISAKMP_NEXT_NONE; + isan.isan_doi = ISAKMP_DOI_IPSEC; + isan.isan_protoid = PROTO_ISAKMP; + isan.isan_spisize = COOKIE_SIZE * 2; + isan.isan_type = type; + if (!out_struct(&isan, &isakmp_notification_desc, &rbody, ¬ify_pbs)) + return STF_INTERNAL_ERROR; + if (!out_raw(st->st_icookie, COOKIE_SIZE, ¬ify_pbs, "notify icookie")) + return STF_INTERNAL_ERROR; + if (!out_raw(st->st_rcookie, COOKIE_SIZE, ¬ify_pbs, "notify rcookie")) + return STF_INTERNAL_ERROR; + if (data != NULL && len > 0) + if (!out_raw(data, len, ¬ify_pbs, "notify data")) + return STF_INTERNAL_ERROR; + close_output_pbs(¬ify_pbs); + } + + { + /* finish computing HASH */ + struct hmac_ctx ctx; + + hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); + hmac_update(&ctx, (const u_char *) &msgid, sizeof(msgid_t)); + hmac_update(&ctx, r_hash_start, rbody.cur-r_hash_start); + hmac_final(r_hashval, &ctx); + + DBG(DBG_CRYPT, + DBG_log("HASH computed:"); + DBG_dump("", r_hashval, ctx.hmac_digest_size)); + } + + /* save old IV (this prevents from copying a whole new state object + * for NOTIFICATION / DELETE messages we don't need to maintain a state + * because there are no retransmissions... + */ + + memcpy(old_new_iv, st->st_new_iv, st->st_new_iv_len); + memcpy(old_iv, st->st_iv, st->st_iv_len); + init_phase2_iv(st, &msgid); + + if (!encrypt_message(&rbody, st)) + return STF_INTERNAL_ERROR; + + { + chunk_t saved_tpacket = st->st_tpacket; + + setchunk(st->st_tpacket, reply.start, pbs_offset(&reply)); + send_packet(st, "ISAKMP notify"); + st->st_tpacket = saved_tpacket; + } + + /* get back old IV for this state */ + memcpy(st->st_new_iv, old_new_iv, st->st_new_iv_len); + memcpy(st->st_iv, old_iv, st->st_iv_len); + + return STF_IGNORE; +} + +static void +dpd_init(struct state *st) +{ + struct state *p1st; + + /* find the related Phase 1 state */ + p1st = find_state(st->st_icookie, st->st_rcookie, + &st->st_connection->that.host_addr, 0); + if (p1st == NULL) + loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD"); + else if (p1st->st_dpd) + event_schedule(EVENT_DPD, st->st_connection->dpd_delay, st); +} + +void +dpd_outI(struct state *p2st) +{ + struct state *st; + time_t tm; + u_int32_t seqno; + time_t delay = p2st->st_connection->dpd_delay; + time_t timeout = p2st->st_connection->dpd_timeout; + + /* find the related Phase 1 state */ + st = find_phase1_state(p2st->st_connection, FALSE); + if (st == NULL) + { + loglog(RC_LOG_SERIOUS, "could not find newest phase 1 state for DPD"); + return; + } + if (!st->st_dpd) + return; + + /* If an R_U_THERE has been sent or received recently, then + * base the resend time on that. */ + tm = now(); + if (tm < st->st_last_dpd + delay) + { + event_schedule(EVENT_DPD, st->st_last_dpd + delay - tm, p2st); + /* If there is still a timeout for the last R_U_THERE sent, + * and the timeout is greater than ours, then reduce it. */ + if (st->st_dpd_event != NULL + && st->st_dpd_event->ev_time > st->st_last_dpd + timeout) + { + delete_dpd_event(st); + event_schedule(EVENT_DPD_TIMEOUT, st->st_last_dpd + timeout - tm, st); + } + return; + } + + event_schedule(EVENT_DPD, delay, p2st); + + if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) + return; + + if (!st->st_dpd_seqno) + { + /* Get a non-zero random value that has room to grow */ + get_rnd_bytes((u_char *)&st->st_dpd_seqno, sizeof(st->st_dpd_seqno)); + st->st_dpd_seqno &= 0x7fff; + st->st_dpd_seqno++; + } + seqno = htonl(st->st_dpd_seqno); + if (send_isakmp_notification(st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE) + { + loglog(RC_LOG_SERIOUS, "could not send R_U_THERE"); + return; + } + + st->st_dpd_expectseqno = st->st_dpd_seqno++; + st->st_last_dpd = tm; + /* Only schedule a new timeout if there isn't one currently, + * or if it would be sooner than the current timeout. */ + if (st->st_dpd_event == NULL + || st->st_dpd_event->ev_time > tm + timeout) + { + delete_dpd_event(st); + event_schedule(EVENT_DPD_TIMEOUT, timeout, st); + } +} + +stf_status +dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *n_pbs) +{ + time_t tm = now(); + u_int32_t seqno; + + if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) + { + loglog(RC_LOG_SERIOUS, "recevied R_U_THERE for unestablished ISKAMP SA"); + return; + } + + if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(n_pbs) < COOKIE_SIZE * 2) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE has invalid SPI length (%d)", n->isan_spisize); + return; + } + + if (memcmp(n_pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE has invalid icookie"); + return; + } + n_pbs->cur += COOKIE_SIZE; + + if (memcmp(n_pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE has invalid rcookie"); + return; + } + n_pbs->cur += COOKIE_SIZE; + + if (pbs_left(n_pbs) != sizeof(seqno)) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE has invalid data length (%d)", pbs_left(n_pbs)); + return; + } + + seqno = ntohl(*(u_int32_t *)n_pbs->cur); + if (st->st_dpd_peerseqno && seqno <= st->st_dpd_peerseqno) { + loglog(RC_LOG_SERIOUS, "received old or duplicate R_U_THERE"); + return; + } + + st->st_dpd_peerseqno = seqno; + delete_dpd_event(st); + + if (send_isakmp_notification(st, R_U_THERE_ACK, n_pbs->cur, pbs_left(n_pbs)) != STF_IGNORE) + { + loglog(RC_LOG_SERIOUS, "could not send R_U_THERE_ACK"); + return STF_IGNORE; + } + + st->st_last_dpd = tm; + return STF_IGNORE; +} + +stf_status +dpd_inR(struct state *st, struct isakmp_notification *const n, pb_stream *n_pbs) +{ + u_int32_t seqno; + + if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) + { + loglog(RC_LOG_SERIOUS, "recevied R_U_THERE_ACK for unestablished ISKAMP SA"); + return; + } + + if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(n_pbs) < COOKIE_SIZE * 2) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid SPI length (%d)", n->isan_spisize); + return; + } + + if (memcmp(n_pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid icookie"); + return; + } + n_pbs->cur += COOKIE_SIZE; + + if (memcmp(n_pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid rcookie"); + return; + } + n_pbs->cur += COOKIE_SIZE; + + if (pbs_left(n_pbs) != sizeof(seqno)) + { + loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid data length (%d)", pbs_left(n_pbs)); + return; + } + + seqno = ntohl(*(u_int32_t *)n_pbs->cur); + if (!st->st_dpd_expectseqno && seqno != st->st_dpd_expectseqno) { + loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has unexpected sequence number"); + return; + } + + st->st_dpd_expectseqno = 0; + delete_dpd_event(st); + return STF_IGNORE; +} + +void +dpd_timeout(struct state *st) +{ + loglog(RC_LOG_SERIOUS, "timeout waiting for DPD ack, replacing SA"); + replace_states_by_peer(&st->st_connection->that.host_addr); +} +#endif diff -uNr freeswan-1.99/pluto/ipsec_doi.h freeswan-1.99.dpd/pluto/ipsec_doi.h --- freeswan-1.99/pluto/ipsec_doi.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/ipsec_doi.h 2003-08-15 15:42:17.000000000 +0000 @@ -49,3 +49,11 @@ enum state_kind state, u_int16_t type); extern void send_notification_from_md(struct msg_digest *md, u_int16_t type); +#ifdef DPD +extern void dpd_outI(struct state *st); +extern stf_status dpd_inI_outR(struct state *st + , struct isakmp_notification *const n, pb_stream *n_pbs); +extern stf_status dpd_inR(struct state *st + , struct isakmp_notification *const n, pb_stream *n_pbs); +extern void dpd_timeout(struct state *st); +#endif diff -uNr freeswan-1.99/pluto/state.c freeswan-1.99.dpd/pluto/state.c --- freeswan-1.99/pluto/state.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/state.c 2003-08-15 15:42:17.000000000 +0000 @@ -285,6 +285,10 @@ struct state *old_cur_state = cur_state == st? NULL : cur_state; set_cur_state(st); +#ifdef DPD + if(st->st_dpd_event != NULL) + delete_dpd_event(st); +#endif /* if there is a suspended state transition, disconnect us */ if (st->st_suspended_md != NULL) @@ -808,3 +812,26 @@ } return cpi; } + +#ifdef DPD +/* Immediately schedule a replace event for all states for a peer. + */ +void replace_states_by_peer(const ip_address *peer) +{ + struct state *st = NULL; + int i; + struct event *ev; + + for (i = 0; st == NULL && i < STATE_TABLE_SIZE; i++) + for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) + /* Only replace if it already has a replace event. */ + if (sameaddr(&st->st_connection->that.host_addr, peer) + && (IS_ISAKMP_SA_ESTABLISHED(st->st_state) || IS_IPSEC_SA_ESTABLISHED(st->st_state)) + && st->st_event->ev_type == EVENT_SA_REPLACE) + { + delete_event(st); + delete_dpd_event(st); + event_schedule(EVENT_SA_REPLACE, 0, st); + } +} +#endif diff -uNr freeswan-1.99/pluto/state.h freeswan-1.99.dpd/pluto/state.h --- freeswan-1.99/pluto/state.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/state.h 2003-08-15 15:42:17.000000000 +0000 @@ -202,6 +202,14 @@ u_int32_t nat_traversal; ip_address nat_oa; #endif +#ifdef DPD + bool st_dpd; /* Peer supports DPD */ + time_t st_last_dpd; /* Time of last DPD transmit */ + u_int32_t st_dpd_seqno; /* Next R_U_THERE to send */ + u_int32_t st_dpd_expectseqno; /* Next R_U_THERE_ACK to receive */ + u_int32_t st_dpd_peerseqno; /* global variables */ + struct event *st_dpd_event; /* backpointer for DPD events */ +#endif }; /* global variables */ @@ -220,6 +228,9 @@ extern void delete_state(struct state *st); struct connection; /* forward declaration of tag */ extern void delete_states_by_connection(struct connection *c); +#ifdef DPD +extern void replace_states_by_peer(const ip_address *peer); +#endif extern struct state *duplicate_state(const struct state *st), diff -uNr freeswan-1.99/pluto/timer.c freeswan-1.99.dpd/pluto/timer.c --- freeswan-1.99/pluto/timer.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/timer.c 2003-08-15 15:42:17.000000000 +0000 @@ -89,9 +89,20 @@ */ if (st != NULL) { +#ifdef DPD + if(type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) + { + passert(st->st_dpd_event == NULL); + st->st_dpd_event = ev; + } else { passert(st->st_event == NULL); st->st_event = ev; } +#else + passert(st->st_event == NULL); + st->st_event = ev; +#endif + } DBG(DBG_CONTROL, if (st == NULL) @@ -187,8 +198,19 @@ if (st != NULL) { c = st->st_connection; +#ifdef DPD + if( type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) + { + passert(st->st_dpd_event == ev); + st->st_dpd_event = NULL; + } else { passert(st->st_event == ev); st->st_event = NULL; + } +#else + passert(st->st_event == ev); + st->st_event = NULL; +#endif peer = c->that.host_addr; set_cur_state(st); } @@ -334,6 +356,9 @@ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec")); ipsecdoi_replace(st, 1); } +#ifdef DPD + delete_dpd_event(st); +#endif event_schedule(EVENT_SA_EXPIRE, st->st_margin, st); } break; @@ -376,6 +401,15 @@ delete_state(st); break; +#ifdef DPD + case EVENT_DPD: + dpd_outI(st); + break; + case EVENT_DPD_TIMEOUT: + dpd_timeout(st); + break; +#endif + #ifdef NAT_TRAVERSAL case EVENT_NAT_T_KEEPALIVE: nat_traversal_ka_event(); @@ -454,3 +488,34 @@ } } } +#ifdef DPD +/* + * Delete a DPD event. + */ +void +delete_dpd_event(struct state *st) +{ + if (st->st_dpd_event != (struct event *) NULL) + { + struct event **ev; + + for (ev = &evlist; ; ev = &(*ev)->ev_next) + { + if (*ev == NULL) + { + DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found", + enum_show(&timer_event_names, st->st_dpd_event->ev_type))); + break; + } + if ((*ev) == st->st_dpd_event) + { + *ev = (*ev)->ev_next; + pfree(st->st_dpd_event); + st->st_dpd_event = (struct event *) NULL; + + break; + } + } + } +} +#endif diff -uNr freeswan-1.99/pluto/timer.h freeswan-1.99.dpd/pluto/timer.h --- freeswan-1.99/pluto/timer.h 2002-01-21 03:14:23.000000000 +0000 +++ freeswan-1.99.dpd/pluto/timer.h 2003-08-15 15:42:17.000000000 +0000 @@ -30,3 +30,7 @@ extern void handle_timer_event(void); extern long next_event(void); extern void delete_event(struct state *st); +#ifdef DPD +extern void delete_event(struct state *st); +extern void delete_dpd_event(struct state *st); +#endif diff -uNr freeswan-1.99/pluto/vendor.c freeswan-1.99.dpd/pluto/vendor.c --- freeswan-1.99/pluto/vendor.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/vendor.c 2003-08-15 15:42:17.000000000 +0000 @@ -308,6 +308,12 @@ } break; #endif +#ifdef DPD + case VID_MISC_DPD: + md->dpd = 1; + vid_usefull = 1; + break; +#endif default: break; } diff -uNr freeswan-1.99/pluto/whack.c freeswan-1.99.dpd/pluto/whack.c --- freeswan-1.99/pluto/whack.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/whack.c 2003-08-15 15:42:17.000000000 +0000 @@ -98,6 +98,10 @@ " \\\n " " [--esp ]" " \\\n " +#ifdef DPD + " [--dpddelay --dpdtimeout ]" +#endif + " \\\n " " [--dontrekey]" "\n\n" "routing: whack" @@ -303,6 +307,10 @@ CD_RKMARGIN, CD_RKFUZZ, CD_KTRIES, +#ifdef DPD + CD_DPDDELAY, + CD_DPDTIMEOUT, +#endif CD_IKE, CD_PFSGROUP, CD_ESP @@ -415,6 +423,10 @@ { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG }, /* OBSOLETE */ { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG }, { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG }, +#ifdef DPD + { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG }, + { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG }, +#endif { "ike", required_argument, NULL, CD_IKE + OO }, { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO }, { "esp", required_argument, NULL, CD_ESP + OO }, @@ -998,6 +1010,15 @@ msg.sa_keying_tries = opt_whole; continue; +#ifdef DPD + case CD_DPDDELAY: + msg.dpd_delay = opt_whole; + continue; + case CD_DPDTIMEOUT: + msg.dpd_timeout = opt_whole; + continue; +#endif + case CD_IKE: /* --ike */ msg.ike = optarg; continue; @@ -1191,6 +1212,11 @@ check_life_time(msg.sa_ipsec_life_seconds, SA_LIFE_DURATION_MAXIMUM , "ipseclifetime", &msg); +#ifdef DPD + if(msg.dpd_delay && !msg.dpd_timeout) + diag("dpddelay specified, but dpdtimeout is zero"); +#endif + /* build esp message as esp=";" */ if (msg.pfsgroup) { snprintf(esp_buf, sizeof (esp_buf), "%s;%s", diff -uNr freeswan-1.99/pluto/whack.h freeswan-1.99.dpd/pluto/whack.h --- freeswan-1.99/pluto/whack.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd/pluto/whack.h 2003-08-15 15:42:17.000000000 +0000 @@ -76,6 +76,10 @@ time_t sa_rekey_margin; unsigned long sa_rekey_fuzz; unsigned long sa_keying_tries; +#ifdef DPD + time_t dpd_delay; + time_t dpd_timeout; +#endif /* note that each end contains string 2/5.id, string 3/6 cert, * and string 4/7 updown