diff -uNr freeswan-1.99.dpd/README.DPD freeswan-1.99.dpd-sfs/README.DPD --- freeswan-1.99.dpd/README.DPD 1970-01-01 00:00:00.000000000 +0000 +++ freeswan-1.99.dpd-sfs/README.DPD 2003-07-08 19:03:15.000000000 +0000 @@ -0,0 +1,99 @@ + Support for Dead Peer Detection: + A Traffic-Based Method of Detecting Dead IKE Peers + + +The DPD patch provides support for draft-ietf-ipsec-dpd-03, aka +dead peer detection. + +DPD works using a keepalive system, where when a tunnel is idle +(established, but no traffic has traversed it for N period (dpddelay=N1) +one or both sides send a "hello" messages (R_U_THERE) and the other +replies with a acknowledge message (R_U_THERE_ACK). If no response +received, this continues until the DPD timeout value (dpdtimeout=N2) +has elapsed. If there still hasn't been any traffic or R_U_THERE_ACK +packets received, the peer is declared to be dead, and the SA deleted, +and related eroute removed from the table. + +DPD support is tuneable on a per connection basis, using the dpdaction, +dpddelay and dpdaction directives. See also the ipsec.conf man page for +more information. + +An example follows: + +conn laptop2myhome + left=%defaultroute + leftnexthop=%defaultroute + right=192.168.0.1 + dpddelay=30 + dpdtimeout=120 + dpdaction=clear + + +In the above example, our keepalive time is 30 seconds, our timeout is 120 +seconds, and our action is clear. So during idle periods, we send +R_U_THERE packets every 30 seconds. If the tunnel is idle and we haven't +received an R_U_THERE_ACK from our peer in 120 seconds, we declare the +peer dead, and clear the SA + eroute (the entire tunnel is removed). + +Note that both sides must have either dpddelay or dpdtimeout set for DPD +to be proposed or accepted. If one directive is set but not the other, +the defaults are used (dpddelay=30, dpdtimeout=120). + +The dpdaction parameter controls what we do when a peer is determined to +be dead. If set to "hold" (the default) it will place the eroute into +%hold status, and wait for the peer to return. If set to "clear" it will +remove the connection entirely, including both the SA and eroute. + +We recommend that "hold" be used for statically defined tunnels, and +"clear" be used for roadwarrior tunnels. + +DPD support in Super FreeS/WAN is based on Philip Craig [1]'s work for +Snapgear's ucLinux [2] and Srinivasan Venkataraman's [3] implementations, +which was ported to Super FreeS/WAN by Paweł Krawczyk, and then hacked +on by Paweł, JuanJo Ciarlante and Ken Bantoft. Thanks to Daniel +Djamaludin [4] and Srinivasan Venkataraman for their support and +advice. + +[1] philipc@snapgear.com +[2] http://cvs.uclinux.org/cgi-bin/cvsweb/uClinux-dist/freeswan/ +[3] http://www.ittc.ku.edu/~sriniven/eecs801/801index.html +[4] danield@snapgear.com + +Inter-operability Test Results: + +Pass: +Super FreeS/WAN 1.99.7 +Cisco Systems: VPN 3000 Concentrator Version 3.6.7.C +Cisco Systems: IOS 12.2.8T +(Cisco interop testing done by Minsu - thanks!) + + +Fail: 12.2(15)T1 +Cisco Systems: IOS *unknown version* + +If you see something like: + +May 8 02:43:02 dev pluto[1888]: "to-cisco" #23: R_U_THERE_ACK has invalid rcookie +May 8 02:43:02 dev pluto[1888]: "to-cisco" #23: sending notification INVALID_COOKIE to 1.2.3.4:500 +May 8 02:43:05 dev pluto[1888]: "to-cisco" #23: R_U_THERE_ACK has invalid rcookie +May 8 02:43:05 dev pluto[1888]: "to-cisco" #23: sending notification INVALID_COOKIE to 1.2.3.4:500 +May 8 02:43:07 dev pluto[1888]: "to-cisco" #23: DPD: No response from peer - declaring peer dead +May 8 02:43:07 dev pluto[1888]: "to-cisco" #27: deleting state (STATE_QUICK_I2) +May 8 02:43:07 dev pluto[1888]: "to-cisco" #26: deleting state (STATE_QUICK_I1) +May 8 02:43:07 dev pluto[1888]: "to-cisco" #23: deleting state (STATE_MAIN_I4) + +in the logfiles, the other end has broken R_U_THERE_ACK cookie code. Since the IETF draft has +not been finalized into an RFC yet, there have been some liberties taken with implementations, +causing inter-op problems. To fix this case, you can change the code in pluto/ipsec_doi.c + +In both the dpd_inR() and dpd_inI_outR() functions, change the lines that read + + return STF_FAIL + INVALID_COOKIE; + +to + return; + +And then ignore the compile-time warnings you receive. Or, just don't use DPD on that connection. + + +# RCSID $Id: README.DPD,v 1.9 2003/07/08 19:03:15 ken Exp $ diff -uNr freeswan-1.99.dpd/pluto/connections.c freeswan-1.99.dpd-sfs/pluto/connections.c --- freeswan-1.99.dpd/pluto/connections.c 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/connections.c 2003-08-15 17:39:53.000000000 +0000 @@ -900,6 +900,7 @@ #ifdef DPD c->dpd_delay = wm->dpd_delay; c->dpd_timeout = wm->dpd_timeout; + c->dpd_action = wm->dpd_action; #endif c->addr_family = wm->addr_family; c->tunnel_addr_family = wm->tunnel_addr_family; diff -uNr freeswan-1.99.dpd/pluto/connections.h freeswan-1.99.dpd-sfs/pluto/connections.h --- freeswan-1.99.dpd/pluto/connections.h 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/connections.h 2003-08-15 17:40:55.000000000 +0000 @@ -124,6 +124,7 @@ #ifdef DPD time_t dpd_delay; time_t dpd_timeout; + int dpd_action; #endif struct end this, diff -uNr freeswan-1.99.dpd/pluto/constants.c freeswan-1.99.dpd-sfs/pluto/constants.c --- freeswan-1.99.dpd/pluto/constants.c 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/constants.c 2003-08-15 18:53:06.000000000 +0000 @@ -69,7 +69,7 @@ }; enum_names timer_event_names = -#ifdef DEAD_PEER_DETECTION +#ifdef DPD { EVENT_NULL, EVENT_DPD_TIMEOUT, timer_event_name, NULL }; #else # ifdef NAT_TRAVERSAL @@ -628,11 +628,6 @@ /* 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", @@ -782,9 +777,23 @@ "IPSEC_INITIAL_CONTACT", }; +#ifdef DPD +static const char *const notification_dpd_name[] = { + "R_U_THERE", + "R_U_THERE_ACK", +}; +enum_names notification_dpd_names = + { R_U_THERE, R_U_THERE_ACK, + notification_dpd_name, NULL }; + +enum_names notification_names = + { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS, + notification_name, ¬ification_dpd_names }; +#else enum_names notification_names = { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS, notification_name, NULL }; +#endif enum_names notification_status_names = { CONNECTED, CONNECTED, diff -uNr freeswan-1.99.dpd/pluto/constants.h freeswan-1.99.dpd-sfs/pluto/constants.h --- freeswan-1.99.dpd/pluto/constants.h 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/constants.h 2003-08-15 17:51:16.000000000 +0000 @@ -218,6 +218,13 @@ #define IKE_UDP_PORT 500 +/* Dead Peer Detection actions */ + +#ifdef DPD +#define DPD_ACTION_CLEAR 0 +#define DPD_ACTION_HOLD 1 +#endif + /* Timer events */ extern enum_names timer_event_names; @@ -931,10 +938,6 @@ #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 * See RFC 2535 DNSsec 3.2 The KEY Algorithm Number Specification. diff -uNr freeswan-1.99.dpd/pluto/demux.c freeswan-1.99.dpd-sfs/pluto/demux.c --- freeswan-1.99.dpd/pluto/demux.c 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/demux.c 2003-08-15 17:58:32.000000000 +0000 @@ -866,7 +866,7 @@ #ifdef DPD struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N]; - /* log contents of any notification payload */ + /* If the Notification Payload is not null... */ if (n_pld != NULL) { pb_stream *const n_pbs = &n_pld->pbs; @@ -874,6 +874,7 @@ int disp_len; char disp_buf[200]; + /* Switch on Notification Type (enum) */ switch (n->isan_type) { case R_U_THERE: @@ -891,9 +892,10 @@ disp_buf[disp_len] = '\0'; /* should indicate from where... FIXME */ - log("Notification: Pid=%d SPIsz=%d Type=%d Val=%s\n" +/* log("Notification: Pid=%d SPIsz=%d Type=%d Val=%s\n" , n->isan_protoid, n->isan_spisize, n->isan_type , disp_buf); +*/ break; } } @@ -1843,6 +1845,10 @@ for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next) { +#ifdef DPD + if(p->payload.notification.isan_type != R_U_THERE + && p->payload.notification.isan_type != R_U_THERE_ACK) +#endif loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s" , enum_show(&ipsec_notification_names, p->payload.notification.isan_type)); DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs)); diff -uNr freeswan-1.99.dpd/pluto/ipsec_doi.c freeswan-1.99.dpd-sfs/pluto/ipsec_doi.c --- freeswan-1.99.dpd/pluto/ipsec_doi.c 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/ipsec_doi.c 2003-08-15 18:23:17.000000000 +0000 @@ -141,6 +141,13 @@ /* needed for PGPnet Vendor ID */ char pgp_vid[] = "OpenPGP10171"; +#ifdef DPD +/* needed for Dead Peer detection */ +char dpd_vid[] = {0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1, + 0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57, 0x01, 0x00}; +#endif + + /* if we haven't already done so, compute a local DH secret (st->st_sec) and * the corresponding public value (g). This is emitted as a KE payload. * KLUDGE: if DODGE_DH_MISSING_ZERO_BUG and we're the responder, @@ -942,9 +949,13 @@ #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")) + if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) { + if (!out_modify_previous_np(ISAKMP_NEXT_VID, &rbody)) + return STF_INTERNAL_ERROR; + if( !out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_vendor_id_desc, + &rbody, dpd_vid, sizeof(dpd_vid), "V_ID")) return STF_INTERNAL_ERROR; + } #endif close_message(&rbody); @@ -2977,9 +2988,13 @@ #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")) + if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) { + if (!out_modify_previous_np(ISAKMP_NEXT_VID, &md->rbody)) + return STF_INTERNAL_ERROR; + if( !out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_vendor_id_desc, + &md->rbody, dpd_vid, sizeof(dpd_vid), "V_ID")) return STF_INTERNAL_ERROR; + } #endif close_message(&md->rbody); @@ -4381,7 +4396,7 @@ c->gw_info->last_worked_time = now(); #ifdef DPD - if (st->st_connection->dpd_delay) + if (st->st_connection->dpd_delay && st->st_connection->dpd_timeout) dpd_init(st); #endif @@ -4424,7 +4439,7 @@ } #ifdef DPD - if(st->st_connection->dpd_delay) + if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) dpd_init(st); #endif @@ -4540,10 +4555,14 @@ &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) + else if (p1st->st_dpd) { + log("Dead Peer Detection (draft-ietf-ipsec-dpd-02) enabled"); event_schedule(EVENT_DPD, st->st_connection->dpd_delay, st); + } } +bool was_eroute_idle(struct state *st, time_t since_when); + void dpd_outI(struct state *p2st) { @@ -4582,6 +4601,11 @@ event_schedule(EVENT_DPD, delay, p2st); + /* Make sure we really need to invoke DPD */ + if(was_eroute_idle(p2st, delay) == FALSE) { + return; + } + if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) return; @@ -4619,40 +4643,40 @@ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { - loglog(RC_LOG_SERIOUS, "recevied R_U_THERE for unestablished ISKAMP SA"); - return; + loglog(RC_LOG_SERIOUS, "received R_U_THERE for unestablished ISKAMP SA"); + return STF_IGNORE; } 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; + return STF_FAIL + PAYLOAD_MALFORMED; } if (memcmp(n_pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) { loglog(RC_LOG_SERIOUS, "R_U_THERE has invalid icookie"); - return; + return STF_FAIL + INVALID_COOKIE; } 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; + return STF_FAIL + INVALID_COOKIE; } 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; + return STF_FAIL + PAYLOAD_MALFORMED; } 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; + return STF_IGNORE; } st->st_dpd_peerseqno = seqno; @@ -4676,39 +4700,39 @@ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { loglog(RC_LOG_SERIOUS, "recevied R_U_THERE_ACK for unestablished ISKAMP SA"); - return; + return STF_FAIL; } 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; + return STF_FAIL + PAYLOAD_MALFORMED; } if (memcmp(n_pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) { loglog(RC_LOG_SERIOUS, "R_U_THERE_ACK has invalid icookie"); - return; + return STF_FAIL + INVALID_COOKIE; } 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; + return STF_FAIL + INVALID_COOKIE; } 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; + return STF_FAIL + PAYLOAD_MALFORMED; } 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; + return STF_FAIL + PAYLOAD_MALFORMED; } st->st_dpd_expectseqno = 0; @@ -4719,7 +4743,32 @@ 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); + int action; + char *name; + + action = st->st_connection->dpd_action; + name = strdup(st->st_connection->name); + + passert(action == DPD_ACTION_HOLD || action == DPD_ACTION_CLEAR); + + loglog(RC_LOG_SERIOUS, "DPD: No response from peer - declaring peer dead"); + + release_connection(st->st_connection); + + if(action == DPD_ACTION_HOLD) { + struct connection *c = con_by_name(name, TRUE); + + if(c != NULL) { + set_cur_connection(c); + if(!trap_connection(c)) + log("cannot trap"); + reset_cur_connection(); + } else + log("cannot find connection"); + } + + if(name != NULL) + free(name); } #endif + diff -uNr freeswan-1.99.dpd/pluto/kernel.c freeswan-1.99.dpd-sfs/pluto/kernel.c --- freeswan-1.99.dpd/pluto/kernel.c 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/kernel.c 2003-08-15 18:31:47.000000000 +0000 @@ -2889,3 +2889,91 @@ } #endif +#ifdef DPD +/* Check if there was traffic on given SA during the last idle_max + * seconds. If TRUE, the SA was idle and DPD exchange should be performed. + * If FALSE, DPD is not necessary. We also return TRUE for errors, as they + * could mean that the SA is broken and needs to be replace anyway. + */ +bool was_eroute_idle(struct state *st, time_t idle_max) { + static const char procname[] = "/proc/net/ipsec_spi"; + FILE *f; + char buf[1024]; + int ret = TRUE; + + passert(st != NULL); + + f = fopen(procname, "r"); + if(f == NULL) + ret = TRUE; + + while(f != NULL) { + char *line; + char text_said[SATOT_BUF]; + u_int8_t proto = 0; + ip_address dst; + ip_said said; + ipsec_spi_t spi = 0; + static const char idle[] = "idle="; + time_t idle_time; /* idle time we read from /proc */ + + dst = st->st_connection->this.host_addr; /* inbound SA */ + if(st->st_ah.present) { + proto = SA_AH; + spi = st->st_ah.our_spi; + } + if(st->st_esp.present) { + proto = SA_ESP; + spi = st->st_esp.our_spi; + } + + if(proto == 0 && spi == 0) { + ret = TRUE; + break; + } + + initsaid(&dst, spi, proto, &said); + satot(&said, 'x', text_said, SATOT_BUF); + + line = fgets(buf, sizeof(buf), f); + if(line == NULL) { /* Reached end of list */ + ret = TRUE; + break; + } + + if(strncmp(line, text_said, strlen(text_said)) == 0) { + /* we found a match, now try to find idle= */ + char *p = strstr(line, idle); + if(p == NULL) { /* SAs which haven't been used yet + don't have it */ + ret = TRUE; /* it didn't have traffic */ + break; + } + p += sizeof(idle)-1; + if(*p == '\0') { + ret = TRUE; /* be paranoid */ + break; + } + if(sscanf(p, "%d", (int *) &idle_time) <= 0) { + ret = TRUE; + break; + } + if(idle_time > idle_max) { + DBG(DBG_KLIPS, + DBG_log("SA %s found idle for more than %ld sec", + text_said, idle_max)); + ret = TRUE; + break; + } + else { + ret = FALSE; + break; + } + } + + } + + fclose(f); + return ret; +} +#endif /* DPD */ diff -uNr freeswan-1.99.dpd/pluto/kernel.h freeswan-1.99.dpd-sfs/pluto/kernel.h --- freeswan-1.99.dpd/pluto/kernel.h 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/kernel.h 2003-08-15 18:32:12.000000000 +0000 @@ -63,3 +63,6 @@ extern bool update_ipsec_sa(struct state *st); #endif +#ifdef DPD +extern bool was_eroute_idle(struct state *st, time_t idle_max); +#endif diff -uNr freeswan-1.99.dpd/pluto/state.c freeswan-1.99.dpd-sfs/pluto/state.c --- freeswan-1.99.dpd/pluto/state.c 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/state.c 2003-08-15 18:33:02.000000000 +0000 @@ -820,7 +820,7 @@ { struct state *st = NULL; int i; - struct event *ev; + /* struct event *ev; currently unused */ for (i = 0; st == NULL && i < STATE_TABLE_SIZE; i++) for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) diff -uNr freeswan-1.99.dpd/pluto/whack.c freeswan-1.99.dpd-sfs/pluto/whack.c --- freeswan-1.99.dpd/pluto/whack.c 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/whack.c 2003-08-15 18:08:55.000000000 +0000 @@ -36,6 +36,12 @@ #include "defs.h" #include "whack.h" +#ifdef DPD +#include "x509.h" +#include "id.h" +#include "connections.h" +#endif + static void help(void) { @@ -100,8 +106,10 @@ " \\\n " #ifdef DPD " [--dpddelay --dpdtimeout ]" -#endif " \\\n " + " [--dpdaction (clear|hold)]" + " \\\n " +#endif " [--dontrekey]" "\n\n" "routing: whack" @@ -310,6 +318,7 @@ #ifdef DPD CD_DPDDELAY, CD_DPDTIMEOUT, + CD_DPDACTION, #endif CD_IKE, CD_PFSGROUP, @@ -426,6 +435,7 @@ #ifdef DPD { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG }, { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG }, + { "dpdaction", required_argument, NULL, CD_DPDACTION + OO }, #endif { "ike", required_argument, NULL, CD_IKE + OO }, { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO }, @@ -1017,6 +1027,15 @@ case CD_DPDTIMEOUT: msg.dpd_timeout = opt_whole; continue; + case CD_DPDACTION: + msg.dpd_action = 255; + if( strcmp(optarg, "clear") == 0) { + msg.dpd_action = DPD_ACTION_CLEAR; + } + if( strcmp(optarg, "hold") == 0) { + msg.dpd_action = DPD_ACTION_HOLD; + } + continue; #endif case CD_IKE: /* --ike */ @@ -1214,7 +1233,13 @@ #ifdef DPD if(msg.dpd_delay && !msg.dpd_timeout) - diag("dpddelay specified, but dpdtimeout is zero"); + diag("dpddelay specified, but dpdtimeout is zero, both should be specified"); + if(!msg.dpd_delay && msg.dpd_timeout) + diag("dpdtimeout specified, but dpddelay is zero, both should be specified"); + if(msg.dpd_action != DPD_ACTION_CLEAR && msg.dpd_action != DPD_ACTION_HOLD) { + diag("dpdaction can only be \"clear\" or \"hold\", defaulting to \"hold\""); + msg.dpd_action = DPD_ACTION_HOLD; + } #endif /* build esp message as esp=";" */ diff -uNr freeswan-1.99.dpd/pluto/whack.h freeswan-1.99.dpd-sfs/pluto/whack.h --- freeswan-1.99.dpd/pluto/whack.h 2003-08-15 15:42:17.000000000 +0000 +++ freeswan-1.99.dpd-sfs/pluto/whack.h 2003-08-15 18:02:06.000000000 +0000 @@ -79,6 +79,8 @@ #ifdef DPD time_t dpd_delay; time_t dpd_timeout; + int dpd_action; + int dpd_count; #endif /* note that each end contains string 2/5.id, string 3/6 cert, diff -uNr freeswan-1.99.dpd/utils/_confread freeswan-1.99.dpd-sfs/utils/_confread --- freeswan-1.99.dpd/utils/_confread 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd-sfs/utils/_confread 2003-08-15 18:38:17.000000000 +0000 @@ -125,6 +125,7 @@ good = "also type auto authby _plutodevel" left = " left leftsubnet leftnexthop leftfirewall leftupdown" akey = " keyexchange auth pfs pfsgroup keylife rekey rekeymargin rekeyfuzz" + akey = akey " dpddelay dpdtimeout dpdaction" akey = akey " compress" obs = " lifetime rekeystart rekeytries" akey = akey " keyingtries ikelifetime disablearrivalcheck ike" obs diff -uNr freeswan-1.99.dpd/utils/auto freeswan-1.99.dpd-sfs/utils/auto --- freeswan-1.99.dpd/utils/auto 2003-08-15 15:41:59.000000000 +0000 +++ freeswan-1.99.dpd-sfs/utils/auto 2003-08-15 18:12:54.000000000 +0000 @@ -12,7 +12,7 @@ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # -# RCSID $Id: auto,v 1.73.2.2 2002/06/21 19:22:47 mcr Exp $ +# RCSID $Id: auto,v 1.9 2003/04/26 02:27:18 ken Exp $ me='ipsec auto' usage="Usage: @@ -324,6 +324,15 @@ fail("only know how to do auth=esp or auth=ah") yesno("pfs") default("pfs", "yes") + duration("dpddelay") + duration("dpdtimeout") + if(("dpddelay" in s) && !("dpdtimeout" in s)) + default("dpdtimeout",120) + if(!("dpddelay" in s) && ("dpdtimeout" in s)) + default("dpddelay",30) + default("dpdaction","hold") + yesno("aggrmode") + default("aggrmode", "no") yesno("compress") default("compress", "no") was("keylife", "lifetime") @@ -416,6 +425,13 @@ if (s["pfsgroup"] != "") settings = settings " --pfsgroup " qs("pfsgroup") } + if (s["dpddelay"]) + settings = settings " --dpddelay " qs("dpddelay") + if (s["dpdtimeout"]) + settings = settings " --dpdtimeout " qs("dpdtimeout") + if (s["dpdaction"]) + settings = settings " --dpdaction " qs("dpdaction") + if (s["compress"] == "yes") settings = settings " --compress" if (op == "--replace") diff -uNr freeswan-1.99.dpd/utils/ipsec.conf.5 freeswan-1.99.dpd-sfs/utils/ipsec.conf.5 --- freeswan-1.99.dpd/utils/ipsec.conf.5 2002-06-21 19:22:47.000000000 +0000 +++ freeswan-1.99.dpd-sfs/utils/ipsec.conf.5 2003-08-15 18:39:13.000000000 +0000 @@ -1,5 +1,5 @@ .TH IPSEC.CONF 5 "26 Nov 2001" -.\" RCSID $Id: ipsec.conf.5,v 1.79.10.2 2002/06/21 19:22:47 mcr Exp $ +.\" RCSID $Id: ipsec.conf.5,v 1.7 2003/04/26 02:27:18 ken Exp $ .SH NAME ipsec.conf \- IPsec configuration and connections .SH DESCRIPTION @@ -512,6 +514,29 @@ if present, a second public key. Either key can authenticate the signature, allowing for key rollover. .TP +.B dpddelay +Set the delay (in seconds) between Dead Peer Dectection +(draft-ietf-ipsec-dpd-02) keepalives (R_U_THERE, R_U_THERE_ACK) +that are sent for this connection (default +.B 30 +seconds). If dpdtimeout is set, but not dpddelay, dpddelay will be set +to the default. +.TP +.B dpdtimeout +Set the length of time (in seconds) we will idle without hearing either an +R_U_THERE poll from our peer, or an R_U_THERE_ACK reply. After this period +has elapsed with no response and no traffic, we will declare the peer dead, +and remove the SA (default +.B 120 +seconds). If dpddelay is set, but not dpdtimeout, dpdtimeout will be set +to the default. +.TP +.B dpdaction +When a DPD enabled peer is declared dead, what action should be taken. +.B hold (default) means the eroute will be put into %hold status, while +.B clear means the eroute and SA with both be cleared. dpdaction=clear is +really only usefull on the server of a Road Warrior config. +.TP .B pfs whether Perfect Forward Secrecy of keys is desired on the connection's keying channel