diff options
| author | Thejaswini Singarajipura <Thejaswini.Singarajipura@Sun.COM> | 2008-09-29 19:18:37 -0400 |
|---|---|---|
| committer | Thejaswini Singarajipura <Thejaswini.Singarajipura@Sun.COM> | 2008-09-29 19:18:37 -0400 |
| commit | 9c2c14ab194d42014417b385d6bf226ba1a37995 (patch) | |
| tree | b8b65c127452666517bb3ad6f156dfdfa85dcc7a /usr | |
| parent | 32d4e834df8b1687b6fe0dcb4bc2c56b9c1823af (diff) | |
| download | illumos-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')
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 |
