#include "grabmyaddr.h"
#include "vpn_control.h"
#include "vpn_control_var.h"
+#include "ike_session.h"
+#include "ipsecSessionTracer.h"
+#include "ipsecMessageTracer.h"
#if defined(SADB_X_EALG_RIJNDAELCBC) && !defined(SADB_X_EALG_AESCBC)
#define SADB_X_EALG_AESCBC SADB_X_EALG_RIJNDAELCBC
static int pk_recvspdget __P((caddr_t *));
static int pk_recvspddump __P((caddr_t *));
static int pk_recvspdflush __P((caddr_t *));
+static int pk_recvgetsastat __P((caddr_t *));
static struct sadb_msg *pk_recv __P((int, int *));
static int (*pkrecvf[]) __P((caddr_t *)) = {
NULL, /* SADB_X_SPDSETIDX */
pk_recvspdexpire,
NULL, /* SADB_X_SPDDELETE2 */
+pk_recvgetsastat, /* SADB_GETSASTAT */
NULL, /* SADB_X_NAT_T_NEW_MAPPING */
NULL, /* SADB_X_MIGRATE */
-#if (SADB_MAX > 24)
+#if (SADB_MAX > 25)
#error "SADB extra message?"
#endif
};
#endif
#endif
-/*
- * PF_KEY packet handler
- * 0: success
- * -1: fail
- */
int
-pfkey_handler()
-{
+pfkey_process(msg)
struct sadb_msg *msg;
- int len;
+{
caddr_t mhp[SADB_EXT_MAX + 1];
int error = -1;
-
- /* receive pfkey message. */
- len = 0;
- msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len);
- if (msg == NULL) {
- if (len < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to recv from pfkey (%s)\n",
- strerror(errno));
- goto end;
- } else {
- /* short message - msg not ready */
- return 0;
- }
- }
-
+
plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n",
s_pfkey_type(msg->sadb_msg_type));
plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3);
return(error);
}
+/*
+ * PF_KEY packet handler
+ * 0: success
+ * -1: fail
+ */
+int
+pfkey_handler()
+{
+ struct sadb_msg *msg;
+ int len;
+
+ /* receive pfkey message. */
+ len = 0;
+ msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len);
+ if (msg == NULL) {
+ if (len < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to recv from pfkey (%s)\n",
+ strerror(errno));
+ return -1;
+ } else {
+ /* short message - msg not ready */
+ return 0;
+ }
+ }
+ return pfkey_process(msg);
+}
+
+void
+pfkey_post_handler()
+{
+ struct saved_msg_elem *elem;
+ struct saved_msg_elem *elem_tmp = NULL;
+
+ TAILQ_FOREACH_SAFE(elem, &lcconf->saved_msg_queue, chain, elem_tmp) {
+ pfkey_process((struct sadb_msg *)elem->msg);
+ TAILQ_REMOVE(&lcconf->saved_msg_queue, elem, chain);
+ racoon_free(elem);
+
+ }
+}
+
+int
+pfkey_save_msg(msg)
+ struct sadb_msg *msg;
+{
+ struct saved_msg_elem *elem;
+
+ elem = (struct saved_msg_elem *)racoon_calloc(sizeof(struct saved_msg_elem), 1);
+ if (elem == NULL)
+ return -1;
+ elem->msg = msg;
+ TAILQ_INSERT_TAIL(&lcconf->saved_msg_queue, elem, chain);
+ return 0;
+}
+
/*
* dump SADB
*/
continue;
}
- if (msg->sadb_msg_type != SADB_DUMP || msg->sadb_msg_pid != pid)
+ if (msg->sadb_msg_pid != pid)
+ continue;
+
+ /*
+ * for multi-processor system this had to be added because the messages can
+ * be interleaved - they won't all be dump messages
+ */
+ if (msg->sadb_msg_type != SADB_DUMP) { /* save for later processing */
+ pfkey_save_msg(msg);
+ msg = NULL;
continue;
+ }
ml = msg->sadb_msg_len << 3;
bl = buf ? buf->l : 0;
return -1;
}
+ if (iph2->is_dying) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "status mismatch phase2 dying (db:%d msg:%d)\n",
+ iph2->status, PHASE2ST_GETSPISENT);
+ return -1;
+ }
+
if (iph2->status != PHASE2ST_GETSPISENT) {
plog(LLV_ERROR, LOCATION, NULL,
"status mismatch (db:%d msg:%d)\n",
return -1;
}
+ // check the underlying iph2->ph1
+ if (!iph2->ph1) {
+ if (!ike_session_update_ph2_ph1bind(iph2)) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "can't proceed with getspi for %s. no suitable ISAKMP-SA found \n",
+ saddrwop2str(iph2->dst));
+ unbindph12(iph2);
+ remph2(iph2);
+ delph2(iph2);
+ return -1;
+ }
+ }
+
/* set SPI, and check to get all spi whether or not */
allspiok = 1;
notfound = 1;
plog(LLV_ERROR, LOCATION, NULL,
"get spi for unknown address %s\n",
saddrwop2str(iph2->dst));
+ unbindph12(iph2);
+ remph2(iph2);
+ delph2(iph2);
return -1;
}
memset (&natt, 0, sizeof (natt));
natt.sport = extract_port (iph2->ph1->remote);
flags |= SADB_X_EXT_NATT;
- if (iph2->ph1->natt_flags & NAT_DETECTED_ME)
- flags |= SADB_X_EXT_NATT_KEEPALIVE;
+ if (iph2->ph1->natt_flags & NAT_DETECTED_ME) {
+ if (iph2->ph1->rmconf->natt_keepalive == TRUE)
+ flags |= SADB_X_EXT_NATT_KEEPALIVE;
+ }
else if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
mode == IPSEC_MODE_TRANSPORT &&
src->sa_family == AF_INET)
return -1;
}
+ if (iph2->is_dying) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "status mismatch phase2 dying (db:%d msg:%d)\n",
+ iph2->status, PHASE2ST_ADDSA);
+ return -1;
+ }
+
if (iph2->status != PHASE2ST_ADDSA) {
plog(LLV_ERROR, LOCATION, NULL,
"status mismatch (db:%d msg:%d)\n",
/* update status */
iph2->status = PHASE2ST_ESTABLISHED;
+ if (iph2->side == INITIATOR) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_SUCC,
+ CONSTSTR("Initiator, Quick-Mode"),
+ CONSTSTR(NULL));
+ } else {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_SUCC,
+ CONSTSTR("Responder, Quick-Mode"),
+ CONSTSTR(NULL));
+ }
+
+ ike_session_ph2_established(iph2);
+
#ifdef ENABLE_STATS
gettimeofday(&iph2->end, NULL);
syslog(LOG_NOTICE, "%s(%s): %8.6f",
#endif
/* count up */
- iph2->ph1->ph2cnt++;
+ if (iph2->ph1)
+ iph2->ph1->ph2cnt++;
/* turn off schedule */
if (iph2->scr)
memset (&natt, 0, sizeof (natt));
natt.dport = extract_port (iph2->ph1->remote);
flags |= SADB_X_EXT_NATT;
- if (iph2->ph1->natt_flags & NAT_DETECTED_ME)
- flags |= SADB_X_EXT_NATT_KEEPALIVE;
+ if (iph2->ph1->natt_flags & NAT_DETECTED_ME) {
+ if (iph2->ph1->rmconf->natt_keepalive == TRUE)
+ flags |= SADB_X_EXT_NATT_KEEPALIVE;
+ }
else if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
mode == IPSEC_MODE_TRANSPORT &&
dst->sa_family == AF_INET)
sadbsecas2str(iph2->src, iph2->dst,
msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode));
+ ike_session_cleanup_other_established_ph2s(iph2->parent_session, iph2);
+
#ifdef ENABLE_VPNCONTROL_PORT
{
u_int32_t address;
sa_mode));
return 0;
}
- if (iph2->status != PHASE2ST_ESTABLISHED) {
+ if (iph2->is_dying || iph2->status != PHASE2ST_ESTABLISHED) {
/*
* If the status is not equal to PHASE2ST_ESTABLISHED,
* racoon ignores this expire message. There are two reason.
*/
plog(LLV_WARNING, LOCATION, NULL,
"the expire message is received "
- "but the handler has not been established.\n");
+ "but the handler is dying or has not been established.\n");
return 0;
}
iph2->status = PHASE2ST_EXPIRED;
- /* INITIATOR, begin phase 2 exchange. */
+ /* INITIATOR, begin phase 2 exchange only if there's no other established ph2. */
/* allocate buffer for status management of pfkey message */
- if (iph2->side == INITIATOR) {
+ if (iph2->side == INITIATOR &&
+ !ike_session_has_other_established_ph2(iph2->parent_session, iph2) &&
+ !ike_session_drop_rekey(iph2->parent_session)) {
initph2(iph2);
if (isakmp_post_acquire(iph2) < 0) {
plog(LLV_ERROR, LOCATION, iph2->dst,
"failed to begin ipsec sa "
- "re-negotication.\n");
+ "re-negotiation.\n");
unbindph12(iph2);
remph2(iph2);
delph2(iph2);
* should ignore such a acquire message because the phase 2
* is just negotiating.
* 2. its state is equal to PHASE2ST_ESTABLISHED, then racoon
- * has to prcesss such a acquire message because racoon may
- * lost the expire message.
+ * has to process such a acquire message because racoon may
+ * have lost the expire message.
*/
iph2[0] = getph2byid(src, dst, xpl->sadb_x_policy_id);
if (iph2[0] != NULL) {
return -1;
/* XXX should use the algorithm list from register message */
}
+#ifdef __APPLE__
+ if (link_sainfo_to_ph2(iph2[n]->sainfo) != 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to link sainfo\n");
+ iph2[n]->sainfo = NULL;
+ delph2(iph2[n]);
+ return -1;
+ }
+#endif
}
if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) {
/* XXX should be looped if there are multiple phase 2 handler. */
if (isakmp_post_acquire(iph2[n]) < 0) {
plog(LLV_ERROR, LOCATION, NULL,
- "failed to begin ipsec sa negotication.\n");
+ "failed to begin ipsec sa negotiation.\n");
goto err;
}
+
+#if !TARGET_OS_EMBEDDED
+ if ( lcconf->vt == NULL){
+ if (!(lcconf->vt = vproc_transaction_begin(NULL)))
+ plog(LLV_ERROR, LOCATION, NULL,
+ "vproc_transaction_begin returns NULL.\n");
+ }
+#endif
+
return 0;
err:
/* sanity check */
if (mhp[0] == NULL
- || mhp[SADB_EXT_SA] == NULL
|| mhp[SADB_EXT_ADDRESS_SRC] == NULL
|| mhp[SADB_EXT_ADDRESS_DST] == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
return -1;
}
+ plog(LLV_DEBUG2, LOCATION, NULL, "SADB delete message: proto-id %d\n", proto_id);
+ plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(src));
+ plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(dst));
+
+ if (!sa) {
+ deleteallph2(src, dst, proto_id);
+ deleteallph1(src, dst);
+ return 0;
+ }
+
iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
if (iph2 == NULL) {
/* ignore */
if (iph2->status == PHASE2ST_ESTABLISHED)
isakmp_info_send_d2(iph2);
+ ike_session_cleanup_ph1s_by_ph2(iph2);
unbindph12(iph2);
remph2(iph2);
delph2(iph2);
return -1;
}
- flushph2();
+ flushph2(false);
+ flushph1(false);
return 0;
}
return -1;
}
+ purgephXbyspid(xpl->sadb_x_policy_id, true);
+
remsp(sp);
delsp(sp);
return -1;
}
+ purgephXbyspid(xpl->sadb_x_policy_id, false);
+
remsp(sp);
delsp(sp);
return -1;
}
+ flushph2(false);
+ flushph1(false);
flushsp();
return 0;
return 0;
}
+int
+pk_sendget_inbound_sastats(ike_session_t *session)
+{
+ u_int32_t max_stats;
+ u_int32_t seq;
+
+ if (!session) {
+ plog(LLV_DEBUG, LOCATION, NULL, "invalid args in %s \n", __FUNCTION__);
+ return -1;
+ }
+
+ session->traffic_monitor.num_in_curr_req = 0;
+ bzero(session->traffic_monitor.in_curr_req, sizeof(session->traffic_monitor.in_curr_req));
+ max_stats = (sizeof(session->traffic_monitor.in_curr_req) / sizeof(session->traffic_monitor.in_curr_req[0]));
+
+ // get list of SAs
+ if ((session->traffic_monitor.num_in_curr_req = ike_session_get_sas_for_stats(session,
+ IPSEC_DIR_INBOUND,
+ &seq,
+ session->traffic_monitor.in_curr_req,
+ max_stats))) {
+ u_int64_t session_ids[] = {(u_int64_t)session, 0};
+
+ plog(LLV_DEBUG, LOCATION, NULL, "about to call %s\n", __FUNCTION__);
+
+ if (pfkey_send_getsastats(lcconf->sock_pfkey,
+ seq,
+ session_ids,
+ 1,
+ IPSEC_DIR_INBOUND,
+ session->traffic_monitor.in_curr_req,
+ session->traffic_monitor.num_in_curr_req) < 0) {
+ return -1;
+ }
+ plog(LLV_DEBUG, LOCATION, NULL, "%s successful\n", __FUNCTION__);
+
+ return session->traffic_monitor.num_in_curr_req;
+ }
+ return 0;
+}
+
+int
+pk_sendget_outbound_sastats(ike_session_t *session)
+{
+ u_int32_t max_stats;
+ u_int32_t seq;
+
+ if (!session) {
+ plog(LLV_DEBUG, LOCATION, NULL, "invalid args in %s \n", __FUNCTION__);
+ return -1;
+ }
+
+ session->traffic_monitor.num_out_curr_req = 0;
+ bzero(session->traffic_monitor.out_curr_req, sizeof(session->traffic_monitor.out_curr_req));
+ max_stats = (sizeof(session->traffic_monitor.out_curr_req) / sizeof(session->traffic_monitor.out_curr_req[0]));
+
+ // get list of SAs
+ if ((session->traffic_monitor.num_out_curr_req = ike_session_get_sas_for_stats(session,
+ IPSEC_DIR_OUTBOUND,
+ &seq,
+ session->traffic_monitor.out_curr_req,
+ max_stats))) {
+ u_int64_t session_ids[] = {(u_int64_t)session, 0};
+
+ plog(LLV_DEBUG, LOCATION, NULL, "about to call %s\n", __FUNCTION__);
+
+ if (pfkey_send_getsastats(lcconf->sock_pfkey,
+ seq,
+ session_ids,
+ 1,
+ IPSEC_DIR_OUTBOUND,
+ session->traffic_monitor.out_curr_req,
+ session->traffic_monitor.num_out_curr_req) < 0) {
+ return -1;
+ }
+ plog(LLV_DEBUG, LOCATION, NULL, "%s successful\n", __FUNCTION__);
+
+ return session->traffic_monitor.num_out_curr_req;
+ }
+ return 0;
+}
+
+/*
+ * receive GETSPDSTAT from kernel.
+ */
+static int
+pk_recvgetsastat(mhp)
+caddr_t *mhp;
+{
+ struct sadb_msg *msg;
+ struct sadb_session_id *session_id;
+ struct sadb_sastat *stat_resp;
+ ike_session_t *session;
+
+ /* validity check */
+ if (mhp[0] == NULL ||
+ mhp[SADB_EXT_SESSION_ID] == NULL ||
+ mhp[SADB_EXT_SASTAT] == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "inappropriate sadb getsastat response.\n");
+ return -1;
+ }
+ msg = (struct sadb_msg *)mhp[0];
+ session_id = (ike_session_t *)mhp[SADB_EXT_SESSION_ID];
+ stat_resp = (struct sadb_sastat *)mhp[SADB_EXT_SASTAT];
+
+ /* the message has to be processed or not ? */
+ if (msg->sadb_msg_pid != getpid()) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s message is not interesting "
+ "because pid %d is not mine.\n",
+ s_pfkey_type(msg->sadb_msg_type),
+ msg->sadb_msg_pid);
+ return -1;
+ }
+ if (!session_id->sadb_session_id_v[0]) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s message is bad "
+ "because session-id[0] is invalid.\n",
+ s_pfkey_type(msg->sadb_msg_type));
+ return -1;
+ }
+ session = (__typeof__(session))session_id->sadb_session_id_v[0];
+
+ if (!stat_resp->sadb_sastat_list_len) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s message is bad "
+ "because it has no sastats.\n",
+ s_pfkey_type(msg->sadb_msg_type));
+ return -1;
+ }
+
+ ike_session_update_traffic_idle_status(session,
+ stat_resp->sadb_sastat_dir,
+ (struct sastat *)(stat_resp + 1),
+ stat_resp->sadb_sastat_list_len);
+ return 0;
+}
+
/*
* check if the algorithm is supported or not.
* OUT 0: ok
*/
static struct sadb_msg *
pk_recv(so, lenp)
-int so;
-int *lenp;
+ int so;
+ int *lenp;
{
struct sadb_msg *newmsg;
int reallen = 0;
if (reallen == 0)
return NULL;
-
+
if ((newmsg = racoon_calloc(1, reallen)) == NULL)
return NULL;
-
+
*lenp = recv(so, (caddr_t)newmsg, reallen, 0);
if (*lenp < 0) {
racoon_free(newmsg);
racoon_free(newmsg);
return NULL;
}
-
+
return newmsg;
}
-
/* see handler.h */
u_int32_t
pk_getseq()