summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorThejaswini Singarajipura <Thejaswini.Singarajipura@Sun.COM>2008-09-29 19:18:37 -0400
committerThejaswini Singarajipura <Thejaswini.Singarajipura@Sun.COM>2008-09-29 19:18:37 -0400
commit9c2c14ab194d42014417b385d6bf226ba1a37995 (patch)
treeb8b65c127452666517bb3ad6f156dfdfa85dcc7a /usr
parent32d4e834df8b1687b6fe0dcb4bc2c56b9c1823af (diff)
downloadillumos-joyent-9c2c14ab194d42014417b385d6bf226ba1a37995.tar.gz
PSARC 2008/523 IPsec session failover
6398024 IPsec should support session failover across machines 6545486 PF_KEY needs to set an SA's sequence number
Diffstat (limited to 'usr')
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c44
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c106
-rw-r--r--usr/src/lib/libipsecutil/common/ikedoor.h17
-rw-r--r--usr/src/lib/libipsecutil/common/ipsec_util.c101
-rw-r--r--usr/src/lib/libipsecutil/common/ipsec_util.h11
-rw-r--r--usr/src/uts/common/inet/ip/ip.c51
-rw-r--r--usr/src/uts/common/inet/ip/ip_sadb.c17
-rw-r--r--usr/src/uts/common/inet/ip/ipdrop.c8
-rw-r--r--usr/src/uts/common/inet/ip/ipsecah.c51
-rw-r--r--usr/src/uts/common/inet/ip/ipsecesp.c47
-rw-r--r--usr/src/uts/common/inet/ip/keysock.c50
-rw-r--r--usr/src/uts/common/inet/ip/sadb.c562
-rw-r--r--usr/src/uts/common/inet/ipdrop.h6
-rw-r--r--usr/src/uts/common/inet/sadb.h51
-rw-r--r--usr/src/uts/common/net/pfkeyv2.h48
-rw-r--r--usr/src/uts/intel/ia32/ml/modstubs.s1
-rw-r--r--usr/src/uts/intel/ip/ip.global-objs.debug644
-rw-r--r--usr/src/uts/intel/ip/ip.global-objs.obj644
-rw-r--r--usr/src/uts/sparc/ip/ip.global-objs.debug644
-rw-r--r--usr/src/uts/sparc/ip/ip.global-objs.obj644
-rw-r--r--usr/src/uts/sparc/ml/modstubs.s1
21 files changed, 1072 insertions, 116 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c
index 7fc33db683..2c42b6ca79 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c
@@ -1377,6 +1377,9 @@ dhstr(int grp)
static void
print_hdr(char *prefix, ike_p1_hdr_t *hdrp)
{
+ char sbuf[TBUF_SIZE];
+ char tbuf[TBUF_SIZE];
+
(void) printf(
gettext("%s Cookies: Initiator 0x%llx Responder 0x%llx\n"),
prefix, ntohll(hdrp->p1hdr_cookies.cky_i),
@@ -1385,8 +1388,36 @@ print_hdr(char *prefix, ike_p1_hdr_t *hdrp)
hdrp->p1hdr_isinit ? gettext("initiator") : gettext("responder"));
(void) printf(gettext("%s ISAKMP version %d.%d; %s exchange\n"), prefix,
hdrp->p1hdr_major, hdrp->p1hdr_minor, xchgstr(hdrp->p1hdr_xchg));
- (void) printf(gettext("%s Current state is %s"), prefix,
+ (void) printf(gettext("%s Current state is %s\n"), prefix,
statestr(hdrp->p1hdr_state));
+ if (hdrp->p1hdr_support_dpd == B_FALSE) {
+ return;
+ }
+ (void) printf(gettext("%s Dead Peer Detection (RFC 3706)"
+ " enabled"), prefix);
+ if (hdrp->p1hdr_dpd_state < DPD_IN_PROGRESS) {
+ (void) printf("\n");
+ return;
+ }
+ if (strftime(tbuf, TBUF_SIZE, NULL,
+ localtime(&hdrp->p1hdr_dpd_time)) == 0) {
+ (void) strlcpy(tbuf, gettext("<time conversion failed>"),
+ TBUF_SIZE);
+ }
+ (void) printf(gettext("\n%s Dead Peer Detection handshake "), prefix);
+ switch (hdrp->p1hdr_dpd_state) {
+ case DPD_SUCCESSFUL:
+ (void) strlcpy(sbuf, gettext("was successful at "), TBUF_SIZE);
+ (void) printf("%s %s", sbuf, tbuf);
+ break;
+ case DPD_FAILURE:
+ (void) strlcpy(sbuf, gettext("failed at "), TBUF_SIZE);
+ (void) printf("%s %s", sbuf, tbuf);
+ break;
+ case DPD_IN_PROGRESS:
+ (void) strlcpy(sbuf, gettext("is in progress."), TBUF_SIZE);
+ break;
+ }
(void) printf("\n");
}
@@ -1863,6 +1894,9 @@ print_rule(ike_rule_t *rp)
gettext("GLOBL: p2_lifetime=%u seconds, p2_softlife=%u seconds\n"),
rp->rule_p2_lifetime_secs, rp->rule_p2_softlife_secs);
(void) printf(
+ gettext("GLOBL: p2_idletime=%u seconds\n"),
+ rp->rule_p2_idletime_secs);
+ (void) printf(
gettext("GLOBL: p2_lifetime_kb=%u seconds,"
" p2_softlife_kb=%u seconds\n"),
rp->rule_p2_lifetime_kb, rp->rule_p2_softlife_kb);
@@ -2003,6 +2037,10 @@ do_print_defaults(ike_defaults_t *dp)
gettext("seconds"), B_FALSE, ddp->rule_p2_softlife_secs,
dp->rule_p2_softlife_secs);
+ print_defaults("p2_idletime_secs", gettext("phase 2 idle time"),
+ gettext("seconds"), B_FALSE, ddp->rule_p2_idletime_secs,
+ dp->rule_p2_idletime_secs);
+
print_defaults("-", gettext("system phase 2 lifetime"),
gettext("seconds"), B_FALSE, ddp->sys_p2_lifetime_secs,
dp->sys_p2_lifetime_secs);
@@ -2011,6 +2049,10 @@ do_print_defaults(ike_defaults_t *dp)
gettext("seconds"), B_FALSE, ddp->sys_p2_softlife_secs,
dp->sys_p2_softlife_secs);
+ print_defaults("-", gettext("system phase 2 idle time"),
+ gettext("seconds"), B_FALSE, ddp->sys_p2_idletime_secs,
+ dp->sys_p2_idletime_secs);
+
print_defaults("p2_lifetime_kb", gettext("phase 2 lifetime"),
gettext("bytes"), B_TRUE, ddp->rule_p2_lifetime_kb,
dp->rule_p2_lifetime_kb);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c
index a156780705..4ab676fc9c 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c
@@ -31,8 +31,6 @@
* to systems without POSIX threads.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
@@ -58,10 +56,12 @@
#include <fcntl.h>
#include <strings.h>
#include <ctype.h>
+#include <sys/cladm.h>
#include <ipsec_util.h>
static int keysock;
+static int cluster_socket;
static uint32_t seq;
static pid_t mypid;
static boolean_t vflag = B_FALSE; /* Verbose? */
@@ -69,6 +69,8 @@ static boolean_t cflag = B_FALSE; /* Check Only */
char *my_fmri = NULL;
FILE *debugfile = stdout;
+static struct sockaddr_in cli_addr;
+static boolean_t in_cluster_mode = B_FALSE;
#define MAX_GET_SIZE 1024
/*
@@ -436,6 +438,9 @@ parsesatype(char *type, char *ebuf)
#define TOK_PAIR_SPI 48
#define TOK_FLAG_INBOUND 49
#define TOK_FLAG_OUTBOUND 50
+#define TOK_REPLAY_VALUE 51
+#define TOK_IDLE_ADDTIME 52
+#define TOK_IDLE_USETIME 53
static struct toktable {
char *string;
@@ -519,6 +524,10 @@ static struct toktable {
{"outbound", TOK_FLAG_OUTBOUND, NULL},
{"inbound", TOK_FLAG_INBOUND, NULL},
+
+ {"replay_value", TOK_REPLAY_VALUE, NEXTNUM},
+ {"idle_addtime", TOK_IDLE_ADDTIME, NEXTNUM},
+ {"idle_usetime", TOK_IDLE_USETIME, NEXTNUM},
{NULL, TOK_UNKNOWN, NEXTEOF}
};
@@ -1191,6 +1200,16 @@ doaddresses(uint8_t sadb_msg_type, uint8_t sadb_msg_satype, int cmd,
if (rc == -1)
Bail("write() to PF_KEY socket "
"(in doaddresses)");
+ /*
+ * Sends the message to the Solaris Cluster daemon
+ */
+
+ if (in_cluster_mode) {
+ (void) sendto(cluster_socket, buffer,
+ SADB_64TO8(msgp->sadb_msg_len), 0,
+ (struct sockaddr *)&cli_addr,
+ sizeof (cli_addr));
+ }
time_critical_enter();
do {
@@ -1417,6 +1436,12 @@ doaddresses(uint8_t sadb_msg_type, uint8_t sadb_msg_satype, int cmd,
if (rc == -1)
Bail("write() to PF_KEY socket (in doaddresses)");
+ if (in_cluster_mode) {
+ (void) sendto(cluster_socket, buffer,
+ SADB_64TO8(msgp->sadb_msg_len), 0,
+ (struct sockaddr *)&cli_addr,
+ sizeof (cli_addr));
+ }
/* Blank the key for paranoia's sake. */
bzero(buffer, buffer_size);
time_critical_enter();
@@ -1541,6 +1566,8 @@ doaddup(int cmd, int satype, char *argv[], char *ebuf)
struct sadb_key *encrypt = NULL, *auth = NULL;
struct sadb_ident *srcid = NULL, *dstid = NULL;
struct sadb_lifetime *hard = NULL, *soft = NULL; /* Current? */
+ struct sadb_lifetime *idle = NULL;
+ struct sadb_x_replay_ctr *replay_ctr = NULL;
struct sockaddr_in6 *sin6;
/* MLS TODO: Need sensitivity eventually. */
int next, token, sa_len, alloclen, totallen = sizeof (msg), prefix;
@@ -2419,6 +2446,58 @@ doaddup(int cmd, int satype, char *argv[], char *ebuf)
case TOK_FLAG_OUTBOUND:
assoc->sadb_sa_flags |= SADB_X_SAFLAGS_OUTBOUND;
break;
+ case TOK_REPLAY_VALUE:
+ if (replay_ctr != NULL) {
+ ERROR(ep, ebuf, gettext(
+ "Can only specify single "
+ "replay value."));
+ break;
+ }
+ replay_ctr = calloc(1, sizeof (*replay_ctr));
+ if (replay_ctr == NULL) {
+ Bail("malloc(replay value)");
+ }
+ /*
+ * We currently do not support a 64-bit
+ * replay value. RFC 4301 will require one,
+ * however, and we have a field in place when
+ * 4301 is built.
+ */
+ replay_ctr->sadb_x_rc_exttype = SADB_X_EXT_REPLAY_VALUE;
+ replay_ctr->sadb_x_rc_len =
+ SADB_8TO64(sizeof (*replay_ctr));
+ totallen += sizeof (*replay_ctr);
+ replay_ctr->sadb_x_rc_replay32 = (uint32_t)parsenum(
+ *argv, B_TRUE, ebuf);
+ argv++;
+ break;
+ case TOK_IDLE_ADDTIME:
+ case TOK_IDLE_USETIME:
+ if (idle == NULL) {
+ idle = calloc(1, sizeof (*idle));
+ if (idle == NULL) {
+ Bail("malloc idle lifetime");
+ }
+ idle->sadb_lifetime_exttype =
+ SADB_X_EXT_LIFETIME_IDLE;
+ idle->sadb_lifetime_len =
+ SADB_8TO64(sizeof (*idle));
+ totallen += sizeof (*idle);
+ }
+ switch (token) {
+ case TOK_IDLE_ADDTIME:
+ idle->sadb_lifetime_addtime =
+ (uint32_t)parsenum(*argv,
+ B_TRUE, ebuf);
+ break;
+ case TOK_IDLE_USETIME:
+ idle->sadb_lifetime_usetime =
+ (uint32_t)parsenum(*argv,
+ B_TRUE, ebuf);
+ break;
+ }
+ argv++;
+ break;
default:
ERROR1(ep, ebuf, gettext(
"Don't use extension %s for add/update.\n"),
@@ -2601,6 +2680,12 @@ doaddup(int cmd, int satype, char *argv[], char *ebuf)
free(soft);
}
+ if (idle != NULL) {
+ bcopy(idle, nexthdr, SADB_64TO8(idle->sadb_lifetime_len));
+ nexthdr += idle->sadb_lifetime_len;
+ free(idle);
+ }
+
if (encrypt == NULL && auth == NULL && cmd == CMD_ADD) {
ERROR(ep, ebuf, gettext(
"Must have at least one key for an add.\n"));
@@ -2706,6 +2791,13 @@ doaddup(int cmd, int satype, char *argv[], char *ebuf)
nexthdr += idst->sadb_address_len;
}
+ if (replay_ctr != NULL) {
+ bcopy(replay_ctr, nexthdr,
+ SADB_64TO8(replay_ctr->sadb_x_rc_len));
+ nexthdr += replay_ctr->sadb_x_rc_len;
+ free(replay_ctr);
+ }
+
if (cflag) {
/*
* Assume the checked cmd would have worked if it was actually
@@ -3289,6 +3381,7 @@ main(int argc, char *argv[])
boolean_t dosave = B_FALSE, readfile = B_FALSE;
char *configfile = NULL;
struct stat sbuf;
+ int bootflags;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
@@ -3383,6 +3476,15 @@ main(int argc, char *argv[])
}
}
+ if ((_cladm(CL_INITIALIZE, CL_GET_BOOTFLAG, &bootflags) != 0) ||
+ (bootflags & CLUSTER_BOOTED)) {
+ in_cluster_mode = B_TRUE;
+ cluster_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ cli_addr.sin_family = AF_INET;
+ cli_addr.sin_addr.s_addr = INADDR_LOOPBACK;
+ cli_addr.sin_port = htons(CLUSTER_UDP_PORT);
+ }
+
if (dosave) {
mask_signals(B_FALSE); /* Mask signals */
dodump(SADB_SATYPE_UNSPEC, savefile);
diff --git a/usr/src/lib/libipsecutil/common/ikedoor.h b/usr/src/lib/libipsecutil/common/ikedoor.h
index 2e4248b5d9..1a67284e38 100644
--- a/usr/src/lib/libipsecutil/common/ikedoor.h
+++ b/usr/src/lib/libipsecutil/common/ikedoor.h
@@ -26,8 +26,6 @@
#ifndef _IKEDOOR_H
#define _IKEDOOR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -81,6 +79,15 @@ typedef enum {
IKE_SVC_ERROR
} ike_svccmd_t;
+/* DPD status */
+
+typedef enum dpd_status {
+ DPD_NOT_INITIATED = 0,
+ DPD_IN_PROGRESS,
+ DPD_SUCCESSFUL,
+ DPD_FAILURE
+} dpd_status_t;
+
#define IKE_SVC_MAX IKE_SVC_ERROR
@@ -161,8 +168,10 @@ typedef struct {
uint32_t rule_p1_nonce_len;
uint32_t rule_p2_lifetime_secs;
uint32_t rule_p2_softlife_secs;
+ uint32_t rule_p2_idletime_secs;
uint32_t sys_p2_lifetime_secs;
uint32_t sys_p2_softlife_secs;
+ uint32_t sys_p2_idletime_secs;
uint32_t rule_p2_lifetime_kb;
uint32_t rule_p2_softlife_kb;
uint32_t sys_p2_lifetime_bytes;
@@ -197,6 +206,9 @@ typedef struct {
uint8_t p1hdr_xchg;
uint8_t p1hdr_isinit;
uint32_t p1hdr_state;
+ boolean_t p1hdr_support_dpd;
+ dpd_status_t p1hdr_dpd_state;
+ time_t p1hdr_dpd_time;
} ike_p1_hdr_t;
/* values for p1hdr_xchg (aligned with RFC2408, section 3.1) */
@@ -344,6 +356,7 @@ typedef struct {
uint32_t rule_p2_pfs;
uint32_t rule_p2_lifetime_secs;
uint32_t rule_p2_softlife_secs;
+ uint32_t rule_p2_idletime_secs;
uint32_t rule_p2_lifetime_kb;
uint32_t rule_p2_softlife_kb;
uint16_t rule_xform_cnt;
diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.c b/usr/src/lib/libipsecutil/common/ipsec_util.c
index 39c37a5b7f..b64c240407 100644
--- a/usr/src/lib/libipsecutil/common/ipsec_util.c
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.c
@@ -1494,7 +1494,7 @@ print_sa(FILE *file, char *prefix, struct sadb_sa *assoc)
}
(void) fprintf(file, dgettext(TEXT_DOMAIN,
- "%sSADB_ASSOC spi=0x%x, replay=%u, state="),
+ "%sSADB_ASSOC spi=0x%x, replay window size=%u, state="),
prefix, ntohl(assoc->sadb_sa_spi), assoc->sadb_sa_replay);
switch (assoc->sadb_sa_state) {
case SADB_SASTATE_LARVAL:
@@ -1509,6 +1509,13 @@ print_sa(FILE *file, char *prefix, struct sadb_sa *assoc)
case SADB_SASTATE_DEAD:
(void) fprintf(file, dgettext(TEXT_DOMAIN, "DEAD"));
break;
+ case SADB_X_SASTATE_ACTIVE_ELSEWHERE:
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "ACTIVE_ELSEWHERE"));
+ break;
+ case SADB_X_SASTATE_IDLE:
+ (void) fprintf(file, dgettext(TEXT_DOMAIN, "IDLE"));
+ break;
default:
(void) fprintf(file, dgettext(TEXT_DOMAIN,
"<unknown %u>"), assoc->sadb_sa_state);
@@ -1595,12 +1602,14 @@ printsatime(FILE *file, int64_t lt, const char *msg, const char *pfx,
*/
void
print_lifetimes(FILE *file, time_t wallclock, struct sadb_lifetime *current,
- struct sadb_lifetime *hard, struct sadb_lifetime *soft, boolean_t vflag)
+ struct sadb_lifetime *hard, struct sadb_lifetime *soft,
+ struct sadb_lifetime *idle, boolean_t vflag)
{
int64_t scratch;
char *soft_prefix = dgettext(TEXT_DOMAIN, "SLT: ");
char *hard_prefix = dgettext(TEXT_DOMAIN, "HLT: ");
char *current_prefix = dgettext(TEXT_DOMAIN, "CLT: ");
+ char *idle_prefix = dgettext(TEXT_DOMAIN, "ILT: ");
if (current != NULL &&
current->sadb_lifetime_len != SADB_8TO64(sizeof (*current))) {
@@ -1623,6 +1632,13 @@ print_lifetimes(FILE *file, time_t wallclock, struct sadb_lifetime *current,
SADB_64TO8(soft->sadb_lifetime_len));
}
+ if (idle != NULL &&
+ idle->sadb_lifetime_len != SADB_8TO64(sizeof (*idle))) {
+ warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
+ "WARNING: IDLE lifetime extension length (%u) is bad."),
+ SADB_64TO8(idle->sadb_lifetime_len));
+ }
+
(void) fprintf(file, " LT: Lifetime information\n");
if (current != NULL) {
@@ -1774,6 +1790,16 @@ print_lifetimes(FILE *file, time_t wallclock, struct sadb_lifetime *current,
}
}
}
+ if (idle != NULL) {
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "%sIdle lifetime information: "), idle_prefix);
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "%s%llu seconds of post-add lifetime.\n"),
+ idle_prefix, idle->sadb_lifetime_addtime);
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "%s%llu seconds of post-use lifetime.\n"),
+ idle_prefix, idle->sadb_lifetime_usetime);
+ }
}
/*
@@ -2157,6 +2183,30 @@ print_kmc(FILE *file, char *prefix, struct sadb_x_kmc *kmc)
"%sProtocol %u, cookie=\"%s\" (%u)\n"), prefix,
kmc->sadb_x_kmc_proto, cookie_label, kmc->sadb_x_kmc_cookie);
}
+
+/*
+ * Print an SADB_X_EXT_REPLAY_CTR extension.
+ */
+
+void
+print_replay(FILE *file, char *prefix, sadb_x_replay_ctr_t *repl)
+{
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "%sReplay Value "), prefix);
+ if ((repl->sadb_x_rc_replay32 == 0) &&
+ (repl->sadb_x_rc_replay64 == 0)) {
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "<Value not found.>"));
+ }
+ /*
+ * We currently do not support a 64-bit replay value.
+ * RFC 4301 will require one, however, and we have a field
+ * in place when 4301 is built.
+ */
+ (void) fprintf(file, "% " PRIu64 "\n",
+ ((repl->sadb_x_rc_replay32 == 0) ?
+ repl->sadb_x_rc_replay64 : repl->sadb_x_rc_replay32));
+}
/*
* Print an SADB_X_EXT_PAIR extension.
*/
@@ -2179,6 +2229,7 @@ print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp,
struct sadb_msg *samsg = (struct sadb_msg *)buffer;
struct sadb_ext *ext;
struct sadb_lifetime *currentlt = NULL, *hardlt = NULL, *softlt = NULL;
+ struct sadb_lifetime *idlelt = NULL;
int i;
time_t wallclock;
@@ -2209,6 +2260,9 @@ print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp,
case SADB_EXT_LIFETIME_SOFT:
softlt = (struct sadb_lifetime *)current;
break;
+ case SADB_X_EXT_LIFETIME_IDLE:
+ idlelt = (struct sadb_lifetime *)current;
+ break;
case SADB_EXT_ADDRESS_SRC:
print_address(file, dgettext(TEXT_DOMAIN, "SRC: "),
@@ -2282,6 +2336,10 @@ print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp,
print_pair(file, dgettext(TEXT_DOMAIN, "OTH: "),
(struct sadb_x_pair *)current);
break;
+ case SADB_X_EXT_REPLAY_VALUE:
+ (void) print_replay(file, dgettext(TEXT_DOMAIN,
+ "RPL: "), (sadb_x_replay_ctr_t *)current);
+ break;
default:
(void) fprintf(file, dgettext(TEXT_DOMAIN,
"UNK: Unknown ext. %d, len %d.\n"),
@@ -2298,9 +2356,10 @@ print_samsg(FILE *file, uint64_t *buffer, boolean_t want_timestamp,
/*
* Print lifetimes NOW.
*/
- if (currentlt != NULL || hardlt != NULL || softlt != NULL)
- print_lifetimes(file, wallclock, currentlt, hardlt, softlt,
- vflag);
+ if (currentlt != NULL || hardlt != NULL || softlt != NULL ||
+ idlelt != NULL)
+ print_lifetimes(file, wallclock, currentlt, hardlt,
+ softlt, idlelt, vflag);
if (current - buffer != samsg->sadb_msg_len) {
warnxfp(EFD(file), dgettext(TEXT_DOMAIN,
@@ -2328,8 +2387,17 @@ save_lifetime(struct sadb_lifetime *lifetime, FILE *ofile)
{
char *prefix;
- prefix = (lifetime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT) ?
- "soft" : "hard";
+ switch (lifetime->sadb_lifetime_exttype) {
+ case SADB_EXT_LIFETIME_HARD:
+ prefix = "hard";
+ break;
+ case SADB_EXT_LIFETIME_SOFT:
+ prefix = "soft";
+ break;
+ case SADB_X_EXT_LIFETIME_IDLE:
+ prefix = "idle";
+ break;
+ }
if (putc('\t', ofile) == EOF)
return (B_FALSE);
@@ -2499,6 +2567,7 @@ save_assoc(uint64_t *buffer, FILE *ofile)
boolean_t seen_proto = B_FALSE, seen_iproto = B_FALSE;
uint64_t *current;
struct sadb_address *addr;
+ struct sadb_x_replay_ctr *repl;
struct sadb_msg *samsg = (struct sadb_msg *)buffer;
struct sadb_ext *ext;
@@ -2575,6 +2644,7 @@ save_assoc(uint64_t *buffer, FILE *ofile)
break;
case SADB_EXT_LIFETIME_HARD:
case SADB_EXT_LIFETIME_SOFT:
+ case SADB_X_EXT_LIFETIME_IDLE:
if (!save_lifetime((struct sadb_lifetime *)ext,
ofile)) {
tidyup();
@@ -2626,6 +2696,23 @@ skip_srcdst:
}
savenl();
break;
+ case SADB_X_EXT_REPLAY_VALUE:
+ repl = (sadb_x_replay_ctr_t *)ext;
+ if ((repl->sadb_x_rc_replay32 == 0) &&
+ (repl->sadb_x_rc_replay64 == 0)) {
+ tidyup();
+ bail(dgettext(TEXT_DOMAIN, "Replay Value"));
+ }
+ if (fprintf(ofile, "replay_value %" PRIu64 "",
+ (repl->sadb_x_rc_replay32 == 0 ?
+ repl->sadb_x_rc_replay64 :
+ repl->sadb_x_rc_replay32)) < 0) {
+ tidyup();
+ bail(dgettext(TEXT_DOMAIN,
+ "save_assoc: fprintf replay value"));
+ }
+ savenl();
+ break;
case SADB_EXT_SENSITIVITY:
default:
/* Skip over irrelevant extensions. */
diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.h b/usr/src/lib/libipsecutil/common/ipsec_util.h
index 00e16238a6..bd147c06ef 100644
--- a/usr/src/lib/libipsecutil/common/ipsec_util.h
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.h
@@ -26,8 +26,6 @@
#ifndef _IPSEC_UTIL_H
#define _IPSEC_UTIL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Headers and definitions for support functions that are shared by
* the ipsec utilities ipseckey and ikeadm.
@@ -84,6 +82,12 @@ extern "C" {
((sbuf).st_mode & S_IRWXG) || ((sbuf).st_mode & S_IRWXO))
#endif
+/*
+ * Solaris UDP port used to communicate with the Solaris Cluster
+ * daemon. It is used only when the node is booted in cluster mode.
+ */
+#define CLUSTER_UDP_PORT 2005
+
/* For keyword-lookup tables */
typedef struct keywdtab {
uint_t kw_tag;
@@ -327,7 +331,8 @@ extern void print_sa(FILE *, char *, struct sadb_sa *);
extern void printsatime(FILE *, int64_t, const char *, const char *,
const char *, boolean_t);
extern void print_lifetimes(FILE *, time_t, struct sadb_lifetime *,
- struct sadb_lifetime *, struct sadb_lifetime *, boolean_t vflag);
+ struct sadb_lifetime *, struct sadb_lifetime *, struct sadb_lifetime *,
+ boolean_t vflag);
extern void print_address(FILE *, char *, struct sadb_address *, boolean_t);
extern void print_asn1_name(FILE *, const unsigned char *, long);
extern void print_key(FILE *, char *, struct sadb_key *);
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index d28bc10425..626ab1eff5 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -197,6 +197,30 @@ uint32_t (*cl_inet_ipident)(uint8_t protocol, sa_family_t addr_family,
uint8_t *laddrp, uint8_t *faddrp) = NULL;
/*
+ * Hook function to generate cluster wide SPI.
+ */
+void (*cl_inet_getspi)(uint8_t, uint8_t *, size_t) = NULL;
+
+/*
+ * Hook function to verify if the SPI is already utlized.
+ */
+
+int (*cl_inet_checkspi)(uint8_t, uint32_t) = NULL;
+
+/*
+ * Hook function to delete the SPI from the cluster wide repository.
+ */
+
+void (*cl_inet_deletespi)(uint8_t, uint32_t) = NULL;
+
+/*
+ * Hook function to inform the cluster when packet received on an IDLE SA
+ */
+
+void (*cl_inet_idlesa)(uint8_t, uint32_t, sa_family_t, in6_addr_t,
+ in6_addr_t) = NULL;
+
+/*
* Synchronization notes:
*
* IP is a fully D_MP STREAMS module/driver. Thus it does not depend on any
@@ -17570,6 +17594,7 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire,
case IPPROTO_AH:
case IPPROTO_ESP: {
ipsec_stack_t *ipss = ipst->ips_netstack->netstack_ipsec;
+ ipsa_t *assoc;
/*
* Fast path for AH/ESP. If this is the first time
@@ -17653,6 +17678,7 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire,
}
ipsec_rc = ii->ipsec_in_esp_sa->ipsa_input_func(
first_mp, esph);
+ assoc = ii->ipsec_in_esp_sa;
} else {
ah_t *ah = ipsec_inbound_ah_sa(first_mp, ns);
if (ah == NULL)
@@ -17661,10 +17687,35 @@ ip_proto_input(queue_t *q, mblk_t *mp, ipha_t *ipha, ire_t *ire,
ASSERT(ii->ipsec_in_ah_sa->ipsa_input_func != NULL);
ipsec_rc = ii->ipsec_in_ah_sa->ipsa_input_func(
first_mp, ah);
+ assoc = ii->ipsec_in_ah_sa;
}
switch (ipsec_rc) {
case IPSEC_STATUS_SUCCESS:
+ /*
+ * The packet is successfully processed but
+ * received on an SA which is in IDLE state.
+ * We queue the packet for subsequent
+ * processing after the SA moves to MATURE
+ * state.
+ */
+ if ((assoc != NULL) &&
+ (assoc->ipsa_state == IPSA_STATE_IDLE)) {
+ ASSERT(cl_inet_idlesa != NULL);
+ in6_addr_t srcaddr, dstaddr;
+ uint8_t protocol;
+ protocol = (assoc->ipsa_type == SADB_SATYPE_AH)
+ ? IPPROTO_AH : IPPROTO_ESP;
+ IPSA_COPY_ADDR(&srcaddr, assoc->ipsa_srcaddr,
+ assoc->ipsa_addrfam);
+ IPSA_COPY_ADDR(&dstaddr, assoc->ipsa_dstaddr,
+ assoc->ipsa_addrfam);
+ cl_inet_idlesa(protocol, assoc->ipsa_spi,
+ assoc->ipsa_addrfam, srcaddr,
+ dstaddr);
+ sadb_buf_pkt(assoc, first_mp, ns);
+ return;
+ }
break;
case IPSEC_STATUS_FAILED:
BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
diff --git a/usr/src/uts/common/inet/ip/ip_sadb.c b/usr/src/uts/common/inet/ip/ip_sadb.c
index c28cd31074..fb174eda6c 100644
--- a/usr/src/uts/common/inet/ip/ip_sadb.c
+++ b/usr/src/uts/common/inet/ip/ip_sadb.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/sunddi.h>
@@ -239,7 +237,7 @@ ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src,
retval->ipsa_auth_alg)
continue;
if (ap->ipa_apply.ipp_ah_minbits >
- retval->ipsa_authkeybits)
+ retval->ipsa_authkeybits)
continue;
} else {
if (!(ap->ipa_apply.ipp_use_esp))
@@ -315,7 +313,7 @@ ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src,
*/
if ((retval->ipsa_flags & IPSA_F_UNIQUE) &&
((unique_id & retval->ipsa_unique_mask) ==
- retval->ipsa_unique_id))
+ retval->ipsa_unique_id))
break;
/*
@@ -708,7 +706,8 @@ ipsec_inbound_ah_sa(mblk_t *mp, netstack_t *ns)
assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af);
mutex_exit(&hptr->isaf_lock);
- if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD) {
+ if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD ||
+ assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
IP_AH_BUMP_STAT(ipss, lookup_failure);
IP_AH_BUMP_STAT(ipss, in_discards);
ipsecah_in_assocfailure(ipsec_in, 0,
@@ -735,6 +734,7 @@ ipsec_inbound_ah_sa(mblk_t *mp, netstack_t *ns)
* already there (innermost SA "wins". The reference to
* the SA will also be used later when doing the policy checks.
*/
+
if (ii->ipsec_in_ah_sa != NULL) {
IPSA_REFRELE(ii->ipsec_in_ah_sa);
}
@@ -790,7 +790,7 @@ ipsec_inbound_esp_sa(mblk_t *ipsec_in_mp, netstack_t *ns)
if (data_mp->b_datap->db_ref > 1 ||
(data_mp->b_wptr - data_mp->b_rptr) <
(isv6 ? (ntohs(ip6h->ip6_plen) + sizeof (ip6_t))
- : ntohs(ipha->ipha_length))) {
+ : ntohs(ipha->ipha_length))) {
placeholder = msgpullup(data_mp, -1);
if (placeholder == NULL) {
IP_ESP_BUMP_STAT(ipss, in_discards);
@@ -846,7 +846,8 @@ ipsec_inbound_esp_sa(mblk_t *ipsec_in_mp, netstack_t *ns)
af);
mutex_exit(&bucket->isaf_lock);
- if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD) {
+ if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD ||
+ ipsa->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
/* This is a loggable error! AUDIT ME! */
IP_ESP_BUMP_STAT(ipss, lookup_failure);
IP_ESP_BUMP_STAT(ipss, in_discards);
diff --git a/usr/src/uts/common/inet/ip/ipdrop.c b/usr/src/uts/common/inet/ip/ipdrop.c
index 40d09933b6..a3d723d628 100644
--- a/usr/src/uts/common/inet/ip/ipdrop.c
+++ b/usr/src/uts/common/inet/ip/ipdrop.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/strsun.h>
@@ -83,6 +81,10 @@ ip_drop_init(ipsec_stack_t *ipss)
"sadb_inlarval_timeout", KSTAT_DATA_UINT64);
kstat_named_init(&ipss->ipsec_ip_drop_types->ipds_sadb_inlarval_replace,
"sadb_inlarval_replace", KSTAT_DATA_UINT64);
+ kstat_named_init(&ipss->ipsec_ip_drop_types->ipds_sadb_inidle_overflow,
+ "sadb_inidle_overflow", KSTAT_DATA_UINT64);
+ kstat_named_init(&ipss->ipsec_ip_drop_types->ipds_sadb_inidle_timeout,
+ "sadb_inidle_timeout", KSTAT_DATA_UINT64);
kstat_named_init(&ipss->ipsec_ip_drop_types->ipds_sadb_acquire_nomem,
"sadb_acquire_nomem", KSTAT_DATA_UINT64);
kstat_named_init(&ipss->ipsec_ip_drop_types->ipds_sadb_acquire_toofull,
diff --git a/usr/src/uts/common/inet/ip/ipsecah.c b/usr/src/uts/common/inet/ip/ipsecah.c
index 7073e8d91b..29ae1f8d61 100644
--- a/usr/src/uts/common/inet/ip/ipsecah.c
+++ b/usr/src/uts/common/inet/ip/ipsecah.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/stropts.h>
@@ -34,6 +32,7 @@
#include <sys/socket.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
+#include <sys/mkdev.h>
#include <sys/kmem.h>
#include <sys/zone.h>
#include <sys/sysmacros.h>
@@ -152,6 +151,8 @@ static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *);
static void *ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
static void ipsecah_stack_fini(netstackid_t stackid, void *arg);
+extern void (*cl_inet_getspi)(uint8_t, uint8_t *, size_t);
+
/* Setable in /etc/system */
uint32_t ah_hash_size = IPSEC_DEFAULT_HASH_SIZE;
@@ -1102,6 +1103,8 @@ ah_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
sadb_lifetime_t *hard =
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
+ sadb_lifetime_t *idle =
+ (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
ipsec_alginfo_t *aalg;
ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
ipsec_stack_t *ipss = ns->netstack_ipsec;
@@ -1138,7 +1141,8 @@ ah_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
/* Sundry ADD-specific reality checks. */
/* XXX STATS : Logging/stats here? */
- if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) {
+ if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) &&
+ (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
return (EINVAL);
}
@@ -1150,8 +1154,7 @@ ah_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
return (EINVAL);
}
-
- if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0)
+ if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0)
return (EINVAL);
ASSERT(src->sin_family == dst->sin_family);
@@ -1208,16 +1211,31 @@ static int
ah_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
ipsecah_stack_t *ahstack, uint8_t sadb_msg_type)
{
+ sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
sadb_address_t *dstext =
(sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
+ mblk_t *buf_pkt;
+ int rcode;
if (dstext == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
return (EINVAL);
}
- return (sadb_update_sa(mp, ksi, &ahstack->ah_sadb, diagnostic,
- ahstack->ah_pfkey_q, ah_add_sa, ahstack->ipsecah_netstack,
- sadb_msg_type));
+
+ rcode = sadb_update_sa(mp, ksi, &buf_pkt, &ahstack->ah_sadb,
+ diagnostic, ahstack->ah_pfkey_q, ah_add_sa,
+ ahstack->ipsecah_netstack, sadb_msg_type);
+
+ if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) ||
+ (rcode != 0)) {
+ return (rcode);
+ }
+
+ HANDLE_BUF_PKT(ah_taskq,
+ ahstack->ipsecah_netstack->netstack_ipsec, ahstack->ah_dropper,
+ buf_pkt);
+
+ return (rcode);
}
/*
@@ -1268,13 +1286,11 @@ ah_dump(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
* Dump each fanout, bailing if error is non-zero.
*/
- error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi->ks_in_serial,
- &ahstack->ah_sadb.s_v4);
+ error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi, &ahstack->ah_sadb.s_v4);
if (error != 0)
goto bail;
- error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi->ks_in_serial,
- &ahstack->ah_sadb.s_v6);
+ error = sadb_dump(ahstack->ah_pfkey_q, mp, ksi, &ahstack->ah_sadb.s_v6);
bail:
ASSERT(mp->b_cont != NULL);
samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
@@ -1365,6 +1381,7 @@ ah_parse_pfkey(mblk_t *mp, ipsecah_stack_t *ahstack)
break;
case SADB_DELETE:
case SADB_X_DELPAIR:
+ case SADB_X_DELPAIR_STATE:
error = ah_del_sa(mp, ksi, &diagnostic, ahstack,
samsg->sadb_msg_type);
if (error != 0) {
@@ -1941,9 +1958,15 @@ ah_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecah_stack_t *ahstack)
/*
* Randomly generate a proposed SPI value.
*/
- (void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t));
+ if (cl_inet_getspi != NULL) {
+ cl_inet_getspi(IPPROTO_AH, (uint8_t *)&newspi,
+ sizeof (uint32_t));
+ } else {
+ (void) random_get_pseudo_bytes((uint8_t *)&newspi,
+ sizeof (uint32_t));
+ }
newbie = sadb_getspi(ksi, newspi, &diagnostic,
- ahstack->ipsecah_netstack);
+ ahstack->ipsecah_netstack, IPPROTO_AH);
if (newbie == NULL) {
sadb_pfkey_error(ahstack->ah_pfkey_q, mp, ENOMEM, diagnostic,
diff --git a/usr/src/uts/common/inet/ip/ipsecesp.c b/usr/src/uts/common/inet/ip/ipsecesp.c
index fa062abf01..84049c0e3f 100644
--- a/usr/src/uts/common/inet/ip/ipsecesp.c
+++ b/usr/src/uts/common/inet/ip/ipsecesp.c
@@ -144,6 +144,8 @@ static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t,
static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t);
static ipsec_status_t esp_submit_req_outbound(mblk_t *, ipsa_t *, uchar_t *,
uint_t);
+extern void (*cl_inet_getspi)(uint8_t, uint8_t *, size_t);
+
/* Setable in /etc/system */
uint32_t esp_hash_size = IPSEC_DEFAULT_HASH_SIZE;
@@ -1484,9 +1486,15 @@ esp_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack)
/*
* Randomly generate a proposed SPI value
*/
- (void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t));
+ if (cl_inet_getspi != NULL) {
+ cl_inet_getspi(IPPROTO_ESP, (uint8_t *)&newspi,
+ sizeof (uint32_t));
+ } else {
+ (void) random_get_pseudo_bytes((uint8_t *)&newspi,
+ sizeof (uint32_t));
+ }
newbie = sadb_getspi(ksi, newspi, &diagnostic,
- espstack->ipsecesp_netstack);
+ espstack->ipsecesp_netstack, IPPROTO_ESP);
if (newbie == NULL) {
sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM, diagnostic,
@@ -1733,7 +1741,6 @@ esp_port_freshness(uint32_t ports, ipsa_t *assoc)
IPSA_REFRELE(outbound_peer);
ESP_BUMP_STAT(espstack, sa_port_renumbers);
}
-
/*
* Finish processing of an inbound ESP packet after processing by the
* crypto framework.
@@ -3417,6 +3424,8 @@ esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
sadb_lifetime_t *hard =
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
+ sadb_lifetime_t *idle =
+ (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
ipsec_stack_t *ipss = ns->netstack_ipsec;
@@ -3455,7 +3464,9 @@ esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
/* Sundry ADD-specific reality checks. */
/* XXX STATS : Logging/stats here? */
- if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) {
+
+ if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) &&
+ (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
return (EINVAL);
}
@@ -3475,7 +3486,7 @@ esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
return (EINVAL);
}
- if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0) {
+ if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0) {
return (EINVAL);
}
ASSERT(src->sin_family == dst->sin_family);
@@ -3608,6 +3619,10 @@ static int
esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
ipsecesp_stack_t *espstack, uint8_t sadb_msg_type)
{
+ sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
+ mblk_t *buf_pkt;
+ int rcode;
+
sadb_address_t *dstext =
(sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
@@ -3616,9 +3631,20 @@ esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
return (EINVAL);
}
- return (sadb_update_sa(mp, ksi, &espstack->esp_sadb,
- diagnostic, espstack->esp_pfkey_q,
- esp_add_sa, espstack->ipsecesp_netstack, sadb_msg_type));
+ rcode = sadb_update_sa(mp, ksi, &buf_pkt, &espstack->esp_sadb,
+ diagnostic, espstack->esp_pfkey_q, esp_add_sa,
+ espstack->ipsecesp_netstack, sadb_msg_type);
+
+ if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) ||
+ (rcode != 0)) {
+ return (rcode);
+ }
+
+ HANDLE_BUF_PKT(esp_taskq,
+ espstack->ipsecesp_netstack->netstack_ipsec,
+ espstack->esp_dropper, buf_pkt);
+
+ return (rcode);
}
/*
@@ -3669,12 +3695,12 @@ esp_dump(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack)
* Dump each fanout, bailing if error is non-zero.
*/
- error = sadb_dump(espstack->esp_pfkey_q, mp, ksi->ks_in_serial,
+ error = sadb_dump(espstack->esp_pfkey_q, mp, ksi,
&espstack->esp_sadb.s_v4);
if (error != 0)
goto bail;
- error = sadb_dump(espstack->esp_pfkey_q, mp, ksi->ks_in_serial,
+ error = sadb_dump(espstack->esp_pfkey_q, mp, ksi,
&espstack->esp_sadb.s_v6);
bail:
ASSERT(mp->b_cont != NULL);
@@ -3757,6 +3783,7 @@ esp_parse_pfkey(mblk_t *mp, ipsecesp_stack_t *espstack)
break;
case SADB_DELETE:
case SADB_X_DELPAIR:
+ case SADB_X_DELPAIR_STATE:
error = esp_del_sa(mp, ksi, &diagnostic, espstack,
samsg->sadb_msg_type);
if (error != 0) {
diff --git a/usr/src/uts/common/inet/ip/keysock.c b/usr/src/uts/common/inet/ip/keysock.c
index fde13d5abf..c982fb4c45 100644
--- a/usr/src/uts/common/inet/ip/keysock.c
+++ b/usr/src/uts/common/inet/ip/keysock.c
@@ -23,9 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stream.h>
@@ -1555,6 +1552,29 @@ keysock_extended_register(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[])
atomic_add_32(&keystack->keystack_num_extended, 1);
}
+static void
+keysock_delpair_all(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[])
+{
+ int i, start, finish;
+ mblk_t *mp1 = NULL;
+ keysock_stack_t *keystack = ks->keysock_keystack;
+
+ start = 0;
+ finish = KEYSOCK_MAX_CONSUMERS - 1;
+
+ for (i = start; i <= finish; i++) {
+ if (keystack->keystack_consumers[i] != NULL) {
+ mp1 = copymsg(mp);
+ if (mp1 == NULL) {
+ keysock_error(ks, mp, ENOMEM,
+ SADB_X_DIAGNOSTIC_NONE);
+ return;
+ }
+ keysock_passdown(ks, mp1, i, extv, B_FALSE);
+ }
+ }
+}
+
/*
* Handle PF_KEY messages.
*/
@@ -1676,6 +1696,14 @@ keysock_parse(queue_t *q, mblk_t *mp)
else keysock_error(ks, mp, EINVAL,
SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
return;
+ case SADB_X_DELPAIR_STATE:
+ if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
+ keysock_delpair_all(ks, mp, extv);
+ } else {
+ keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv,
+ B_FALSE);
+ }
+ return;
case SADB_ACQUIRE:
/*
* If I _receive_ an acquire, this means I should spread it
@@ -1730,9 +1758,8 @@ keysock_parse(queue_t *q, mblk_t *mp)
*/
break;
case SADB_FLUSH:
- case SADB_DUMP: /* not used by normal applications */
/*
- * Nuke all SAs, or dump out the whole SA table to sender only.
+ * Nuke all SAs.
*
* No extensions at all. Return to all listeners.
*
@@ -1742,7 +1769,7 @@ keysock_parse(queue_t *q, mblk_t *mp)
*/
if (extv[0] != NULL) {
/*
- * FLUSH or DUMP messages shouldn't have extensions.
+ * FLUSH messages shouldn't have extensions.
* Return EINVAL.
*/
ks2dbg(keystack, ("FLUSH message with extension.\n"));
@@ -1753,6 +1780,17 @@ keysock_parse(queue_t *q, mblk_t *mp)
/* Passing down of DUMP/FLUSH messages are special. */
qwriter(q, mp, keysock_do_flushdump, PERIM_INNER);
return;
+ case SADB_DUMP: /* not used by normal applications */
+ if ((extv[0] != NULL) &&
+ ((msgsize >
+ (sizeof (sadb_msg_t) + sizeof (sadb_x_edump_t))) ||
+ (extv[SADB_X_EXT_EDUMP] == NULL))) {
+ keysock_error(ks, mp, EINVAL,
+ SADB_X_DIAGNOSTIC_NO_EXT);
+ return;
+ }
+ qwriter(q, mp, keysock_do_flushdump, PERIM_INNER);
+ return;
case SADB_X_PROMISC:
/*
* Promiscuous processing message.
diff --git a/usr/src/uts/common/inet/ip/sadb.c b/usr/src/uts/common/inet/ip/sadb.c
index 8f8e8c51a9..a329a87da2 100644
--- a/usr/src/uts/common/inet/ip/sadb.c
+++ b/usr/src/uts/common/inet/ip/sadb.c
@@ -83,6 +83,11 @@ static mblk_t *sadb_sa2msg(ipsa_t *, sadb_msg_t *);
static time_t sadb_add_time(time_t, uint64_t);
static void lifetime_fuzz(ipsa_t *);
static void age_pair_peer_list(templist_t *, sadb_t *, boolean_t);
+static void ipsa_set_replay(ipsa_t *ipsa, uint32_t offset);
+
+extern void (*cl_inet_getspi)(uint8_t protocol, uint8_t *ptr, size_t len);
+extern int (*cl_inet_checkspi)(uint8_t protocol, uint32_t spi);
+extern void (*cl_inet_deletespi)(uint8_t protocol, uint32_t spi);
/*
* ipsacq_maxpackets is defined here to make it tunable
@@ -320,6 +325,20 @@ sadb_unlinkassoc(ipsa_t *ipsa)
IPSA_REFRELE(ipsa);
}
+void
+sadb_delete_cluster(ipsa_t *assoc)
+{
+ uint8_t protocol;
+
+ if (cl_inet_deletespi &&
+ ((assoc->ipsa_state == IPSA_STATE_LARVAL) ||
+ (assoc->ipsa_state == IPSA_STATE_MATURE))) {
+ protocol = (assoc->ipsa_type == SADB_SATYPE_AH) ?
+ IPPROTO_AH : IPPROTO_ESP;
+ cl_inet_deletespi(protocol, assoc->ipsa_spi);
+ }
+}
+
/*
* Create a larval security association with the specified SPI. All other
* fields are zeroed.
@@ -547,12 +566,13 @@ sadb_keysock_out(minor_t serial)
*/
static int
sadb_dump_fanout(queue_t *pfkey_q, mblk_t *mp, minor_t serial, isaf_t *fanout,
- int num_entries, boolean_t do_peers)
+ int num_entries, boolean_t do_peers, time_t active_time)
{
int i, error = 0;
mblk_t *original_answer;
ipsa_t *walker;
sadb_msg_t *samsg;
+ time_t current;
/*
* For each IPSA hash bucket do:
@@ -566,12 +586,16 @@ sadb_dump_fanout(queue_t *pfkey_q, mblk_t *mp, minor_t serial, isaf_t *fanout,
if (original_answer == NULL)
return (ENOMEM);
+ current = gethrestime_sec();
for (i = 0; i < num_entries; i++) {
mutex_enter(&fanout[i].isaf_lock);
for (walker = fanout[i].isaf_ipsa; walker != NULL;
walker = walker->ipsa_next) {
if (!do_peers && walker->ipsa_haspeer)
continue;
+ if ((active_time != 0) &&
+ ((current - walker->ipsa_lastuse) > active_time))
+ continue;
error = sadb_dump_deliver(pfkey_q, original_answer,
walker, samsg);
if (error == ENOBUFS) {
@@ -605,19 +629,26 @@ sadb_dump_fanout(queue_t *pfkey_q, mblk_t *mp, minor_t serial, isaf_t *fanout,
*/
int
-sadb_dump(queue_t *pfkey_q, mblk_t *mp, minor_t serial, sadb_t *sp)
+sadb_dump(queue_t *pfkey_q, mblk_t *mp, keysock_in_t *ksi, sadb_t *sp)
{
int error;
+ time_t active_time = 0;
+ sadb_x_edump_t *edump =
+ (sadb_x_edump_t *)ksi->ks_in_extv[SADB_X_EXT_EDUMP];
+
+ if (edump != NULL) {
+ active_time = edump->sadb_x_edump_timeout;
+ }
/* Dump outbound */
- error = sadb_dump_fanout(pfkey_q, mp, serial, sp->sdb_of,
- sp->sdb_hashsize, B_TRUE);
+ error = sadb_dump_fanout(pfkey_q, mp, ksi->ks_in_serial, sp->sdb_of,
+ sp->sdb_hashsize, B_TRUE, active_time);
if (error)
return (error);
/* Dump inbound */
- return sadb_dump_fanout(pfkey_q, mp, serial, sp->sdb_if,
- sp->sdb_hashsize, B_FALSE);
+ return sadb_dump_fanout(pfkey_q, mp, ksi->ks_in_serial, sp->sdb_if,
+ sp->sdb_hashsize, B_FALSE, active_time);
}
/*
@@ -989,18 +1020,31 @@ sadb_ill_download(ill_t *ill, uint_t sa_type)
* when a module is unloaded).
*/
static void
-sadb_destroyer(isaf_t **tablep, uint_t numentries, boolean_t forever)
+sadb_destroyer(isaf_t **tablep, uint_t numentries, boolean_t forever,
+ boolean_t inbound)
{
int i;
isaf_t *table = *tablep;
+ uint8_t protocol;
if (table == NULL)
return;
for (i = 0; i < numentries; i++) {
mutex_enter(&table[i].isaf_lock);
- while (table[i].isaf_ipsa != NULL)
+ while (table[i].isaf_ipsa != NULL) {
+ if (inbound && cl_inet_deletespi &&
+ (table[i].isaf_ipsa->ipsa_state !=
+ IPSA_STATE_ACTIVE_ELSEWHERE) &&
+ (table[i].isaf_ipsa->ipsa_state !=
+ IPSA_STATE_IDLE)) {
+ protocol = (table[i].isaf_ipsa->ipsa_type ==
+ SADB_SATYPE_AH) ? IPPROTO_AH : IPPROTO_ESP;
+ cl_inet_deletespi(protocol,
+ table[i].isaf_ipsa->ipsa_spi);
+ }
sadb_unlinkassoc(table[i].isaf_ipsa);
+ }
table[i].isaf_gen++;
mutex_exit(&table[i].isaf_lock);
if (forever)
@@ -1025,8 +1069,8 @@ sadb_flush(sadb_t *sp, netstack_t *ns)
* heels of a flush. With keysock's enforcement, however, this
* makes ESP's job easy.
*/
- sadb_destroyer(&sp->sdb_of, sp->sdb_hashsize, B_FALSE);
- sadb_destroyer(&sp->sdb_if, sp->sdb_hashsize, B_FALSE);
+ sadb_destroyer(&sp->sdb_of, sp->sdb_hashsize, B_FALSE, B_FALSE);
+ sadb_destroyer(&sp->sdb_if, sp->sdb_hashsize, B_FALSE, B_TRUE);
/* For each acquire, destroy it; leave the bucket mutex alone. */
sadb_destroy_acqlist(&sp->sdb_acq, sp->sdb_hashsize, B_FALSE, ns);
@@ -1035,8 +1079,8 @@ sadb_flush(sadb_t *sp, netstack_t *ns)
static void
sadb_destroy(sadb_t *sp, netstack_t *ns)
{
- sadb_destroyer(&sp->sdb_of, sp->sdb_hashsize, B_TRUE);
- sadb_destroyer(&sp->sdb_if, sp->sdb_hashsize, B_TRUE);
+ sadb_destroyer(&sp->sdb_of, sp->sdb_hashsize, B_TRUE, B_FALSE);
+ sadb_destroyer(&sp->sdb_if, sp->sdb_hashsize, B_TRUE, B_TRUE);
/* For each acquire, destroy it, including the bucket mutex. */
sadb_destroy_acqlist(&sp->sdb_acq, sp->sdb_hashsize, B_TRUE, ns);
@@ -1093,7 +1137,8 @@ sadbp_destroy(sadbp_t *spp, netstack_t *ns)
* EINVAL.
*/
int
-sadb_hardsoftchk(sadb_lifetime_t *hard, sadb_lifetime_t *soft)
+sadb_hardsoftchk(sadb_lifetime_t *hard, sadb_lifetime_t *soft,
+ sadb_lifetime_t *idle)
{
if (hard == NULL || soft == NULL)
return (0);
@@ -1118,6 +1163,28 @@ sadb_hardsoftchk(sadb_lifetime_t *hard, sadb_lifetime_t *soft)
hard->sadb_lifetime_usetime < soft->sadb_lifetime_usetime)
return (SADB_X_DIAGNOSTIC_USETIME_HSERR);
+ if (idle != NULL) {
+ if (hard->sadb_lifetime_addtime != 0 &&
+ idle->sadb_lifetime_addtime != 0 &&
+ hard->sadb_lifetime_addtime < idle->sadb_lifetime_addtime)
+ return (SADB_X_DIAGNOSTIC_ADDTIME_HSERR);
+
+ if (soft->sadb_lifetime_addtime != 0 &&
+ idle->sadb_lifetime_addtime != 0 &&
+ soft->sadb_lifetime_addtime < idle->sadb_lifetime_addtime)
+ return (SADB_X_DIAGNOSTIC_ADDTIME_HSERR);
+
+ if (hard->sadb_lifetime_usetime != 0 &&
+ idle->sadb_lifetime_usetime != 0 &&
+ hard->sadb_lifetime_usetime < idle->sadb_lifetime_usetime)
+ return (SADB_X_DIAGNOSTIC_USETIME_HSERR);
+
+ if (soft->sadb_lifetime_usetime != 0 &&
+ idle->sadb_lifetime_usetime != 0 &&
+ soft->sadb_lifetime_usetime < idle->sadb_lifetime_usetime)
+ return (SADB_X_DIAGNOSTIC_USETIME_HSERR);
+ }
+
return (0);
}
@@ -1342,6 +1409,7 @@ sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
sadb_ident_t *ident;
sadb_sens_t *sens;
sadb_ext_t *walker; /* For when we need a generic ext. pointer. */
+ sadb_x_replay_ctr_t *repl_ctr;
sadb_x_pair_t *pair_ext;
mblk_t *mp;
@@ -1349,6 +1417,7 @@ sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
uint8_t *cur, *end;
/* These indicate the presence of the above extension fields. */
boolean_t soft, hard, isrc, idst, auth, encr, sensinteg, srcid, dstid;
+ boolean_t idle;
boolean_t paired;
uint32_t otherspi;
@@ -1409,6 +1478,13 @@ sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
hard = B_FALSE;
}
+ if (ipsa->ipsa_idleaddlt != 0 || ipsa->ipsa_idleuselt != 0) {
+ alloclen += sizeof (sadb_lifetime_t);
+ idle = B_TRUE;
+ } else {
+ idle = B_FALSE;
+ }
+
/* Inner addresses. */
if (ipsa->ipsa_innerfam == 0) {
isrc = B_FALSE;
@@ -1489,6 +1565,10 @@ sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
if ((ipsa->ipsa_kmp != 0) || (ipsa->ipsa_kmc != 0))
alloclen += sizeof (sadb_x_kmc_t);
+ if (ipsa->ipsa_replay != 0) {
+ alloclen += sizeof (sadb_x_replay_ctr_t);
+ }
+
/* Make sure the allocation length is a multiple of 8 bytes. */
ASSERT((alloclen & 0x7) == 0);
@@ -1546,6 +1626,14 @@ sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
lt->sadb_lifetime_usetime = ipsa->ipsa_softuselt;
}
+ if (idle) {
+ lt++;
+ lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt));
+ lt->sadb_lifetime_exttype = SADB_X_EXT_LIFETIME_IDLE;
+ lt->sadb_lifetime_addtime = ipsa->ipsa_idleaddlt;
+ lt->sadb_lifetime_usetime = ipsa->ipsa_idleuselt;
+ }
+
cur = (uint8_t *)(lt + 1);
/* NOTE: Don't fill in ports here if we are a tunnel-mode SA. */
@@ -1703,6 +1791,15 @@ sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
walker->sadb_ext_len);
}
+ if (ipsa->ipsa_replay != 0) {
+ repl_ctr = (sadb_x_replay_ctr_t *)walker;
+ repl_ctr->sadb_x_rc_len = SADB_8TO64(sizeof (*repl_ctr));
+ repl_ctr->sadb_x_rc_exttype = SADB_X_EXT_REPLAY_VALUE;
+ repl_ctr->sadb_x_rc_replay32 = ipsa->ipsa_replay;
+ repl_ctr->sadb_x_rc_replay64 = 0;
+ walker = (sadb_ext_t *)(repl_ctr + 1);
+ }
+
bail:
/* Pardon any delays... */
mutex_exit(&ipsa->ipsa_lock);
@@ -1743,6 +1840,7 @@ sadb_strip(sadb_msg_t *samsg)
while ((uint8_t *)ext < msgend) {
if (ext->sadb_ext_type == SADB_EXT_RESERVED ||
ext->sadb_ext_type == SADB_EXT_KEY_AUTH ||
+ ext->sadb_ext_type == SADB_X_EXT_EDUMP ||
ext->sadb_ext_type == SADB_EXT_KEY_ENCRYPT) {
/*
* Aha! I found a header to be erased.
@@ -1859,6 +1957,7 @@ sadb_pfkey_echo(queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
case SADB_ADD:
case SADB_UPDATE:
case SADB_X_UPDATEPAIR:
+ case SADB_X_DELPAIR_STATE:
case SADB_FLUSH:
case SADB_DUMP:
/*
@@ -1870,11 +1969,9 @@ sadb_pfkey_echo(queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
* message.
*/
justecho:
- ASSERT(samsg->sadb_msg_type != SADB_DUMP ||
- samsg->sadb_msg_len == SADB_8TO64(sizeof (sadb_msg_t)));
-
if (ksi->ks_in_extv[SADB_EXT_KEY_AUTH] != NULL ||
- ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT] != NULL) {
+ ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT] != NULL ||
+ ksi->ks_in_extv[SADB_X_EXT_EDUMP] != NULL) {
sadb_strip(samsg);
/* Assume PF_KEY message is contiguous. */
ASSERT(mp->b_cont->b_cont == NULL);
@@ -2396,7 +2493,9 @@ struct sadb_purge_state
uint16_t sidtype;
uint16_t didtype;
uint32_t kmproto;
+ uint8_t sadb_sa_state;
mblk_t *mq;
+ sadb_t *sp;
};
static void
@@ -2424,6 +2523,9 @@ sadb_purge_cb(isaf_t *head, ipsa_t *entry, void *cookie)
return;
}
+ if (ps->inbnd) {
+ sadb_delete_cluster(entry);
+ }
entry->ipsa_state = IPSA_STATE_DEAD;
(void) sadb_torch_assoc(head, entry, ps->inbnd, &ps->mq);
}
@@ -2538,6 +2640,57 @@ sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp, queue_t *pfkey_q,
return (0);
}
+static void
+sadb_delpair_state(isaf_t *head, ipsa_t *entry, void *cookie)
+{
+ struct sadb_purge_state *ps = (struct sadb_purge_state *)cookie;
+ isaf_t *inbound_bucket;
+ ipsa_t *peer_assoc;
+
+ ASSERT(MUTEX_HELD(&head->isaf_lock));
+
+ mutex_enter(&entry->ipsa_lock);
+
+ if ((entry->ipsa_state != ps->sadb_sa_state) ||
+ ((ps->src != NULL) &&
+ !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, ps->src, ps->af))) {
+ mutex_exit(&entry->ipsa_lock);
+ return;
+ }
+
+ /*
+ * The isaf_t *, which is passed in , is always an outbound bucket,
+ * and we are preserving the outbound-then-inbound hash-bucket lock
+ * ordering. The sadb_walker() which triggers this function is called
+ * only on the outbound fanout, and the corresponding inbound bucket
+ * lock is safe to acquire here.
+ */
+
+ if (entry->ipsa_haspeer) {
+ inbound_bucket = INBOUND_BUCKET(ps->sp, entry->ipsa_spi);
+ mutex_enter(&inbound_bucket->isaf_lock);
+ peer_assoc = ipsec_getassocbyspi(inbound_bucket,
+ entry->ipsa_spi, entry->ipsa_srcaddr,
+ entry->ipsa_dstaddr, entry->ipsa_addrfam);
+ } else {
+ inbound_bucket = INBOUND_BUCKET(ps->sp, entry->ipsa_otherspi);
+ mutex_enter(&inbound_bucket->isaf_lock);
+ peer_assoc = ipsec_getassocbyspi(inbound_bucket,
+ entry->ipsa_otherspi, entry->ipsa_dstaddr,
+ entry->ipsa_srcaddr, entry->ipsa_addrfam);
+ }
+
+ entry->ipsa_state = IPSA_STATE_DEAD;
+ (void) sadb_torch_assoc(head, entry, B_FALSE, &ps->mq);
+ if (peer_assoc != NULL) {
+ mutex_enter(&peer_assoc->ipsa_lock);
+ peer_assoc->ipsa_state = IPSA_STATE_DEAD;
+ (void) sadb_torch_assoc(inbound_bucket, peer_assoc,
+ B_FALSE, &ps->mq);
+ }
+ mutex_exit(&inbound_bucket->isaf_lock);
+}
+
/*
* Common code to delete/get an SA.
*/
@@ -2555,15 +2708,51 @@ sadb_delget_sa(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
mblk_t *torchq = NULL;
uint_t error = 0;
- if (dstext == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
- return (EINVAL);
- }
if (assoc == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
return (EINVAL);
}
+ if (sadb_msg_type == SADB_X_DELPAIR_STATE) {
+ struct sockaddr_in *src;
+ struct sockaddr_in6 *src6;
+ struct sadb_purge_state ps;
+
+ if (srcext == NULL) {
+ *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
+ return (EINVAL);
+ }
+ ps.src = NULL;
+ ps.mq = NULL;
+ src = (struct sockaddr_in *)(srcext + 1);
+ ps.af = src->sin_family;
+ if (src->sin_family == AF_INET6) {
+ src6 = (struct sockaddr_in6 *)(srcext + 1);
+ ps.src = (uint32_t *)&src6->sin6_addr;
+ ps.sp = &spp->s_v6;
+ } else {
+ ps.src = (uint32_t *)&src->sin_addr;
+ ps.sp = &spp->s_v4;
+ }
+ ps.inbnd = B_FALSE;
+ ps.sadb_sa_state = assoc->sadb_sa_state;
+ sadb_walker(ps.sp->sdb_of, ps.sp->sdb_hashsize,
+ sadb_delpair_state, &ps);
+
+ if (ps.mq != NULL)
+ sadb_drain_torchq(pfkey_q, ps.mq);
+
+ ASSERT(mp->b_cont != NULL);
+ sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
+ ksi, NULL);
+ return (0);
+ }
+
+ if (dstext == NULL) {
+ *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
+ return (EINVAL);
+ }
+
ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
if (ipsapp == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
@@ -2585,6 +2774,9 @@ sadb_delget_sa(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
if (ipsapp->ipsap_sa_ptr != NULL) {
mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ if (ipsapp->ipsap_sa_ptr->ipsa_flags & IPSA_F_INBOUND) {
+ sadb_delete_cluster(ipsapp->ipsap_sa_ptr);
+ }
ipsapp->ipsap_sa_ptr->ipsa_state = IPSA_STATE_DEAD;
(void) sadb_torch_assoc(ipsapp->ipsap_bucket,
ipsapp->ipsap_sa_ptr, B_FALSE, &torchq);
@@ -2597,6 +2789,11 @@ sadb_delget_sa(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
if (ipsapp->ipsap_psa_ptr != NULL) {
mutex_enter(&ipsapp->ipsap_psa_ptr->ipsa_lock);
if (sadb_msg_type == SADB_X_DELPAIR) {
+ if (ipsapp->ipsap_psa_ptr->ipsa_flags &
+ IPSA_F_INBOUND) {
+ sadb_delete_cluster(
+ ipsapp->ipsap_psa_ptr);
+ }
ipsapp->ipsap_psa_ptr->ipsa_state =
IPSA_STATE_DEAD;
(void) sadb_torch_assoc(ipsapp->ipsap_pbucket,
@@ -2812,7 +3009,6 @@ get_ipsa_pair(sadb_sa_t *assoc, sadb_address_t *srcext, sadb_address_t *dstext,
ipsapp->ipsap_psa_ptr = ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
pair_spi, pair_dstaddr, pair_srcaddr, af);
mutex_exit(&ipsapp->ipsap_pbucket->isaf_lock);
-
ASSERT(ipsapp->ipsap_bucket != NULL);
ASSERT(ipsapp->ipsap_pbucket != NULL);
return (ipsapp);
@@ -2990,6 +3186,10 @@ sadb_common_add(queue_t *ip_q, queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
sadb_x_pair_t *pair_ext =
(sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
+ sadb_x_replay_ctr_t *replayext =
+ (sadb_x_replay_ctr_t *)ksi->ks_in_extv[SADB_X_EXT_REPLAY_VALUE];
+ uint8_t protocol =
+ (samsg->sadb_msg_satype == SADB_SATYPE_AH) ? IPPROTO_AH:IPPROTO_ESP;
#if 0
/*
* XXXMLS - When Trusted Solaris or Multi-Level Secure functionality
@@ -3003,12 +3203,15 @@ sadb_common_add(queue_t *ip_q, queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
sadb_lifetime_t *hard =
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
+ sadb_lifetime_t *idle =
+ (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
sa_family_t af;
int error = 0;
boolean_t isupdate = (newbie != NULL);
uint32_t *src_addr_ptr, *dst_addr_ptr, *isrc_addr_ptr, *idst_addr_ptr;
mblk_t *ctl_mp = NULL;
ipsec_stack_t *ipss = ns->netstack_ipsec;
+ int rcode;
if (srcext == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
@@ -3049,6 +3252,15 @@ sadb_common_add(queue_t *ip_q, queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
dst_addr_ptr = (uint32_t *)&dst6->sin6_addr;
}
+ if (!isupdate && (clone == B_TRUE || is_inbound == B_TRUE) &&
+ cl_inet_checkspi &&
+ (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
+ rcode = cl_inet_checkspi(protocol, assoc->sadb_sa_spi);
+ if (rcode == -1) {
+ return (EEXIST);
+ }
+ }
+
/*
* Check to see if the new SA will be cloned AND paired. The
* reason a SA will be cloned is the source or destination addresses
@@ -3147,7 +3359,8 @@ sadb_common_add(queue_t *ip_q, queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
src_addr_ptr, dst_addr_ptr);
newbie->ipsa_type = samsg->sadb_msg_satype;
- ASSERT(assoc->sadb_sa_state == SADB_SASTATE_MATURE);
+ ASSERT((assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
+ (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE));
newbie->ipsa_auth_alg = assoc->sadb_sa_auth;
newbie->ipsa_encr_alg = assoc->sadb_sa_encrypt;
@@ -3201,6 +3414,13 @@ sadb_common_add(queue_t *ip_q, queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
newbie->ipsa_hardalloc = hard->sadb_lifetime_allocations;
SET_EXPIRE(newbie, hardaddlt, hardexpiretime);
}
+ if (idle != NULL) {
+ newbie->ipsa_idleaddlt = idle->sadb_lifetime_addtime;
+ newbie->ipsa_idleuselt = idle->sadb_lifetime_usetime;
+ newbie->ipsa_idleexpiretime = newbie->ipsa_addtime +
+ newbie->ipsa_idleaddlt;
+ newbie->ipsa_idletime = newbie->ipsa_idleaddlt;
+ }
newbie->ipsa_authtmpl = NULL;
newbie->ipsa_encrtmpl = NULL;
@@ -3358,6 +3578,16 @@ sadb_common_add(queue_t *ip_q, queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
#endif
+ if (replayext != NULL) {
+ if ((replayext->sadb_x_rc_replay32 == 0) &&
+ (replayext->sadb_x_rc_replay64 != 0)) {
+ error = EOPNOTSUPP;
+ mutex_exit(&newbie->ipsa_lock);
+ goto error;
+ }
+ newbie->ipsa_replay = replayext->sadb_x_rc_replay32;
+ }
+
/* now that the SA has been updated, set its new state */
newbie->ipsa_state = assoc->sadb_sa_state;
@@ -3542,6 +3772,8 @@ sadb_set_usetime(ipsa_t *assoc)
mutex_enter(&assoc->ipsa_lock);
assoc->ipsa_lastuse = snapshot;
+ assoc->ipsa_idleexpiretime = snapshot + assoc->ipsa_idletime;
+
/*
* Caller does check usetime before calling me usually, and
* double-checking is better than a mutex_enter/exit hit.
@@ -3691,13 +3923,19 @@ sadb_expire_assoc(queue_t *pfkey_q, ipsa_t *assoc)
expire->sadb_lifetime_bytes = assoc->ipsa_hardbyteslt;
expire->sadb_lifetime_addtime = assoc->ipsa_hardaddlt;
expire->sadb_lifetime_usetime = assoc->ipsa_harduselt;
- } else {
- ASSERT(assoc->ipsa_state == IPSA_STATE_DYING);
+ } else if (assoc->ipsa_state == IPSA_STATE_DYING) {
expire->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
expire->sadb_lifetime_allocations = assoc->ipsa_softalloc;
expire->sadb_lifetime_bytes = assoc->ipsa_softbyteslt;
expire->sadb_lifetime_addtime = assoc->ipsa_softaddlt;
expire->sadb_lifetime_usetime = assoc->ipsa_softuselt;
+ } else {
+ ASSERT(assoc->ipsa_state == IPSA_STATE_MATURE);
+ expire->sadb_lifetime_exttype = SADB_X_EXT_LIFETIME_IDLE;
+ expire->sadb_lifetime_allocations = 0;
+ expire->sadb_lifetime_bytes = 0;
+ expire->sadb_lifetime_addtime = assoc->ipsa_idleaddlt;
+ expire->sadb_lifetime_usetime = assoc->ipsa_idleuselt;
}
mp->b_wptr = sadb_make_addr_ext(mp->b_wptr, end, SADB_EXT_ADDRESS_SRC,
@@ -3745,7 +3983,8 @@ sadb_age_bytes(queue_t *pfkey_q, ipsa_t *assoc, uint64_t bytes,
newtotal = assoc->ipsa_bytes + bytes;
if (assoc->ipsa_hardbyteslt != 0 &&
newtotal >= assoc->ipsa_hardbyteslt) {
- if (assoc->ipsa_state < IPSA_STATE_DEAD) {
+ if (assoc->ipsa_state != IPSA_STATE_DEAD) {
+ sadb_delete_cluster(assoc);
/*
* Send EXPIRE message to PF_KEY. May wish to pawn
* this off on another non-interrupt thread. Also
@@ -3879,7 +4118,10 @@ sadb_age_assoc(isaf_t *head, queue_t *pfkey_q, ipsa_t *assoc,
mutex_enter(&assoc->ipsa_lock);
- if ((assoc->ipsa_state == IPSA_STATE_LARVAL) &&
+ if (((assoc->ipsa_state == IPSA_STATE_LARVAL) ||
+ ((assoc->ipsa_state == IPSA_STATE_IDLE) ||
+ (assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) &&
+ (assoc->ipsa_hardexpiretime != 0))) &&
(assoc->ipsa_hardexpiretime <= current)) {
assoc->ipsa_state = IPSA_STATE_DEAD;
return (sadb_torch_assoc(head, assoc, inbound, mq));
@@ -3898,6 +4140,10 @@ sadb_age_assoc(isaf_t *head, queue_t *pfkey_q, ipsa_t *assoc,
if (assoc->ipsa_state == IPSA_STATE_DEAD)
return (sadb_torch_assoc(head, assoc, inbound, mq));
+ if (inbound) {
+ sadb_delete_cluster(assoc);
+ }
+
/*
* Send SADB_EXPIRE with hard lifetime, delay for unlinking.
*/
@@ -3943,6 +4189,18 @@ sadb_age_assoc(isaf_t *head, queue_t *pfkey_q, ipsa_t *assoc,
retval = assoc;
}
sadb_expire_assoc(pfkey_q, assoc);
+ } else if (assoc->ipsa_idletime != 0 &&
+ assoc->ipsa_idleexpiretime <= current) {
+ if (assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
+ assoc->ipsa_state = IPSA_STATE_IDLE;
+ }
+
+ /*
+ * Need to handle Mature case
+ */
+ if (assoc->ipsa_state == IPSA_STATE_MATURE && !inbound) {
+ sadb_expire_assoc(pfkey_q, assoc);
+ }
} else {
/* Check idle time activities. */
dropped_mutex = sadb_idle_activities(assoc,
@@ -4132,7 +4390,7 @@ sadb_retimeout(hrtime_t begin, queue_t *pfkey_q, void (*ager)(void *),
*/
static void
sadb_update_lifetimes(ipsa_t *assoc, sadb_lifetime_t *hard,
- sadb_lifetime_t *soft, boolean_t outbound)
+ sadb_lifetime_t *soft, sadb_lifetime_t *idle, boolean_t outbound)
{
mutex_enter(&assoc->ipsa_lock);
@@ -4208,15 +4466,100 @@ sadb_update_lifetimes(ipsa_t *assoc, sadb_lifetime_t *hard,
if (soft->sadb_lifetime_allocations != 0)
assoc->ipsa_softalloc = soft->sadb_lifetime_allocations;
}
+
+ if (idle != NULL) {
+ time_t current = gethrestime_sec();
+ if ((assoc->ipsa_idleexpiretime <= current) &&
+ (assoc->ipsa_idleaddlt == idle->sadb_lifetime_addtime)) {
+ assoc->ipsa_idleexpiretime =
+ current + assoc->ipsa_idleaddlt;
+ }
+ if (idle->sadb_lifetime_addtime != 0)
+ assoc->ipsa_idleaddlt = idle->sadb_lifetime_addtime;
+ if (idle->sadb_lifetime_usetime != 0)
+ assoc->ipsa_idleuselt = idle->sadb_lifetime_usetime;
+ if (assoc->ipsa_idleaddlt != 0) {
+ assoc->ipsa_idleexpiretime =
+ current + idle->sadb_lifetime_addtime;
+ assoc->ipsa_idletime = idle->sadb_lifetime_addtime;
+ }
+ if (assoc->ipsa_idleuselt != 0) {
+ if (assoc->ipsa_idletime != 0) {
+ assoc->ipsa_idletime = min(assoc->ipsa_idletime,
+ assoc->ipsa_idleuselt);
+ assoc->ipsa_idleexpiretime =
+ current + assoc->ipsa_idletime;
+ } else {
+ assoc->ipsa_idleexpiretime =
+ current + assoc->ipsa_idleuselt;
+ assoc->ipsa_idletime = assoc->ipsa_idleuselt;
+ }
+ }
+ }
mutex_exit(&assoc->ipsa_lock);
}
+static int
+sadb_update_state(ipsa_t *assoc, uint_t new_state, mblk_t **ipkt_lst)
+{
+ int rcode = 0;
+ time_t current = gethrestime_sec();
+
+ mutex_enter(&assoc->ipsa_lock);
+
+ switch (new_state) {
+ case SADB_X_SASTATE_ACTIVE_ELSEWHERE:
+ if (assoc->ipsa_state == SADB_X_SASTATE_IDLE) {
+ assoc->ipsa_state = IPSA_STATE_ACTIVE_ELSEWHERE;
+ assoc->ipsa_idleexpiretime =
+ current + assoc->ipsa_idletime;
+ }
+ break;
+ case SADB_X_SASTATE_IDLE:
+ if (assoc->ipsa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
+ assoc->ipsa_state = IPSA_STATE_IDLE;
+ assoc->ipsa_idleexpiretime =
+ current + assoc->ipsa_idletime;
+ } else {
+ rcode = EINVAL;
+ }
+ break;
+
+ case SADB_X_SASTATE_ACTIVE:
+ if (assoc->ipsa_state != SADB_X_SASTATE_IDLE) {
+ rcode = EINVAL;
+ break;
+ }
+ assoc->ipsa_state = IPSA_STATE_MATURE;
+ assoc->ipsa_idleexpiretime = current + assoc->ipsa_idletime;
+
+ if (ipkt_lst == NULL) {
+ break;
+ }
+
+ if (assoc->ipsa_bpkt_head != NULL) {
+ *ipkt_lst = assoc->ipsa_bpkt_head;
+ assoc->ipsa_bpkt_head = assoc->ipsa_bpkt_tail = NULL;
+ assoc->ipsa_mblkcnt = 0;
+ } else {
+ *ipkt_lst = NULL;
+ }
+ break;
+ default:
+ rcode = EINVAL;
+ break;
+ }
+
+ mutex_exit(&assoc->ipsa_lock);
+ return (rcode);
+}
+
/*
* Common code to update an SA.
*/
int
-sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
+sadb_update_sa(mblk_t *mp, keysock_in_t *ksi, mblk_t **ipkt_lst,
sadbp_t *spp, int *diagnostic, queue_t *pfkey_q,
int (*add_sa_func)(mblk_t *, keysock_in_t *, int *, netstack_t *),
netstack_t *ns, uint8_t sadb_msg_type)
@@ -4230,16 +4573,21 @@ sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
(sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
+ sadb_x_replay_ctr_t *replext =
+ (sadb_x_replay_ctr_t *)ksi->ks_in_extv[SADB_X_EXT_REPLAY_VALUE];
sadb_lifetime_t *soft =
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
sadb_lifetime_t *hard =
(sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
+ sadb_lifetime_t *idle =
+ (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
sadb_x_pair_t *pair_ext =
(sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
ipsa_t *echo_target = NULL;
int error = 0;
ipsap_t *ipsapp = NULL;
uint32_t kmp = 0, kmc = 0;
+ time_t current = gethrestime_sec();
/* I need certain extensions present for either UPDATE message. */
@@ -4278,6 +4626,50 @@ sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
}
}
+ if (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
+ if (ipsapp->ipsap_sa_ptr != NULL &&
+ ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_IDLE) {
+ if ((error = sadb_update_state(ipsapp->ipsap_sa_ptr,
+ assoc->sadb_sa_state, NULL)) != 0) {
+ *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
+ goto bail;
+ }
+ }
+ if (ipsapp->ipsap_psa_ptr != NULL &&
+ ipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_IDLE) {
+ if ((error = sadb_update_state(ipsapp->ipsap_psa_ptr,
+ assoc->sadb_sa_state, NULL)) != 0) {
+ *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
+ goto bail;
+ }
+ }
+ }
+ if (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE) {
+ if (ipsapp->ipsap_sa_ptr != NULL) {
+ error = sadb_update_state(ipsapp->ipsap_sa_ptr,
+ assoc->sadb_sa_state,
+ (ipsapp->ipsap_sa_ptr->ipsa_flags &
+ IPSA_F_INBOUND) ? ipkt_lst : NULL);
+ if (error) {
+ *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
+ goto bail;
+ }
+ }
+ if (ipsapp->ipsap_psa_ptr != NULL) {
+ error = sadb_update_state(ipsapp->ipsap_psa_ptr,
+ assoc->sadb_sa_state,
+ (ipsapp->ipsap_psa_ptr->ipsa_flags &
+ IPSA_F_INBOUND) ? ipkt_lst : NULL);
+ if (error) {
+ *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
+ goto bail;
+ }
+ }
+ sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
+ ksi, echo_target);
+ goto bail;
+ }
+
/*
* Reality checks for updates of active associations.
* Sundry first-pass UPDATE-specific reality checks.
@@ -4285,7 +4677,8 @@ sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
* XXX STATS : logging/stats here?
*/
- if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) {
+ if (!((assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
+ (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE))) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
error = EINVAL;
goto bail;
@@ -4301,7 +4694,8 @@ sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
error = EOPNOTSUPP;
goto bail;
}
- if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0) {
+
+ if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0) {
error = EINVAL;
goto bail;
}
@@ -4336,6 +4730,17 @@ sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
error = EINVAL;
goto bail;
}
+ /*
+ * Do not allow replay value change for MATURE or LARVAL SA.
+ */
+
+ if ((replext != NULL) &&
+ ((ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) ||
+ (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_MATURE))) {
+ *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
+ error = EINVAL;
+ goto bail;
+ }
}
if (ipsapp->ipsap_psa_ptr != NULL) {
@@ -4361,17 +4766,45 @@ sadb_update_sa(mblk_t *mp, keysock_in_t *ksi,
}
if (ipsapp->ipsap_sa_ptr != NULL) {
- sadb_update_lifetimes(ipsapp->ipsap_sa_ptr, hard, soft, B_TRUE);
+ sadb_update_lifetimes(ipsapp->ipsap_sa_ptr, hard, soft,
+ idle, B_TRUE);
if (kmp != 0)
ipsapp->ipsap_sa_ptr->ipsa_kmp = kmp;
if (kmc != 0)
ipsapp->ipsap_sa_ptr->ipsa_kmc = kmc;
+ if ((replext != NULL) &&
+ (ipsapp->ipsap_sa_ptr->ipsa_replay_wsize != 0)) {
+ /*
+ * If an inbound SA, update the replay counter
+ * and check off all the other sequence number
+ */
+ if (ksi->ks_in_dsttype == KS_IN_ADDR_ME) {
+ if (!sadb_replay_check(ipsapp->ipsap_sa_ptr,
+ replext->sadb_x_rc_replay32)) {
+ error = EINVAL;
+ goto bail;
+ }
+ mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ ipsapp->ipsap_sa_ptr->ipsa_idleexpiretime =
+ current +
+ ipsapp->ipsap_sa_ptr->ipsa_idletime;
+ mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ } else {
+ mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ ipsapp->ipsap_sa_ptr->ipsa_replay =
+ replext->sadb_x_rc_replay32;
+ ipsapp->ipsap_sa_ptr->ipsa_idleexpiretime =
+ current +
+ ipsapp->ipsap_sa_ptr->ipsa_idletime;
+ mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ }
+ }
}
if (sadb_msg_type == SADB_X_UPDATEPAIR) {
if (ipsapp->ipsap_psa_ptr != NULL) {
sadb_update_lifetimes(ipsapp->ipsap_psa_ptr, hard, soft,
- B_FALSE);
+ idle, B_FALSE);
if (kmp != 0)
ipsapp->ipsap_psa_ptr->ipsa_kmp = kmp;
if (kmc != 0)
@@ -4454,7 +4887,8 @@ update_pairing(ipsap_t *ipsapp, keysock_in_t *ksi, int *diagnostic,
undo_pair = B_TRUE;
} else {
ipsa_flags = oipsapp->ipsap_psa_ptr->ipsa_flags;
- if (oipsapp->ipsap_psa_ptr->ipsa_state > IPSA_STATE_MATURE) {
+ if ((oipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) ||
+ (oipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DYING)) {
/* Its dead Jim! */
*diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
undo_pair = B_TRUE;
@@ -5377,7 +5811,7 @@ sadb_setup_acquire(ipsacq_t *acqrec, uint8_t satype, ipsec_stack_t *ipss)
*/
ipsa_t *
sadb_getspi(keysock_in_t *ksi, uint32_t master_spi, int *diagnostic,
- netstack_t *ns)
+ netstack_t *ns, uint_t sa_type)
{
sadb_address_t *src =
(sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC],
@@ -5389,6 +5823,8 @@ sadb_getspi(keysock_in_t *ksi, uint32_t master_spi, int *diagnostic,
uint32_t *srcaddr, *dstaddr;
sa_family_t af;
uint32_t add, min, max;
+ uint8_t protocol =
+ (sa_type == SADB_SATYPE_AH) ? IPPROTO_AH : IPPROTO_ESP;
if (src == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
@@ -5432,7 +5868,12 @@ sadb_getspi(keysock_in_t *ksi, uint32_t master_spi, int *diagnostic,
if (master_spi < min || master_spi > max) {
/* Return a random value in the range. */
- (void) random_get_pseudo_bytes((uint8_t *)&add, sizeof (add));
+ if (cl_inet_getspi) {
+ cl_inet_getspi(protocol, (uint8_t *)&add, sizeof (add));
+ } else {
+ (void) random_get_pseudo_bytes((uint8_t *)&add,
+ sizeof (add));
+ }
master_spi = min + (add % (max - min + 1));
}
@@ -5801,7 +6242,7 @@ ipsec_udp_pol(ipsec_selector_t *sel, ipsec_policy_t **ppp, ip_stack_t *ipst)
conn_t *connp = NULL;
ipsec_selector_t portonly;
- bzero((void*)&portonly, sizeof (portonly));
+ bzero((void *)&portonly, sizeof (portonly));
if (sel->ips_local_port == 0)
return;
@@ -6413,6 +6854,8 @@ sadb_set_lpkt(ipsa_t *ipsa, mblk_t *npkt, netstack_t *ns)
mblk_t *opkt;
ipsec_stack_t *ipss = ns->netstack_ipsec;
+ ASSERT(ipsa->ipsa_state == IPSA_STATE_LARVAL);
+
membar_producer();
do {
opkt = ipsa->ipsa_lpkt;
@@ -6440,6 +6883,51 @@ sadb_clear_lpkt(ipsa_t *ipsa)
return (opkt);
}
+void
+sadb_buf_pkt(ipsa_t *ipsa, mblk_t *bpkt, netstack_t *ns)
+{
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
+
+ ASSERT(ipsa->ipsa_state == IPSA_STATE_IDLE);
+ mutex_enter(&ipsa->ipsa_lock);
+ ipsa->ipsa_mblkcnt++;
+ if (ipsa->ipsa_bpkt_head == NULL) {
+ ipsa->ipsa_bpkt_head = ipsa->ipsa_bpkt_tail = bpkt;
+ } else {
+ ipsa->ipsa_bpkt_tail->b_next = bpkt;
+ ipsa->ipsa_bpkt_tail = bpkt;
+ if (ipsa->ipsa_mblkcnt > SADB_MAX_IDLEPKTS) {
+ mblk_t *tmp;
+ tmp = ipsa->ipsa_bpkt_head;
+ ipsa->ipsa_bpkt_head = ipsa->ipsa_bpkt_head->b_next;
+ ip_drop_packet(tmp, B_TRUE, NULL, NULL,
+ DROPPER(ipss, ipds_sadb_inidle_overflow),
+ &ipss->ipsec_sadb_dropper);
+ ipsa->ipsa_mblkcnt --;
+ }
+ }
+ mutex_exit(&ipsa->ipsa_lock);
+
+}
+
+/*
+ * Stub function that taskq_dispatch() invokes to take the mblk (in arg)
+ * and put into STREAMS again.
+ */
+void
+sadb_clear_buf_pkt(void *ipkt)
+{
+ mblk_t *tmp, *buf_pkt;
+
+ buf_pkt = (mblk_t *)ipkt;
+
+ while (buf_pkt != NULL) {
+ tmp = buf_pkt->b_next;
+ buf_pkt->b_next = NULL;
+ ip_fanout_proto_again(buf_pkt, NULL, NULL, NULL);
+ buf_pkt = tmp;
+ }
+}
/*
* Walker callback used by sadb_alg_update() to free/create crypto
* context template when a crypto software provider is removed or
diff --git a/usr/src/uts/common/inet/ipdrop.h b/usr/src/uts/common/inet/ipdrop.h
index 048f2490f7..88dcda264c 100644
--- a/usr/src/uts/common/inet/ipdrop.h
+++ b/usr/src/uts/common/inet/ipdrop.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _INET_IPDROP_H
#define _INET_IPDROP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -64,6 +62,8 @@ struct ip_dropstats {
/* SADB-specific drop statistics. */
kstat_named_t ipds_sadb_inlarval_timeout;
kstat_named_t ipds_sadb_inlarval_replace;
+ kstat_named_t ipds_sadb_inidle_timeout;
+ kstat_named_t ipds_sadb_inidle_overflow;
kstat_named_t ipds_sadb_acquire_nomem;
kstat_named_t ipds_sadb_acquire_toofull;
kstat_named_t ipds_sadb_acquire_timeout;
diff --git a/usr/src/uts/common/inet/sadb.h b/usr/src/uts/common/inet/sadb.h
index 224d1fd50c..ca2e983e71 100644
--- a/usr/src/uts/common/inet/sadb.h
+++ b/usr/src/uts/common/inet/sadb.h
@@ -26,8 +26,6 @@
#ifndef _INET_SADB_H
#define _INET_SADB_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -87,6 +85,10 @@ typedef struct ipsa_s {
uint64_t *ipsa_integ; /* Integrity bitmap */
uint64_t *ipsa_sens; /* Sensitivity bitmap */
mblk_t *ipsa_lpkt; /* Packet received while larval (CAS me) */
+ mblk_t *ipsa_bpkt_head; /* Packets received while idle */
+ mblk_t *ipsa_bpkt_tail;
+#define SADB_MAX_IDLEPKTS 100
+ uint8_t ipsa_mblkcnt; /* Number of packets received while idle */
/*
* PF_KEYv2 supports a replay window size of 255. Hence there is a
@@ -137,9 +139,11 @@ typedef struct ipsa_s {
time_t ipsa_addtime; /* Time I was added. */
time_t ipsa_usetime; /* Time of my first use. */
time_t ipsa_lastuse; /* Time of my last use. */
+ time_t ipsa_idletime; /* Seconds of idle time */
time_t ipsa_last_nat_t_ka; /* Time of my last NAT-T keepalive. */
time_t ipsa_softexpiretime; /* Time of my first soft expire. */
time_t ipsa_hardexpiretime; /* Time of my first hard expire. */
+ time_t ipsa_idleexpiretime; /* Time of my next idle expire time */
/*
* The following fields are directly reflected in PF_KEYv2 LIFETIME
@@ -150,6 +154,8 @@ typedef struct ipsa_s {
time_t ipsa_softuselt; /* Seconds of soft lifetime after first use. */
time_t ipsa_hardaddlt; /* Seconds of hard lifetime after add. */
time_t ipsa_harduselt; /* Seconds of hard lifetime after first use. */
+ time_t ipsa_idleaddlt; /* Seconds of idle time after add */
+ time_t ipsa_idleuselt; /* Seconds of idle time after first use */
uint64_t ipsa_softbyteslt; /* Bytes of soft lifetime. */
uint64_t ipsa_hardbyteslt; /* Bytes of hard lifetime. */
uint64_t ipsa_bytes; /* Bytes encrypted/authed by this SA. */
@@ -364,10 +370,12 @@ typedef struct ipsa_s {
/* SA states are important for handling UPDATE PF_KEY messages. */
-#define IPSA_STATE_LARVAL SADB_SASTATE_LARVAL
-#define IPSA_STATE_MATURE SADB_SASTATE_MATURE
-#define IPSA_STATE_DYING SADB_SASTATE_DYING
-#define IPSA_STATE_DEAD SADB_SASTATE_DEAD
+#define IPSA_STATE_LARVAL SADB_SASTATE_LARVAL
+#define IPSA_STATE_MATURE SADB_SASTATE_MATURE
+#define IPSA_STATE_DYING SADB_SASTATE_DYING
+#define IPSA_STATE_DEAD SADB_SASTATE_DEAD
+#define IPSA_STATE_IDLE SADB_X_SASTATE_IDLE
+#define IPSA_STATE_ACTIVE_ELSEWHERE SADB_X_SASTATE_ACTIVE_ELSEWHERE
/*
* NOTE: If the document authors do things right in defining algorithms, we'll
@@ -599,7 +607,7 @@ void sadb_unlinkassoc(ipsa_t *);
/* Support routines to interface a keysock consumer to PF_KEY. */
mblk_t *sadb_keysock_out(minor_t);
-int sadb_hardsoftchk(sadb_lifetime_t *, sadb_lifetime_t *);
+int sadb_hardsoftchk(sadb_lifetime_t *, sadb_lifetime_t *, sadb_lifetime_t *);
void sadb_pfkey_echo(queue_t *, mblk_t *, sadb_msg_t *, struct keysock_in_s *,
ipsa_t *);
void sadb_pfkey_error(queue_t *, mblk_t *, int, int, uint_t);
@@ -617,7 +625,7 @@ int sadb_common_add(queue_t *, queue_t *, mblk_t *, sadb_msg_t *,
netstack_t *, sadbp_t *);
void sadb_set_usetime(ipsa_t *);
boolean_t sadb_age_bytes(queue_t *, ipsa_t *, uint64_t, boolean_t);
-int sadb_update_sa(mblk_t *, keysock_in_t *, sadbp_t *,
+int sadb_update_sa(mblk_t *, keysock_in_t *, mblk_t **, sadbp_t *,
int *, queue_t *, int (*)(mblk_t *, keysock_in_t *, int *, netstack_t *),
netstack_t *, uint8_t);
void sadb_acquire(mblk_t *, ipsec_out_t *, boolean_t, boolean_t);
@@ -625,11 +633,11 @@ void sadb_acquire(mblk_t *, ipsec_out_t *, boolean_t, boolean_t);
void sadb_destroy_acquire(ipsacq_t *, netstack_t *);
struct ipsec_stack;
mblk_t *sadb_setup_acquire(ipsacq_t *, uint8_t, struct ipsec_stack *);
-ipsa_t *sadb_getspi(keysock_in_t *, uint32_t, int *, netstack_t *);
+ipsa_t *sadb_getspi(keysock_in_t *, uint32_t, int *, netstack_t *, uint_t);
void sadb_in_acquire(sadb_msg_t *, sadbp_t *, queue_t *, netstack_t *);
boolean_t sadb_replay_check(ipsa_t *, uint32_t);
boolean_t sadb_replay_peek(ipsa_t *, uint32_t);
-int sadb_dump(queue_t *, mblk_t *, minor_t, sadb_t *);
+int sadb_dump(queue_t *, mblk_t *, keysock_in_t *, sadb_t *);
void sadb_replay_delete(ipsa_t *);
void sadb_ager(sadb_t *, queue_t *, queue_t *, int, netstack_t *);
@@ -638,6 +646,28 @@ timeout_id_t sadb_retimeout(hrtime_t, queue_t *, void (*)(void *), void *,
void sadb_sa_refrele(void *target);
void sadb_set_lpkt(ipsa_t *, mblk_t *, netstack_t *);
mblk_t *sadb_clear_lpkt(ipsa_t *);
+void sadb_buf_pkt(ipsa_t *, mblk_t *, netstack_t *);
+void sadb_clear_buf_pkt(void *ipkt);
+
+#define HANDLE_BUF_PKT(taskq, stack, dropper, buf_pkt) \
+{ \
+ if (buf_pkt != NULL) { \
+ if (taskq_dispatch(taskq, sadb_clear_buf_pkt, \
+ (void *) buf_pkt, TQ_NOSLEEP) == 0) { \
+ /* Dispatch was unsuccessful drop the packets. */ \
+ mblk_t *tmp; \
+ while (buf_pkt != NULL) { \
+ tmp = buf_pkt->b_next; \
+ buf_pkt->b_next = NULL; \
+ ip_drop_packet(buf_pkt, B_TRUE, NULL, \
+ NULL, DROPPER(stack, \
+ ipds_sadb_inidle_timeout), \
+ &dropper); \
+ buf_pkt = tmp; \
+ } \
+ } \
+ } \
+} \
/*
* Hw accel-related calls (downloading sadb to driver)
@@ -810,6 +840,7 @@ do { \
_NOTE(CONSTCOND) \
} while (0)
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/net/pfkeyv2.h b/usr/src/uts/common/net/pfkeyv2.h
index 21154be38a..777e0dcaa0 100644
--- a/usr/src/uts/common/net/pfkeyv2.h
+++ b/usr/src/uts/common/net/pfkeyv2.h
@@ -26,8 +26,6 @@
#ifndef _NET_PFKEYV2_H
#define _NET_PFKEYV2_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Definitions and structures for PF_KEY version 2. See RFC 2367 for
* more details. SA == Security Association, which is what PF_KEY provides
@@ -498,6 +496,29 @@ typedef struct sadb_x_pair {
} sadb_x_pair_t;
/*
+ * For the Sequence numbers to be used with SADB_DUMP, SADB_GET, SADB_UPDATE.
+ */
+
+typedef struct sadb_x_replay_ctr {
+ uint16_t sadb_x_rc_len;
+ uint16_t sadb_x_rc_exttype;
+ uint32_t sadb_x_rc_replay32; /* For 240x SAs. */
+ uint64_t sadb_x_rc_replay64; /* For 430x SAs. */
+} sadb_x_replay_ctr_t;
+
+/*
+ * For extended DUMP request. Dumps the SAs which were idle for
+ * longer than the timeout specified.
+ */
+
+typedef struct sadb_x_edump {
+ uint16_t sadb_x_edump_len;
+ uint16_t sadb_x_edump_exttype;
+ uint32_t sadb_x_edump_reserved;
+ uint64_t sadb_x_edump_timeout;
+} sadb_x_edump_t;
+
+/*
* Base message types.
*/
@@ -515,8 +536,9 @@ typedef struct sadb_x_pair {
#define SADB_X_PROMISC 11
#define SADB_X_INVERSE_ACQUIRE 12
#define SADB_X_UPDATEPAIR 13
-#define SADB_X_DELPAIR 14
-#define SADB_MAX 14
+#define SADB_X_DELPAIR 14
+#define SADB_X_DELPAIR_STATE 15
+#define SADB_MAX 15
/*
* SA flags
@@ -553,12 +575,15 @@ typedef struct sadb_x_pair {
* SA state.
*/
-#define SADB_SASTATE_LARVAL 0
-#define SADB_SASTATE_MATURE 1
-#define SADB_SASTATE_DYING 2
-#define SADB_SASTATE_DEAD 3
+#define SADB_SASTATE_LARVAL 0
+#define SADB_SASTATE_MATURE 1
+#define SADB_SASTATE_DYING 2
+#define SADB_SASTATE_DEAD 3
+#define SADB_X_SASTATE_ACTIVE_ELSEWHERE 4
+#define SADB_X_SASTATE_IDLE 5
+#define SADB_X_SASTATE_ACTIVE 6
-#define SADB_SASTATE_MAX 3
+#define SADB_SASTATE_MAX 6
/*
* SA type. Gaps are present in the number space because (for the time being)
@@ -633,8 +658,11 @@ typedef struct sadb_x_pair {
#define SADB_X_EXT_ADDRESS_NATT_REM 21
#define SADB_X_EXT_ADDRESS_INNER_DST 22
#define SADB_X_EXT_PAIR 23
+#define SADB_X_EXT_REPLAY_VALUE 24
+#define SADB_X_EXT_EDUMP 25
+#define SADB_X_EXT_LIFETIME_IDLE 26
-#define SADB_EXT_MAX 23
+#define SADB_EXT_MAX 26
/*
* Identity types.
diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s
index a1352a260b..e4e34559ab 100644
--- a/usr/src/uts/intel/ia32/ml/modstubs.s
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s
@@ -516,6 +516,7 @@ fcnname/**/_info: \
WSTUB(ipsecah, sadb_insertassoc, nomod_zero);
WSTUB(ipsecah, ipsecah_in_assocfailure, nomod_zero);
WSTUB(ipsecah, sadb_set_lpkt, nomod_zero);
+ WSTUB(ipsecah, sadb_buf_pkt, nomod_zero);
WSTUB(ipsecah, ipsecah_icmp_error, nomod_zero);
END_MODULE(ipsecah);
#endif
diff --git a/usr/src/uts/intel/ip/ip.global-objs.debug64 b/usr/src/uts/intel/ip/ip.global-objs.debug64
index b850d68d82..01f8be179d 100644
--- a/usr/src/uts/intel/ip/ip.global-objs.debug64
+++ b/usr/src/uts/intel/ip/ip.global-objs.debug64
@@ -33,6 +33,10 @@ cl_inet_isclusterwide
cl_inet_listen
cl_inet_unbind
cl_inet_unlisten
+cl_inet_getspi
+cl_inet_checkspi
+cl_inet_deletespi
+cl_inet_idlesa
cl_sctp_assoc_change
cl_sctp_check_addrs
cl_sctp_connect
diff --git a/usr/src/uts/intel/ip/ip.global-objs.obj64 b/usr/src/uts/intel/ip/ip.global-objs.obj64
index b31f005c78..17712b7c14 100644
--- a/usr/src/uts/intel/ip/ip.global-objs.obj64
+++ b/usr/src/uts/intel/ip/ip.global-objs.obj64
@@ -33,6 +33,10 @@ cl_inet_isclusterwide
cl_inet_listen
cl_inet_unbind
cl_inet_unlisten
+cl_inet_getspi
+cl_inet_checkspi
+cl_inet_deletespi
+cl_inet_idlesa
cl_sctp_assoc_change
cl_sctp_check_addrs
cl_sctp_connect
diff --git a/usr/src/uts/sparc/ip/ip.global-objs.debug64 b/usr/src/uts/sparc/ip/ip.global-objs.debug64
index b850d68d82..01f8be179d 100644
--- a/usr/src/uts/sparc/ip/ip.global-objs.debug64
+++ b/usr/src/uts/sparc/ip/ip.global-objs.debug64
@@ -33,6 +33,10 @@ cl_inet_isclusterwide
cl_inet_listen
cl_inet_unbind
cl_inet_unlisten
+cl_inet_getspi
+cl_inet_checkspi
+cl_inet_deletespi
+cl_inet_idlesa
cl_sctp_assoc_change
cl_sctp_check_addrs
cl_sctp_connect
diff --git a/usr/src/uts/sparc/ip/ip.global-objs.obj64 b/usr/src/uts/sparc/ip/ip.global-objs.obj64
index b31f005c78..17712b7c14 100644
--- a/usr/src/uts/sparc/ip/ip.global-objs.obj64
+++ b/usr/src/uts/sparc/ip/ip.global-objs.obj64
@@ -33,6 +33,10 @@ cl_inet_isclusterwide
cl_inet_listen
cl_inet_unbind
cl_inet_unlisten
+cl_inet_getspi
+cl_inet_checkspi
+cl_inet_deletespi
+cl_inet_idlesa
cl_sctp_assoc_change
cl_sctp_check_addrs
cl_sctp_connect
diff --git a/usr/src/uts/sparc/ml/modstubs.s b/usr/src/uts/sparc/ml/modstubs.s
index 15377f736c..b83f3af53a 100644
--- a/usr/src/uts/sparc/ml/modstubs.s
+++ b/usr/src/uts/sparc/ml/modstubs.s
@@ -404,6 +404,7 @@ stubs_base:
WSTUB(ipsecah, sadb_insertassoc, nomod_zero);
WSTUB(ipsecah, ipsecah_in_assocfailure, nomod_zero);
WSTUB(ipsecah, sadb_set_lpkt, nomod_zero);
+ WSTUB(ipsecah, sadb_buf_pkt, nomod_zero);
WSTUB(ipsecah, ipsecah_icmp_error, nomod_zero);
END_MODULE(ipsecah);
#endif