Index: vpnc-0.5.1/vpnc.h
===================================================================
--- vpnc-0.5.1.orig/vpnc.h
+++ vpnc-0.5.1/vpnc.h
@@ -27,5 +27,6 @@ void process_late_ike(struct sa_block *s
 void keepalive_ike(struct sa_block *s);
 void dpd_ike(struct sa_block *s);
 void print_vid(const unsigned char *vid, uint16_t len);
+void rekey_phase1(struct sa_block *s);
 
 #endif
Index: vpnc-0.5.1/vpnc.c
===================================================================
--- vpnc-0.5.1.orig/vpnc.c
+++ vpnc-0.5.1/vpnc.c
@@ -1064,7 +1064,7 @@ static void lifetime_ipsec_process(struc
 		s->ipsec.life.kbytes = value;
 }
 
-static void do_phase1(const char *key_id, const char *shared_key, struct sa_block *s)
+static void do_phase1(const char *key_id, const char *shared_key, struct sa_block *s, int re_key)
 {
 	unsigned char i_nonce[20];
 	struct group *dh_grp;
@@ -1823,16 +1823,18 @@ static void do_phase1(const char *key_id
 		p2->isakmp_version = ISAKMP_VERSION;
 		p2->exchange_type = ISAKMP_EXCHANGE_AGGRESSIVE;
 	/* XXX CERT Add id(?), cert and sig here in case of cert auth */
-		p2->payload = new_isakmp_data_payload(ISAKMP_PAYLOAD_HASH,
+		p2->payload = pl = new_isakmp_data_payload(ISAKMP_PAYLOAD_HASH,
 			returned_hash, s->ike.md_len);
-		p2->payload->next = pl = new_isakmp_payload(ISAKMP_PAYLOAD_N);
-		pl->u.n.doi = ISAKMP_DOI_IPSEC;
-		pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
-		pl->u.n.type = ISAKMP_N_IPSEC_INITIAL_CONTACT;
-		pl->u.n.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
-		pl->u.n.spi = xallocc(2 * ISAKMP_COOKIE_LENGTH);
-		memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 0, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);
-		memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 1, s->ike.r_cookie, ISAKMP_COOKIE_LENGTH);
+		if (!re_key) {
+			p2->payload->next = pl = new_isakmp_payload(ISAKMP_PAYLOAD_N);
+			pl->u.n.doi = ISAKMP_DOI_IPSEC;
+			pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
+			pl->u.n.type = ISAKMP_N_IPSEC_INITIAL_CONTACT;
+			pl->u.n.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
+			pl->u.n.spi = xallocc(2 * ISAKMP_COOKIE_LENGTH);
+			memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 0, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);
+			memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 1, s->ike.r_cookie, ISAKMP_COOKIE_LENGTH);
+		}
 
 		/* send PSK-hash if hybrid authentication is negotiated */
 		if (s->ike.auth_algo == IKE_AUTH_HybridInitRSA ||
@@ -1938,7 +1940,7 @@ static void do_phase1(const char *key_id
 	group_free(dh_grp);
 }
 
-static int do_phase2_notice_check(struct sa_block *s, struct isakmp_packet **r_p)
+static int do_phase2_notice_check(struct sa_block *s, struct isakmp_packet **r_p, int life_only)
 {
 	int reject = 0;
 	struct isakmp_packet *r;
@@ -1981,6 +1983,8 @@ static int do_phase2_notice_check(struct
 						lifetime_ipsec_process(s, r->payload->next->u.n.attributes);
 					else
 						DEBUG(2, printf("got unknown lifetime notice, ignoring..\n"));
+					if (life_only)
+					   	return 0;
 					r_length = sendrecv(s, r_packet, sizeof(r_packet), NULL, 0, 0);
 					continue;
 				} else if (r->payload->next->u.n.type == ISAKMP_N_IPSEC_INITIAL_CONTACT) {
@@ -2011,7 +2015,7 @@ static int do_phase2_notice_check(struct
 
 static int do_phase2_xauth(struct sa_block *s)
 {
-	struct isakmp_packet *r;
+	struct isakmp_packet *r = NULL;
 	int loopcount;
 	int reject;
 	int passwd_used = 0;
@@ -2027,7 +2031,9 @@ static int do_phase2_xauth(struct sa_blo
 		DEBUGTOP(2, printf("S5.2 notice_check\n"));
 		
 		/* recv and check for notices */
-		reject = do_phase2_notice_check(s, &r);
+		if (r) free_isakmp_packet(r);
+		r = NULL;
+		reject = do_phase2_notice_check(s, &r, 0);
 		if (reject == -1)
 			return 1;
 		
@@ -2191,9 +2197,11 @@ static int do_phase2_xauth(struct sa_blo
 			ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
 			r->message_id, 0, 0, 0, 0, 0, 0, 0);
 		
-		reject = do_phase2_notice_check(s, &r);
-		if (reject == -1)
+		reject = do_phase2_notice_check(s, &r, 0);
+		if (reject == -1) {
+			free_isakmp_packet(r);
 			return 1;
+		}
 	}
 	
 	DEBUGTOP(2, printf("S5.6 process xauth response\n"));
@@ -2272,9 +2280,11 @@ static int do_phase2_config(struct sa_bl
 	sendrecv_phase2(s, rp, ISAKMP_EXCHANGE_MODECFG_TRANSACTION, msgid, 0, 0, 0, 0, 0, 0, 0);
 
 	/* recv and check for notices */
-	reject = do_phase2_notice_check(s, &r);
-	if (reject == -1)
+	reject = do_phase2_notice_check(s, &r, 0);
+	if (reject == -1) {
+		if (r) free_isakmp_packet(r);
 		return 1;
+	}
 		
 	/* Check the transaction type & message ID are OK.  */
 	if (reject == 0 && r->message_id != msgid)
@@ -2937,14 +2947,22 @@ static int do_rekey(struct sa_block *s,
 
 void process_late_ike(struct sa_block *s, uint8_t *r_packet, ssize_t r_length)
 {
-	int reject;
+	int reject = 0;
 	struct isakmp_packet *r;
 	struct isakmp_payload *rp;
 	
 	DEBUG(2,printf("got late ike paket: %zd bytes\n", r_length));
-	/* we should ignore resent pakets here.
-	 * unpack_verify_phase2 will fail to decode them probably */
-	reject = unpack_verify_phase2(s, r_packet, r_length, &r, NULL, 0);
+
+	if (r_length > ISAKMP_PAYLOAD_O && r_packet[ISAKMP_EXCHANGE_TYPE_O] == ISAKMP_EXCHANGE_AGGRESSIVE) {
+		DEBUG(2,printf("can't respond to phase1 aggressive... terminating\n"));
+		do_kill = -1;
+		return;
+	} else {
+		/* we should ignore resent pakets here.
+		 * unpack_verify_phase2 will fail to decode them probably */
+		DEBUG(2,printf("processing as phase2\n"));
+		reject = unpack_verify_phase2(s, r_packet, r_length, &r, NULL, 0);
+	}
 	
 	/* just ignore broken stuff for now */
 	if (reject != 0)
@@ -2967,6 +2985,7 @@ void process_late_ike(struct sa_block *s
 	}
 
 	if (r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL) {
+		DEBUG(3, printf("got ISAKMP_EXCHANGE_INFORMATIONAL\n"));
 		/* Search for notify payloads */
 		for (rp = r->payload->next; rp; rp = rp->next) {
 			if (rp->type != ISAKMP_PAYLOAD_N)
@@ -3000,6 +3019,13 @@ void process_late_ike(struct sa_block *s
 					continue;
 				}
 				DEBUG(2, printf("got r-u-there ack\n"));
+			} else if (rp->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME) {
+				if (r->payload->next->u.n.protocol == ISAKMP_IPSEC_PROTO_ISAKMP)
+					lifetime_ike_process(s, r->payload->next->u.n.attributes);
+				else if (r->payload->next->u.n.protocol == ISAKMP_IPSEC_PROTO_IPSEC_ESP)
+					lifetime_ipsec_process(s, r->payload->next->u.n.attributes);
+				else
+					DEBUG(2, printf("got unknown lifetime notice, ignoring..\n"));
 			}
 		}
 	}
@@ -3068,7 +3094,7 @@ int main(int argc, char **argv)
 	do_load_balance = 0;
 	do {
 		DEBUGTOP(2, printf("S4 do_phase1\n"));
-		do_phase1(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], s);
+		do_phase1(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], s, 0);
 		DEBUGTOP(2, printf("S5 do_phase2_xauth\n"));
 		/* FIXME: Create and use a generic function in supp.[hc] */
 		if (s->ike.auth_algo >= IKE_AUTH_HybridInitRSA)
@@ -3084,3 +3110,45 @@ int main(int argc, char **argv)
 
 	return 0;
 }
+
+void rekey_phase1(struct sa_block *s) {
+	struct isakmp_packet *r;
+	uint8_t i_cookie[ISAKMP_COOKIE_LENGTH], r_cookie[ISAKMP_COOKIE_LENGTH];
+
+	memcpy(i_cookie, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);
+	memcpy(r_cookie, s->ike.r_cookie, ISAKMP_COOKIE_LENGTH);
+
+	do_phase1(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], s, 1);
+
+	(void)do_phase2_xauth(s);
+
+	DEBUG(3, printf("notice_checks\n"));
+	r_length = sendrecv(s, r_packet, sizeof(r_packet), NULL, 0, 0);
+	do_phase2_notice_check(s, &r, 1);
+	if (r)
+	   	free_isakmp_packet(r);
+	DEBUG(3, printf("notice_checks done\n"));
+
+	/* delete the old SA and read the response */
+	DEBUG(3, printf("delete old cookie\n"));
+    {
+        struct isakmp_payload *d_isakmp;
+        uint8_t del_msgid;
+
+        gcry_create_nonce((uint8_t *) & del_msgid, sizeof(del_msgid));
+        d_isakmp = new_isakmp_payload(ISAKMP_PAYLOAD_D);
+        d_isakmp->u.d.doi = ISAKMP_DOI_IPSEC;
+        d_isakmp->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
+        d_isakmp->u.d.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
+        d_isakmp->u.d.num_spi = 1;
+        d_isakmp->u.d.spi = xallocc(1 * sizeof(uint8_t *));
+        d_isakmp->u.d.spi[0] = xallocc(2 * ISAKMP_COOKIE_LENGTH);
+        memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 0, i_cookie,
+            ISAKMP_COOKIE_LENGTH);
+        memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 1, r_cookie,
+            ISAKMP_COOKIE_LENGTH);
+		sendrecv_phase2(s, d_isakmp, ISAKMP_EXCHANGE_INFORMATIONAL,
+			del_msgid, 1, NULL, NULL, NULL, 0, NULL, 0);
+    }
+}
+
Index: vpnc-0.5.1/tunip.c
===================================================================
--- vpnc-0.5.1.orig/tunip.c
+++ vpnc-0.5.1/tunip.c
@@ -876,12 +876,14 @@ static void vpnc_main_loop(struct sa_blo
 					}
 				}
 			}
-			DEBUG(2,printf("lifetime status: %ld of %u seconds used, %u|%u of %u kbytes used\n",
+			DEBUG(2,printf("lifetime status: %ld of %u seconds used, %u|%u of %u kbytes used, ike: %ld of %u seconds used\n",
 				time(NULL) - s->ipsec.life.start,
 				s->ipsec.life.seconds,
 				s->ipsec.life.rx/1024,
 				s->ipsec.life.tx/1024,
-				s->ipsec.life.kbytes));
+				s->ipsec.life.kbytes,
+				time(NULL) - s->ike.life.start,
+				s->ike.life.seconds));
 		} while ((presult == 0 || (presult == -1 && errno == EINTR)) && !do_kill);
 		if (presult == -1) {
 			syslog(LOG_ERR, "select: %m");
@@ -907,6 +909,12 @@ static void vpnc_main_loop(struct sa_blo
 		if (timed_mode) {
 			time_t now = time(NULL);
 			time_t next_up = now + 86400;
+
+			if ((now - s->ike.life.start) + ((s->ike.life.seconds*20)/100) > s->ike.life.seconds) {
+				DEBUG(3,printf("starting phase1 rekey\n"));
+				rekey_phase1(s);
+			}
+
 			if (enable_keepalives) {
 				/* never wait more than 9 seconds for a UDP keepalive */
 				next_up = now + 9;
